需求: 基于水系分析河流溯源路径
输入: 河流数据
实现思路: 基于网络模型, 根据 河流交点打断生成河流网数据, 这跟路网不同, 河流一般都是单向流向, 所以是有向图.
基于GDAL gnm算法数据结构有以下实现:
/// \brief 顶点对象, 顶点内不带几何,方便算法运行,要查询几何可以直接去Storage根据ID查询
struct Vertex
{
public:
/// \brief 顶点ID
long long VertexID = 0;
/// \brief 是否阻碍
bool bIsBloked = false;
/// \brief bIsBloked为true参与计算
/// 阻抗值 要么无限大就是无法通的点, 要么是来源一个字段的值,会累加权值消耗
double ImpedanceCost = 0;
/// \brief 此点对应的原始边的ID
long long SourcePathID = 0;
/// 图中下几条边ID, 默认
vector<long long> anOutEdgeFIDs = {};
vector<long long> anInEdgeFIDs = {};
Vertex()
{
}
Vertex(long long vid)
{
VertexID = vid;
}
Vertex(const Vertex & o);
bool IsValid();
};
/// \brief 边对象
struct Edge
{
public:
/// \brief 起始点ID
long long nSrcVertexFID = 0;
/// \brief 结束点ID
long long nTgtVertexFID = 0;
/// \brief 唯一权值, 此权值对于不同模型可以动态从不同字段取
double dfDirCost = 0.;
/// \brief 逆向权值
double dfInvCost = 0.;
/// \brief 图的边ID,经过打断处理的边ID 必须字段,
long long EdgeID = 0;
/// \brief 未打断前的数据边ID, 非必需的, 如果为0, 说明是通过规则构建的虚拟边, 比如换乘边
long long SourcePathID = 0;
/// \brief 是否双向
bool bIsBidir = false;
/// \brief 是否阻碍
bool bIsBloked = false;
Edge();
Edge(long long innSrcVertexFID, long long innTgtVertexFID, double dfDirCost = 0., long long EdgeID = 0);
Edge(const Edge& o);
bool IsValid();
};
std::map<long long, Vertex> m_mstVerticesCache;
std::map<long long, Edge> m_mstEdgesCache;
查找溯源河流边得函数如下:
#define GNMGFID long long
typedef std::pair<long long, long long> EDGEVERTEXPAIR;
typedef std::vector< EDGEVERTEXPAIR > GNMPATH;
void gnm_algorithm::TraceSources(std::queue<long long>& vertexQueue, std::set<long long>& markedVertIds, GNMPATH & connectedIds)
{
GNMCONSTVECTOR::const_iterator it;
std::queue<GNMGFID> neighbours_queue;
while (!vertexQueue.empty())
{
GNMGFID nCurVertID = vertexQueue.front();
if (markedVertIds.find(nCurVertID) == markedVertIds.end())
{
markedVertIds.insert(nCurVertID);
LPGNMCONSTVECTOR panOutcomeEdgeIDs = QueryStartVID(nCurVertID);
if (nullptr != panOutcomeEdgeIDs)
{
for (it = panOutcomeEdgeIDs->begin(); it != panOutcomeEdgeIDs->end(); ++it)
{
GNMGFID nCurStartID = *it;
connectedIds.push_back(GsPair<long long, long long>(nCurStartID, nCurVertID ));
if ((markedVertIds.find(nCurStartID) == markedVertIds.end()))
neighbours_queue.push(nCurStartID);
}
}
}
vertexQueue.pop();
}
if (!neighbours_queue.empty())
TraceTargets(neighbours_queue, markedVertIds, connectedIds);
}