该文章也同时在开源中国( 发布:非广告)作者为:sapperjiang。版权:sapperjiang所有。 /u/214547/admin/edit-blog?blog=358845
3 葵花宝典
首先,抛开理论。我将灌输一段心法(鄙视?心法也是理论)如下(感谢自己的硕士论文,我打字打够了,女票的小手在哪里?)
下面我们将就交通里面的几个基本要求进行建模:
静态交通模型:车道(RoadLane,在计算机这货看来是个队列,用于容纳元胞空间)、道路(试车道的集合,有方向的队列容器,内部有一系列车道)、交叉口(棋盘类似,用来容纳元胞空间或者说,车辆或者行人空间,计算机看来是个矩阵)、路网(NetWork,计算机看来是个图,为了表示交通中的单行道贺双行道的区别,注意,这个应该是有向图);
动态交通模型:车辆CAR 和行人(行人模型在本系统中为抽象的car没有体现,元胞自动机的粒度要小于车辆);
交通控制模型:信号灯、交通灯(信号控制,包含一组信号灯);
交通规则模型:速度限制(交通规则模型),可变信息板(vms)。
首先来看静态交通模型的表示:
(1)车道和道路模型
这里面涉及到三个实体、车道、道路(有方向)
实际道路网络中的路段形式往往不是一直不变的,路段是由多条不同类型的车道组成的,如左转车道,右转车道,直行车道等等,而且,路段中进口道的宽度和出口道的宽度时不相等的,进口道往往进行了拓宽以增加交叉口的通行能力。在进行利用元胞自动机进行仿真系统建模的过程中,需要对这进口道展宽这一几何特征在元胞空间中进行描述。
在基于元胞自动机的交通仿真系统中,交通中的动态元素如车辆的移动是用不同位置处的元胞不断变化的状态来进行模拟的。为了模拟道路进口道展宽这一现象,需要引入特殊的元胞,这些元胞在仿真的任何时刻元胞状态都是被占用的状态(本文中称为堵塞元胞)。利用堵塞元胞(图中黑色格子),可以利用图4.1所示的方法来模拟进口道展宽。在进口道中,增加一条车道,该车道的一部分在起始状态全部由堵塞元胞占据,车道的剩余部分则是正常元胞空间网格,在正常元胞空间网格中如果元胞的状态为占用状态,则表示某一时刻该位置处被车辆占据,其他车辆不能进入。在被堵塞的元胞空间网格中(图中黑色部分),任何时刻都是被占用状态,这样就不能代表有表示车辆的状态变化,在宏观上表现为车俩不能进入这些空间。图4.1和图4.2都是利用该方法建立的展宽渐变段元胞空间模型。
图4.1进口道左转展宽示意图
图4.2进口道右转展宽示意图
车道模型的代码:
namespaceSubSys_SimDriving.TrafficModel{///<summary>///½»Í¨ÊµÌåÀïÃæµÄ³µµÀ///</summary>publicclassRoadLane:RoadEntity,IComparable<RoadLane>,IComparer<RoadLane>{privatestaticintiRoadLaneCount=0;/<summary>/ÿ´Î¸üÐÂCurrTimeStepµÄʱºò¾Í×Ô¶¯´¦ÀíµÈ´ýÁбí/</summary>publicoverrideintiLength{get{returnthis.Container.iLength;}}publicoverrideintiWidth{get{returnSimSettings.iCarWidth;}}publicoverrideEntityShapeEntityShape{get{EntityShapeeShape=base.EntityShape;if(eShape.Count==0)//shapeûÓгõʼ»¯{CreateShape(eShape);//EntityShapees=this.Container.EntityShape;//MyPointpUnitNormVect=VectorTools.GetNormalVector(this.Container.ToVector());//MyPointmpOffset=newMyPoint(pUnitNormVect._X*(this.Rank-1),pUnitNormVect._Y*(this.Rank-1));ƽÒÆ×ø±ê//MyPointpFirst=Coordinates.Offset(es[0],mpOffset);¼ÆËãÖÕµã//MyPointpFEnd=Coordinates.Offset(es[es.Count-1],mpOffset);Ìí¼Óµ½shape//eShape.Add(pFirst);//eShape.Add(pFEnd);}returneShape;}}privatevoidCreateShape(EntityShapeeShape){EntityShapees=this.Container.EntityShape;MyPointpNorm=VectorTools.GetNormalVector(this.Container.ToVector());MyPointmpOffset=newMyPoint(pNorm._X*(this.Rank-0.5f),pNorm._Y*(this.Rank-0.5f));//ƽÒÆ×ø±êMyPointpFirst=Coordinates.Offset(es[0],mpOffset);//¼ÆËãÖÕµãMyPointpFEnd=Coordinates.Offset(es[es.Count-1],mpOffset);MyPointmp=newMyPoint(pFEnd._X-pFirst._X,pFEnd._Y-pFirst._Y);intiLoopCount=this.iLength;//Ôª°û³¤¶È£¬³õʼ»¯²Î¼ûregisterservicefloatxSplit=mp._X/iLoopCount;//×ÔÉíÓÐÕý¸ººÅfloatySplit=mp._Y/iLoopCount;//×ÔÉíÓÐÕý¸ººÅ//MyPointtep=newMyPoint(pFirst._X+iLoopCount*xSplit,pFirst._Y+iLoopCount*ySplit);//System.Diagnostics.Debug.Assert(pFEnd==tep);eShape.Add(pFirst);for(inti=1;i<iLoopCount;i++)//xÐÐ{//ÖеãeShape.Add(newMyPoint(pFirst._X+(i-0.5f)*xSplit,pFirst._Y+(i-0.5f)*ySplit));}eShape.Add(pFEnd);}internalboolIsLaneBlocked(intiAheadSpace){returnthis.iLastPos-1<=iAheadSpace;}///<summary>///¹Û²ìÕßģʽÖиºÔð֪ͨÄÚ²¿Ôª°ûÐÞ¸Ä/±£´æ״̬µÄ´úÂë///</summary>///<summary>///³µµÀµÄ×îºóÒ»¸öÔª°ûµÄλÖã¬Ó¦µ±ÊÇY×ø±ê///</summary>privateint_ilastPos;///<summary>///»ñÈ¡³µµÀµÄ×îºóÒ»¸öÔª±¦µÄλÖã¬Èç¹ûûÓÐÔª°ûÔò·µ»Ø³µµÀ³¤¶È///</summary>internalintiLastPos{get{Cellce=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>///<paramname="iAheadSpace"></param>///<returns></returns>internalboolIsLaneEmpty(intiAheadSpace){if(this.cells.PeekLast().RltPos.Y<iAheadSpace){returnfalse;//×îºóÒ»¸öÔª°ûµÄλÖÃСÓÚ³µÍ·Ê±¾à¾Í²»Îª¿Õ}returntrue;}///<summary>///³µµÀµÄÅÅÐò£¬´ÓÄڲ೵µÀ¿ªÊ¼µÄµÚ¼¸¸ö³µµÀ,ÓÃÀ´¶Ô³µµÀ½øÐÐÅÅÐò///</summary>publicintRank;publicint[]PreCarPos;///<summary>///·Ö³µµÀµÄÐźÅ///</summary>internalSignalLightSignalLight;privateRoadEdgeGetContainer(){returnthis.ContainerasRoadEdge;}internalvoidPlaySignal(intiCrtTimeStep){RoadNoderN=this.GetContainer().To;if(SignalLight==null)//ÎÞÐźŽ»²æ¿Ú{rN.UnblockLane(this);return;}if(this.SignalLight.IsGreen(iCrtTimeStep)==false){//ºìµÆ»òÕßÊǻƵÆÔò×èÈûrN.BlockLane(this);}else//Â̵Æ{rN.UnblockLane(this);}}publicoverrideMyPointToVector(){MyPointpA=this.EntityShape[0];MyPointpB=this.EntityShape[this.EntityShape.Count-1];returnnewMyPoint(pB._X-pA._X,pB._Y-pA._Y);}[System.Obsolete("½ûֹʹÓõĹ¹ÔìÐÎ")]privateRoadLane(){this.laneType=LaneType.Straight;}///<summary>///µ÷ÓÃÁËÁ½²ÎÊý¹¹ÔìÐÎ///</summary>///<paramname="re"></param>internalRoadLane(RoadEdgere):this(re,LaneType.Straight){}internalRoadLane(LaneTypelt):this(null,lt){}///<summary>///ûÓнøÐÐÄÚ²¿×¢²á£¬Ó¦µ±ÓÉÆä¹ÜÀíÕßµ÷ÓÃregistere½øÐÐ×¢²á///</summary>///<paramname="re"></param>///<paramname="lt"></param>internalRoadLane(RoadEdgere,LaneTypelt){this.PreCarPos=newint[512];this.PreCarPos[0]=-1;Container=re;this.laneType=lt;this._id=RoadLane.iRoadLaneCount++;}publicvoidAddCell(Cellce){//¸øÈÝÆ÷¸³Öµ£»ce.Container=this;//ÐÞ¸Ä×ø±êce.RltPos=newPoint(this.Rank,ce.RltPos.Y);System.Diagnostics.Debug.Assert(ce.RltPos.Y<this.iLastPos);this.cells.Enqueue(ce);}publicCellRemoveCell(){returnthis.cells.Dequeue();}internalLaneTypelaneType;privateCellLinkedQueuecells=newCellLinkedQueue();privateQueue<Cell>waitedQueue=newQueue<Cell>();///<summary>///×¢²áÈÝÆ÷///</summary>///<paramname="ce"></param>publicvoidEnterWaitedQueue(Cellce){//¸øÈÝÆ÷¸³Öµ£»ce.Container=this;this.waitedQueue.Enqueue(ce);}privatevoidDisposeWaitedQueue(){while(this.waitedQueue.Count>0){if(this.iLastPos==0)//Èç¹û³µµÀÒѾÂúÁ˾Ͳ»ÄÜ´¦Àí¶ÓÁÐÁË{break;}this.AddCell(this.waitedQueue.Dequeue());}}///<summary>///ûÓе÷ÓÃvisitorģʽ£¬µ÷ÓÃËùÓи½¼ÓµÄ·þÎñ¡¢´¦ÀíµÈ´ý¶ÓÁÐ///</summary>[System.Obsolete("µ÷ÓÃËùÓи½¼ÓµÄ·þÎñºÍ´¦ÀíµÈ´ý¶ÓÁÐ")]publicoverridevoidUpdateStatus(){base.UpdateStatus();}protectedoverridevoidOnStatusChanged(){this.DisposeWaitedQueue();//´¦ÀíµÈ´ýµÄÔª°û//µ÷ÓûùÀàµÄÈÕÖ¾·þÎñthis.InvokeServices(this);//ÀûÓÃÈÕÖ¾¼Ç¼roadLane±äÁ¿}#regionÁ½¸öÀàÏ໥±È½ÏµÄËã·¨ºÍº¯ÊýpublicintCompareTo(RoadLaneother){if(this.laneType==other.laneType){return0;}returnthis.laneType>other.laneType?1:-1;}publicintCompare(RoadLanex,RoadLaney){pareTo(y);}///<summary>///¾²Ì¬·½·¨///</summary>///<paramname="from"></param>///<paramname="to"></param>///<returns></returns>publicstaticintCompareTo(RoadLanefrom,RoadLaneto){pareTo(to);}#endregionpublicCellthis[intindex]{get{returnthis.cells[index];}}publicintCellCount{get{returnthis.cells.Count;}}publicIEnumerator<Cell>GetEnumerator(){returnthis.cells.GetEnumerator();}publicoverrideintGetHashCode(){returnbase.GetHashCode();//returnbase.GetHashCode();}}}
道路模型的代码(一组车道的容器):
namespaceSubSys_SimDriving.TrafficModel{///<summary>///Ò»°ãÀ´½²RoadEdgeµÄ³¤¶ÈÓëRoadLane³¤¶ÈÒ»Ñù£¬µ«ÊÇ»·Ðν»²æ¿Ú£¬ÒÔ¼°ÒÔºóµÄÍØÕ¹³ýÍâ///</summary>publicclassRoadEdge:RoadEntity{///<summary>///µ±Ç°ËùÓз¶ÎµÄͬ²½Ê±¿Ì///</summary>internalstaticintiTimeStep;internalstaticintiRoadEdgeCount=0;#region¹¹Ô캯Êý²¿·Ö³ÉÔ±µÄ³õʼ»¯ÓÉRegiserService½øÐÐ//publicRoadEdge():this(newRoadNode(),newRoadNode()){}///<summary>///Ç¿ÖÆÏȹ¹Ôì½Úµã///</summary>///<paramname="from"></param>///<paramname="to"></param>internalRoadEdge(RoadNodefrom,RoadNodeto){if(from==null&&to==null){thrownewArgumentNullException("ÎÞ·¨Ê¹ÓÿյĽڵ㹹Ôì±ß");}this.From=from;this.To=to;this._lanes=newRoadLaneChain();this._id=RoadEdge.iRoadEdgeCount++;}internalRoadEdge(RoadNodefrom,RoadNodeto,TripCostAnalyzertripCost):this(from,to){this._tripCostAnalyzer=tripCost;}#endregionpublicoverrideintiLength{get{intpreNodeDistance=Coordinates.Distance(this.From.RltPos,this.To.RltPos);intiRealLength=preNodeDistance-2*SimSettings.iMaxLanes;if(iRealLength<10){ThrowHelper.ThrowArgumentException("Á½¸ö½ÚµãÖ®¼ä¾àÀëÌ«¶Ì");}returniRealLength;}}publicoverrideintiWidth{get{returnthis.Lanes.Count*SimSettings.iCarWidth;}}publicRoadNodeFrom;publicRoadNodeTo;#region·¶ÎÄÚ²¿µÄ³µµÀÏà¹ØµÄÊý¾Ý½á¹¹ºÍ²Ù×÷º¯Êý///<summary>///ÓɸºÔðÌí¼ÓµÄÀà½øÐзÂÕæÉÏÏÂÎÄͬ²½,ÄÚ²¿½øÐÐÁËRoadLane×¢²á///</summary>///<paramname="rl"></param>internalvoidAddLane(RoadLanerl){if(rl!=null){//·ÀÖ¹Ìí¼ÓÁ˽϶àµÄ³µµÀif(this.Lanes.Count==SimSettings.iMaxLanes){thrownewArgumentOutOfRangeException("ÎÞ·¨Ìí¼Ó³¬¹ý"+SimSettings.iMaxLanes+"¸ö³µµÀ");}rl.Container=this;//Á½ÐдúÂëÒ»¶¨²»Òª¸ß·´ÁËrl.Register();////ͬ²½·ÂÕæÉÏÏÂÎĵÄÊý¾Ý¼Ç¼//°´ÕÕlaneRankingºÍlaneTypeÅÅÐò£¬²åÈëµ½ºÏÊʵÄλÖò¢ÇÒ¸øÓèÇ¡µ±µÄ//laneRanking±ãÓÚ½øÐÐ×ø±êË÷Òýinti=this._lanes.Count;if(i==0)//µÚÒ»¸öÒªÌí¼ÓµÄ³µµÀ{this._lanes.Add(rl);rl.Rank=1;}while(i-->=1)//¸öÊý³¬¹ýÒ»¸ö³µµÀ½øÐвåÈë²Ù×÷{RoadLanerLane=this._lanes[i];//iÒѾ±äСÁËÒ»¸öÊýif(rLane.laneType>rl.laneType){//½«ºóÐø´óµÄlaneRankingµÄÖµÔö1rLane.Rank+=1;if(i==0){this.Lanes.Insert(0,rl);//²åÈë×îÓұߵijµµÀrl.Rank=1;}}//rank×î´óµÄÒ»¸öÏàͬ³µµÀif(rLane.laneType<=rl.laneType){//²åÈëеÄlane£¬µ±Ç°Ë÷ÒýÊÇi£¬Òª²åÈëÖ®ºó£¬Ë÷ÒýÓ¦µ±ÊÇi+1this._lanes.Insert(i+1,rl);//rl.Rank=i+2;//rank±ÈË÷Òý´ó1rl.Rank=i+2;//this.Lanes.Count;break;}}//this.ilength=¶ËµãµÄ³¤¶È//¶Ëµã×ø±êÖ®¼äµÄ¾àÀë}else{thrownewArgumentNullException();}}internalvoidAddLane(LaneTypelt){RoadLanerl=newRoadLane(this,lt);this.AddLane(rl);}internalRoadLaneGetLane(RoadLanerlCurr,stringstrLorR){RoadLanerl=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;}returnrl;}///<summary>///ÓɸºÔðɾ³ýµÄÀà½øÐзÂÕæÉÏÏÂÎÄͬ²½///</summary>///<paramname="rl"></param>//[System.Obsolete("Ó¦µ±¸ù¾Ýʵ¼ÊµÄÇé¿öÈ·¶¨É¾³ý³µµÀÐèÒªµÄº¯ÊýÀàÐÍ")]internalvoidRemoveLane(RoadLanerl){if(rl!=null){for(inti=rl.Rank;i<this.Lanes.Count;i++){this.Lanes[i].Rank-=1;}this._lanes.Remove(rl);//µÚrank¸ö³µµÀÊǵÚrank-1¸öÀàÐÍ//ͬ²½·ÂÕæÉÏÏÂÎĵÄÊý¾Ý¼Ç¼rl.UnRegiser();//½øÐз´×¢²á}else{thrownewArgumentNullException();}}///<summary>///´æ´¢±ßÄÚ²¿µÄ³µµÀroadlane£¬Õâ¸öÓësimContext²»Í¬///</summary>privateRoadLaneChain_lanes;publicRoadLaneChainLanes{get{returnthis._lanes;}}#endregion#region³öÐзÑÓÃinternalTripCostAnalyzer_tripCostAnalyzer;privateint_tripCost;///<summary>///·¶ÎµÄ½»Í¨·ÑÓÃ/³É±¾///</summary>internalintTripCost{get{return_tripCost;}}///<summary>///¸üз¶ÎµÄ½»Í¨³É±¾///</summary>[System.Obsolete("²»½¨ÒéʹÓøüгɹ¦")]internalvoidUpdateTripCost(){if(this._tripCostAnalyzer!=null){//this._tripCost=_tripCostAnalyzer.GetTripCost(this);}else{thrownewSystem.MissingFieldException("ûÓкÏÊʵijöÐзÑÓüÆËãÀ࣡");}}#endregion#region¹þÏ£º¯Êý///<summary>///¸ù¾ÝÆðʼ½ÚµãºÍ½áÊø½Úµã¼ÆËã±ßµÄ¹þÏ£Öµ///</summary>///<returns></returns>publicoverrideintGetHashCode(){//returnRoadEdge.iRoadEdgeCount;returnstring.Concat(From.GetHashCode().ToString(),To.GetHashCode().ToString()).GetHashCode();}///<summary>///¾²Ì¬µÄ¹þÏ£º¯Êý£¬ÓÃÀ´¼ÆËãijÌõ±ßµÄ¹þÏ£Öµ///</summary>internalstaticintGetHashCode(RoadNodernFrom,RoadNodernTo){returnstring.Concat(rnFrom.GetHashCode().ToString(),rnTo.GetHashCode().ToString()).GetHashCode();}#endregion///<summary>///µ÷ÓÃvisitorģʽÈçvmsagentµÈ¡£È»ºóÇý¶¯Ôª°ûÄ£ÐÍ£¬È»ºóµ÷ÓÃËùÓзþÎñ///</summary>publicoverridevoidUpdateStatus(){¸üÐÂÒì²½ÏûÏ¢for(inti=0;i<this.asynAgents.Count;i++){Agents.AgentvisitorAgent=this.asynAgents[i];visitorAgent.VisitUpdate(this);//.VisitUpdate();}//ÓÃroadedgeµ÷ÓÃÔª°ûµÄdriveÄ¿µÄÔÚÓÚÈóµÁ¾¿ÉÒÔ»»µÀforeach(varlaneinthis.Lanes){for(inti=0;i<lane.CellCount;i++){lane[i].Drive(this);//ÕâÊÇÒ»¸öÔª°ûµÄ·½·¨}lane.UpdateStatus();//µ÷ÓÃ×¢²áÔÚ³µµÀÉϵķþÎñ¡£}base.UpdateStatus();//µ÷ÓÃ×¢²áÔÚ·¶ÎÉϵķþÎñ£¬ÈçRoadEdgePaintService}///<summary>///·¶ÎµÄOnStatusChangedίÍиøRoadLane´¦Àí///</summary>[System.Obsolete("µ÷ÓÃÁË·þÎñ")]protectedoverridevoidOnStatusChanged(){this.InvokeServices(this);}///<summary>///ÆðµãÏòÁ¿¼õÈ¥ÖÕµãÏòÁ¿///</summary>///<returns></returns>[System.Obsolete("Ëæ»úÊý·¢ÉúÆ÷ÓпÉÄܲúÉúÁ½¸öÍêÈ«Ò»ÑùµÄ·¶Î¶Ëµã×ø±ê£¬¸Ãº¯ÊýµÄÊÔͼ½â¾öÕâÒ»ÎÊÌ⣬Õýʽ³ÌÐò²»Ó¦µ±Ê¹ÓÃ")]publicoverrideMyPointToVector(){MyPointp=newMyPoint(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;//thrownewException("RoadEdge²úÉúÁËÁãÏòÁ¿£¡");}returnp;}publicoverrideEntityShapeEntityShape{get{EntityShapeeShape=base.EntityShape;if(eShape.Count==0)//shapeûÓгõʼ»¯{intpX=this.To.RltPos.X-this.From.RltPos.X;intpY=this.To.RltPos.Y-this.From.RltPos.Y;//ÏòÁ¿µÈ·ÖfloatdLq=this.iLength+2*SimSettings.iMaxLanes;//·ÖĸfloatxSplit=pX/dLq;//×ÔÉíÓÐÕý¸ººÅfloatySplit=pY/dLq;//×ÔÉíÓÐÕý¸ººÅ//¼ÆËãÆðµãintiOffset=SimSettings.iMaxLanes;eShape.Add(newMyPoint(this.From.RltPos.X+iOffset*xSplit,this.From.RltPos.Y+iOffset*ySplit));//¼ÆËãÖÕµãeShape.Add(newMyPoint(this.To.RltPos.X-iOffset*xSplit,this.To.RltPos.Y-iOffset*ySplit));}returneShape;}}///<summary>///»ñÈ¡ÔÚÒ»¸öRoadÄÚ²¿µÄÓëRoadEdgeÏà¶ÔÓ¦µÄ·´Ïò·¶Î///</summary>///<returns></returns>publicRoadEdgeGetReverse(){return(WorkasIRoadNetWork).FindRoadEdge(this.To,this.From);}///<summary>///´æ´¢´Ó½»²æ¿ÚroadNode½øÈ뷶εijµÁ¾£¬ÒòΪʱ¼ä³¬Ç°Ò»¸öʱ¼ä²½³¤£¬///ÐèÒª·ÅÈë¶ÓÁÐÖзÀÖ¹Ò»¸öÔª°ûÏȸüе½Â·¶Î£¬È»ºóÔÚ·¶ÎÄÚÓÖ¸üÐÂÒ»´Î¸üÐÂÁ½´Î///</summary>privateQueue<Cell>queWaitedCell=newQueue<Cell>();///<summary>///ÐÞ¸ÄÐźŵÆ×éºÏ///</summary>///<paramname="sl">еÄÐźŵÆ</param>///<paramname="lt">ÒªÐ޸ĵijµµÀÀàÐÍ</param>publicvoidModifySignalGroup(SignalLightsl,LaneTypelt){foreach(RoadLanerlinthis.Lanes){if(rl.laneType==lt){rl.SignalLight=sl;}}}///<summary>///·¶ÎÏÞËÙ///</summary>internalSpeedLeveliSpeedLimit;}}
(3)交叉口模型
交叉口是道路路网的重要节点,道路交叉口情况和环境复杂,多种因素交互作用,相互影响,如信号灯,不同流向的车流之间争夺有限的时空资源,往往产生多种冲突和矛盾,因此道路交叉口的管理水平往往对整个道路交通网络的运行状态起着决定性的作用。同时,道路交叉口也是交通仿真技术的难点和重点之一,不少交通仿真软件对于交叉口的处理采取了简化的手段,如Transims不对交叉口时空状态进行详细描述,仅仅在车辆经过交叉口的时候引入一个适当的延误来模拟交叉口对整个路网的影响,这对于大规模交通路网的宏观交通交通模拟仿真是可以接受的。然而对于细粒度的微观交通仿真,对交叉口的处理需要更加细化,需要对交叉口每一个仿真步长的时空状态进行细致的刻画和描述。这种要求使得类似于Transims的交叉口处理方法变得不适合用于交叉口的仿真。
按照交通管理方式的不同,平面交叉口有无控制交叉口、让路交叉口、信号控制交叉口和环岛交叉口等几种类型。实际道路网路中的交叉口的形状变化非常多,本文为简化建模,仅仅对常规四路交叉口进行建模,并且将其简化为矩形的网格状空间,每个空间代表一个元胞,当有车辆元胞占据时,元胞状态为1,否则为0。代表交叉口的矩阵的长度为系统容许的路段的最大车道数。利用这种方法,可以清晰描述交叉口范围内任意仿真时刻的车辆元胞的空间位置,也可以很容易的模拟车辆在交叉口的由于争夺空间资源而产生的冲突。在图中,当一个元胞空间被车辆元胞占据之后,其他车辆元胞就不可以再进入这个元胞空间。这一特性就可以避免交叉口中出现车辆穿越车辆的情况,关于车辆空间资源的竞争。有学者提出采用博弈论的方法来模拟两辆竞争道路系统空间资源的两辆车辆,并且提出了详尽的模型。[3]。本文中将问题简化,采取随机处理的方法,两个车辆中随机选择一辆车辆进入竞争的元胞空间,来避免复杂的计算。
在偷懒粘贴交叉口模型代码之前,必须对邻接矩阵进行粘贴:
singSystem;usingSystem.Collections.Generic;namespaceSubSys_SimDriving.TrafficModel{///<summary>///程序的GUI可能要求使用对象的坐标来查询路段顶点的位置,采用对象的position用作///哈希值可以快速检索对象,也比使用list泛型高效,负责保存节点到仿真上下文中,///不负责保存边到上下文中,边由network保存///</summary>internalclassAdjacencyTable<T>{Dictionary<T,RoadNode>dicRoadNode;//图的顶点集合///<summary>///使用SimDrivingContext仿真上下文初始化保存路段节点的字典///</summary>internalAdjacencyTable(Dictionary<T,RoadNode>dic){dicRoadNode=dic;}//构造方法privateAdjacencyTable()//私有构造防止外部初始化指定容量的构造方法{}internalvoidAddRoadNode(Tkey,RoadNodevalue)/*添加?个顶点*/{//不允许插入重复值if(Contains(key))//哈希值一致就认为顶点一致{thrownewArgumentException("插入了重复顶点!");}dicRoadNode.Add(key,value);}internalvoidRemoveRoadNode(Tkey){dicRoadNode.Remove(key);}internalintRoadNodeCount{get{returndicRoadNode.Count;}}internalintRoadEdgeCount{get{intiCount=0;foreach(RoadNodeitemindicRoadNode.Values){iCount+=item.RoadEdges.Count;}returniCount;}}internalboolContains(Tkey)//查找图中是否包含某RoadNode,key是根据对象位置进行的哈希散列值{if(key!=null){returndicRoadNode.ContainsKey(key);}returnfalse;}internalRoadNodeFind(Tkey)//查找指定项并返回{if(key!=null){if(!dicRoadNode.ContainsKey(key)){thrownewException("无法找到没有添加的RoadNode节点");}returndicRoadNode[key]asRoadNode;}returnnull;}///<summary>///添加有向边///</summary>///<paramname="fromRoadNodeHash">要将将边添加到RoadNode哈希表中的RoadNode</param>///<paramname="Edge">要添加的边</param>internalvoidAddDirectedEdge(TfromRoadNodeHash,RoadEdgeEdge){RoadNodern=this.Find(fromRoadNodeHash);if(rn!=null){rn.AddRoadEdge(Edge);}}internalvoidRemoveDirectedEdge(TroadNodeHash,RoadEdgeedge){RoadNodern=this.Find(roadNodeHash);if(rn!=null){rn.RemoveEdge(edge);}}//internaloverridestringToString()//仅用于测试//{//打印每个节点和它的邻接点//strings=string.Empty;//foreach(RoadNode<T>vinitems)//{//s+=v.data.ToString()+":";//if(v.firstEdge!=null)//{//Nodetmp=v.firstEdge;//while(tmp!=null)//{//s+=tmp.adjvex.data.ToString();//tmp=tmp.next;//}//}//s+="\r\n";//}//returns;//}//嵌套类,表示链表中的表结点//internalRoadNode<T>RoadNode}}
然后是交叉口的模型代码:
namespaceSubSys_SimDriving.TrafficModel{///<summary>///ʹÓþØÕóÀàÐ͵ĽṹÒâζ×Ų»Ö§³ÖÎå·½»²æ.»·Â·µÄÖ§³ÖÓдýÌÖÂÛ£¬Èý·½»²æÊÇÖ§³ÖµÄ///</summary>publicclassRoadNode:RoadEntity{///<summary>///·¶Îת»¯ÎªÖÐÐÄ×ø±êµã,iahead²»Ó¦µ±Ð¡ÓÚÁã///</summary>privatePointMakeCenterXY(RoadLanerl,intiAhead){returnnewPoint(rl.Rank,iAhead-SimSettings.iMaxLanes);}#region³µµÀ²Ù×÷º¯Êý///<summary>///ÅжÏÖ¸¶¨³µµÀÇ°²¿µÚAhead¸öλÖô¦ÊÇ·ñÓÐÔª°ûÕ¼¾Ý///</summary>internalboolIsBlocked(RoadLanerl,intiAhead){PointirltXY=this.MakeCenterXY(rl,iAhead);PointiRealXY=Coordinates.GetRealXY(irltXY,rl.ToVector());returncells.IsBlocked(iRealXY.X,iRealXY.Y);}///<summary>///ÅжÏÖ¸¶¨³µµÀÇ°²¿µÚAhead¸öλÖô¦ÊÇ·ñÓÐÔª°ûÕ¼¾Ý///</summary>internalboolIsBlocked(PointiRealXY){returncells.IsBlocked(iRealXY.X,iRealXY.Y);}///<summary>///½«³µµÀ¶ÂÈû///</summary>///<paramname="rl"></param>internalvoidBlockLane(RoadLanerl){if(rl==null){thrownewArgumentNullException();}if(IsBlocked(rl,1)==false)//¿ÕµÄÔòÌí¼Ó{this.AddCell(rl,1);}}///<summary>///½«³µµÀÊèͨ///</summary>///<paramname="rl"></param>internalvoidUnblockLane(RoadLanerl){if(rl==null){thrownewArgumentNullException();}if(IsBlocked(rl,1)==true)//·Ç¿ÕÔòɾ³ý{//ÓÃnull½«Î»ÖÃrl.rankºÍµÚ1-6¸öλÖõÄÔª°ûÕ¼¾Ýthis.RemoveCell(rl,1);//(id,rl.parEntity,null);}}///<summary>///ÅжϵÚx¸ö³µµÀÇ°ÃæÊÇ·ñÓÐiAheadSpace¸ö³µÁ¾///</summary>///<returns></returns>internalboolIsLaneBlocked(RoadLanerl,intiAheadSpace){boolisBlocked=false;for(inti=1;i<=iAheadSpace;i++){isBlocked=this.IsBlocked(rl,i);if(isBlocked==true)break;}returnisBlocked;}internalboolIsLaneBlocked(RoadLanerl){returnthis.IsBlocked(rl,1);}#endregion#regionÔª°û²Ù×÷º¯Êý///<summary>///ΪºìÂ̵ÆÌí¼Ó×¼±¸µÄ·½·¨£¬²»ÊÇÕý³£µÄÔª°û///</summary>privatevoidAddCell(RoadLanerl,intiAheadSpace){Pointipt=this.MakeCenterXY(rl,1);ipt=Coordinates.GetRealXY(ipt,rl.ToVector());cells.Add(ipt.X,ipt.Y,null);//¶ÂÈû×÷ÓõÄÔª°û¿ÉÒÔΪnull}///<summary>///ÔÚÖ¸¶¨µÄµãÌí¼ÓÒ»¸öÔª°û£¬///</summary>internalvoidAddCell(Cellca){ca.Container=this;cells.Add(ca.Track.pCurrPos.X,ca.Track.pCurrPos.Y,ca);}///<summary>///ÒªÇóÁ½¸ö²ÎÊýÊǾø¶Ô×ø±ê///</summary>///<paramname="iOldPoint"></param>///<paramname="iNewPoint"></param>///<returns></returns>internalboolMoveCell(PointiOldPoint,PointiNewPoint){returncells.Move(iOldPoint,iNewPoint);}internalboolRemoveCell(Cellce){//ce.Container=nureturnthis.cells.Remove(ce.Track.pCurrPos.X,ce.Track.pCurrPos.Y);}///<summary>///°´ÕÕÖ¸¶¨µÄ·¶Î£¬Â·¶ÎÇ°²¿µÄ¾àÀë½øÐÐɾ³ýÔª°û///</summary>///<paramname="rl">Ðýת×ø±êϵËùÒªÓõ½µÄ¼ÆËãÐýת½Ç¶ÈµÄÏòÁ¿</param>///<paramname="iAheadSpace">Ç°ÐоàÀëÊý</param>internalboolRemoveCell(RoadLanerl,intiAheadSpace){Pointipt=this.MakeCenterXY(rl,1);PointiRealIndex=Coordinates.GetRealXY(ipt,rl.ToVector());returncells.Remove(iRealIndex.X,iRealIndex.Y);}#endregion///<summary>///еÄroadnodeµÄ¹þϣɢÁÐÖµÓÉÆäÖÐÐÄPositionµÄ¹þÏ£ÖµºÍÆäID¹¹³É///</summary>///<returns></returns>privateHashMatrix<Cell>cells=newHashMatrix<Cell>();///<summary>///´æÖü±¾½ÚµãËùÓгö±ßµÄ¹þÏ£±í£¬¼üÖµÊÇ´ú±í±ßµÄRoadEdge¹þÏ££¬ÖµÊÇ´ú±íRoadEdge///</summary>privateDictionary<int,RoadEdge>dicEdge=newDictionary<int,RoadEdge>();internalCellthis[intindex]{get{returnthis.cells[index];}}internalICollection<int>Keys{get{returnthis.cells.Keys;}}///<summary>///Ìṩ¶Ô¹þÏ£¾ØÕóÄÚ²¿ÔªËصıéÀú///</summary>///<returns></returns>publicIEnumerator<Cell>GetEnumerator(){returnthis.cells.GetEnumerator();}publicICollectionRoadEdges{get{returnthis.dicEdge.Values;}}#regionÓÃÀ´±£´æÁÚ½Ó¾ØÕóÖнڵã³ö±ßµÄ±ß³ÉÔ±,²»Ó¦µ±Ê¹ÓÃRoadNetworkÖ®ÍâµÄÀà·ÃÎÊÕâЩ³ÉÔ±///<summary>///×¢ÒâÔÚ³ö±ß±íÖУ¬±£³ÖroadedgeµÄfrom×Ö¶ÎÊÇthis½Úµã£¬·ñÔòº¯ÊýÅ׳öÒì³£///</summary>///<paramname="roadEdge"></param>internalvoidAddRoadEdge(RoadEdgeroadEdge){if(roadEdge!=null){if(!Contains(roadEdge.GetHashCode())){//¼ÓÈëÅжÏÊÇ·ñÊǵ±Ç°µãµÄ³ö±ßµÄÐÅÏ¢·ÀÖ¹³ö´íif(roadEdge.From!=this){thrownewException("Ìí¼ÓÁ˲»ÊôÓڸö¥µãµÄ±ß");}dicEdge.Add(roadEdge.GetHashCode(),roadEdge);}else{thrownewArgumentException("Ìí¼ÓÁËÖظ´µÄ±ß£¡");}}else{thrownewArgumentNullException();}}///<summary>///ÕÒµ½±ß´Óthisµ½toNode½ÚµãµÄ±ß£¬³ö±ß±í///</summary>///<paramname="fromRN"></param>internalvoidRemoveEdge(RoadEdgere){if(re==null){thrownewArgumentNullException();}dicEdge.Remove(re.GetHashCode());}internalvoidRemoveEdge(RoadNodetoRN){if(toRN==null){ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj);}dicEdge.Remove(RoadEdge.GetHashCode(this,toRN));}///<summary>///²éÕÒ·½·¨£¬ÐµĽṹ²ÉÓóö±ß±í///</summary>///<paramname="toRoadNode">³ö½Úµã</param>///<returns></returns>publicRoadEdgeFindRoadEdge(RoadNodetoRoadNode){intiHashkey=RoadEdge.GetHashCode(this,toRoadNode);if(dicEdge.ContainsKey(iHashkey)){returndicEdge[iHashkey];}returnnull;}publicboolContains(intEdgeKey){returndicEdge.ContainsKey(EdgeKey);}#endregion///<summary>///¿ØÖÆRoadNodeIDµÄÊýÁ¿///</summary>privatestaticintiRoadNodeID;[System.Obsolete("ʹÓÃÓвÎÊýµÄ¹¹Ô캯Êý")]internalRoadNode(){this._id=++iRoadNodeID;Randomrd=newRandom();this.gisPos=newMyPoint(rd.Next(65535),rd.Next(65535));///Ö±½ÓʹÓÃÉÏÏÂÎĵÄÊý¾Ý½á¹¹,bug²»Ó¦µ±Ê¹ÓÃÉÏÏÂÎĽṹif(this.gisPos._X==0.0f&&this.gisPos._Y==0.0f){thrownewException("RoadNode²úÉúÁËÁã×ø±ê£¡");}}internalRoadNode(PointrltPostion){this._id=++iRoadNodeID;Randomrd=newRandom();this.RltPos=rltPostion;this.gisPos=newMyPoint(rd.Next(65535),rd.Next(65535));}publicoverrideintGetHashCode(){intiHash=this.gisPos.GetHashCode()+this.ID.GetHashCode();returniHash.GetHashCode();}///<summary>///¸üÐÂagent£¬¸üÐÂÔª°û£¨¼ÝÊ»£©£¬µ÷Ó÷þÎñ///</summary>publicoverridevoidUpdateStatus(){//¸üÐÂÒì²½agent£¬Èç¹ûÓеĻ°for(inti=0;i<this.asynAgents.Count;i++){Agentvisitor=this.asynAgents[i];visitor.VisitUpdate(this);//.VisitUpdate();}//ͨ¹ý²Ù×÷ÁíÍâÒ»¸ö¼¯ºÏ½øÐÐforeach(variteminnewList<int>(this.Keys)){this[item].Drive(this);}//foreach(inti=0;i<this.Keys.Count;i++)//{//this[this.Keys[i]].Drive(this);//}base.UpdateStatus();//»ùÀàµ÷ÓÃÁËOnStatusChanged½øÐлæͼ·þÎñ}protectedoverridevoidOnStatusChanged(){this.InvokeServices(this);}}
这里,为了利用元宝自动机的并行计算优势:
必须在数据结构上进行优化,为了快速检索大型交叉口的元素。发挥创新精神,建立了哈希矩阵这一个组合的数据结构,几年前发表在CSDN上,不知道现在如何了。找个链接贴过来:
/sapperjiang/article/details/7157296三年过去了398个人阅读。还可以。
usingSystem;usingSystem.Drawing;usingSystem.Collections.Generic;usingSubSys_SimDriving.SysSimContext;namespaceSubSys_SimDriving.TrafficModel{publicclassHashKeyProvider{//利用(x,y)计算新存储结构的哈希值,以支持利用x.y快速访问矩阵元素publicstaticintGetHashCode(intix,intiy){returnix*1000+iy;//.GetHashCode();//.ToString().GetHashCode().ToString().GetHashCode()+iy.ToString().GetHashCode()).GetHashCode();}publicstaticintGetHashCode(intiCode){returniCode.ToString().GetHashCode();}}internalclassHashMatrix<T>{///<summary>///最大六个车道,坐标远点是RoadNode的positon///</summary>internalreadonlyintiMaxWidth=SimSettings.iMaxLanes;privateDictionary<int,T>hashMat=newDictionary<int,T>();///<summary>///判断元胞是否被占用了///</summary>///<paramname="x"></param>///<paramname="y"></param>///<returns></returns>internalboolIsBlocked(intx,inty){returnhashMat.ContainsKey(HashKeyProvider.GetHashCode(x,y));}///<summary>///把元宝从o点移动到d点///</summary>internalboolMove(PointinXY,PointinXY_D){intiHashkey=HashKeyProvider.GetHashCode(inXY.X,inXY.Y);Tcac;if(hashMat.TryGetValue(iHashkey,outcac)==true){hashMat.Remove(iHashkey);iHashkey=HashKeyProvider.GetHashCode(inXY_D.X,inXY_D.Y);if(hashMat.ContainsKey(iHashkey)==true){returnfalse;}else{hashMat.Add(iHashkey,cac);returntrue;}}returnfalse;}internalvoidAdd(intx,inty,Tcell){//更新行和列的最大索引if(Math.Abs(x)>this.iMaxWidth||Math.Abs(y)>this.iMaxWidth){thrownewArgumentOutOfRangeException("x或者y参数超出了默认的最大数值");}intiHKey=HashKeyProvider.GetHashCode(x,y);if(!hashMat.ContainsKey(iHKey)){hashMat.Add(iHKey,cell);}}internalboolRemove(intx,inty){returnhashMat.Remove(HashKeyProvider.GetHashCode(x,y));}internalintCount{get{returnhashMat.Count;}}internalDictionary<int,T>.ValueCollectionValues{get{returnhashMat.Values;}}#region枚举器///<summary>///提供对存储元素的高效遍历///</summary>///<returns></returns>internalIEnumerator<T>GetEnumerator(){returnthis.hashMat.Values.GetEnumerator();}#endregion//[System.Obsolete("没有实现")]//publicintIndexOf(Titem)//{//thrownewNotImplementedException();//}//[System.Obsolete("没有实现")]//publicvoidInsert(intindex,Titem)//{//thrownewNotImplementedException();//}//[System.Obsolete("没有实现")]//publicvoidRemoveAt(intindex)//{//thrownewNotImplementedException();//}internalTthis[intindex]{get{returnhashMat[index];}}internalICollection<int>Keys{get{returnhashMat.Keys;}}//[System.Obsolete("没有实现")]//publicvoidAdd(Titem)//{//thrownewNotImplementedException();//}//[System.Obsolete("没有实现")]//publicvoidClear()//{//thrownewNotImplementedException();//}//[System.Obsolete("没有实现")]//publicboolContains(Titem)//{//thrownewNotImplementedException();//}//[System.Obsolete("没有实现")]//publicvoidCopyTo(T[]array,intarrayIndex)//{//thrownewNotImplementedException();//}//intICollection<T>.Count//{//get{thrownewNotImplementedException();}//}//publicboolIsReadOnly//{//get{thrownewNotImplementedException();}//}//publicboolRemove(Titem)//{//thrownewNotImplementedException();//}//IEnumerator<T>IEnumerable<T>.GetEnumerator()//{//thrownewNotImplementedException();//}//System.Collections.IEnumeratorSystem.Collections.IEnumerable.GetEnumerator()//{//thrownewNotImplementedException();//}}}
(3)路网模型
路网的表示。道路路网提供机动车辆行驶的环境,而在仿真系统中利用路网作为容纳车辆元胞的容器,提供车辆元胞演化和状态更新的空间,从元胞角度看,路网是所有车辆元胞可以达到的空间网格的集合。在道路路网外部是车辆元胞不可到达的区域。
交通仿真系统中的道路网络的拓扑结构可以按照图论中图的理论进行表示和抽象,按照图论的相关内容,对于不存在单行道的道路网络,可以将其表示为无向图,对于有单行道的道路网络,可以将其表示为有向图。考虑到交通仿真系统的复杂性,对于需要计算路段阻抗和效用函数的高级应用如,车辆动态路径规划问题,需要将道路网络进一步表示为带权有向图。关于无向图,有向图,带权有向图的概念请参见图论相关文献。
图4.4有向图和无向图的矩阵表示法
图4.5有向图和无向图的邻接表表示法
由于道路网络规模可能很大,为了节省计算机资源,本文中采用邻接矩阵表示法来表示道路网络,在每个道路网络中引入广义费用或者阻抗函数作为道路路段的权重。关于路段阻抗函数的定义和分析将在路径规划中进行说明。