📄 pathfinder.cpp
字号:
/*
Copyright 1995-2004 ESRI
All rights reserved under the copyright laws of the United States.
You may freely redistribute and use this sample code, with or without modification.
Disclaimer: THE SAMPLE CODE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESRI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) SUSTAINED BY YOU OR A THIRD PARTY, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ARISING IN ANY WAY OUT OF THE USE OF THIS SAMPLE CODE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
For additional information contact: Environmental Systems Research Institute, Inc.
Attn: Contracts Dept.
380 New York Street
Redlands, California, U.S.A. 92373
Email: contracts@esri.com
*/
// 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 + -