📄 pathfinder.cpp
字号:
// PathFinder.cpp : Implementation of CPathFinder
#include "stdafx.h"
#include "NetObjVC6.h"
#include "PathFinder.h"
/////////////////////////////////////////////////////////////////////////////
// CPathFinder
STDMETHODIMP CPathFinder::OpenFeatureDatasetNetwork(IFeatureDataset* FeatureDS)
{
// close down the last one if opened
CloseWorkspace();
// initialize Network and Map (m_ipNetwork, m_ipMap)
return InitializeNetworkAndMap(FeatureDS);
}
STDMETHODIMP CPathFinder::OpenAccessNetwork(BSTR AccessFileName, BSTR FeatureDatasetName)
{
IWorkspaceFactoryPtr ipWorkspaceFactory(CLSID_AccessWorkspaceFactory);
IWorkspacePtr ipWorkspace;
IFeatureWorkspacePtr ipFeatureWorkspace;
IFeatureDatasetPtr ipFeatureDataset;
HRESULT hr;
// After this function exits, we'll have an INetwork interface
// and an IMap interface initialized for the network we'll be using.
// close down the last one if opened
CloseWorkspace();
// open the mdb
hr = ipWorkspaceFactory->OpenFromFile(AccessFileName,0,&ipWorkspace);
if (FAILED(hr)) return hr;
// get the FeatureWorkspace
hr = ipWorkspace->QueryInterface(&ipFeatureWorkspace);
if (FAILED(hr)) return hr;
// open the FeatureDataset
hr = ipFeatureWorkspace->OpenFeatureDataset(FeatureDatasetName, &ipFeatureDataset);
if (FAILED(hr)) return hr;
// initialize Network and Map (m_ipNetwork, m_ipMap)
hr = InitializeNetworkAndMap(ipFeatureDataset);
if (FAILED(hr)) return hr;
return S_OK;
}
void CPathFinder::CloseWorkspace()
{
// make sure we let go of everything and start
// with new results
m_ipGeometricNetwork = 0;
m_ipPoints = 0;
m_ipPointToEID = 0;
m_ipEnumNetEID_Junctions = 0;
m_ipEnumNetEID_Edges = 0;
m_ipPolyline = 0;
}
HRESULT 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;
HRESULT hr;
// get the networks
hr = FeatureDataset->QueryInterface(&ipNetworkCollection);
if (FAILED(hr)) return hr;
// 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
hr = ipNetworkCollection->get_GeometricNetworkCount(&intCount);
if (FAILED(hr)) return hr;
if (intCount == 0) return S_FALSE; // 'No networks found'
// get the first Geometric Newtork (0 - based)
hr = ipNetworkCollection->get_GeometricNetwork(0, &m_ipGeometricNetwork);
if (FAILED(hr)) return hr;
// get the Network
hr = m_ipGeometricNetwork->get_Network(&ipNetwork);
if (FAILED(hr)) return hr;
// 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_ipMap == NULL)
{
hr = m_ipMap.CreateInstance(CLSID_Map);
if (FAILED(hr)) return hr;
// Add each of the Feature Classes in this Geometric Network as a map Layer
hr = m_ipGeometricNetwork->QueryInterface(&ipFeatureClassContainer);
if (FAILED(hr)) return hr;
hr = ipFeatureClassContainer->get_ClassCount(&lngCount);
if (FAILED(hr)) return hr;
if (lngCount == 0) return E_FAIL; // 'No (network) feature classes found'
for (i = 0; i <= lngCount - 1; i++)
{
// get the feature class
hr = ipFeatureClassContainer->get_Class(i, &ipFeatureClass);
if (FAILED(hr)) return hr;
// make a layer
hr = ipFeatureLayer.CreateInstance(CLSID_FeatureLayer);
if (FAILED(hr)) return hr;
hr = ipFeatureLayer->putref_FeatureClass(ipFeatureClass);
if (FAILED(hr)) return hr;
// add layer to the map
hr = m_ipMap->AddLayer((ILayerPtr)ipFeatureLayer);
if (FAILED(hr)) return hr;
}
} // if we needed to make a Map
// Calculate point snap tolerance as 1/100 of map width.
hr = m_ipMap->get_LayerCount(&lngCount);
if (FAILED(hr)) return hr;
hr = ipMaxEnvelope.CreateInstance(CLSID_Envelope);
if (FAILED(hr)) return hr;
for (i = 0; i <= lngCount - 1; i++)
{
hr = m_ipMap->get_Layer(i, &ipLayer);
if (FAILED(hr)) return hr;
hr = ipLayer->QueryInterface(&ipFeatureLayer);
if (FAILED(hr)) return hr;
// get its dimensions (for setting search tolerance)
hr = ipFeatureLayer->QueryInterface(&ipGeoDataset);
if (FAILED(hr)) return hr;
hr = ipGeoDataset->get_Extent(&ipEnvelope);
if (FAILED(hr)) return hr;
// merge with max dimensions
hr = ipMaxEnvelope->Union(ipEnvelope);
if (FAILED(hr)) return hr;
}
// finally, we can set up the IPointToEID ...
hr = m_ipPointToEID.CreateInstance(CLSID_PointToEID);
if (FAILED(hr)) return hr;
hr = m_ipPointToEID->putref_SourceMap(m_ipMap);
if (FAILED(hr)) return hr;
hr = m_ipPointToEID->putref_GeometricNetwork(m_ipGeometricNetwork);
if (FAILED(hr)) return hr;
// set snap tolerance
hr = ipMaxEnvelope->get_Width(&dblWidth);
if (FAILED(hr)) return hr;
hr = ipMaxEnvelope->get_Height(&dblHeight);
if (FAILED(hr)) return hr;
if (dblWidth > dblHeight)
dblSearchTol = dblWidth / 100;
else
dblSearchTol = dblHeight / 100;
hr = m_ipPointToEID->put_SnapTolerance(dblSearchTol);
if (FAILED(hr)) return hr;
return S_OK;
}
STDMETHODIMP CPathFinder::get_StopPoints(IPointCollection **pVal)
{
if(m_ipPoints == NULL)
return E_POINTER;
*pVal = m_ipPoints;
(*pVal)->AddRef();
return S_OK;
}
STDMETHODIMP CPathFinder::putref_StopPoints(IPointCollection *newVal)
{
if (!newVal)
return E_POINTER;
m_ipPoints = newVal;
return S_OK;
}
STDMETHODIMP CPathFinder::get_Map(IMap **pVal)
{
if(m_ipMap == NULL)
return E_POINTER;
*pVal = m_ipMap;
(*pVal)->AddRef();
return S_OK;
}
STDMETHODIMP CPathFinder::putref_Map(IMap *newVal)
{
if (!newVal)
return E_POINTER;
m_ipMap = newVal;
return S_OK;
}
STDMETHODIMP CPathFinder::get_PathCost(double *pVal)
{
*pVal = m_dblPathCost;
return S_OK;
}
STDMETHODIMP CPathFinder::get_PathPolyLine(IPolyline **pVal)
{
IEIDHelperPtr ipEIDHelper;
long count, i;
IEIDInfoPtr ipEIDInfo;
IEnumEIDInfoPtr ipEnumEIDInfo;
IGeometryPtr ipGeometry;
IGeometryCollectionPtr ipNewGeometryColl;
ISpatialReferencePtr ipSpatialReference;
HRESULT hr;
// if the line is already computed since the last path, just return it
if (m_ipPolyline)
{
*pVal = m_ipPolyline;
(*pVal)->AddRef();
return S_OK;
}
// a path should be solved first
if (m_ipEnumNetEID_Edges == NULL) return E_FAIL; // 'No results computed yet.'
// make the new polyline instance
hr = m_ipPolyline.CreateInstance(CLSID_Polyline);
if (FAILED(hr)) return hr;
// get its geometry collection interface
hr = m_ipPolyline->QueryInterface(&ipNewGeometryColl);
if (FAILED(hr)) return hr;
// make an EIDHelper object to translate edges to geometric features
hr = ipEIDHelper.CreateInstance(CLSID_EIDHelper);
if (FAILED(hr)) return hr;
hr = ipEIDHelper->putref_GeometricNetwork(m_ipGeometricNetwork);
if (FAILED(hr)) return hr;
// use the spatial reference from the current map
hr = m_ipMap->get_SpatialReference(&ipSpatialReference);
if (FAILED(hr)) return hr;
hr = ipEIDHelper->putref_OutputSpatialReference(ipSpatialReference);
if (FAILED(hr)) return hr;
hr = ipEIDHelper->put_ReturnGeometries(VARIANT_TRUE);
if (FAILED(hr)) return hr;
// get the details using the IEIDHelper classes
hr = ipEIDHelper->CreateEnumEIDInfo(m_ipEnumNetEID_Edges, &ipEnumEIDInfo);
if (FAILED(hr)) return hr;
hr = ipEnumEIDInfo->get_Count(&count);
if (FAILED(hr)) return hr;
// set the iterator to beginning
hr = ipEnumEIDInfo->Reset();
if (FAILED(hr)) return hr;
for (i = 1; i <= count; i++)
{
// get the next EID and a copy of its geometry (it makes a Clone)
hr = ipEnumEIDInfo->Next(&ipEIDInfo);
if (FAILED(hr)) return hr;
hr = ipEIDInfo->get_Geometry(&ipGeometry);
if (FAILED(hr)) return hr;
// if ipGeometry is null, then the corresponding eid was invalid!
if (ipGeometry != NULL)
{
hr = ipNewGeometryColl->AddGeometryCollection((IGeometryCollectionPtr)ipGeometry);
if (FAILED(hr)) return hr;
}
}
*pVal = m_ipPolyline;
(*pVal)->AddRef();
return S_OK;
}
STDMETHODIMP CPathFinder::SolvePath(BSTR WeightName)
{
INetworkPtr ipNetwork;
ITraceFlowSolverPtr ipTraceFlowSolver;
INetSolverPtr ipNetSolver;
INetFlagPtr ipNetFlag;
IEdgeFlag** ipaEdgeFlag;
IPointPtr ipEdgePoint;
INetElementsPtr ipNetElements;
long lngEdgeUserClassID, lngEdgeUserID, lngEdgeUserSubID, lngEdgeID;
IPointPtr ipFoundEdgePoint;
double dblEdgePercent;
INetWeightPtr ipNetWeight;
INetSolverWeightsPtr ipNetSolverWeights;
INetSchemaPtr ipNetSchema;
long lngCount;
int i;
VARIANT* pvaSegmentCosts;
HRESULT hr;
// make sure we are ready
if (m_ipPoints == NULL) return E_FAIL; // 'StopPoints are not set'
if (m_ipGeometricNetwork == NULL) return E_FAIL; // 'Network is not set'
// instantiate a trace flow solver
hr = ipTraceFlowSolver.CreateInstance(CLSID_TraceFlowSolver);
if (FAILED(hr)) return hr;
// get the INetSolver interface
hr = ipTraceFlowSolver->QueryInterface(&ipNetSolver);
if (FAILED(hr)) return hr;
// set the source network to solve on
hr = m_ipGeometricNetwork->get_Network(&ipNetwork);
if (FAILED(hr)) return hr;
hr = ipNetSolver->putref_SourceNetwork(ipNetwork);
if (FAILED(hr)) return hr;
// make edge flags from the points
// the INetElements interface is needed to get UserID, UserClassID,
// and UserSubID from the element id (EID)
hr = ipNetwork->QueryInterface(&ipNetElements);
if (FAILED(hr)) return hr;
// get the count
hr = m_ipPoints->get_PointCount(&lngCount);
if (FAILED(hr)) return hr;
if (lngCount < 2) return E_FAIL; // '2 or more points are needed'
// dimension our IEdgeFlag array
ipaEdgeFlag = new IEdgeFlag*[lngCount];
// for each point
for (i = 0; i <= lngCount - 1; i++)
{
// make a new Edge Flag
hr = ipNetFlag.CreateInstance(CLSID_EdgeFlag);
if (FAILED(hr)) return hr;
hr = m_ipPoints->get_Point(i, &ipEdgePoint);
if (FAILED(hr)) return hr;
// look up the EID for the current point (this will populate intEdgeID and dblEdgePercent)
hr = m_ipPointToEID->GetNearestEdge(ipEdgePoint, &lngEdgeID, &ipFoundEdgePoint, &dblEdgePercent);
if (FAILED(hr)) return hr;
if (lngEdgeID < 1) return E_FAIL; // 'Point (eid) not found'
hr = ipNetElements->QueryIDs(lngEdgeID, esriETEdge, &lngEdgeUserClassID, &lngEdgeUserID, &lngEdgeUserSubID);
if (FAILED(hr)) return hr;
if ((lngEdgeUserClassID < 1) && (lngEdgeUserID < 1)) return E_FAIL; // 'eid not found'
hr = ipNetFlag->put_UserClassID(lngEdgeUserClassID);
if (FAILED(hr)) return hr;
hr = ipNetFlag->put_UserID(lngEdgeUserID);
if (FAILED(hr)) return hr;
hr = ipNetFlag->put_UserSubID(lngEdgeUserSubID);
if (FAILED(hr)) return hr;
ipaEdgeFlag[i] = (IEdgeFlagPtr)ipNetFlag;
ipNetFlag->AddRef();
}
// add these edge flags
hr = ipTraceFlowSolver->PutEdgeOrigins(lngCount, &ipaEdgeFlag[0]);
if (FAILED(hr)) return hr;
// set the weight (cost field) to solve on
// get the INetSchema interface
hr = ipNetwork->QueryInterface(&ipNetSchema);
if (FAILED(hr)) return hr;
hr = ipNetSchema->get_WeightByName(WeightName, &ipNetWeight);
if (FAILED(hr)) return hr;
if (ipNetWeight == NULL) return E_FAIL; // 'Weight: ' + WeightName + ' not found'
// set the weight (use the same for both directions)
// Note: You could also set Junction weights here.
hr = ipTraceFlowSolver->QueryInterface(&ipNetSolverWeights);
if (FAILED(hr)) return hr;
hr = ipNetSolverWeights->putref_ToFromEdgeWeight(ipNetWeight);
if (FAILED(hr)) return hr;
hr = ipNetSolverWeights->putref_FromToEdgeWeight(ipNetWeight);
if (FAILED(hr)) return hr;
// initialize array for results to number of segments in result
pvaSegmentCosts = new VARIANT[lngCount-1];
// solve it
hr = ipTraceFlowSolver->FindPath( esriFMConnected, esriSPObjFnMinSum, &m_ipEnumNetEID_Junctions, &m_ipEnumNetEID_Edges, lngCount - 1, &pvaSegmentCosts[0]);
if (FAILED(hr)) return hr;
// 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
delete m_ipPolyline;
// release NetFlags
for (i = 0; i <= lngCount - 1; i++)
{
ipNetFlag = (INetFlagPtr)ipaEdgeFlag[i];
ipNetFlag->Release();
}
// delete arrays
delete ipaEdgeFlag;
delete pvaSegmentCosts;
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -