Shape线数据判断连通性

    本篇文章将描述判断Shape线数据的连通性问题。Shape线数据描述出来的是一幅图,判断图上两点是否连通通常使用深度遍历或者广度遍历。整个算法的过程分为下面几个部分:

  • 构建图
  • 判断起始点和终点是否连通
  • 如果连通,获得连通的通路
  • 遍历分为有向图遍历和无向图遍历
    如果单独判断图的连通话,那么问题就很简单。但是Shape数据是不含拓扑关系,而且数据量不知,所以不能使用矩阵的方式来存储连通性。所以构建图也是重点工作之一。因为在构建图的过程中,或多或少的可以判断起始点和终点是否连接了。这样就能减少避免等全图全部构建后再判断连通性,从而提高算法的性能。
     Shape构建的图有一点特殊性,就是它是基于位置的。也就是说如果连通,那么连通中的点大部分在一个Buffer内。就好像北京到上海的线路选择不会考虑先跑到新疆然后再折回到上,所以考虑的数据可以是起始点和终点构成的一个Buffer中。至于这个Buffer如何抉择,暂时没有深度的考虑。或许可以基于起始点和终点构建一个如下图的一个椭圆Buffer。
    
     所以,整个算法调整为下面几个步骤。
  • 读取Shape的Geo包围盒。并对这个包围盒进行分割,划分多个块,从而加快构建图
  • 依次读取一条线段记录(Shape线数据保存的是线数据,如果考虑Buffer,可以进行裁剪)
  • 根据这条记录的位置快速找到所在的块,并和已经存在的数据建立拓扑关系。
  • 如果这条记录是起始点记录,在建立拓扑的时候,它所连接的点设置属性:ReachToStart=true,表明它连接的点是可以连通到起始点的。
  • 如果这条记录是终点记录,那么处理过程类似起始点记录的处理
  • 如果这个记录是普通节点,那么判断它连接的点是否可以到起始点,如果可以那么设置ReachToStart=true。类似的处理是否可以连通到终点。
  • 如果一个节点是新设置为ReachToStart=true,那么它可以到起始点的信息扩散到它连接点。类似的处理ReachToEnd=true的问题。
  • 如果在处理过程中,发现一个节点既可以ReachToStart也可以ReachToEnd,表明已经判断起始点和终点是可以连接的。
  • 判断可以连通之后,存在ReachToStart或者ReachToEnd节点构建的是一个连通图,只要简单的深度遍历就可以找到中间连通节点。
      可以看出,整个过程将构建拓扑和判断连通性融合在一起,从而减少构建完全拓扑后再判断连通的处理。同样利用可达的扩散性,不需要对记录进行排序,依次读取记录即可。同时,算法利用数据的空间性,构建空间块和构建Buffer,加快构建拓扑结构。
      本算法只识别是否是否连通,并不考虑最短路径和连通全集。如果需要,那么整个算法的性能跟先构建图,再判断连通性没有差异,因为需要对所有的数据都读取一遍而且不能使用Buffer.

      下面粘贴部分代码供参考。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WorldWind;
using WorldWind.PipeSystem.DataSource;
using WorldWind.Renderable.Shape;

namespace Connection
{
    /// <summary>
    /// 一个节点的信息
    /// </summary>
    public class NodeInfo
    {
        #region 熟悉
        private bool m_ReachToStart = false;
        private bool m_ReachToEnd = false;
        private bool m_IsStartNode = false;
        private bool m_IsEndNode = false;
        #endregion

        /// <summary>
        /// 节点的位置
        /// </summary>
        public Shapefile_Point NodePos;
        /// <summary>
        /// 包含本节点的线段集合
        /// </summary>
        public List<ShapeRecord> BelongSRs = new List<ShapeRecord>();
        /// <summary>
        /// 前一个可达起始点的节点
        /// </summary>
        public NodeInfo PreStartReachNode = null;

        #region 对外属性
        public bool IsStartNode
        {
            get { return m_IsStartNode; }
            set
            {
                m_IsStartNode = value;
                m_ReachToStart = value;
            }
        }
        public bool IsEndNode
        {
            get { return m_IsEndNode; }
            set
            {
                m_IsEndNode = value;
                m_ReachToEnd = value;
            }
        }
        public bool ReachToStart
        {
            get { return m_ReachToStart; }
            set { m_ReachToStart = value; }
        }
        public bool ReachToEnd
        {
            get { return m_ReachToEnd; }
            set { m_ReachToEnd = value; }
        }
        /// <summary>
        /// 连接到本节点的数据
        /// </summary>
        public List<NodeInfo> IncomeSRs = new List<NodeInfo>();
        /// <summary>
        /// 本节点连接出的数据
        /// </summary>
        public List<NodeInfo> OutcomeSRs = new List<NodeInfo>();
        #endregion

        #region 级联
        public NodeInfo SetPreStartNode()
        {
            if (this.IsEndNode)
                return this;
            foreach (NodeInfo item in IncomeSRs)
            {
                if (this.PreStartReachNode == item)
                {
                    continue;
                }
                if (item.PreStartReachNode == null)
                {
                    item.PreStartReachNode = this;
                    NodeInfo startNode = item.SetPreStartNode();
                    if (startNode != null)
                    {
                        return startNode;
                    }
                }
            }
            foreach (NodeInfo item in OutcomeSRs)
            {
                if (this.PreStartReachNode == item)
                {
                    continue;
                }
                if (item.PreStartReachNode == null)
                {
                    item.PreStartReachNode = this;
                    NodeInfo startNode = item.SetPreStartNode();
                    if (startNode != null)
                    {
                        return startNode;
                    }
                }
            }
            return null;
        }
        #endregion

        #region 其他
        public bool EqualPos(Shapefile_Point pos)
        {
            if (NodePos.X == pos.X
                && NodePos.Y == pos.Y
                && NodePos.Z == pos.Z)
            {
                return true;
            }
            return false;
        }
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(BelongSRs[0].RecordIndex.ToString());
            for (int i = 1; i < BelongSRs.Count; i++)
            {
                sb.Append(',' + BelongSRs[i].RecordIndex.ToString());
            }
            return sb.ToString();
        }
        #endregion

    }

    public class NodeTree
    {
        #region 属性
        private GeographicBoundingBox m_box;
        private List<NodeArea> m_nodeAreas = new List<NodeArea>();
        private NodeInfo m_convergeNode = null;
        private NodeInfo m_startNode;
        private NodeInfo m_endNode;

        private bool m_flowDirection = false;

        #endregion
       
        #region 对外属性
        public NodeInfo EndNode
        {
            get { return m_endNode; }
        }

        public NodeInfo StartNode
        {
            get { return m_startNode; }
        }
        /// <summary>
        /// 是否考虑流向
        /// </summary>
        public bool FlowDirection
        {
            get { return m_flowDirection; }
            set { m_flowDirection = value; }
        }
        #endregion

        #region 构造函数
        public NodeTree(GeographicBoundingBox box)
        {
            m_box = box;
        }
        #endregion

        private void GetNodeAreeIndex(Shapefile_Point point, out int rowIndex, out int columnIndex)
        {
            rowIndex = (int)((point.Y - m_box.South) / 100 + 1);
            columnIndex = (int)((point.X - m_box.West) / 100 + 1);
        }

        public bool AddNode(ShapeRecord BelongSR, bool isStartSR, bool isEndSR)
        {
            NodeInfo leftNode = InsertNode(BelongSR, 0);
            NodeInfo rightNode = InsertNode(BelongSR, 1);

            if (isStartSR)
            {
                leftNode.IsStartNode = true;
                rightNode.IsStartNode = true;
                m_startNode = rightNode;
            }
            if (isEndSR)
            {
                leftNode.IsEndNode = true;
                rightNode.IsEndNode = true;
                m_endNode = leftNode;
            }

            leftNode.OutcomeSRs.Add(rightNode);
            rightNode.IncomeSRs.Add(leftNode);

            if (m_flowDirection == false)
            {
                //如果考虑方向,那么Right是无法到Left的
                leftNode.ReachToStart |= (rightNode.ReachToStart);
            }
            leftNode.ReachToEnd|=(rightNode.ReachToEnd);

            rightNode.ReachToStart |= (leftNode.ReachToStart);
            if (m_flowDirection == false)
            {
                //如果考虑方向,那么Right是无法到Left的
                rightNode.ReachToEnd |= (leftNode.ReachToEnd);
            }

            if (leftNode.ReachToEnd && leftNode.ReachToStart)
            {
                m_convergeNode = leftNode;
                return true;
            }
            if (rightNode.ReachToEnd && rightNode.ReachToStart)
            {
                m_convergeNode = rightNode;
                return true;
            }

            if (leftNode.ReachToStart)
            {
                if (EffectStart(leftNode))
                    return true;
            }
            if (leftNode.ReachToEnd)
            {
                if (EffectEnd(leftNode))
                    return true;
            }
            if (rightNode.ReachToStart)
            {
                if (EffectStart(rightNode))
                    return true;
            }
            if (rightNode.ReachToEnd)
            {
                if (EffectEnd(rightNode))
                    return true;
            }


            return false;
        }

        #region 获得
        public List<NodeInfo> GetPathNodes()
        {
            m_endNode = m_startNode.SetPreStartNode();

            List<NodeInfo> items = new List<NodeInfo>();
            items.Add(m_endNode);
            NodeInfo preNode = m_endNode.PreStartReachNode;
            while (preNode != null)
            {
                items.Add(preNode);
                preNode = preNode.PreStartReachNode;
            }

            return items;
        }
        #endregion

        #region 病毒传染
        /// <summary>
        /// currentNode相关的节点,因为currentNode能够通往起点而能够通往起点
        /// </summary>
        /// <param name="currentNode"></param>
        /// <returns></returns>
        private bool EffectStart(NodeInfo currentNode)
        {
            if (m_flowDirection == false)
            {
                if (EffectStart(currentNode, currentNode.IncomeSRs))
                    return true;
            }
            if (EffectStart(currentNode, currentNode.OutcomeSRs))
                return true;
            return false;
        }
        /// <summary>
        /// SRS所有的数据因为currentNode从起点来,而能够从起点来
        /// </summary>
        /// <param name="currentNode"></param>
        /// <param name="SRS"></param>
        /// <returns></returns>
        private bool EffectStart(NodeInfo currentNode, List<NodeInfo> SRS)
        {
            foreach (NodeInfo item in SRS)
            {
                if (item.ReachToStart == true)
                    continue;
                item.ReachToStart = true;
                if (item.ReachToEnd && item.ReachToStart)
                {
                    m_convergeNode = item;
                    return true;
                }
                EffectStart(item);
            }
            return false;
        }
        /// <summary>
        /// currentNode相关的节点,因为currentNode能够通往目的地而能够通往目的地
        /// </summary>
        /// <param name="currentNode"></param>
        /// <returns></returns>
        private bool EffectEnd(NodeInfo currentNode)
        {
            if (EffectEnd(currentNode, currentNode.IncomeSRs))
                return true;
            if (m_flowDirection == false)
            {
                if (EffectEnd(currentNode, currentNode.OutcomeSRs))
                    return true;
            }
            return false;
        }
        /// <summary>
        /// SRS所有的数据因为currentNode能够到目的地
        /// </summary>
        /// <param name="currentNode"></param>
        /// <param name="SRS"></param>
        /// <returns></returns>
        private bool EffectEnd(NodeInfo currentNode, List<NodeInfo> SRS)
        {
            foreach (NodeInfo item in SRS)
            {
                if (item.ReachToEnd == true)
                    continue;
                item.ReachToEnd = true;
                if (item.ReachToEnd && item.ReachToStart)
                {
                    m_convergeNode = item;
                    return true;
                }
                EffectEnd(item);
            }
            return false;
        }
        #endregion

        #region 插入一个节点
        private NodeInfo InsertNode(ShapeRecord BelongSR, int pointIndex)
        {
            int rowIndex = 0;
            int columnIndex = 0;

            GetNodeAreeIndex(BelongSR.PolyLine.Points[pointIndex], out rowIndex, out columnIndex);
            NodeInfo leftNode = null;
            foreach (NodeArea item in m_nodeAreas)
            {
                if (item.AreaCodeColumnIndex == columnIndex &&
                    item.AreaCodeRowIndex == rowIndex)
                {
                    leftNode = item.AddNode(BelongSR.PolyLine.Points[pointIndex], BelongSR);
                    break;
                }
            }
            if (leftNode == null)
            {
                NodeArea na = new NodeArea(rowIndex, columnIndex);
                leftNode = na.AddNode(BelongSR.PolyLine.Points[pointIndex], BelongSR);
                m_nodeAreas.Add(na);
            }
            return leftNode;
        }
        #endregion

    }

    public class NodeArea
    {
        public int AreaCodeRowIndex;
        public int AreaCodeColumnIndex;

        public List<NodeInfo> Nodes;

        #region 构造函数
        public NodeArea(int rowIndex, int columnIndex)
        {
            AreaCodeRowIndex = rowIndex;
            AreaCodeColumnIndex = columnIndex;
            Nodes = new List<NodeInfo>();
        }
        #endregion

        public NodeInfo AddNode(Shapefile_Point point, ShapeRecord BelongSR)
        {
            foreach (NodeInfo node in Nodes)
            {
                if (node.EqualPos(point))
                {
                    node.BelongSRs.Add(BelongSR);
                    return node;
                }
            }
            NodeInfo nnode = new NodeInfo();
            nnode.BelongSRs.Add(BelongSR);
            nnode.NodePos = point;

            Nodes.Add(nnode);

            return nnode;
        }
    }
}
   下面是调用的代码
NodeTree nt = new NodeTree(shp.SourceGeoBB);
            nt.FlowDirection = this.checkBox_FlowDirection.Checked;

            int index=0;
            this.listBox1.Items.Clear();
            bool isConnected = false;
            foreach (ShapeRecord sr in shp.DataRecord)
            {
                bool isStartNode = (index == m_startIndex);
                bool isEndNode = (index == endIndex);
                if (nt.AddNode(sr, isStartNode, isEndNode))
                {
                    isConnected = true;
                    break;
                }
                index++;
            }
      上面代码中,部分类没有写出来的是自定义类,读者可以自行实现。最后附上效果图



     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值