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

📄 pathfinder.cpp

📁 最短路径查询,用的是ESRI公司arcobject组件开发的,已经作成dll,用起来非常的方便
💻 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 + -