|
阅读:1650回复:4
本人用A*实现的最优路径算法源代码
简介:在GIS网络中,指定两地图上任意的两点,求最优路径。我在全上海大数据量下在普通PC下测试计算时间小于1秒。<br>
#ifndef _CGIS_NET_PATH_FINDER_H_<br> #define _CGIS_NET_PATH_FINDER_H_<br> <br> #include "map.h"<br> #include "vector.h"<br> <br> using namespace __STD;<br> <br> /*******************************************************<br> **purpose: net path finder <br> **author: Kemp(MeiPing Ke, in Shanghai)<br> **time: 2005/05/29<br> ********************************************************/<br> <br> class CGIS_NetPathFinder<br> {<br> public:<br> CGIS_NetPathFinder();<br> virtual ~CGIS_NetPathFinder();<br> <br> public:<br> //set layer<br> void SetNetLayer(CGIS_Layer* pNetLayer){m_pNetLayer = pNetLayer;}<br> <br> //get layer<br> CGIS_Layer* GetNetLayer(){return m_pNetLayer;}<br> <br> //set start position<br> void SetStartPos(CGIS_Point* pPoint){m_StartPos = *pPoint;}<br> <br> //get start position<br> CGIS_Point* GetStartPos(){return ;m_StartPos;}<br> <br> //set end position<br> void SetEndPos(CGIS_Point* pPoint){m_EndPos = *pPoint;}<br> <br> //get end position<br> CGIS_Point* GetEndPos(){return ;m_EndPos;}<br> <br> public:<br> //find path<br> bool FindPath(vector<int>; vResNode, vector<int>; vResArc);<br> <br> //reset<br> void Reset();<br> public:<br> //node info<br> struct NODE<br> {<br> //G<br> double g;<br> <br> //F<br> double f;<br> <br> //FID<br> int fid;<br> <br> //Arc<br> int iArc;<br> <br> //parent node<br> NODE *pParent; <br> };<br> <br> //virtual node info <br> struct V_NODE<br> {<br> //FID<br> int iNodeID;<br> <br> //Arc<br> int iArcID;<br> <br> //start arc node<br> int iStartNode;<br> <br> //start weight<br> double dStartWeight;<br> <br> //end arc node<br> int iEndNode;<br> <br> //end weight<br> double dEndWeight;<br> };<br> protected:<br> //init virtual nodes<br> bool InitVirtualNode(CGIS_Point; Pos, V_NODE; vNod, int iNodID);<br> <br> //calculate weight<br> virtual inline double CalWeight(CGIS_Point* pFromPoint, CGIS_Point* pToPoint);<br> virtual inline double CalWeight(int x, int y, int x2, int y2);<br> virtual inline double CalWeight(int iArcFid);<br> <br> //get the result path<br> void GetResultPath(NODE* pNode, vector<int>; vResNod, vector<int>; vResArc);<br> <br> //get near arc<br> int GetNearSetion (int x, int y, int; iDis, CGIS_Feature** ppFeature);<br> protected:<br> //net layer<br> CGIS_Layer* m_pNetLayer;<br> <br> //start point<br> CGIS_Point m_StartPos;<br> <br> //end point<br> CGIS_Point m_EndPos;<br> <br> //open list<br> map<double, NODE*> m_mOpenList;<br> <br> //close list<br> map<int, NODE*> m_mCloseList;<br> <br> //start virtual node<br> V_NODE m_StartVNode;<br> <br> //end virtual node<br> V_NODE m_EndVNode;<br> };<br> <br> #endif<br> <br> <br> #include "stdafx.h"<br> #include "CGeoMath.h"<br> #include "CGIS_CircleShape.h"<br> #include "public_share.h"<br> #include "CGIS_NetPathFinder.h"<br> <br> /*******************************************************<br> **purpose: net path finder <br> **author: Kemp(MeiPing Ke, in Shanghai)<br> **time: 2005/05/29<br> ********************************************************/<br> <br> <br> CGIS_NetPathFinder::CGIS_NetPathFinder():m_StartPos(0, 0), m_EndPos(0, 0)<br> {<br> //net layer<br> m_pNetLayer = NULL;<br> <br> //start virtual node<br> memset(;m_StartVNode, 0, sizeof(V_NODE));<br> <br> //end virtual nod<br> memset(;m_EndVNode, 0, sizeof(V_NODE));<br> }<br> <br> CGIS_NetPathFinder::~CGIS_NetPathFinder()<br> {<br> Reset();<br> }<br> <br> //reset<br> void CGIS_NetPathFinder::Reset()<br> {<br> //clean open list<br> map<double, NODE*>::iterator it = m_mOpenList.begin();<br> for (; it != m_mOpenList.end(); it++)<br> {<br> delete it->second;<br> }<br> m_mOpenList.clear();<br> <br> //clean close list<br> map<int, NODE*>::iterator itClose = m_mCloseList.begin();<br> for (; itClose != m_mCloseList.end(); itClose++)<br> {<br> delete itClose->second;<br> }<br> m_mCloseList.clear();<br> <br> //reset virtual node<br> memset(;m_StartVNode, 0, sizeof(V_NODE));<br> memset(;m_EndVNode, 0, sizeof(V_NODE));<br> }<br> <br> //find path<br> bool CGIS_NetPathFinder::FindPath(vector<int>; vResNode, vector<int>; vResArc)<br> {<br> ASSERT(m_pNetLayer != NULL);<br> ASSERT(m_StartPos != m_EndPos);<br> <br> //init virtual nodes<br> int iVirtualNodeID = m_pNetLayer->GetMaxFeatureIDInMem() + 1;<br> if (!InitVirtualNode(m_StartPos, m_StartVNode, iVirtualNodeID++))<br> return false;<br> if (!InitVirtualNode(m_EndPos, m_EndVNode, iVirtualNodeID++))<br> return false;<br> <br> //add the first nod to the open list<br> NODE* pNode = new NODE;<br> pNode->g = 0.;<br> pNode->f = pNode->g + CalWeight(;m_StartPos, ;m_EndPos);<br> pNode->pParent = NULL;<br> pNode->iArc = m_StartVNode.iArcID;<br> pNode->fid = m_StartVNode.iNodeID;<br> <br> m_mOpenList.insert(map<double, NODE*>::value_type(pNode->f, pNode));<br> <br> //find<br> map<double, NODE*>::iterator itOpen;<br> map<int, int> mNodeArc;<br> map<int, int>::iterator itArc;<br> CGIS_GeoArc* pGeoArc = NULL;<br> CGIS_GeoPoint* pGeoPoint = NULL;<br> CGIS_Feature* pFeature = NULL;<br> NODE* pNewNode = NULL;<br> vector<int> vNearNode;<br> register int i = 0;<br> int iCount = 0, iArcID = 0, iNodeID = 0;<br> double h = 0.;<br> <br> while (m_mOpenList.size() > 0)<br> {<br> //get min "f"<br> itOpen = m_mOpenList.begin();<br> <br> //found ?<br> pNode = itOpen->second;<br> if (pNode->fid == m_EndVNode.iNodeID)<br> {<br> GetResultPath(pNode, vResNode, vResArc);<br> return true;<br> }<br> else<br> { <br> //close it <br> m_mOpenList.erase(itOpen);<br> m_mCloseList.insert(map<int, NODE*>::value_type(pNode->fid, pNode));<br> }<br> <br> //get it's near nodes<br> vNearNode.clear();<br> mNodeArc.clear();<br> if (pNode->fid == m_StartVNode.iNodeID)<br> {<br> vNearNode.push_back(m_StartVNode.iStartNode);<br> vNearNode.push_back(m_StartVNode.iEndNode);<br> }<br> else if (pNode->fid == m_EndVNode.iNodeID)<br> {<br> vNearNode.push_back(m_EndVNode.iStartNode);<br> vNearNode.push_back(m_EndVNode.iEndNode); <br> }<br> else<br> {<br> pGeoPoint = m_pNetLayer->GetAllFeaturesPtr()->GetPointFeatureSetPtr()->GetFeaturePtr(pNode->fid)->GetGeoPointPtr(); <br> iCount = pGeoPoint->GetArcCount();<br> for ( i = 0; i < iCount; i++)<br> {<br> iArcID = pGeoPoint->GetArcID(i);<br> iArcID = abs(iArcID);<br> if (iArcID != m_StartVNode.iArcID)<br> {<br> pFeature = m_pNetLayer->GetAllFeaturesPtr()->GetFeaturePtr(iArcID);<br> if (!pFeature)<br> {<br> ASSERT(false);<br> return false;<br> }<br> <br> if (iArcID != m_EndVNode.iArcID)<br> { <br> iNodeID = pFeature->GetGeoArcPtr()->GetStartNodeID();<br> if (iNodeID != pNode->fid)<br> {<br> vNearNode.push_back(iNodeID);<br> mNodeArc.insert(map<int, int>::value_type(iNodeID, iArcID));<br> }<br> else <br> {<br> iNodeID = pFeature->GetGeoArcPtr()->GetEndNodeID();<br> vNearNode.push_back(iNodeID);<br> mNodeArc.insert(map<int, int>::value_type(iNodeID, iArcID));<br> }<br> }<br> else<br> {<br> vNearNode.push_back(m_EndVNode.iNodeID);<br> }<br> }<br> }<br> }<br> <br> //do near nodes<br> for (i = 0; i < vNearNode.size(); i++)<br> {<br> if (m_mCloseList.find(vNearNode) != m_mCloseList.end())<br> continue;<br> <br> //add the node to open list<br> if (m_mOpenList.find(vNearNode) != m_mOpenList.end())<br> continue;<br> <br> pNewNode = new NODE;<br> pNewNode->fid = vNearNode;<br> pNewNode->g = 0.;<br> h = 0.;<br> pNewNode->pParent = pNode;<br> pNewNode->iArc = 0;<br> <br> if (pNode->fid == m_StartVNode.iNodeID ;; pNewNode->fid == m_StartVNode.iStartNode)<br> {<br> pNewNode->iArc = m_StartVNode.iArcID;<br> pNewNode->g = pNewNode->pParent->g + m_StartVNode.dStartWeight;<br> }<br> else if (pNode->fid == m_StartVNode.iNodeID ;; pNewNode->fid == m_StartVNode.iEndNode)<br> {<br> pNewNode->iArc = m_StartVNode.iArcID;<br> pNewNode->g = pNewNode->pParent->g + m_StartVNode.dEndWeight;<br> }<br> else if ((pNode->fid == m_EndVNode.iNodeID ;; pNewNode->fid == m_EndVNode.iEndNode)<br> || (pNode->fid == m_EndVNode.iEndNode ;; pNewNode->fid == m_EndVNode.iNodeID))<br> {<br> pNewNode->iArc = m_EndVNode.iArcID;<br> pNewNode->g = pNewNode->pParent->g + m_EndVNode.dEndWeight;<br> }<br> else if ((pNode->fid == m_EndVNode.iNodeID ;; pNewNode->fid == m_EndVNode.iEndNode)<br> || (pNode->fid == m_EndVNode.iEndNode ;; pNewNode->fid == m_EndVNode.iNodeID))<br> {<br> pNewNode->iArc = m_EndVNode.iArcID;<br> pNewNode->g = pNewNode->pParent->g + m_EndVNode.dEndWeight;<br> }<br> else if (pNewNode->fid != m_StartVNode.iNodeID<br> ;; pNewNode->fid != m_EndVNode.iNodeID<br> ;; pNode->fid != m_StartVNode.iNodeID<br> ;; pNode->fid != m_EndVNode.iNodeID)<br> {<br> if ((itArc = mNodeArc.find(pNewNode->fid)) != mNodeArc.end())<br> {<br> pNewNode->iArc = itArc->second;<br> pNewNode->g = pNewNode->pParent->g + CalWeight(itArc->second);<br> }<br> }<br> <br> if (pNewNode->fid == m_StartVNode.iNodeID)<br> {<br> h = CalWeight(;m_StartPos, ;m_EndPos);<br> }<br> else if (pNewNode->fid == m_EndVNode.iNodeID)<br> {<br> h = 0.;<br> }<br> else<br> {<br> pFeature = m_pNetLayer->GetAllFeaturesPtr()->GetFeaturePtr(pNewNode->fid);<br> if (pFeature == NULL)<br> {<br> ASSERT(false);<br> return false;<br> }<br> <br> h = CalWeight(pFeature->GetGeoPointPtr()->GetPointPtr(), ;m_EndPos);<br> }<br> <br> pNewNode->f = pNewNode->g + h;<br> m_mOpenList.insert(map<double, NODE*>::value_type(pNewNode->f, pNewNode));<br> }<br> }<br> <br> return false;<br> }<br> <br> //init virtual nods<br> bool CGIS_NetPathFinder::InitVirtualNode(CGIS_Point; Pos, V_NODE; vNode, int iNodeID)<br> {<br> CGIS_Feature* pNearArc = NULL;<br> int iDis = 0;<br> D_DOT pt, ptOut;<br> D_DOT* pLin = NULL;<br> double dDis = 0.;<br> int iSub = -1;<br> int iCount = 0;<br> <br> try<br> {<br> GetNearSetion (Pos.x, Pos.y, iDis, ;pNearArc);<br> if (pNearArc == NULL)<br> {<br> AfxMessageBox("无法找到最近段!");<br> return false;<br> }<br> <br> pt.x = ((double)Pos.Getx ()) / 10000.;<br> pt.y = ((double)Pos.Gety ()) / 10000.;<br> <br> iCount = pNearArc->GetGeoArcPtr()->GetPointCount();<br> pLin = new D_DOT[iCount]; <br> for (int i = 0; i < iCount; i++)<br> {<br> pLin.x = pNearArc->GetGeoArcPtr()->GetPointPtr(i)->Getx() / 10000.;<br> pLin.y = pNearArc->GetGeoArcPtr()->GetPointPtr(i)->Gety() / 10000.;<br> }<br> <br> iSub = GetNearSubInLin( pt, pLin, iCount);<br> if (iSub < 0)<br> throw "";<br> if (0 == GetNearPtInLin(pt, pLin, iCount, ptOut, dDis))<br> throw "";<br> <br> memset(;vNode, 0, sizeof(V_NODE));<br> vNode.iArcID = pNearArc->GetFeatureID();<br> vNode.iStartNode = pNearArc->GetGeoArcPtr()->GetStartNodeID();<br> vNode.iEndNode = pNearArc->GetGeoArcPtr()->GetEndNodeID();<br> <br> CGIS_Feature* pF1 = m_pNetLayer->GetAllFeaturesPtr()->GetFeaturePtr(vNode.iStartNode); <br> if (pF1 == NULL)<br> throw "";<br> double dWight1 = CalWeight(pLin[0].x * 10000, pLin[0].y * 10000, pF1->GetGeoPointPtr()->GetPointPtr()->Getx(), pF1->GetGeoPointPtr()->GetPointPtr()->Gety());<br> double dWight2 = CalWeight(pLin[iCount - 1].x * 10000, pLin[iCount - 1].y * 10000, pF1->GetGeoPointPtr()->GetPointPtr()->Getx(), pF1->GetGeoPointPtr()->GetPointPtr()->Gety());<br> if (dWight1 > dWight2)<br> {<br> int iTemp = vNode.iStartNode;<br> vNode.iStartNode = vNode.iEndNode;<br> vNode.iEndNode = iTemp;<br> }<br> <br> vNode.iNodeID = iNodeID;<br> vNode.dStartWeight = 0.;<br> vNode.dEndWeight = 0.;<br> <br> for (i = 0; i < iSub; i++)<br> vNode.dStartWeight += CalWeight(pLin.x * 10000, pLin.y * 10000, pLin[i + 1].x * 10000, pLin[i + 1].y * 10000);<br> vNode.dStartWeight += CalWeight(pLin[iSub].x * 10000, pLin[iSub].y * 10000, ptOut.x * 10000, ptOut.y * 10000);<br> <br> vNode.dEndWeight += CalWeight(ptOut.x * 10000, ptOut.y * 10000, pLin[iSub + 1].x * 10000, pLin[iSub + 1].y * 10000);<br> for (i = iSub + 1; i < iCount - 1; i++)<br> vNode.dEndWeight += CalWeight(pLin.x * 10000, pLin.y * 10000, pLin[i + 1].x * 10000, pLin[i + 1].y * 10000);<br> }<br> catch (LPSTR)<br> {<br> delete [] pLin;<br> return false;<br> }<br> <br> delete [] pLin;<br> <br> return true;<br> }<br> <br> //calculate weight<br> inline double CGIS_NetPathFinder::CalWeight(CGIS_Point* pFromPoint, CGIS_Point* pToPoint)<br> {<br> double dx = (pFromPoint->x - pToPoint->x)/10000.; <br> double dy = (pFromPoint->y - pToPoint->y)/10000.;<br> <br> return sqrt(dx * dx + dy * dy);<br> }<br> <br> inline double CGIS_NetPathFinder::CalWeight(int x, int y, int x2, int y2)<br> {<br> double dx = (x - x2)/10000.; <br> double dy = (y - y2)/10000.;<br> <br> return sqrt(dx * dx + dy * dy); <br> }<br> <br> inline double CGIS_NetPathFinder::CalWeight(int iArcFid)<br> {<br> ASSERT(m_pNetLayer != NULL);<br> <br> CGIS_GeoArc* pGeoArc = m_pNetLayer->GetAllFeaturesPtr()->GetFeaturePtr(iArcFid)->GetGeoArcPtr();<br> double dWeight = 0.;<br> int iCount = pGeoArc->GetPointCount();<br> for (int i = 0; i < iCount - 1; i++)<br> {<br> dWeight += CalWeight(pGeoArc->GetPointPtr(i), pGeoArc->GetPointPtr(i + 1));<br> }<br> <br> return dWeight;<br> }<br> <br> //get the result path<br> void CGIS_NetPathFinder::GetResultPath(NODE* pNode, vector<int>; vResNode, vector<int>; vResArc)<br> {<br> ASSERT(pNode != NULL ;; pNode->iArc != 0);<br> <br> NODE* pParentNode = pNode;<br> while (pParentNode != NULL)<br> {<br> if (pParentNode->fid != m_StartVNode.iNodeID<br> ;; pParentNode->fid != m_EndVNode.iNodeID)<br> {<br> vResNode.push_back(pParentNode->fid);<br> }<br> <br> vResArc.push_back(pParentNode->iArc);<br> <br> pParentNode = pParentNode->pParent;<br> }<br> }<br> <br> int CGIS_NetPathFinder::GetNearSetion (int x,int y,int; iDis,CGIS_Feature** ppFeature)<br> {<br> CGIS_Point CenterPos;<br> CenterPos.Setx (x);<br> CenterPos.Sety (y);<br> <br> CGIS_FeatureSet SectionSet(m_pNetLayer, "temp query set");<br> int iRadiu = 10 * 10000;<br> CGIS_CircleShape CircleShape;<br> while (SectionSet.GetArcFeatureSetPtr()->GetFeatureCount() < 1 ;; iRadiu < 500 * 100 * 10000)<br> {<br> CircleShape.SetCentrePoint(CenterPos);<br> CircleShape.SetRadius(iRadiu);<br> <br> pNetLayer->GetAllFeaturesPtr()->QueryByShape(;CircleShape, GIS_SPATIAL_INTERSECT, ;SectionSet);<br> <br> iRadiu += 10 * 10000;<br> }<br> <br> D_DOT pt,ptOut,*pLin = NULL;<br> int iHaveLen = 0;<br> double dDist = 0,dMinDist = 99999999999999.;// a impossible max value<br> int iFindID = 0;<br> <br> pt.x = x;<br> pt.y = y;<br> <br> CGIS_Feature* pFeature =SectionSet.GetArcFeatureSetPtr () ->GetFirstFeaturePtr ();<br> while (pFeature)<br> {<br> if (iHaveLen < pFeature ->GetGeoArcPtr () ->GetPointCount ())<br> {<br> if (pLin)<br> delete [] pLin;<br> pLin = new D_DOT[pFeature ->GetGeoArcPtr () ->GetPointCount ()];<br> if (!pLin)<br> return 0;<br> iHaveLen = pFeature ->GetGeoArcPtr () ->GetPointCount ();<br> }<br> <br> for (int i = 0; i < pFeature ->GetGeoArcPtr () ->GetPointCount (); i ++)<br> {<br> pLin.x = pFeature ->GetGeoArcPtr () ->GetPointPtr (i) ->Getx ();<br> pLin.y = pFeature ->GetGeoArcPtr () ->GetPointPtr (i) ->Gety ();<br> }<br> dDist = 0.;<br> GetNearPtInLin(pt,pLin,pFeature ->GetGeoArcPtr () ->GetPointCount (),ptOut,dDist);<br> if (dDist < dMinDist)<br> {<br> dMinDist = dDist;<br> iFindID = pFeature ->GetFeatureID ();<br> if (ppFeature)<br> *ppFeature = pFeature;<br> }<br> pFeature =SectionSet.GetArcFeatureSetPtr () ->GetNextFeaturePtr (); <br> } <br> if (pLin)<br> delete [] pLin;<br> <br> iDis = dMinDist;<br> return iFindID;<br> }<br> |
|
|
1楼#
发布于:2005-05-31 11:40
<P>支持楼主,不知道你用什么数据实现的,给个小例子给大家就方便了</P>
<img src="images/post/smile/dvbbs/em01.gif" /><img src="images/post/smile/dvbbs/em02.gif" /><img src="images/post/smile/dvbbs/em04.gif" /> |
|
|
|
2楼#
发布于:2005-08-23 17:02
<P>感谢楼主,提供了一个解决思路</P>
|
|
|
3楼#
发布于:2007-03-19 17:38
回复:(johnxt)本人用A*实现的最优路径算法源代码
//add the node to open list<BR><BR> if (m_mOpenList.find(vNearNode) != m_mOpenList.end())<BR><BR> continue;<BR>这里是不是有问题。map数组的键值显然是double,而vNearNode返回为INT。显然,这一步判断是失败的。永远没法查证某个结点是不是在OPEN表。 |
|
|
4楼#
发布于:2007-03-20 18:54
<P>关注!</P>
|
|