📄 pathfinder.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 + -