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

📄 pathfinder.cpp

📁 路径查找代码[vc版本代码]
💻 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 + -