⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pathfinder.cpp

📁 我用的是arcengine开发,在几何网络中寻找最短路径.
💻 CPP
字号:
// PathFinder.cpp: implementation of the CPathFinder class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "yunres.h"
#include "PathFinder.h"
#include "../BaseFunc/Global.h"
__declspec(dllimport) CGlobal m_Global;
#include <afxtempl.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPathFinder::CPathFinder()
{

}

CPathFinder::~CPathFinder()
{

}

void CPathFinder::OpenFeatureDatasetNetwork(IFeatureDataset *FeatureDS)
{
	CloseWorkspace();
	InitializeNetworkAndMap(FeatureDS);
}


void CPathFinder::CloseWorkspace()
{
	// make sure we let go of everything and start
	// with new results
	m_pGeometricNetwork = 0;
	m_pPoints = 0;
	m_pPointToEID = 0;
	m_pEnumNetEID_Junctions = 0;
	m_pEnumNetEID_Edges = 0;
	m_pPolyline = 0;	
}

bool CPathFinder::InitializeNetworkAndMap(IFeatureDatasetPtr FeatureDataset)
{
	INetworkCollectionPtr     ipNetworkCollection;
	INetworkPtr               ipNetwork;
	int                       intCount, i;
	long                      lngCount;
	IFeatureClassContainerPtr ipFeatureClassContainer;
	IFeatureClassPtr          ipFeatureClass;
	IGeoDatasetPtr            ipGeoDataset;
	ILayerPtr                 ipLayer;
	IFeatureLayerPtr          ipFeatureLayer;
	IEnvelopePtr              ipEnvelope,ipMaxEnvelope;
	double                    dblSearchTol;
	double                    dblWidth, dblHeight;

	try
	{
		// get the networks
		ipNetworkCollection = FeatureDataset;
		// even though a FeatureDataset can have many networks, we'll just
		// assume the first one (otherwise you would pass the network name in, etc.)

		// get the count of networks
		intCount = ipNetworkCollection->GetGeometricNetworkCount();
		if (intCount == 0) return false;  // 'No networks found'

		// get the first Geometric Newtork (0 - based)
		m_pGeometricNetwork = ipNetworkCollection->GetGeometricNetwork(0);

		// get the Network
		ipNetwork = m_pGeometricNetwork->GetNetwork();

		// The EID Helper class that converts points to EIDs needs a
		// IMap, so we'll need one around with all our layers added.
		// This Pathfinder object has an optional Map property than may be set
		// before opening the Network.
		if (m_pMap == NULL)
		{
			m_pMap.CreateInstance(__uuidof(Map));

			// Add each of the Feature Classes in this Geometric Network as a map Layer
			ipFeatureClassContainer = m_pGeometricNetwork;
			lngCount = ipFeatureClassContainer->GetClassCount();
			if (lngCount == 0) return false;  // 'No (network) feature classes found'
			for (i = 0; i <= lngCount - 1; i++)
			{
				// get the feature class
				ipFeatureClass = ipFeatureClassContainer->GetClass(i);

				// make a layer
				ipFeatureLayer.CreateInstance(__uuidof(FeatureLayer));
				ipFeatureLayer->PutRefFeatureClass(ipFeatureClass);

				// add layer to the map
				m_pMap->AddLayer((ILayerPtr)ipFeatureLayer);
			}
		}         // if we needed to make a Map


		// Calculate point snap tolerance as 1/100 of map width.
		lngCount = m_pMap->GetLayerCount();
		ipMaxEnvelope.CreateInstance(__uuidof(Envelope));

		for (i = 0; i <= lngCount - 1; i++)
		{
			ipLayer = m_pMap->GetLayer(i);
			ipFeatureLayer = ipLayer;

			// get its dimensions (for setting search tolerance)
			ipGeoDataset = ipFeatureLayer;
			ipEnvelope = ipGeoDataset->GetExtent();

			// merge with max dimensions
			ipMaxEnvelope->Union(ipEnvelope);
		}

		// finally, we can set up the IPointToEID ...
		m_pPointToEID.CreateInstance(__uuidof(PointToEID));
		m_pPointToEID->PutRefSourceMap(m_pMap);
		m_pPointToEID->PutRefGeometricNetwork(m_pGeometricNetwork);

		// set snap tolerance
		dblWidth = ipMaxEnvelope->GetWidth();
		dblHeight = ipMaxEnvelope->GetHeight();
		if (dblWidth > dblHeight) 
			dblSearchTol = dblWidth / 100;
		else
			dblSearchTol = dblHeight / 100;
		m_pPointToEID->PutSnapTolerance(dblSearchTol);
	}
	catch(_com_error &e)
	{
		_bstr_t err = e.Description();
		return(false);
	}
	return(true);
}

void CPathFinder::PutPoints(IPointCollection *newVal)
{
	m_pPoints = newVal;
}

int CPathFinder::SolvePath(CString WeightName)
{
	INetworkPtr          ipNetwork;
	ITraceFlowSolverPtr  ipTraceFlowSolver;
	INetSolverPtr        ipNetSolver;
	INetFlagPtr          ipNetFlag;
	IJunctionFlag**      ipJunctionFlag;
	IPointPtr            ipEdgePoint;
	INetElementsPtr      ipNetElements;
	long                 lngEdgeUserClassID, lngEdgeUserID, lngEdgeUserSubID, lngEdgeID;
	IPointPtr            ipFoundEdgePoint;
	INetWeightPtr        ipNetWeight;
	INetSolverWeightsPtr ipNetSolverWeights;
	INetSchemaPtr        ipNetSchema;
	long                 lngCount;
	int                  i;
	VARIANT*             pvaSegmentCosts;

	try
	{
		// make sure we are ready
		if (m_pPoints == NULL) return -1;            // 'StopPoints are not set'
		if (m_pGeometricNetwork == NULL) return -1;  // 'Network is not set'

		// instantiate a trace flow solver
		ipTraceFlowSolver.CreateInstance(__uuidof(TraceFlowSolver));

		// get the INetSolver interface
		ipNetSolver = ipTraceFlowSolver;

		// set the source network to solve on
		ipNetwork = m_pGeometricNetwork->GetNetwork();
		ipNetSolver->PutRefSourceNetwork(ipNetwork);

		// make edge flags from the points

		// the INetElements interface is needed to get UserID, UserClassID,
		// and UserSubID from the element id (EID)
		ipNetElements = ipNetwork;

		// get the count
		lngCount = m_pPoints->GetPointCount();

		if (lngCount < 2) return -1;         // '2 or more points are needed'

		// dimension our IEdgeFlag array
		ipJunctionFlag = new IJunctionFlag*[lngCount];

		// for each point
		for (i = 0; i <= lngCount - 1; i++)
		{
			// make a new Edge Flag
			ipNetFlag.CreateInstance(__uuidof(JunctionFlag));
			ipEdgePoint = m_pPoints->GetPoint(i);
			// look up the EID for the current point  (this will populate intEdgeID and dblEdgePercent)
			m_pPointToEID->GetNearestJunction(ipEdgePoint, &lngEdgeID, &ipFoundEdgePoint);

 			if (lngEdgeID < 1) return -1;   // 'Point (eid) not found'

			ipNetElements->QueryIDs(lngEdgeID, esriETJunction, &lngEdgeUserClassID, &lngEdgeUserID, &lngEdgeUserSubID);

			if ((lngEdgeUserClassID < 1) && (lngEdgeUserID < 1)) return -1;  // 'eid not found'

			ipNetFlag->PutUserClassID(lngEdgeUserClassID);
			ipNetFlag->PutUserID(lngEdgeUserID);
			ipNetFlag->PutUserSubID(lngEdgeUserSubID);

			ipJunctionFlag[i] = (IJunctionFlagPtr)ipNetFlag;
			ipNetFlag->AddRef();
		}

		// add these edge flags
		ipTraceFlowSolver->PutJunctionOrigins(lngCount, &ipJunctionFlag[0]);

		// set the weight (cost field) to solve on

		// get the INetSchema interface
		ipNetSchema = ipNetwork;

		ipNetWeight = ipNetSchema->GetWeightByName((_bstr_t)WeightName);

		if (ipNetWeight == NULL) return -1;   // 'Weight: ' + WeightName + ' not found'

		// set the weight (use the same for both directions)
		// Note: You could also set Junction weights here.
		ipNetSolverWeights = ipTraceFlowSolver;
		ipNetSolverWeights->PutRefToFromEdgeWeight(ipNetWeight);
		ipNetSolverWeights->PutRefFromToEdgeWeight(ipNetWeight);

		// initialize array for results to number of segments in result
		pvaSegmentCosts = new VARIANT[lngCount-1];

		// solve it
		ipTraceFlowSolver->FindPath( esriFMConnected, esriSPObjFnMinSum, &m_pEnumNetEID_Junctions, &m_pEnumNetEID_Edges, lngCount - 1, &pvaSegmentCosts[0]);

		// compute total cost
		m_dblPathCost = 0;
		for (i = 0; i <= lngCount - 2; i++)
			m_dblPathCost = m_dblPathCost + pvaSegmentCosts[i].dblVal;

		// clear the last polyline result
		if(m_pPolyline != NULL)
			m_pPolyline.Release();

		// release NetFlags
		for (i = 0; i <= lngCount - 1; i++)
		{
			ipNetFlag = (INetFlagPtr)ipJunctionFlag[i];
			ipNetFlag->Release();
		}

		// delete arrays
		delete ipJunctionFlag;
		delete pvaSegmentCosts;
	}
	catch(_com_error &e)
	{
		_bstr_t err = e.Description();
		return(-1);
	}
	return(1);
}

void CPathFinder::GetPathPolyLine(IPolyline **pVal,CArray<IFeature *,IFeature *> &arrLineFeature)
{
	IEIDHelperPtr          ipEIDHelper;
	long                   count, i;
	IEIDInfoPtr            ipEIDInfo;
	IEnumEIDInfoPtr        ipEnumEIDInfo;
	IGeometryPtr           ipGeometry;
	IGeometryCollectionPtr ipNewGeometryColl;
	ISpatialReferencePtr   ipSpatialReference;
	try
	{
		// if the line is already computed since the last path, just return it
		if (m_pPolyline)
		{
			*pVal = m_pPolyline;
			(*pVal)->AddRef();
			return ;
		}

		// a path should be solved first
		if (m_pEnumNetEID_Edges == NULL) return ;  // 'No results computed yet.'

		// make the new polyline instance
		m_pPolyline.CreateInstance(__uuidof(esriCore::Polyline));

		// get its geometry collection interface
		ipNewGeometryColl = m_pPolyline; 

		// make an EIDHelper object to translate edges to geometric features
		ipEIDHelper.CreateInstance(__uuidof(EIDHelper));
		ipEIDHelper->PutRefGeometricNetwork(m_pGeometricNetwork);

		// use the spatial reference from the current map
		ipSpatialReference = m_pMap->GetSpatialReference();
		ipEIDHelper->PutRefOutputSpatialReference(ipSpatialReference);
		ipEIDHelper->PutReturnGeometries(VARIANT_TRUE);
		// if get the feature,must be add this cstring , and add the fields where
		// to query the value of this feature . for example ,the street'name、length
		ipEIDHelper->PutReturnFeatures(VARIANT_TRUE);
		//  get and add fields
		// ---- get the layer who provide the polyline to network analysis
		IFeatureLayerPtr pNetWorkLayer = m_Global.m_pMapControl->GetLayer(
			m_Global.m_pMapInfo.GetNetWorkPolyLineLayerID());
		// ---- get the layer name
		CString sLayerName = (const char*)pNetWorkLayer->GetName();
		// ---- get fields'name for the feature
		CArray<CString,CString&> arrFieldsName;
		m_Global.m_pMapInfo.GetFieldsForNetWorkPolyLineLayer(
			m_Global.GetCurUserName(),sLayerName,arrFieldsName);
		// ---- add the fields to the helper who 
		//      can help the feature query the fields'value
		for(i=0;i<arrFieldsName.GetSize();i++)
			ipEIDHelper->AddField((_bstr_t)arrFieldsName.GetAt(i));
		// get the details using the  IEIDHelper classes
		ipEnumEIDInfo = ipEIDHelper->CreateEnumEIDInfo(m_pEnumNetEID_Edges);
		count = ipEnumEIDInfo->GetCount();

		// set the iterator to beginning
		ipEnumEIDInfo->Reset();
		for (i = 1; i <= count; i++)
		{
			// get the next EID and a copy of its geometry (it makes a Clone)
			ipEIDInfo = ipEnumEIDInfo->Next();
			ipGeometry = ipEIDInfo->GetGeometry();
			// test , add new parameter to get the array of the feature with findpath
			arrLineFeature.Add(ipEIDInfo->GetFeature().Detach());
			// if ipGeometry is null, then the corresponding eid was invalid!
			if (ipGeometry != NULL)
				ipNewGeometryColl->AddGeometryCollection((IGeometryCollectionPtr)ipGeometry);
		}

		*pVal = m_pPolyline;
		(*pVal)->AddRef();
	}
	catch(_com_error &e)
	{
		_bstr_t err = e.Description ();
	}
}

double CPathFinder::GetPathCost()
{
	return(m_dblPathCost);
}

void CPathFinder::ResetWorkspace()
{
	m_pPoints = 0;	
}

IPointCollectionPtr CPathFinder::GetPoints()
{
	return(m_pPoints);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -