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

📄 netlayer.cs

📁 经典的GIS二次开发系列书籍的一本
💻 CS
📖 第 1 页 / 共 3 页
字号:
		{
			nFNode = -1;
			nTNode = -1;
			for ( int i = 0; i < m_arrLinks.Count; i++ )
			{
				if ( nLineID == ((NetLink)m_arrLinks[i]).m_GeoID )
				{
					nFNode = ((NetLink)m_arrLinks[i]).m_nFNode;
					nTNode = ((NetLink)m_arrLinks[i]).m_nTNode;
					return i;
				}
			}
			return -1;
		}

		// 计算两点间的最短路径
		// 参数含义:  nBeginNode	起始结点
		//            nEndNode		终止结点
		//            pNodes		路径顺序经过的结点数组, 返回参数
		//			  bWeight		TRUE为计算考虑方向权重最优路径, FALSE为不考虑方向权重的最短路径
		// 注意: pNode在函数内部开辟内存, 函数调用者负责在外部删除该内存
		// 返回路径总长度,<0 表示没有连通的路径
		private double Path( int nBeginNode, int nEndNode, out ArrayList pNodes, bool bWeight )
		{
			pNodes= null;
			if ( nBeginNode < 0 || nBeginNode >= m_arrNodes.Count )
				return -1;
			if ( nEndNode < 0 || nEndNode >= m_arrNodes.Count )
				return -1;

			pNodes = new ArrayList();
			// 如果两个结点相同
			if ( nBeginNode == nEndNode )
			{
				pNodes.Add( nBeginNode );
				return 0;
			}
			// 计算nBeginNode到其他所有结点的最短路径
			if ( !CalcPath( nBeginNode, nEndNode, bWeight ) )
				return -1;

			// 提取从nBeginNode到nEndNode的路径
			// 从nEndNode向前搜索前趋结点
			int nNode;
			nNode = nEndNode;
			while ( true )
			{
				// 如果没有前趋结点, 不连通
				if ( m_pPath[nNode].m_nPreNode == -1 )
					return -1;

				// 如果前趋结点为起始结点, 路径结束
				if ( m_pPath[nNode].m_nPreNode == nBeginNode )
				{
					pNodes.Add( nNode );
					break;
				}

				// 加入中间结点
				pNodes.Add( nNode );
				nNode = m_pPath[nNode].m_nPreNode;
			}

			// 加入起点
			pNodes.Add( nBeginNode );
			// 因为是从nEndNode到nBeginNode加入的, 所以要作一次倒序
			pNodes.Reverse();

			return m_pPath[nEndNode].m_dLength;
		}

		// 计算一个点到所有点的最短路径. 采用Dijkstra算法
		// 参数bWeight表示是否考虑方向权重
		// 如果nEndNode不等于-1, 则只计算nNode到nEndNode的最短路径,
		private bool CalcPath( int nNode, int nEndNode , bool bWeight )
		{
			if ( nNode < 0 || nNode >= m_arrNodes.Count )
				return false;

			int i, j, nNodeNum;
			int nLink;
			byte[] pMark = null;		// 处理标志数组
			nNodeNum = m_arrNodes.Count;
			if ( nNodeNum == 0 )
				return true;

			pMark = new byte[nNodeNum];
			for ( i = 0; i < nNodeNum; i++ )
				pMark[i] = 0;

			// (1) 初始化
			// 初始化路径数组, 类的构造函数会将长度置为-1, 前趋结点为-1
			m_pPath = null;
			m_pPath = new NetPath[nNodeNum];
			for ( i = 0; i < nNodeNum; i++ )
				m_pPath[i] = new NetPath();
			// 自身
			m_pPath[nNode].m_dLength = 0;
			m_pPath[nNode].m_nPreNode = nNode;

			// 对于与该结点直接相连的点, 初始化路径长度为连接弧度的阻力
			for ( i = 0; i < ((NetNode)m_arrNodes[nNode]).m_arrLinks.Count; i++ )
			{
				nLink = ((NetEdge)((NetNode)m_arrNodes[nNode]).m_arrLinks[i]).nLink;
				if ( ((NetLink)m_arrLinks[nLink]).m_nFNode == nNode )
				{
					// 路径长度, 正向
					m_pPath[((NetLink)m_arrLinks[nLink]).m_nTNode].m_dLength = 
						bWeight ? ((NetLink)m_arrLinks[nLink]).m_fFromImp  : ((NetLink)m_arrLinks[nLink]).m_fLength;

					// 前趋结点, 如果长度<0, 无前趋结点
					if ( m_pPath[((NetLink)m_arrLinks[nLink]).m_nTNode].m_dLength < 0 )
						m_pPath[((NetLink)m_arrLinks[nLink]).m_nTNode].m_nPreNode = -1;
					else
						m_pPath[((NetLink)m_arrLinks[nLink]).m_nTNode].m_nPreNode = nNode;
				}
				else if ( ((NetLink)m_arrLinks[nLink]).m_nTNode == nNode )
				{
					// 路径长度, 逆向
					m_pPath[((NetLink)m_arrLinks[nLink]).m_nFNode].m_dLength = 
						bWeight ? ((NetLink)m_arrLinks[nLink]).m_fToImp : ((NetLink)m_arrLinks[nLink]).m_fLength;

					// 前趋结点, 如果长度<0, 无前趋结点
					if ( m_pPath[((NetLink)m_arrLinks[nLink]).m_nFNode].m_dLength < 0 )
						m_pPath[((NetLink)m_arrLinks[nLink]).m_nFNode].m_nPreNode = -1;
					else
						m_pPath[((NetLink)m_arrLinks[nLink]).m_nFNode].m_nPreNode = nNode;
				}
			}
	
			// 开始处理
			int nMinNode;
			double dDist, dMinDist;
			for ( i = 0; i < nNodeNum; i++ )
			{
				// (2) 在未处理结点中找出距离值最小的结点
				nMinNode = -1;
				dMinDist = 1.7e+308;
				for ( j = 0; j < nNodeNum; j++ )
				{
					// 让过自身
					if ( j == nNode )
						continue;
					// 让过不连通结点
					if ( m_pPath[j].m_dLength < 0 )		// <0 表示无穷大
						continue;
					// 让过处理过的结点
					if ( pMark[j] == 1 )
						continue;

					// 在未处理过的结点中找出距离最小的
					if ( m_pPath[j].m_dLength < dMinDist )
					{
						dMinDist = m_pPath[j].m_dLength;
						nMinNode = j;
					}
				}

				// 如果没找到, 则表示与其他点不连通
				if ( nMinNode == -1 )
				{
					pMark = null;
					return true;
				}
				// 处理该距离最小的点
				pMark[nMinNode] = 1;
				
				// (3) 调整余下的结点的最短路径
				for ( j = 0; j < nNodeNum; j++ )
				{
					// 让过自身
					if ( j == nNode )
						continue;

					// 让过处理过的结点
					if ( pMark[j] == 1 )
						continue;

					// 调整未处理过的结点的最短路径
					// 计算直接相连的结点间的距离
					dDist = GetConnectedDistance( nMinNode, j, bWeight );
					if ( dDist < 0 )	// 不连通
						continue;

					// 更新未处理过的结点的最短路径
					if ( m_pPath[j].m_dLength < 0 || 
						m_pPath[j].m_dLength > m_pPath[nMinNode].m_dLength + dDist )
					{
						m_pPath[j].m_dLength = m_pPath[nMinNode].m_dLength + dDist ;
						m_pPath[j].m_nPreNode = nMinNode;
					}
				}
			}

			pMark = null;
			return true;
		}

		// 得到两个结点直接连接的距离, 不直接连接则返回-1
		// 返回的结果考虑了方向权重, 因此是与nNode1,nNode2的参数顺序有关的
		private double GetConnectedDistance( int nNode1, int nNode2, bool bWeight )
		{
			if ( nNode1 < 0 || nNode1 >= m_arrNodes.Count )
				return -1;
			if ( nNode2 < 0 || nNode2 >= m_arrNodes.Count )
				return -1;
			if ( nNode1 == nNode2 )
				return 0;

			int nLink;
			double dDistance;
			double dMinDist = 1.7e+308;
			int nRes = 0;
			int i = 0;
			// 遍历与结点1相连的弧段, 判断弧段的另一端的结点是否为结点2, 是则返回距离
			for ( i = 0; i < ((NetNode)m_arrNodes[nNode1]).m_arrLinks.Count; i++ )
			{
				nLink = ((NetEdge)((NetNode)m_arrNodes[nNode1]).m_arrLinks[i]).nLink;
				if ( ((NetLink)m_arrLinks[nLink]).m_nFNode == nNode1 )
				{
					if ( ((NetLink)m_arrLinks[nLink]).m_nTNode == nNode2 )
					{
						dDistance = bWeight ? ((NetLink)m_arrLinks[nLink]).m_fFromImp : ((NetLink)m_arrLinks[nLink]).m_fLength;
						if ( dDistance < dMinDist )
						{
							dMinDist = dDistance;
							nRes = 1;
						}
					}
				}
				else if ( ((NetLink)m_arrLinks[nLink]).m_nTNode == nNode1 )
				{
					if ( ((NetLink)m_arrLinks[nLink]).m_nFNode == nNode2 )
					{
						dDistance = bWeight ? ((NetLink)m_arrLinks[nLink]).m_fToImp : ((NetLink)m_arrLinks[nLink]).m_fLength;
						if ( dDistance < dMinDist )
						{
							dMinDist = dDistance;
							nRes = -1;
						}
					}
				}
			}

			if ( nRes == 0 )
				return -1;
			return dMinDist;
		}

		// 由结点生成路径的结果图层
		// 参数含义: pNodes:	网络分析结果结点集
		//           nNum:		结点数目
		//           szLayerName: 结果图层名称
		//           bWeight	TRUE为计算考虑方向权重最优路径, FALSE为不考虑方向权重的最短路径
		private bool CreateResultPath( ArrayList pNodes, out NetLine line, bool bWeight )
		{

			line = new NetLine(m_layer);
			int i, j;

			// 将分析结果结点集转换为线加入到结果图层中
			int nNum;
			int nRes;
			int nNode1, nNode2, nLink;
			double dDistance, dRatio;
			double dTotalImp;
			nNum = pNodes.Count;

			int idLine;
			dTotalImp = 0;
			for ( i = 0; i < nNum-1; i++ )
			{
				// 得到连接两个结点的最短弧段
				nNode1 = (int)pNodes[i];
				nNode2 = (int)pNodes[i+1];
				nRes = IsConnectedDirectly( nNode1, nNode2, out nLink, out dDistance, bWeight );

				// 不连通则返回false. 这种情况理论上是不可能出现的.
				if ( nRes == 0 )
				{
					return false;
				}
				if ( nLink == -1 )
					continue;

				// 将该弧段的结点按路径顺序加入到结果图层的线中去
				idLine = ((NetLink)m_arrLinks[nLink]).m_GeoID;
				NetLine tmpLine = new NetLine(m_layer);
				tmpLine.GetLineData( idLine );

				// 只加入起始结点和终止结点之间的点
				double dDist;
				int nSegIndex1, nSegIndex2;
				NetPoint ptNearst1, ptNearst2, ptTemp;

				ptTemp = new NetPoint();
				ptTemp.x= ((NetNode)m_arrNodes[nNode1]).x;
				ptTemp.y= ((NetNode)m_arrNodes[nNode1]).y;
				tmpLine.GetNearestPoint( ptTemp, out ptNearst1, out nSegIndex1, out dDist );
				ptTemp.x= ((NetNode)m_arrNodes[nNode2]).x;
				ptTemp.y= ((NetNode)m_arrNodes[nNode2]).y;
				tmpLine.GetNearestPoint( ptTemp, out ptNearst2, out nSegIndex2, out dDist );		
				dRatio = ((NetLink)m_arrLinks[nLink]).m_fLength / tmpLine.CalcLength();

				if ( nRes == 1 )
				{
					// 正向
					line.AddCoord( ptNearst1 );
					for ( j = nSegIndex1; j < nSegIndex2; j++ )
						line.AddCoord( (NetPoint)tmpLine.m_pCoords[j+1] );
					line.AddCoord( ptNearst2 );
					dTotalImp += ((NetLink)m_arrLinks[nLink]).m_fFromImp;
				}
				else if ( nRes == -1 )
				{
					// 逆向
					line.AddCoord( ptNearst1 );
					for ( j = nSegIndex1; j > nSegIndex2; j-- )
						line.AddCoord( (NetPoint)tmpLine.m_pCoords[j] );
					line.AddCoord( ptNearst2 );
					dTotalImp += ((NetLink)m_arrLinks[nLink]).m_fToImp;
				}
				tmpLine = null;

				if ( line.m_pCoords.Count < 2 )
				{
					line.m_pCoords.Clear();
					continue;
				}
			}

			return true;
		}

		// 判断两个结点是否直接相连. 即两个结点在同一条弧段上
		// 返回值: 0  不直接连通
		//         1  直接连通, 且从nNode1到nNode2为正向连接
		//         -1 直接连通, 且从nNode1到nNode2为逆向连接
		// 如果两个结点直接连通, 则同时返回连接两个结点的弧段nLink,以及直接连通的最小阻力加权距离dDistance
		// 如果不直接连通, 则nLink=-1, dDistance=-1
		private int IsConnectedDirectly( int nNode1, int nNode2, out int nLink, out double dDistance, bool bWeight )
		{
			nLink = -1;
			dDistance = 0;
			if ( nNode1 < 0 || nNode1 >= m_arrNodes.Count )
				return 0;
			if ( nNode2 < 0 || nNode2 >= m_arrNodes.Count )
				return 0;
			if ( nNode1 == nNode2 )
				return 1;

			int i = 0;
			int nRes = 0;
			int nMinLink = -1;
			double dMinDist = 1.7e+308;
			// 遍历与结点1相连的弧段, 判断弧段的另一端的结点是否为结点2
			for ( i = 0; i < ((NetNode)m_arrNodes[nNode1]).m_arrLinks.Count; i++ )
			{
				nLink = ((NetEdge)((NetNode)m_arrNodes[nNode1]).m_arrLinks[i]).nLink;
				if ( ((NetLink)m_arrLinks[nLink]).m_nFNode == nNode1 )
				{
					if ( ((NetLink)m_arrLinks[nLink]).m_nTNode == nNode2 )
					{
						dDistance = bWeight ?((NetLink)m_arrLinks[nLink]).m_fFromImp : ((NetLink)m_arrLinks[nLink]).m_fLength;
						if ( dDistance < dMinDist )
						{
							dMinDist = dDistance;
							nMinLink = nLink;
							nRes = 1;
						}
					}
				}
				else if ( ((NetLink)m_arrLinks[nLink]).m_nTNode == nNode1 )
				{
					if ( ((NetLink)m_arrLinks[nLink]).m_nFNode == nNode2 )
					{
						dDistance = bWeight ? ((NetLink)m_arrLinks[nLink]).m_fToImp : ((NetLink)m_arrLinks[nLink]).m_fLength;
						if ( dDistance < dMinDist )
						{
							dMinDist = dDistance;
							nMinLink = nLink;
							nRes = -1;
						}
					}
				}
			}

			if ( nRes == 0 )
			{
				nLink = -1;
				dDistance = -1;
				return 0;
			}

			nLink = nMinLink;
			dDistance = dMinDist;
			return nRes;
		}

		// 去除加入的站点或中心点. UnloadStops与LoadStops必须一一对应
		private bool UnloadStops()
		{
			int i, j;
			int nLink, nNode;
			double dAngle;
			// 清空站点表
			m_arrStops.Clear();

			// 利用备份数据, 恢复弧段表和结点表, 并清除备份数据
			for ( i = 0; i < m_arrLinkBackups.Count; i++ )
			{
				nLink = ((NetLinkBackup)m_arrLinkBackups[i]).m_nIndex;
				// 恢复弧段表
				((NetLink)m_arrLinks[nLink]).Copy( ((NetLinkBackup)m_arrLinkBackups[i]).m_Link );

				// 恢复点表
				nNode = ((NetLink)m_arrLinks[nLink]).m_nTNode;
				dAngle = ((NetNode)m_arrNodes[nNode]).GetLinkAngle( nLink );
				for ( j = ((NetNode)m_arrNodes[nNode]).m_arrLinks.Count-1; j >=0 ; j-- )
				{
					if ( ((NetEdge)((NetNode)m_arrNodes[nNode]).m_arrLinks[j]).nLink >= m_nLinkNum )
					{
						((NetNode)m_arrNodes[nNode]).m_arrLinks.RemoveAt( j );
					}
				}
				((NetNode)m_arrNodes[nNode]).Add( nLink, dAngle );
			}
			m_arrLinkBackups.Clear();
			m_pPath = null;
			return true;
		}

	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -