NetLayer.cs
上传用户:xum6868
上传日期:2009-12-02
资源大小:102k
文件大小:37k
- 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>
- /// Summary description for NetLayer.
- /// </summary>
- 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;
- }
- }
- }