如何自己编写一个交通仿真软件(二)原野。
2014-12-23 10:58
330 查看
该文章也同时在开源中国(www.oschina.net 发布:非广告)作者为:sapperjiang。版权:sapperjiang所有。 http://my.oschina.net/u/214547/admin/edit-blog?blog=358845
3 葵花宝典
首先,抛开理论。我将灌输一段心法(鄙视?心法也是理论)如下(感谢自己的硕士论文,我打字打够了,女票的小手在哪里?)下面我们将就交通里面的几个基本要求进行建模:
静态交通模型:车道(RoadLane,在计算机这货看来是个队列,用于容纳元胞空间)、道路(试车道的集合,有方向的队列容器,内部有一系列车道)、交叉口(棋盘类似,用来容纳元胞空间或者说,车辆或者行人空间,计算机看来是个矩阵)、路网(NetWork,计算机看来是个图,为了表示交通中的单行道贺双行道的区别,注意,这个应该是有向图);
动态交通模型:车辆CAR 和行人(行人模型在本系统中为抽象的car没有体现,元胞自动机的粒度要小于车辆);
交通控制模型:信号灯、交通灯(信号控制,包含一组信号灯);
交通规则模型:速度限制(交通规则模型),可变信息板(vms)。
首先来看静态交通模型的表示:
(1)车道和道路模型
这里面涉及到三个实体、车道、道路(有方向)实际道路网络中的路段形式往往不是一直不变的,路段是由多条不同类型的车道组成的,如左转车道,右转车道,直行车道等等,而且,路段中进口道的宽度和出口道的宽度时不相等的,进口道往往进行了拓宽以增加交叉口的通行能力。在进行利用元胞自动机进行仿真系统建模的过程中,需要对这进口道展宽这一几何特征在元胞空间中进行描述。
在基于元胞自动机的交通仿真系统中,交通中的动态元素如车辆的移动是用不同位置处的元胞不断变化的状态来进行模拟的。为了模拟道路进口道展宽这一现象,需要引入特殊的元胞,这些元胞在仿真的任何时刻元胞状态都是被占用的状态(本文中称为堵塞元胞)。利用堵塞元胞(图中黑色格子),可以利用图4.1所示的方法来模拟进口道展宽。在进口道中,增加一条车道,该车道的一部分在起始状态全部由堵塞元胞占据,车道的剩余部分则是正常元胞空间网格,在正常元胞空间网格中如果元胞的状态为占用状态,则表示某一时刻该位置处被车辆占据,其他车辆不能进入。在被堵塞的元胞空间网格中(图中黑色部分),任何时刻都是被占用状态,这样就不能代表有表示车辆的状态变化,在宏观上表现为车俩不能进入这些空间。图4.1和图4.2 都是利用该方法建立的展宽渐变段元胞空间模型。
图4.1 进口道左转展宽示意图
图4.2 进口道右转展宽示意图
车道模型的代码:
namespace SubSys_SimDriving.TrafficModel { /// <summary> /// ½»Í¨ÊµÌåÀïÃæµÄ³µµÀ /// </summary> public class RoadLane : RoadEntity, IComparable<RoadLane>, IComparer<RoadLane> { private static int iRoadLaneCount=0; ///// <summary> ///// ÿ´Î¸üÐÂCurrTimeStepµÄʱºò¾Í×Ô¶¯´¦ÀíµÈ´ýÁбí ///// </summary> public override int iLength { get { return this.Container.iLength; } } public override int iWidth { get { return SimSettings.iCarWidth; } } public override EntityShape EntityShape { get { EntityShape eShape = base.EntityShape; if (eShape.Count == 0)//shape ûÓгõʼ»¯ { CreateShape(eShape); //EntityShape es = this.Container.EntityShape; //MyPoint pUnitNormVect = VectorTools.GetNormalVector(this.Container.ToVector()); //MyPoint mpOffset = new MyPoint(pUnitNormVect._X * (this.Rank - 1), pUnitNormVect._Y * (this.Rank - 1)); ////ƽÒÆ×ø±ê //MyPoint pFirst = Coordinates.Offset(es[0], mpOffset); ////¼ÆËãÖÕµã //MyPoint pFEnd = Coordinates.Offset( es[es.Count-1], mpOffset); ////Ìí¼Óµ½shape //eShape.Add(pFirst); //eShape.Add(pFEnd); } return eShape; } } private void CreateShape(EntityShape eShape) { EntityShape es = this.Container.EntityShape; MyPoint pNorm = VectorTools.GetNormalVector(this.Container.ToVector()); MyPoint mpOffset = new MyPoint(pNorm._X*(this.Rank - 0.5f),pNorm._Y * (this.Rank - 0.5f)); //ƽÒÆ×ø±ê MyPoint pFirst = Coordinates.Offset(es[0], mpOffset); //¼ÆËãÖÕµã MyPoint pFEnd = Coordinates.Offset(es[es.Count - 1], mpOffset); MyPoint mp = new MyPoint(pFEnd._X-pFirst._X,pFEnd._Y-pFirst._Y); int iLoopCount = this.iLength;//Ôª°û³¤¶È£¬³õʼ»¯²Î¼ûregisterservice float xSplit = mp._X / iLoopCount;//×ÔÉíÓÐÕý¸ººÅ float ySplit = mp._Y / iLoopCount;//×ÔÉíÓÐÕý¸ººÅ //MyPoint tep=new MyPoint(pFirst._X + iLoopCount * xSplit, pFirst._Y + iLoopCount * ySplit); //System.Diagnostics.Debug.Assert(pFEnd==tep); eShape.Add(pFirst); for (int i = 1; i < iLoopCount; i++)//xÐÐ { //Öеã eShape.Add(new MyPoint(pFirst._X + (i-0.5f) * xSplit, pFirst._Y + (i-0.5f) * ySplit)); } eShape.Add(pFEnd); } internal bool IsLaneBlocked(int iAheadSpace) { return this.iLastPos-1 <= iAheadSpace ; } /// <summary> /// ¹Û²ìÕßģʽÖиºÔð֪ͨÄÚ²¿Ôª°ûÐÞ¸Ä/±£´æ״̬µÄ´úÂë /// </summary> /// <summary> /// ³µµÀµÄ×îºóÒ»¸öÔª°ûµÄλÖã¬Ó¦µ±ÊÇY×ø±ê /// </summary> private int _ilastPos; /// <summary> /// »ñÈ¡³µµÀµÄ×îºóÒ»¸öÔª±¦µÄλÖã¬Èç¹ûûÓÐÔª°ûÔò·µ»Ø³µµÀ³¤¶È /// </summary> internal int iLastPos { get { Cell ce = this.cells.PeekLast(); if (ce== null) { this._ilastPos = this.iLength; } else //if (this._ilastPos > ce.RltPos.Y) { this._ilastPos = ce.RltPos.Y; } return _ilastPos; } } /// <summary> /// ÅжϴӵÀ·Æðµã´¦µ½iAheadSpace´¦ÊÇ·ñÓÐÔª°û /// </summary> /// <param name="iAheadSpace"></param> /// <returns></returns> internal bool IsLaneEmpty(int iAheadSpace) { if (this.cells.PeekLast().RltPos.Y<iAheadSpace) { return false;//×îºóÒ»¸öÔª°ûµÄλÖÃСÓÚ³µÍ·Ê±¾à¾Í²»Îª¿Õ } return true; } /// <summary> ///³µµÀµÄÅÅÐò£¬´ÓÄڲ೵µÀ¿ªÊ¼µÄµÚ¼¸¸ö³µµÀ,ÓÃÀ´¶Ô³µµÀ½øÐÐÅÅÐò /// </summary> public int Rank; public int[] PreCarPos; /// <summary> /// ·Ö³µµÀµÄÐźŠ/// </summary> internal SignalLight SignalLight; private RoadEdge GetContainer() { return this.Container as RoadEdge; } internal void PlaySignal(int iCrtTimeStep) { RoadNode rN = this.GetContainer().To; if (SignalLight == null)//ÎÞÐźŽ»²æ¿Ú { rN.UnblockLane(this); return; } if (this.SignalLight.IsGreen(iCrtTimeStep) == false) {//ºìµÆ»òÕßÊǻƵÆÔò×èÈû rN.BlockLane(this); } else//ÂÌµÆ { rN.UnblockLane(this); } } public override MyPoint ToVector() { MyPoint pA = this.EntityShape[0]; MyPoint pB = this.EntityShape[this.EntityShape.Count - 1]; return new MyPoint(pB._X-pA._X,pB._Y-pA._Y); } [System.Obsolete("½ûֹʹÓõĹ¹ÔìÐÎ")] private RoadLane() { this.laneType = LaneType.Straight; } /// <summary> /// µ÷ÓÃÁËÁ½²ÎÊý¹¹ÔìÐÎ /// </summary> /// <param name="re"></param> internal RoadLane(RoadEdge re):this(re,LaneType.Straight){ } internal RoadLane(LaneType lt):this(null,lt) { } /// <summary> /// ûÓнøÐÐÄÚ²¿×¢²á£¬Ó¦µ±ÓÉÆä¹ÜÀíÕßµ÷ÓÃregistere½øÐÐ×¢²á /// </summary> /// <param name="re"></param> /// <param name="lt"></param> internal RoadLane(RoadEdge re,LaneType lt) { this.PreCarPos = new int[512]; this.PreCarPos[0] = -1; Container = re; this.laneType = lt; this._id = RoadLane.iRoadLaneCount++; } public void AddCell(Cell ce) { //¸øÈÝÆ÷¸³Öµ£» ce.Container = this; //ÐÞ¸Ä×ø±ê ce.RltPos = new Point(this.Rank, ce.RltPos.Y); System.Diagnostics.Debug.Assert(ce.RltPos.Y < this.iLastPos); this.cells.Enqueue(ce); } public Cell RemoveCell() { return this.cells.Dequeue(); } internal LaneType laneType; private CellLinkedQueue cells = new CellLinkedQueue(); private Queue<Cell> waitedQueue = new Queue<Cell>(); /// <summary> /// ×¢²áÈÝÆ÷ /// </summary> /// <param name="ce"></param> public void EnterWaitedQueue(Cell ce) { //¸øÈÝÆ÷¸³Öµ£» ce.Container = this; this.waitedQueue.Enqueue(ce); } private void DisposeWaitedQueue() { while (this.waitedQueue.Count > 0) { if (this.iLastPos == 0)//Èç¹û³µµÀÒѾÂúÁ˾Ͳ»ÄÜ´¦Àí¶ÓÁÐÁË { break; } this.AddCell(this.waitedQueue.Dequeue()); } } /// <summary> /// ûÓе÷ÓÃvisitorģʽ£¬µ÷ÓÃËùÓи½¼ÓµÄ·þÎñ¡¢´¦ÀíµÈ´ý¶ÓÁÐ /// </summary> [System.Obsolete("µ÷ÓÃËùÓи½¼ÓµÄ·þÎñºÍ´¦Àí µÈ´ý¶ÓÁÐ")] public override void UpdateStatus() { base.UpdateStatus(); } protected override void OnStatusChanged() { this.DisposeWaitedQueue();//´¦ÀíµÈ´ýµÄÔª°û //µ÷ÓûùÀàµÄÈÕÖ¾·þÎñ this.InvokeServices(this);//ÀûÓÃÈÕÖ¾¼Ç¼roadLane±äÁ¿ } #region Á½¸öÀàÏ໥±È½ÏµÄËã·¨ºÍº¯Êý public int CompareTo(RoadLane other) { if (this.laneType == other.laneType) { return 0; } return this.laneType > other.laneType ? 1 : -1; } public int Compare(RoadLane x, RoadLane y) { return x.CompareTo(y); } /// <summary> /// ¾²Ì¬·½·¨ /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <returns></returns> public static int CompareTo(RoadLane from, RoadLane to) { return from.CompareTo(to); } #endregion public Cell this[int index] { get { return this.cells[index]; } } public int CellCount { get { return this.cells.Count; } } public IEnumerator<Cell> GetEnumerator() { return this.cells.GetEnumerator(); } public override int GetHashCode() { return base.GetHashCode(); //return base.GetHashCode(); } } }
道路模型的代码(一组车道的容器):
namespace SubSys_SimDriving.TrafficModel { /// <summary> /// Ò»°ãÀ´½²RoadEdgeµÄ³¤¶ÈÓëRoadLane³¤¶ÈÒ»Ñù£¬µ«ÊÇ»·Ðν»²æ¿Ú£¬ÒÔ¼°ÒÔºóµÄÍØÕ¹³ýÍâ /// </summary> public class RoadEdge : RoadEntity { /// <summary> /// µ±Ç°ËùÓз¶ÎµÄͬ²½Ê±¿Ì /// </summary> internal static int iTimeStep; internal static int iRoadEdgeCount = 0; #region ¹¹Ô캯Êý ²¿·Ö³ÉÔ±µÄ³õʼ»¯ÓÉRegiserService½øÐÐ //public RoadEdge():this(new RoadNode(),new RoadNode()){} /// <summary> /// Ç¿ÖÆÏȹ¹Ôì½Úµã /// </summary> /// <param name="from"></param> /// <param name="to"></param> internal RoadEdge(RoadNode from, RoadNode to) { if (from ==null && to == null) { throw new ArgumentNullException("ÎÞ·¨Ê¹ÓÿյĽڵ㹹Ôì±ß"); } this.From =from; this.To = to; this._lanes = new RoadLaneChain(); this._id = RoadEdge.iRoadEdgeCount++; } internal RoadEdge(RoadNode from, RoadNode to,TripCostAnalyzer tripCost):this(from,to) { this._tripCostAnalyzer = tripCost; } #endregion public override int iLength { get { int preNodeDistance = Coordinates.Distance(this.From.RltPos, this.To.RltPos); int iRealLength = preNodeDistance- 2* SimSettings.iMaxLanes; if (iRealLength<10) { ThrowHelper.ThrowArgumentException("Á½¸ö½ÚµãÖ®¼ä¾àÀëÌ«¶Ì"); } return iRealLength; } } public override int iWidth { get { return this.Lanes.Count*SimSettings.iCarWidth; } } public RoadNode From; public RoadNode To; #region ·¶ÎÄÚ²¿µÄ³µµÀÏà¹ØµÄÊý¾Ý½á¹¹ºÍ²Ù×÷º¯Êý /// <summary> /// ÓɸºÔðÌí¼ÓµÄÀà½øÐзÂÕæÉÏÏÂÎÄͬ²½,ÄÚ²¿½øÐÐÁËRoadLane×¢²á /// </summary> /// <param name="rl"></param> internal void AddLane(RoadLane rl) { if (rl != null) { //·ÀÖ¹Ìí¼ÓÁ˽϶àµÄ³µµÀ if (this.Lanes.Count ==SimSettings.iMaxLanes) { throw new ArgumentOutOfRangeException("ÎÞ·¨Ìí¼Ó³¬¹ý" + SimSettings.iMaxLanes + "¸ö³µµÀ"); } rl.Container = this;//Á½ÐдúÂëÒ»¶¨²»Òª¸ß·´ÁË rl.Register();// //ͬ²½·ÂÕæÉÏÏÂÎĵÄÊý¾Ý¼Ç¼ //°´ÕÕlaneRanking ºÍlaneTypeÅÅÐò£¬²åÈëµ½ºÏÊʵÄλÖò¢ÇÒ¸øÓèÇ¡µ±µÄ //laneRanking±ãÓÚ½øÐÐ×ø±êË÷Òý int i = this._lanes.Count ; if (i == 0)//µÚÒ»¸öÒªÌí¼ÓµÄ³µµÀ { this._lanes.Add(rl); rl.Rank = 1; } while (i-->=1)//¸öÊý³¬¹ýÒ»¸ö³µµÀ½øÐвåÈë²Ù×÷ { RoadLane rLane = this._lanes[i];//iÒѾ±äСÁËÒ»¸öÊý if (rLane.laneType > rl.laneType) { //½«ºóÐø´óµÄlaneRankingµÄÖµÔö1 rLane.Rank += 1; if (i==0) { this.Lanes.Insert(0, rl);//²åÈë×îÓұߵijµµÀ rl.Rank = 1; } }//rank×î´óµÄÒ»¸öÏàͬ³µµÀ if (rLane.laneType <= rl.laneType) { //²åÈëеÄlane£¬µ±Ç°Ë÷ÒýÊÇi£¬Òª²åÈëÖ®ºó£¬Ë÷ÒýÓ¦µ±ÊÇi+1 this._lanes.Insert(i+1, rl); //rl.Rank = i+2;//rank ±ÈË÷Òý´ó1 rl.Rank = i + 2;// this.Lanes.Count; break; } } //this.ilength =¶ËµãµÄ³¤¶È//¶Ëµã×ø±êÖ®¼äµÄ¾àÀë } else { throw new ArgumentNullException(); } } internal void AddLane(LaneType lt) { RoadLane rl = new RoadLane(this, lt); this.AddLane(rl); } internal RoadLane GetLane(RoadLane rlCurr, string strLorR) { RoadLane rl = null; switch (strLorR) { case "L": if (rlCurr.Rank>1)//´óÓÚ1²ÅÓÐ×ó±ßµÄ³µµÀ { rl = this._lanes[rl.Rank - 2];//×ó²àµÄË÷ÒýΪrank-2£» } break; case "R": if (rlCurr.Rank < this.Lanes.Count)//´óÓÚ1²ÅÓÐ×ó±ßµÄ³µµÀ { rl = this._lanes[rl.Rank];//ÓÒ²àµÄË÷ÒýΪrank } break; default: ThrowHelper.ThrowArgumentException("´íÎóµÄ¶î²ÎÊý2"); break; } return rl; } /// <summary> /// ÓɸºÔðɾ³ýµÄÀà½øÐзÂÕæÉÏÏÂÎÄͬ²½ /// </summary> /// <param name="rl"></param> //[System.Obsolete("Ó¦µ±¸ù¾Ýʵ¼ÊµÄÇé¿öÈ·¶¨É¾³ý³µµÀÐèÒªµÄº¯ÊýÀàÐÍ")] internal void RemoveLane(RoadLane rl) { if (rl != null) { for (int i = rl.Rank; i < this.Lanes.Count; i++) { this.Lanes[i].Rank -= 1; } this._lanes.Remove(rl);//µÚrank¸ö³µµÀÊǵÚrank-1¸öÀàÐÍ //ͬ²½·ÂÕæÉÏÏÂÎĵÄÊý¾Ý¼Ç¼ rl.UnRegiser();//½øÐз´×¢²á }else { throw new ArgumentNullException(); } } /// <summary> /// ´æ´¢±ßÄÚ²¿µÄ³µµÀroadlane£¬Õâ¸öÓësimContext ²»Í¬ /// </summary> private RoadLaneChain _lanes; public RoadLaneChain Lanes { get { return this._lanes; } } #endregion #region ³öÐзÑÓà internal TripCostAnalyzer _tripCostAnalyzer; private int _tripCost; /// <summary> /// ·¶ÎµÄ½»Í¨·ÑÓÃ/³É±¾ /// </summary> internal int TripCost { get { return _tripCost; } } /// <summary> /// ¸üз¶ÎµÄ½»Í¨³É±¾ /// </summary> [System.Obsolete("²»½¨ÒéʹÓøüгɹ¦")] internal void UpdateTripCost() { if (this._tripCostAnalyzer != null) { //this._tripCost = _tripCostAnalyzer.GetTripCost(this); } else { throw new System.MissingFieldException("ûÓкÏÊʵijöÐзÑÓüÆËãÀ࣡"); } } #endregion #region ¹þÏ£º¯Êý /// <summary> /// ¸ù¾ÝÆðʼ½ÚµãºÍ½áÊø½Úµã¼ÆËã±ßµÄ¹þÏ£Öµ /// </summary> /// <returns></returns> public override int GetHashCode() { //return RoadEdge.iRoadEdgeCount; return string.Concat(From.GetHashCode().ToString(), To.GetHashCode().ToString()).GetHashCode(); } /// <summary> /// ¾²Ì¬µÄ¹þÏ£º¯Êý£¬ÓÃÀ´¼ÆËãijÌõ±ßµÄ¹þÏ£Öµ /// </summary> internal static int GetHashCode(RoadNode rnFrom,RoadNode rnTo) { return string.Concat(rnFrom.GetHashCode().ToString(), rnTo.GetHashCode().ToString()).GetHashCode(); } #endregion /// <summary> /// µ÷ÓÃvisitor ģʽÈçvmsagentµÈ¡£È»ºóÇý¶¯Ôª°ûÄ£ÐÍ£¬È»ºóµ÷ÓÃËùÓзþÎñ /// </summary> public override void UpdateStatus() { ////¸üÐÂÒì²½ÏûÏ¢ for (int i = 0; i < this.asynAgents.Count; i++) { Agents.Agent visitorAgent = this.asynAgents[i]; visitorAgent.VisitUpdate(this);//.VisitUpdate(); } //ÓÃroadedgeµ÷ÓÃÔª°ûµÄdrive Ä¿µÄÔÚÓÚÈóµÁ¾¿ÉÒÔ»»µÀ foreach (var lane in this.Lanes) { for (int i = 0; i < lane.CellCount; i++) { lane[i].Drive(this);//ÕâÊÇÒ»¸öÔª°ûµÄ·½·¨ } lane.UpdateStatus();//µ÷ÓÃ×¢²áÔÚ³µµÀÉϵķþÎñ¡£ } base.UpdateStatus();//µ÷ÓÃ×¢²áÔÚ·¶ÎÉϵķþÎñ£¬ÈçRoadEdgePaintService } /// <summary> /// ·¶ÎµÄOnStatusChangedίÍиøRoadLane´¦Àí /// </summary> [System.Obsolete("µ÷ÓÃÁË·þÎñ")] protected override void OnStatusChanged() { this.InvokeServices(this); } /// <summary> /// ÆðµãÏòÁ¿¼õÈ¥ÖÕµãÏòÁ¿ /// </summary> /// <returns></returns> [System.Obsolete("Ëæ»úÊý·¢ÉúÆ÷ÓпÉÄܲúÉúÁ½¸öÍêÈ«Ò»ÑùµÄ·¶Î¶Ëµã×ø±ê£¬¸Ãº¯ÊýµÄÊÔͼ½â¾öÕâÒ»ÎÊÌ⣬Õýʽ³ÌÐò²»Ó¦µ±Ê¹ÓÃ")] public override MyPoint ToVector() { MyPoint p = new MyPoint(To.RltPos.X - From.RltPos.X, To.RltPos.Y - From.RltPos.Y); if (p._X == 0.0f && p._Y == 0.0f) { p._X = 12; p._Y = 12; //throw new Exception("RoadEdge²úÉúÁËÁãÏòÁ¿£¡"); } return p; } public override EntityShape EntityShape { get { EntityShape eShape = base.EntityShape; if (eShape.Count == 0)//shape ûÓгõʼ»¯ { int pX =this.To.RltPos.X - this.From.RltPos.X; int pY = this.To.RltPos.Y - this.From.RltPos.Y; //ÏòÁ¿µÈ·Ö float dLq = this.iLength + 2 * SimSettings.iMaxLanes;//·Öĸ float xSplit = pX / dLq;//×ÔÉíÓÐÕý¸ººÅ float ySplit = pY / dLq;//×ÔÉíÓÐÕý¸ººÅ //¼ÆËãÆðµã int iOffset = SimSettings.iMaxLanes; eShape.Add(new MyPoint(this.From.RltPos.X + iOffset * xSplit, this.From.RltPos.Y + iOffset * ySplit)); //¼ÆËãÖÕµã eShape.Add(new MyPoint(this.To.RltPos.X - iOffset * xSplit, this.To.RltPos.Y - iOffset * ySplit)); } return eShape; } } /// <summary> /// »ñÈ¡ÔÚÒ»¸öRoadÄÚ²¿µÄÓëRoadEdgeÏà¶ÔÓ¦µÄ·´Ïò·¶Î /// </summary> /// <returns></returns> public RoadEdge GetReverse() { return (ISimCtx.NetWork as IRoadNetWork).FindRoadEdge(this.To, this.From); } /// <summary> /// ´æ´¢´Ó½»²æ¿ÚroadNode½øÈ뷶εijµÁ¾£¬ÒòΪʱ¼ä³¬Ç°Ò»¸öʱ¼ä²½³¤£¬ /// ÐèÒª·ÅÈë¶ÓÁÐÖзÀÖ¹Ò»¸öÔª°ûÏȸüе½Â·¶Î£¬È»ºóÔÚ·¶ÎÄÚÓÖ¸üÐÂÒ»´Î¸üÐÂÁ½´Î /// </summary> private Queue<Cell> queWaitedCell = new Queue<Cell>(); /// <summary> /// ÐÞ¸ÄÐźŵÆ×éºÏ /// </summary> /// <param name="sl">еÄÐźŵÆ</param> /// <param name="lt">ÒªÐ޸ĵijµµÀÀàÐÍ</param> public void ModifySignalGroup(SignalLight sl, LaneType lt) { foreach (RoadLane rl in this.Lanes) { if (rl.laneType == lt) { rl.SignalLight = sl; } } } /// <summary> /// ·¶ÎÏÞËÙ /// </summary> internal SpeedLevel iSpeedLimit; } }
(3)交叉口模型
交叉口是道路路网的重要节点,道路交叉口情况和环境复杂,多种因素交互作用,相互影响,如信号灯,不同流向的车流之间争夺有限的时空资源,往往产生多种冲突和矛盾,因此道路交叉口的管理水平往往对整个道路交通网络的运行状态起着决定性的作用。同时,道路交叉口也是交通仿真技术的难点和重点之一,不少交通仿真软件对于交叉口的处理采取了简化的手段,如Transims不对交叉口时空状态进行详细描述,仅仅在车辆经过交叉口的时候引入一个适当的延误来模拟交叉口对整个路网的影响,这对于大规模交通路网的宏观交通交通模拟仿真是可以接受的。然而对于细粒度的微观交通仿真,对交叉口的处理需要更加细化,需要对交叉口每一个仿真步长的时空状态进行细致的刻画和描述。这种要求使得类似于Transims的交叉口处理方法变得不适合用于交叉口的仿真。按照交通管理方式的不同,平面交叉口有无控制交叉口、让路交叉口、信号控制交叉口和环岛交叉口等几种类型。实际道路网路中的交叉口的形状变化非常多,本文为简化建模,仅仅对常规四路交叉口进行建模,并且将其简化为矩形的网格状空间,每个空间代表一个元胞,当有车辆元胞占据时,元胞状态为1,否则为0。代表交叉口的矩阵的长度为系统容许的路段的最大车道数。利用这种方法,可以清晰描述交叉口范围内任意仿真时刻的车辆元胞的空间位置,也可以很容易的模拟车辆在交叉口的由于争夺空间资源而产生的冲突。在图中,当一个元胞空间被车辆元胞占据之后,其他车辆元胞就不可以再进入这个元胞空间。这一特性就可以避免交叉口中出现车辆穿越车辆的情况,关于车辆空间资源的竞争。有学者提出采用博弈论的方法来模拟两辆竞争道路系统空间资源的两辆车辆,并且提出了详尽的模型。[3]。本文中将问题简化,采取随机处理的方法,两个车辆中随机选择一辆车辆进入竞争的元胞空间,来避免复杂的计算。
在偷懒粘贴交叉口模型代码之前,必须对邻接矩阵进行粘贴:
sing System; using System.Collections.Generic; namespace SubSys_SimDriving.TrafficModel { /// <summary> /// 程序的GUI可能要求使用对象的坐标来查询路段顶点的位置,采用对象的position用作 /// 哈希值可以快速检索对象,也比使用list泛型高效,负责保存节点到仿真上下文中, /// 不负责保存边到上下文中,边由network保存 /// </summary> internal class AdjacencyTable<T> { Dictionary<T,RoadNode> dicRoadNode; //图的顶点集合 /// <summary> /// 使用SimDrivingContext 仿真上下文初始化保存路段节点的字典 /// </summary> internal AdjacencyTable(Dictionary<T,RoadNode> dic) { dicRoadNode = dic; } //构造方法 private AdjacencyTable() //私有构造防止外部初始化指定容量的构造方法 { } internal void AddRoadNode(T key,RoadNode value) /*添加?个顶点 */ { //不允许插入重复值 if (Contains(key))//哈希值一致就认为顶点一致 { throw new ArgumentException("插入了重复顶点!"); } dicRoadNode.Add(key,value); } internal void RemoveRoadNode(T key) { dicRoadNode.Remove(key); } internal int RoadNodeCount { get { return dicRoadNode.Count; } } internal int RoadEdgeCount { get { int iCount = 0; foreach (RoadNode item in dicRoadNode.Values) { iCount += item.RoadEdges.Count; } return iCount; } } internal bool Contains(T key) //查找图中是否包含某RoadNode,key是根据对象位置进行的哈希散列值 { if (key != null) { return dicRoadNode.ContainsKey(key); } return false; } internal RoadNode Find(T key) //查找指定项并返回 { if (key != null) { if(!dicRoadNode.ContainsKey(key)){ throw new Exception("无法找到没有添加的RoadNode节点"); } return dicRoadNode[key] as RoadNode; } return null; } /// <summary> /// 添加有向边 /// </summary> /// <param name="fromRoadNodeHash">要将将边添加到RoadNode哈希表中的RoadNode</param> /// <param name="Edge">要添加的边</param> internal void AddDirectedEdge(T fromRoadNodeHash,RoadEdge Edge) { RoadNode rn= this.Find(fromRoadNodeHash); if(rn!=null) { rn.AddRoadEdge(Edge); } } internal void RemoveDirectedEdge(T roadNodeHash, RoadEdge edge) { RoadNode rn = this.Find(roadNodeHash); if (rn != null) { rn.RemoveEdge(edge); } } //internal override string ToString() //仅用于测试 //{ //打印每个节点和它的邻接点 // string s = string.Empty; // foreach (RoadNode<T> v in items) // { // s += v.data.ToString() + ":"; // if (v.firstEdge != null) // { // Node tmp = v.firstEdge; // while (tmp != null) // { // s += tmp.adjvex.data.ToString(); // tmp = tmp.next; // } // } // s += "\r\n"; // } // return s; //} //嵌套类,表示链表中的表结点 //internal RoadNode<T> RoadNode } }
然后是交叉口的模型代码:
namespace SubSys_SimDriving.TrafficModel { /// <summary> /// ʹÓþØÕóÀàÐ͵ĽṹÒâζ×Ų»Ö§³ÖÎå·½»²æ.»·Â·µÄÖ§³ÖÓдýÌÖÂÛ£¬Èý·½»²æÊÇÖ§³ÖµÄ /// </summary> public class RoadNode : RoadEntity { /// <summary> /// ·¶Îת»¯ÎªÖÐÐÄ×ø±êµã,iahead ²»Ó¦µ±Ð¡ÓÚÁã /// </summary> private Point MakeCenterXY(RoadLane rl, int iAhead) { return new Point(rl.Rank, iAhead - SimSettings.iMaxLanes); } #region ³µµÀ²Ù×÷º¯Êý /// <summary> /// ÅжÏÖ¸¶¨³µµÀÇ°²¿µÚAhead¸öλÖô¦ÊÇ·ñÓÐÔª°ûÕ¼¾Ý /// </summary> internal bool IsBlocked(RoadLane rl, int iAhead) { Point irltXY = this.MakeCenterXY(rl,iAhead); Point iRealXY = Coordinates.GetRealXY(irltXY,rl.ToVector()); return cells.IsBlocked(iRealXY.X, iRealXY.Y); } /// <summary> /// ÅжÏÖ¸¶¨³µµÀÇ°²¿µÚAhead¸öλÖô¦ÊÇ·ñÓÐÔª°ûÕ¼¾Ý /// </summary> internal bool IsBlocked(Point iRealXY) { return cells.IsBlocked(iRealXY.X, iRealXY.Y); } /// <summary> /// ½«³µµÀ¶ÂÈû /// </summary> /// <param name="rl"></param> internal void BlockLane(RoadLane rl) { if (rl == null) { throw new ArgumentNullException(); } if (IsBlocked(rl,1)==false)//¿ÕµÄÔòÌí¼Ó { this.AddCell(rl, 1); } } /// <summary> /// ½«³µµÀÊèͨ /// </summary> /// <param name="rl"></param> internal void UnblockLane(RoadLane rl) { if (rl == null) { throw new ArgumentNullException(); } if (IsBlocked(rl, 1)==true)//·Ç¿ÕÔòɾ³ý {//ÓÃnull ½«Î»Öà rl.rank ºÍµÚ1-6¸öλÖõÄÔª°ûÕ¼¾Ý this.RemoveCell(rl, 1);//(id, rl.parEntity, null); } } /// <summary> /// ÅжϵÚx¸ö³µµÀÇ°ÃæÊÇ·ñÓÐiAheadSpace¸ö³µÁ¾ /// </summary> /// <returns></returns> internal bool IsLaneBlocked(RoadLane rl, int iAheadSpace) { bool isBlocked = false; for (int i = 1; i <= iAheadSpace; i++) { isBlocked = this.IsBlocked(rl, i); if (isBlocked == true) break; } return isBlocked; } internal bool IsLaneBlocked(RoadLane rl) { return this.IsBlocked(rl, 1); } #endregion #region Ôª°û²Ù×÷º¯Êý /// <summary> /// ΪºìÂ̵ÆÌí¼Ó×¼±¸µÄ·½·¨£¬²»ÊÇÕý³£µÄÔª°û /// </summary> private void AddCell(RoadLane rl, int iAheadSpace) { Point ipt = this.MakeCenterXY(rl, 1); ipt = Coordinates.GetRealXY(ipt, rl.ToVector()); cells.Add(ipt.X, ipt.Y, null);//¶ÂÈû×÷ÓõÄÔª°û¿ÉÒÔΪnull } /// <summary> /// ÔÚÖ¸¶¨µÄµãÌí¼ÓÒ»¸öÔª°û£¬ /// </summary> internal void AddCell(Cell ca) { ca.Container = this; cells.Add(ca.Track.pCurrPos.X,ca.Track.pCurrPos.Y, ca); } /// <summary> /// ÒªÇóÁ½¸ö²ÎÊýÊǾø¶Ô×ø±ê /// </summary> /// <param name="iOldPoint"></param> /// <param name="iNewPoint"></param> /// <returns></returns> internal bool MoveCell(Point iOldPoint, Point iNewPoint) { return cells.Move(iOldPoint, iNewPoint); } internal bool RemoveCell(Cell ce) { //ce.Container = nu return this.cells.Remove(ce.Track.pCurrPos.X, ce.Track.pCurrPos.Y); } /// <summary> /// °´ÕÕÖ¸¶¨µÄ·¶Î£¬Â·¶ÎÇ°²¿µÄ¾àÀë½øÐÐɾ³ýÔª°û /// </summary> /// <param name="rl">Ðýת×ø±êϵËùÒªÓõ½µÄ¼ÆËãÐýת½Ç¶ÈµÄÏòÁ¿</param> /// <param name="iAheadSpace">Ç°ÐоàÀëÊý</param> internal bool RemoveCell(RoadLane rl, int iAheadSpace) { Point ipt = this.MakeCenterXY(rl, 1); Point iRealIndex = Coordinates.GetRealXY(ipt, rl.ToVector()); return cells.Remove(iRealIndex.X, iRealIndex.Y); } #endregion /// <summary> /// еÄroadnodeµÄ¹þϣɢÁÐÖµÓÉÆäÖÐÐÄPositionµÄ¹þÏ£ÖµºÍÆäID¹¹³É /// </summary> /// <returns></returns> private HashMatrix<Cell> cells = new HashMatrix<Cell>(); /// <summary> /// ´æÖü±¾½ÚµãËùÓгö±ßµÄ¹þÏ£±í£¬¼üÖµÊÇ´ú±í±ßµÄRoadEdge¹þÏ££¬ÖµÊÇ´ú±íRoadEdge /// </summary> private Dictionary<int, RoadEdge> dicEdge = new Dictionary<int,RoadEdge>(); internal Cell this[int index] { get { return this.cells[index]; } } internal ICollection<int> Keys { get { return this.cells.Keys; } } /// <summary> /// Ìṩ¶Ô¹þÏ£¾ØÕóÄÚ²¿ÔªËصıéÀú /// </summary> /// <returns></returns> public IEnumerator<Cell> GetEnumerator() { return this.cells.GetEnumerator(); } public ICollection RoadEdges { get { return this.dicEdge.Values; } } #region ÓÃÀ´±£´æÁÚ½Ó¾ØÕóÖнڵã³ö±ßµÄ±ß³ÉÔ±,²»Ó¦µ±Ê¹ÓÃRoadNetworkÖ®ÍâµÄÀà·ÃÎÊÕâЩ³ÉÔ± /// <summary> /// ×¢ÒâÔÚ³ö±ß±íÖУ¬±£³ÖroadedgeµÄfrom×Ö¶ÎÊÇthis½Úµã£¬·ñÔòº¯ÊýÅ׳öÒì³£ /// </summary> /// <param name="roadEdge"></param> internal void AddRoadEdge(RoadEdge roadEdge) { if (roadEdge != null) { if (!Contains(roadEdge.GetHashCode())) { //¼ÓÈëÅжÏÊÇ·ñÊǵ±Ç°µãµÄ³ö±ßµÄÐÅÏ¢·ÀÖ¹³ö´í if (roadEdge.From !=this) { throw new Exception("Ìí¼ÓÁ˲»ÊôÓڸö¥µãµÄ±ß"); } dicEdge.Add(roadEdge.GetHashCode(), roadEdge); } else { throw new ArgumentException("Ìí¼ÓÁËÖظ´µÄ±ß£¡"); } } else { throw new ArgumentNullException(); } } /// <summary> /// ÕÒµ½±ß ´Óthisµ½toNode½ÚµãµÄ±ß£¬³ö±ß±í /// </summary> /// <param name="fromRN"></param> internal void RemoveEdge(RoadEdge re) { if (re == null ) { throw new ArgumentNullException(); } dicEdge.Remove(re.GetHashCode()); } internal void RemoveEdge(RoadNode toRN) { if (toRN == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj); } dicEdge.Remove(RoadEdge.GetHashCode(this,toRN)); } /// <summary> /// ²éÕÒ·½·¨£¬ÐµĽṹ²ÉÓóö±ß±í /// </summary> /// <param name="toRoadNode">³ö½Úµã</param> /// <returns></returns> public RoadEdge FindRoadEdge(RoadNode toRoadNode) { int iHashkey = RoadEdge.GetHashCode(this,toRoadNode); if (dicEdge.ContainsKey(iHashkey)) { return dicEdge[iHashkey]; } return null; } public bool Contains(int EdgeKey) { return dicEdge.ContainsKey(EdgeKey); } #endregion /// <summary> /// ¿ØÖÆRoadNodeIDµÄÊýÁ¿ /// </summary> private static int iRoadNodeID; [System.Obsolete("ʹÓÃÓвÎÊýµÄ¹¹Ô캯Êý")] internal RoadNode() { this._id = ++iRoadNodeID; Random rd = new Random(); this.gisPos = new MyPoint(rd.Next(65535), rd.Next(65535)); /// Ö±½ÓʹÓÃÉÏÏÂÎĵÄÊý¾Ý½á¹¹,bug²»Ó¦µ±Ê¹ÓÃÉÏÏÂÎĽṹ if (this.gisPos._X == 0.0f && this.gisPos._Y == 0.0f) { throw new Exception("RoadNode²úÉúÁËÁã×ø±ê£¡"); } } internal RoadNode(Point rltPostion) { this._id = ++iRoadNodeID; Random rd = new Random(); this.RltPos = rltPostion; this.gisPos = new MyPoint(rd.Next(65535), rd.Next(65535)); } public override int GetHashCode() { int iHash = this.gisPos.GetHashCode() +this.ID.GetHashCode(); return iHash.GetHashCode(); } /// <summary> /// ¸üÐÂagent£¬¸üÐÂÔª°û£¨¼ÝÊ»£©£¬µ÷Ó÷þÎñ /// </summary> public override void UpdateStatus() { //¸üÐÂÒì²½agent£¬Èç¹ûÓеĻ° for (int i = 0; i < this.asynAgents.Count; i++) { Agent visitor = this.asynAgents[i]; visitor.VisitUpdate(this);//.VisitUpdate(); } //ͨ¹ý²Ù×÷ÁíÍâÒ»¸ö¼¯ºÏ½øÐÐ foreach (var item in new List<int>(this.Keys)) { this[item].Drive(this); } //foreach (int i = 0; i < this.Keys.Count; i++) //{ // this[this.Keys[i]].Drive(this); //} base.UpdateStatus();//»ùÀàµ÷ÓÃÁËOnStatusChanged ½øÐлæͼ·þÎñ } protected override void OnStatusChanged() { this.InvokeServices(this); } }
必须在数据结构上进行优化,为了快速检索大型交叉口的元素。发挥创新精神,建立了哈希矩阵这一个组合的数据结构,几年前发表在CSDN上,不知道现在如何了。找个链接贴过来:
/article/10330709.html 三年过去了398个人阅读。还可以。
using System; using System.Drawing; using System.Collections.Generic; using SubSys_SimDriving.SysSimContext; namespace SubSys_SimDriving.TrafficModel { public class HashKeyProvider { //利用(x,y)计算新存储结构的哈希值,以支持利用x.y快速访问矩阵元素 public static int GetHashCode(int ix, int iy) { return ix*1000+iy;//.GetHashCode();//.ToString().GetHashCode().ToString().GetHashCode() + iy.ToString().GetHashCode()).GetHashCode(); } public static int GetHashCode(int iCode) { return iCode.ToString().GetHashCode(); } } internal class HashMatrix<T> { /// <summary> /// 最大六个车道,坐标远点是RoadNode的positon /// </summary> internal readonly int iMaxWidth = SimSettings.iMaxLanes; private Dictionary<int, T> hashMat = new Dictionary<int, T>(); /// <summary> /// 判断元胞是否被占用了 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> internal bool IsBlocked(int x, int y) { return hashMat.ContainsKey(HashKeyProvider.GetHashCode(x, y)); } /// <summary> /// 把元宝从o点移动到d点 /// </summary> internal bool Move(Point inXY, Point inXY_D) { int iHashkey = HashKeyProvider.GetHashCode(inXY.X, inXY.Y); T cac; if (hashMat.TryGetValue(iHashkey, out cac) == true) { hashMat.Remove(iHashkey); iHashkey = HashKeyProvider.GetHashCode(inXY_D.X, inXY_D.Y); if (hashMat.ContainsKey(iHashkey)==true) { return false; }else { hashMat.Add(iHashkey, cac); return true; } } return false; } internal void Add(int x, int y, T cell) { //更新行和列的最大索引 if (Math.Abs(x) > this.iMaxWidth || Math.Abs(y) > this.iMaxWidth) { throw new ArgumentOutOfRangeException("x或者y 参数超出了默认的最大数值"); } int iHKey = HashKeyProvider.GetHashCode(x, y); if (!hashMat.ContainsKey(iHKey)) { hashMat.Add(iHKey, cell); } } internal bool Remove(int x, int y) { return hashMat.Remove(HashKeyProvider.GetHashCode(x, y)); } internal int Count { get { return hashMat.Count; } } internal Dictionary<int, T>.ValueCollection Values { get { return hashMat.Values; } } #region 枚举器 /// <summary> /// 提供对存储元素的高效遍历 /// </summary> /// <returns></returns> internal IEnumerator<T> GetEnumerator() { return this.hashMat.Values.GetEnumerator(); } #endregion //[System.Obsolete("没有实现")] //public int IndexOf(T item) //{ // throw new NotImplementedException(); //} //[System.Obsolete("没有实现")] //public void Insert(int index, T item) //{ // throw new NotImplementedException(); //} //[System.Obsolete("没有实现")] //public void RemoveAt(int index) //{ // throw new NotImplementedException(); //} internal T this[int index] { get { return hashMat[index]; } } internal ICollection<int> Keys { get { return hashMat.Keys; } } //[System.Obsolete("没有实现")] //public void Add(T item) //{ // throw new NotImplementedException(); //} //[System.Obsolete("没有实现")] //public void Clear() //{ // throw new NotImplementedException(); //} //[System.Obsolete("没有实现")] //public bool Contains(T item) //{ // throw new NotImplementedException(); //} //[System.Obsolete("没有实现")] //public void CopyTo(T[] array, int arrayIndex) //{ // throw new NotImplementedException(); //} //int ICollection<T>.Count //{ // get { throw new NotImplementedException(); } //} //public bool IsReadOnly //{ // get { throw new NotImplementedException(); } //} //public bool Remove(T item) //{ // throw new NotImplementedException(); //} //IEnumerator<T> IEnumerable<T>.GetEnumerator() //{ // throw new NotImplementedException(); //} //System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() //{ // throw new NotImplementedException(); //} } }
(3)路网模型
路网的表示。道路路网提供机动车辆行驶的环境,而在仿真系统中利用路网作为容纳车辆元胞的容器,提供车辆元胞演化和状态更新的空间,从元胞角度看,路网是所有车辆元胞可以达到的空间网格的集合。在道路路网外部是车辆元胞不可到达的区域。交通仿真系统中的道路网络的拓扑结构可以按照图论中图的理论进行表示和抽象,按照图论的相关内容,对于不存在单行道的道路网络,可以将其表示为无向图,对于有单行道的道路网络,可以将其表示为有向图。考虑到交通仿真系统的复杂性,对于需要计算路段阻抗和效用函数的高级应用如,车辆动态路径规划问题,需要将道路网络进一步表示为带权有向图。关于无向图,有向图,带权有向图的概念请参见图论相关文献。
图4.4有向图和无向图的矩阵表示法
图4.5 有向图和无向图的邻接表表示法
由于道路网络规模可能很大,为了节省计算机资源,本文中采用邻接矩阵表示法来表示道路网络,在每个道路网络中引入广义费用或者阻抗函数作为道路路段的权重。关于路段阻抗函数的定义和分析将在路径规划中进行说明。
相关文章推荐
- 如何自己编写一个交通仿真软件(一)火种
- 如何自己编写一个交通仿真软件 开篇---- 走火入魔。
- 如何自己在Android编写一个Sqlite动态操作软件
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统?
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统?
- 如何将自己编写的软件放在真机上运行
- 如何将自己编写的软件放在真机上运行 推荐
- python3 自己编写了一个Mac下分类软件,每次只需要启动 terminal 终端就会自动分类。
- 如何自己编写一个easyui插件续
- 如何将自己编写的软件放在真机上运行
- 关于Excel操作编写的一个软件设计构思案例[连载] --如何创建快捷菜单执行人机交互操作、软件初始化设置
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统?
- 如何把自己做好的系统做成一个安装软件
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统
- 如何编写一个自己的校验框架
- 如何将自己编写的软件放在真机上运行(ios证书相关的)
- 朋友的一个问题:Linux开机如何自动运行自己编写好的shell脚本
- 如何将自己编写的软件放在真机上运行
- 如何将自己编写的软件放在真机上运行