www.pudn.com > C sharp和MapObjects实现.rar > NetLayer.cs


using System; 
using System.Collections; 
 
namespace MainSystem 
{ 
	public class NetPoint 
	{ 
		public double x; 
		public double y; 
 
		public NetPoint() 
		{ 
			x = 0; 
			y = 0; 
		} 
 
		public NetPoint( double x, double y ) 
		{ 
			this.x = x; 
			this.y = y; 
		} 
	} 
 
	public class NetLine 
	{ 
		// 属性 
		public ArrayList				m_pCoords = null; 
		private MapObjects2.MapLayer	m_layer = null; 
 
		// 构造函数 
		public NetLine(MapObjects2.MapLayer layer) 
		{ 
			m_pCoords = new ArrayList(); 
			m_layer = layer; 
		} 
 
		// 计算线的几何长度 
		public double CalcLength() 
		{ 
			double	dLength = 0.0 ;		// 保存计算出的线几何长度的结果 
			int		loop ;				// 保存循环计数 
 
			// 检查线的有效性 
			if ( m_pCoords.Count < 2 ) 
				return 0.0 ; 
			// 计算线的几何长度 
			double	dist = 0.0 ; 
			for ( loop = 1 ; loop < m_pCoords.Count ; loop ++ ) 
			{ 
				dist = Math.Sqrt ( ( ((NetPoint)m_pCoords[loop -1]).x - ((NetPoint)m_pCoords[loop]).x ) *  
					( ((NetPoint)m_pCoords[loop -1]).x - ((NetPoint)m_pCoords[loop]).x ) +  
					( ((NetPoint)m_pCoords[loop -1]).y - ((NetPoint)m_pCoords[loop]).y ) *  
					( ((NetPoint)m_pCoords[loop -1]).y - ((NetPoint)m_pCoords[loop]).y ) ) ; 
				dLength += dist ; 
			} 
 
			return dLength ; 
		} 
 
		// 通过线的id得到线数据 
		public bool GetLineData(int id) 
		{ 
			MapObjects2.Recordset rs; 
			rs = m_layer.SearchExpression("GeoID = " + id.ToString()); 
 
			if (null == rs) 
				return false; 
 
			rs.MoveFirst(); 
  
			if (rs.EOF)  
				return false; 
 
			MapObjects2.Line		line = (MapObjects2.Line)rs.Fields.Item("shape").Value; 
			MapObjects2.Points	pts; 
 
			pts = (MapObjects2.Points)line.Parts.Item(0); 
   
			m_pCoords.Clear(); 
  
			for (int i = 0; i < pts.Count; i ++) 
			{ 
				NetPoint pt = new NetPoint(pts.Item(i).X,pts.Item(i).Y); 
				m_pCoords.Add(pt);  
			} 
 
			return true; 
		} 
 
		// 得到距离某点最近的线段,返回该线段的id 
		public int GetNearestLineData( double x, double y) 
		{ 
			MapObjects2.Recordset rs = m_layer.Records; 
			MapObjects2.Point		pt = new MapObjects2.PointClass(); 
			pt.X = x; 
			pt.Y = y; 
 
			double	dDist = 9999999; 
			int		id = -1; 
 
			rs.MoveFirst();  
			while(!rs.EOF) 
			{ 
				MapObjects2.Line	line= (MapObjects2.Line)rs.Fields.Item("shape").Value; 
				double				d = line.DistanceTo(pt);   					 
 
				if (dDist > d) 
				{ 
					dDist = d; 
					string szValue = rs.Fields.Item("Geoid").ValueAsString; 
					id = Convert.ToInt32(szValue); 
				} 
				rs.MoveNext();  
			} 
 
			if (id != -1) 
			{ 
				if (!GetLineData(id)) 
					return -1; 
			} 
			return id; 
		} 
 
		public void AddCoord( NetPoint pt ) 
		{ 
			m_pCoords.Add( pt ); 
		} 
 
		public bool IsPtCoincide( NetPoint ptFirst, NetPoint ptSecond ) 
		{ 
			if ( Math.Abs(ptFirst.x - ptSecond.x ) <= 0.00000001 &&  
				Math.Abs(ptFirst.y - ptSecond.y ) <= 0.00000001 ) 
				return true; 
			return false; 
		} 
 
		public void GetNearestPoint( NetPoint ptP, NetPoint ptA, NetPoint ptB, 
			out NetPoint ptNearest, out double dDistance ) 
		{ 
			double Px,Py,Ax,Ay,Bx,By ; 
			double AB2,PA2,PB2,AB,PA,PB,S,AREA ; 
			double med,med1,k1,k2,b1,b2 ; 
 
			ptNearest = new NetPoint(); 
			dDistance = 0; 
 
			if ( IsPtCoincide(ptA,ptB) ) 
			{ 
				ptNearest = ptA; 
				return ; 
			} 
 
			Px = ptP.x ; 
			Py = ptP.y ; 
			Ax = ptA.x ; 
			Ay = ptA.y ; 
			Bx = ptB.x ; 
			By = ptB.y ; 
			AB2 = (Ax - Bx) * (Ax - Bx) + (Ay - By) * (Ay - By) ; 
			PB2 = (Px - Bx) * (Px - Bx) + (Py - By) * (Py - By) ; 
			PA2 = (Ax - Px) * (Ax - Px) + (Ay - Py) * (Ay - Py) ;	 
	 
			if(PA2 + AB2 < PB2 || AB2 + PB2 < PA2)	 
			{                        
				if(PA2>PB2) 
				{ 
					med = PB2 ; 
					ptNearest.x = Bx ; 
					ptNearest.y = By ; 
				} 
				else 
				{ 
					med = PA2 ; 
					ptNearest.x = Ax ; 
					ptNearest.y = Ay ; 
				} 
				med = Math.Sqrt(med) ;	 
				dDistance = med ; 
				return ; 
			} 
 
			if (PA2 < 0.00000001 || PB2 < 0.00000001) 
			{ 
				if(PA2 < 0.00000001) 
				{ 
					med = Math.Sqrt(PA2) ; 
					dDistance = med ; 
					ptNearest.x = Ax ; 
					ptNearest.y = Ay ; 
					return ; 
				} 
				else  
				{ 
					med = Math.Sqrt(PB2) ; 
					dDistance = med ; 
					ptNearest.x = Bx ; 
					ptNearest.y = By ; 
					return ; 
				} 
			} 
 
			AB = Math.Sqrt(AB2) ; 
			PA = Math.Sqrt(PA2) ; 
			PB = Math.Sqrt(PB2) ; 
			S = (AB + PA + PB) / 2.0 ; 
			AREA = S ; 
			AREA *= (S - PA) ; 
			AREA *= (S - PB) ; 
			AREA *= (S - AB) ; 
			AREA = Math.Sqrt(AREA) ; 
			med = (2.0 * AREA) / AB ; 
			dDistance = med ; 
	 
			med = Ay - By ; 
			med1 = Ax - Bx ; 
			if(Math.Abs(med) < 0.00000001 || Math.Abs(med1) < 0.00000001)		 
			{	 
				if(Math.Abs(med) < 0.00000001) 
				{ 
					ptNearest.x = Px ; 
					ptNearest.y = Ay ; 
				} 
				else 
				{ 
					ptNearest.y = Py ; 
					ptNearest.x = Ax ; 
				} 
			} 
			else 
			{	 
				k1 = (Ay - By) / ( Ax - Bx) ;	 
				k2 = -1.0 / k1 ;			 
				b1 = Ay - k1 * Ax ; 
				b2 = Py - k2 * Px ; 
				S = (b2 - b1) / (k1 - k2) ; 
				ptNearest.x = S ; 
				S = k1 * S + b1 ; 
				ptNearest.y = S ; 
			} 
			return; 
		} 
 
		public void GetNearestPoint( NetPoint point, out NetPoint ptNearestPoint,  
			out int nSegmentIndex,out double dLeastDistance	) 
		{ 
 
			int nPointNum = m_pCoords.Count;			 
			double dDistance; 
			NetPoint ptTemp; 
	 
			GetNearestPoint( point, (NetPoint)m_pCoords[0],(NetPoint)m_pCoords[1],out ptNearestPoint,out dLeastDistance); 
			nSegmentIndex = 0 ; 
	 
			//遍历每一条弧段来搜索最近的点 
			int nIndex ; 
			for( nIndex = 1 ; nIndex < nPointNum-1 ; nIndex ++ )  
			{		 
				//得到最近的点 
				GetNearestPoint( point, (NetPoint)m_pCoords[0], (NetPoint)m_pCoords[1], out ptTemp, out dDistance ) ; 
 
				//比较最小的距离 
				if( dDistance < dLeastDistance ) 
				{ 
					dLeastDistance = dDistance ; 
					ptNearestPoint = ptTemp ;  
					nSegmentIndex = nIndex ; 
				} 
			} 
			return ; 
		} 
 
		// 获得根据给定点分裂线得到的两个部分的比例, 但并不真正分裂线 
		// point: 给定点 
		// ptNearestPoint: 分裂线时的分裂点 (返回) 
		// dRatio: 起始结点部分的比例 (返回) 
		public bool GetSplitRatioByNearestPoint( NetPoint point, out NetPoint ptNearest, out double dRatio ) 
		{ 
			int nIndex; 
			double dDistance; 
 
			int nPointNum = m_pCoords.Count; 
			//首先得到最近的点和线段索引 
			GetNearestPoint( point, out ptNearest, out nIndex, out dDistance ); 
	 
			//检查线上最近的点是否与首尾点相重合 
			if( nIndex == 0 ) 
			{ 
				if( IsPtCoincide( ptNearest, (NetPoint)m_pCoords[0] ) ) 
				{ 
					dRatio = 0; 
					return true; 
				} 
			} 
 
			if( nIndex == nPointNum-2 ) 
			{ 
				if( IsPtCoincide( ptNearest, (NetPoint)m_pCoords[nPointNum-1] )) 
				{ 
					dRatio = 1; 
					return true; 
				} 
			} 
 
			//计算分裂出来的第二条线的长度 
			int nLoop; 
			double dLength = 0; 
			//如果最近点与本线上的下一点不重合,则需将最近点计算在内 
			if ( !IsPtCoincide(ptNearest, (NetPoint)m_pCoords[nIndex+1] ) ) 
			{ 
				dLength += Math.Sqrt( ( ((NetPoint)m_pCoords[nIndex+1]).x - ptNearest.x ) *  
					( ((NetPoint)m_pCoords[nIndex+1]).x - ptNearest.x ) +  
					( ((NetPoint)m_pCoords[nIndex+1]).y - ptNearest.y ) *  
					( ((NetPoint)m_pCoords[nIndex+1]).y - ptNearest.y ) 
					); 
			} 
			for( nLoop = nIndex+2 ; nLoop < nPointNum ; nLoop ++ ) 
			{ 
				dLength += Math.Sqrt( ( ((NetPoint)m_pCoords[nLoop]).x - ((NetPoint)m_pCoords[nLoop-1]).x ) *  
					( ((NetPoint)m_pCoords[nLoop]).x - ((NetPoint)m_pCoords[nLoop-1]).x ) +  
					( ((NetPoint)m_pCoords[nLoop]).y - ((NetPoint)m_pCoords[nLoop-1]).y ) *  
					( ((NetPoint)m_pCoords[nLoop]).y - ((NetPoint)m_pCoords[nLoop-1]).y ) 
					); 
			} 
 
			dRatio = 1 - dLength / CalcLength(); 
			return true; 
		} 
	} 
 
	public class NetEdge 
	{ 
		public int 		nLink;		// 连接的弧段索引(数组下标索引) 
		public float	fAngle;		// 该弧段的水平夹角 
 
		public NetEdge() 
		{ 
			nLink = -1; 
			fAngle = 0; 
		} 
	}; 
 
	public class NetNode : NetPoint 
	{		 
		public ArrayList m_arrLinks = null;	// 与该点连接的弧段数组, 弧段按角度排序 
		 
		public NetNode()  
		{ 
			m_arrLinks = new ArrayList(); 
		} 
 
		public NetNode( double x, double y )  
		{ 
			this.x = x; 
			this.y = y; 
			m_arrLinks = new ArrayList(); 
		} 
 
		// 加入一个连接的弧段(调用前需确定弧段是连接在该点上的) 
		public bool Add( int nLink, double dAngle ) 
		{ 
			// 结点连接的弧段按角度排序 
			int i = 0; 
			for (  i = 0; i < m_arrLinks.Count; i++ ) 
			{ 
				if ( dAngle < ((NetEdge)m_arrLinks[i]).fAngle ) 
					break; 
			} 
			NetEdge pEdge = new NetEdge(); 
			pEdge.nLink = nLink; 
			pEdge.fAngle = (float)dAngle; 
			m_arrLinks.Insert(i, pEdge ); 
 
			return true; 
		} 
 
		// 删除一个已连接的弧段 
		public bool Remove( int nLink ) 
		{ 
			for ( int i = 0; i < m_arrLinks.Count ; i++ ) 
			{ 
				if ( nLink == ((NetEdge)m_arrLinks[i]).nLink ) 
				{ 
					m_arrLinks.RemoveAt( i ); 
					break; 
				} 
			} 
			return true; 
		} 
 
		// 得到一个连接弧段的角度 
		public double GetLinkAngle( int nLink ) 
		{ 
			for ( int i = 0; i < m_arrLinks.Count ; i++ ) 
			{ 
				if ( nLink == ((NetEdge)m_arrLinks[i]).nLink ) 
				{ 
					return ((NetEdge)m_arrLinks[i]).fAngle; 
				} 
			} 
			return -1; 
		} 
	} 
 
	// 网络弧段(链)类 
	public class NetLink 
	{ 
		public int m_GeoID;				// 弧段ID(GeoID) 
		public int m_nFNode;			// 起始结点(数组下标索引) 
		public int m_nTNode;			// 终止结点(数组下标索引) 
		public double m_fLength;			// 长度 
		public double m_fFromImp;		// 正向阻力(阻力系数*长度 或 (1+阻力系数)*长度) 
		public double m_fToImp;			// 逆向阻力 
 
		public NetLink() 
		{ 
			m_GeoID = -1; 
			m_nFNode = -1; 
			m_nTNode = -1; 
			m_fLength = 0; 
			m_fFromImp = 0; 
			m_fToImp = 0; 
		} 
 
		public void Copy( NetLink link ) 
		{ 
			m_GeoID = link.m_GeoID; 
			m_nFNode = link.m_nFNode; 
			m_nTNode = link.m_nTNode; 
			m_fLength = link.m_fLength; 
			m_fFromImp = link.m_fFromImp; 
			m_fToImp = link.m_fToImp; 
		} 
 
		public bool IsEqual( NetLink link ) 
		{ 
			return m_GeoID == link.m_GeoID; 
		} 
	} 
 
	public class NetLinkSeg 
	{ 
		public int		nSegID;		// 分裂点后面的部分的弧段索引(数组下标索引) 
		public double	dRatio;		// 分裂点前面的到起始结点部分的比例 
	}; 
	 
	// 用于备份弧段的类 
	public class NetLinkBackup 
	{ 
		public int			m_nIndex;	// 弧段的索引 
		public NetLink		m_Link=null;		// 备份的弧段对象 
		public ArrayList	m_arrSegs;	// 该弧段被多次分割的比例列表, 数目=段数-1, 即等于分裂点数 
 
		public NetLinkBackup() 
		{ 
			m_nIndex = -1; 
			m_Link = new NetLink(); 
			m_arrSegs = new ArrayList(); 
		} 
 
		public bool Add( int nSeg, double dRatio ) 
		{ 
			int i = 0; 
			for ( i = 0; i < m_arrSegs.Count; i++ ) 
			{ 
				if ( dRatio < ((NetLinkSeg)m_arrSegs[i]).dRatio ) 
					break; 
			} 
			NetLinkSeg pSeg = new NetLinkSeg(); 
			pSeg.nSegID = nSeg; 
			pSeg.dRatio = dRatio; 
			m_arrSegs.Insert( i, pSeg ); 
 
			return true; 
		} 
	} 
 
	public class NetPath 
	{ 
		public double	m_dLength;		// 该点到给定点的最短路径长度, -1表示无穷大,即不连通 
		public int		m_nPreNode;		// 该点在该路径上的前趋结点 
		public	NetPath() 
		{ 
			m_dLength = -1; 
			m_nPreNode = -1; 
		} 
	} 
 
	///  
	/// Summary description for NetLayer. 
	///  
	public class NetLayer 
	{ 
		private ArrayList	m_arrLinks;		// 弧段表 
		private ArrayList	m_arrNodes;		// 结点表 
		private ArrayList	m_arrStops;		// 站点表 
		private ArrayList	m_arrLinkBackups;		// 弧段备份表 
		 
		private int		m_nLinkNum;			// 原始弧段数目(网络拓扑建立完成后) 注意: 和m_arrLinks的大小可能是不相等的 
		private int		m_nNodeNum;			// 原始结点数目(网络拓扑建立完成后) 注意: 和m_arrNodes的大小可能是不相等的 
		private NetPath[]	m_pPath;			// 某一个点到所有点的最短路径. 每个点只记录它在路径上的前趋结点 
 
		private MapObjects2.MapLayer	m_layer = null; 
		private System.Data.DataSet	m_dataSet = null;  
 
		public NetLayer(MapObjects2.MapLayer layer, System.Data.DataSet dataSet) 
		{ 
			m_nLinkNum = 0; 
			m_nNodeNum = 0; 
			m_pPath = null; 
			m_dataSet = dataSet; 
			m_layer = layer; 
		} 
 
		public bool ReadNetTable() 
		{ 
			m_arrLinks = new ArrayList(); 
			m_arrNodes = new ArrayList(); 
			m_arrStops = new ArrayList(); 
			m_arrLinkBackups = new ArrayList(); 
 
			System.Data.DataTable Tbl = m_dataSet.Tables["AAT"];			 
			System.Data.DataRow[] rows = Tbl.Select(); 
			foreach (System.Data.DataRow myRow in rows) 
			{ 
				NetLink lk = new NetLink(); 
				lk.m_GeoID = (int)myRow["GeoID"]; 
				lk.m_nFNode = (int)myRow["FNODE"]; 
				lk.m_nTNode = (int)myRow["TNODE"]; 
				lk.m_fLength = (double)myRow["LENGTH"]; 
				lk.m_fFromImp  = (double)myRow["FIMP"];  
				lk.m_fToImp  = (double)myRow["TIMP"];  
				m_arrLinks.Add( lk ); 
			} 
 
			Tbl = m_dataSet.Tables["NAT"];						 
			rows = Tbl.Select(); 
			foreach (System.Data.DataRow myRow in rows) 
			{ 
				int nNode, nLink; 
				double x, y, dAngle; 
				string szArcID, szAngle; 
 
				nNode = (int)myRow["NODEID"]; 
				x = (double)myRow["X"]; 
				y = (double)myRow["Y"]; 
				szArcID = myRow["ARCID"].ToString(); 
				szAngle = myRow["ANGLE"].ToString(); 
				NetNode node = new NetNode(x,y); 
				m_arrNodes.Add( node ); 
 
				int nPos; 
				string szTemp; 
				while ( (nPos = szArcID.IndexOf( ';' )) != -1 ) 
				{ 
					szTemp = szArcID.Substring( 0,nPos ); 
					nLink = Convert.ToInt32( szTemp ); 
					szArcID = szArcID.Substring( nPos+1 ); 
 
					nPos = szAngle.IndexOf( ';' ); 
					if ( nPos == -1 ) 
						continue; 
					szTemp = szAngle.Substring(0, nPos ); 
					dAngle = Convert.ToDouble( szTemp ); 
					szAngle = szAngle.Substring( nPos + 1 ); 
					node.Add( nLink, dAngle ); 
				}			 
			} 
			return true; 
		} 
 
		public bool PathAnalysis( double x1, double y1, double x2, double y2, out ArrayList path ) 
		{ 
			path = new ArrayList(); 
			NetPoint pt1 = new NetPoint( x1, y1 ); 
			NetPoint pt2 = new NetPoint( x2, y2 ); 
 
			ArrayList points = new ArrayList(); 
			points.Add( pt1 ); 
			points.Add( pt2 ); 
 
			ArrayList stops = null; 
			if ( !LoadStops( points, out stops ) ) 
				return false; 
			if ( stops.Count != 2 ) 
				return false; 
 
			ArrayList nodes = null; 
			double dDistance; 
			dDistance = Path( (int)stops[0], (int)stops[1], out nodes, false ); 
			if ( dDistance < 0 ) 
				return false; 
 
			NetLine line = null; 
			if ( !CreateResultPath( nodes, out line, false ) ) 
				return false; 
 
			for ( int i = 0; i < line.m_pCoords.Count; i++ ) 
			{ 
				path.Add( ((NetPoint)line.m_pCoords[i]).x ); 
				path.Add( ((NetPoint)line.m_pCoords[i]).y ); 
			} 
			UnloadStops(); 
			return true; 
		} 
 
 
		// 加入一组坐标作为站点或者中心点, 用于分析. LoadStops与UnloadStops必须一一对应 
		private bool LoadStops( ArrayList pPoints, out ArrayList pNodes ) 
		{	 
			int nLineID; 
			int i, nNewNode; 
			NetPoint ptNearest; 
			double dRatio; 
			pNodes = new ArrayList(); 
 
			// 先清空站点表 
			m_arrStops.Clear(); 
			int nNum = pPoints.Count; 
			for ( i = 0; i < nNum; i++ ) 
			{ 
				// 计算距离该点最近的线 
				NetLine line = new NetLine(m_layer); 
				nLineID = line.GetNearestLineData( ((NetPoint)pPoints[i]).x, ((NetPoint)pPoints[i]).y); 
				if ( nLineID == -1 ) 
				{ 
					line = null; 
					return false; 
				} 
 
				// 计算该点分裂该线的位置, 并不实际分裂该线, 只是计算分裂的比例, 用于更改弧段表和结点表 
				dRatio = 0; 
				line.GetSplitRatioByNearestPoint( (NetPoint)pPoints[i], out ptNearest, out dRatio ); 
 
				// 更新弧段表和结点表 
				UpdateLinkNodeTable( nLineID, ptNearest, dRatio, out nNewNode ); 
				line = null; 
 
				if ( pNodes.Count > 0 ) 
				{ 
					if ( ((int)pNodes[pNodes.Count-1]) == nNewNode ) 
						continue; 
				} 
				pNodes.Add( nNewNode ); 
			} 
 
			// 填充需要返回的结点数组 
			if ( pNodes.Count == 0 ) 
			{ 
				pNodes = null; 
				return false; 
			} 
			return true; 
		} 
 
		// 外部结点更新弧段表和结点表 
		// nNewNode: 加入该点后返回的新结点的标识 
		private bool UpdateLinkNodeTable( int nLineID, NetPoint ptNearest, double dRatio, out int nNewNode ) 
		{ 
			int i, j; 
			bool bFound; 
			double dRatio2; 
			int nCurLink, nNewLink; 
			int nCurFNode, nCurTNode;			 
			nNewNode = -1; 
 
			// 与某条弧段的首点或者位点重合, 不需要更改弧段表和结点表 
			if ( Math.Abs(dRatio) < 0.00000001 ) 
			{ 
				// 首点 
				nCurLink = GetNode( nLineID, out nCurFNode, out nCurTNode ); 
				nNewNode = nCurFNode; 
				return true; 
			} 
			else if ( Math.Abs(1-dRatio) < 0.00000001 ) 
			{ 
				// 尾点 
				nCurLink = GetNode( nLineID, out nCurFNode, out nCurTNode ); 
				nNewNode = nCurTNode; 
				return true; 
			} 
 
			bFound = false; 
			for ( i = 0; i < m_arrLinkBackups.Count; i++ ) 
			{ 
				if ( ((NetLinkBackup)m_arrLinkBackups[i]).m_Link.m_GeoID == nLineID ) 
				{ 
					bFound = true; 
					break; 
				} 
			} 
 
			if ( bFound ) 
			{ 
				for ( j = 0; j < ((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs.Count; j++ ) 
				{ 
					// 如果新点与原有的点重合, 则直接返回原来的点 
					double r = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[j]).dRatio; 
					if ( Math.Abs( r - dRatio) < 0.00000001 ) 
					{ 
						if ( j == 0 ) 
						{ 
							nCurLink = GetNode( nLineID, out nCurFNode, out nCurTNode ); 
							nNewNode = nCurTNode; 
							return true; 
						} 
						else 
						{ 
							nCurLink = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[j-1]).nSegID; 
							nNewNode = ((NetLink)m_arrLinks[nCurLink]).m_nTNode; 
							return true; 
						} 
					} 
 
					// 没有重合的点 
					r = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[j]).dRatio; 
					if ( dRatio < r ) 
						break; 
				} 
				if ( j == 0 )	 
				{	 
					// 第一段 
					nCurLink = GetNode( nLineID, out nCurFNode, out nCurTNode ); 
					if ( nCurLink == -1 ) 
						return false; 
 
					// 更新结点表 
					nNewLink = m_arrLinks.Count; 
					NetNode pNode = new NetNode( ptNearest.x, ptNearest.y ); 
					pNode.Add( nNewLink, -1 );	// 这里暂时用-1角度,待修改 Add code here 
					pNode.Add( nCurLink, -1 ); 
					m_arrNodes.Add( pNode ); 
 
					((NetNode)m_arrNodes[nCurTNode]).Remove( nCurLink ); 
					((NetNode)m_arrNodes[nCurTNode]).Add( nNewLink, -1 ); 
 
					// 更新弧段表 
					nNewNode = m_arrNodes.Count - 1; 
					dRatio2 = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[0]).dRatio; 
					NetLink pLink = new NetLink(); 
					pLink.m_GeoID = nLineID; 
					pLink.m_nFNode = nNewNode; 
					pLink.m_nTNode = ((NetLink)m_arrLinks[((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[0]).nSegID]).m_nFNode; 
					pLink.m_fLength = (float)(((NetLink)m_arrLinks[nCurLink]).m_fLength * ( dRatio2 - dRatio )); 
					pLink.m_fFromImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fFromImp * ( dRatio2 - dRatio )); 
					pLink.m_fToImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fToImp * ( dRatio2 - dRatio )); 
					m_arrLinks.Add( pLink ); 
 
					((NetLink)m_arrLinks[nCurLink]).m_nTNode = nNewNode; 
					((NetLink)m_arrLinks[nCurLink]).m_fLength = (float)(((NetLink)m_arrLinks[nCurLink]).m_fLength * dRatio); 
					((NetLink)m_arrLinks[nCurLink]).m_fFromImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fFromImp * dRatio); 
					((NetLink)m_arrLinks[nCurLink]).m_fToImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fToImp* dRatio); 
 
					((NetLinkBackup)m_arrLinkBackups[i]).Add( nNewLink, dRatio ); 
				} 
				else if ( j == ((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs.Count )	 
				{	 
					// 最后一段 
					nCurLink = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[j-1]).nSegID; 
					nCurFNode = ((NetLink)m_arrLinks[nCurLink]).m_nFNode; 
					nCurTNode = ((NetLink)m_arrLinks[nCurLink]).m_nTNode; 
 
					// 更新结点表 
					nNewLink = m_arrLinks.Count; 
					NetNode pNode = new NetNode( ptNearest.x, ptNearest.y ); 
					pNode.Add( nNewLink, -1 );	// 这里暂时用-1角度,待修改 Add code here 
					pNode.Add( nCurLink, -1 ); 
					m_arrNodes.Add( pNode ); 
 
					double dAngle = ((NetNode)m_arrNodes[nCurTNode]).GetLinkAngle( nCurLink );	// 最后一段保留原角度 
					((NetNode)m_arrNodes[nCurTNode]).Remove( nCurLink ); 
					((NetNode)m_arrNodes[nCurTNode]).Add( nNewLink, dAngle ); 
 
					// 更新弧段表 
					nNewNode = m_arrNodes.Count - 1; 
					NetLink pLink = new NetLink(); 
					pLink.m_GeoID = nLineID; 
					pLink.m_nFNode = nNewNode; 
					pLink.m_nTNode = nCurTNode; 
					pLink.m_fLength = (float)(((NetLink)m_arrLinks[i]).m_fLength * ( 1 - dRatio )); 
					pLink.m_fFromImp = (float)(((NetLink)m_arrLinks[i]).m_fFromImp * ( 1 - dRatio )); 
					pLink.m_fToImp = (float)(((NetLink)m_arrLinks[i]).m_fToImp * ( 1 - dRatio )); 
					m_arrLinks.Add( pLink ); 
 
					dRatio2 = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[j-1]).dRatio; 
					((NetLink)m_arrLinks[nCurLink]).m_nTNode = nNewNode; 
					((NetLink)m_arrLinks[nCurLink]).m_fLength = (float)(((NetLink)m_arrLinks[nCurLink]).m_fLength * ( dRatio - dRatio2) ); 
					((NetLink)m_arrLinks[nCurLink]).m_fFromImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fFromImp * ( dRatio - dRatio2) ); 
					((NetLink)m_arrLinks[nCurLink]).m_fToImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fToImp* ( dRatio - dRatio2) ); 
					((NetLinkBackup)m_arrLinkBackups[i]).Add( nNewLink, dRatio ); 
				} 
				else 
				{ 
					// 中间某一段 
					nCurLink = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[j-1]).nSegID; 
					nCurFNode = ((NetLink)m_arrLinks[nCurLink]).m_nFNode; 
					nCurTNode = ((NetLink)m_arrLinks[nCurLink]).m_nTNode; 
 
					// 更新结点表 
					nNewLink = m_arrLinks.Count; 
					NetNode pNode = new NetNode( ptNearest.x, ptNearest.y ); 
					pNode.Add( nNewLink, -1 );	// 这里暂时用-1角度,待修改 Add code here 
					pNode.Add( nCurLink, -1 ); 
					m_arrNodes.Add( pNode ); 
 
					((NetNode)m_arrNodes[nCurTNode]).Remove( nCurLink ); 
					((NetNode)m_arrNodes[nCurTNode]).Add( nNewLink, -1 ); 
 
					// 更新弧段表 
					nNewNode = m_arrNodes.Count - 1; 
					dRatio2 = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[j]).dRatio; 
					NetLink pLink = new NetLink(); 
					pLink.m_GeoID = nLineID; 
					pLink.m_nFNode = nNewNode; 
					pLink.m_nTNode = nCurTNode; 
					pLink.m_fLength = (float)(((NetLink)m_arrLinks[i]).m_fLength * ( dRatio2 - dRatio )); 
					pLink.m_fFromImp = (float)(((NetLink)m_arrLinks[i]).m_fFromImp * ( dRatio2 - dRatio )); 
					pLink.m_fToImp = (float)(((NetLink)m_arrLinks[i]).m_fToImp * ( dRatio2 - dRatio )); 
					m_arrLinks.Add( pLink ); 
 
					dRatio2 = ((NetLinkSeg)((NetLinkBackup)m_arrLinkBackups[i]).m_arrSegs[j-1]).dRatio; 
					((NetLink)m_arrLinks[nCurLink]).m_nTNode = nNewNode; 
					((NetLink)m_arrLinks[nCurLink]).m_fLength = (float)(((NetLink)m_arrLinks[nCurLink]).m_fLength * ( dRatio - dRatio2) ); 
					((NetLink)m_arrLinks[nCurLink]).m_fFromImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fFromImp * ( dRatio - dRatio2) ); 
					((NetLink)m_arrLinks[nCurLink]).m_fToImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fToImp* ( dRatio - dRatio2) ); 
					((NetLinkBackup)m_arrLinkBackups[i]).Add( nNewLink, dRatio ); 
				} 
			} 
			else 
			{ 
				nCurLink = GetNode( nLineID, out nCurFNode, out nCurTNode ); 
				if ( nCurLink == -1 ) 
					return false; 
 
				nNewLink = m_arrLinks.Count; 
				// 备份 
				NetLinkBackup pBackup = new NetLinkBackup(); 
				pBackup.m_nIndex = nCurLink; 
				pBackup.m_Link.Copy((NetLink)m_arrLinks[nCurLink]); 
				pBackup.Add( nNewLink, dRatio ); 
				m_arrLinkBackups.Add( pBackup ); 
 
				// 更新结点表 
				NetNode pNode = new NetNode( ptNearest.x, ptNearest.y ); 
				pNode.Add( nNewLink, -1 );	// 这里暂时用0角度,待修改 Add code here 
				pNode.Add( nCurLink, -1 ); 
				m_arrNodes.Add( pNode ); 
 
				double dAngle = ((NetNode)m_arrNodes[nCurTNode]).GetLinkAngle( nCurLink );	// 最后一段保留原角度 
				((NetNode)m_arrNodes[((NetLink)m_arrLinks[nCurLink]).m_nTNode]).Remove( nCurLink ); 
				((NetNode)m_arrNodes[((NetLink)m_arrLinks[nCurLink]).m_nTNode]).Add( nNewLink, dAngle ); 
 
				// 更新弧段表 
				nNewNode = m_arrNodes.Count - 1; 
				NetLink pLink = new NetLink(); 
				pLink.m_GeoID = nLineID; 
				pLink.m_nFNode = nNewNode; 
				pLink.m_nTNode = ((NetLink)m_arrLinks[nCurLink]).m_nTNode; 
				pLink.m_fLength = (float)(((NetLink)m_arrLinks[nCurLink]).m_fLength * ( 1 - dRatio )); 
				pLink.m_fFromImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fFromImp * ( 1 - dRatio )); 
				pLink.m_fToImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fToImp * ( 1 - dRatio )); 
				m_arrLinks.Add( pLink ); 
 
				((NetLink)m_arrLinks[nCurLink]).m_nTNode = nNewNode; 
				((NetLink)m_arrLinks[nCurLink]).m_fLength = (float)(((NetLink)m_arrLinks[nCurLink]).m_fLength * dRatio); 
				((NetLink)m_arrLinks[nCurLink]).m_fFromImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fFromImp * dRatio); 
				((NetLink)m_arrLinks[nCurLink]).m_fToImp = (float)(((NetLink)m_arrLinks[nCurLink]).m_fToImp* dRatio); 
			} 
			return true; 
		} 
 
		// 得到结点号, 返回弧段索引号(数组下标索引), -1表示失败 
		private int GetNode( int nLineID, out int nFNode, out int nTNode ) 
		{ 
			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; 
		} 
 
	} 
}