对于
三维场景中的道路的铺设,大多使用TerraExplorer Pro中提供的工具进行铺设,但是也要一条一条的在三维场景中画。
如果我们有道路中心线矢量 图层,那么这一切将变得非常简单,我们根据道路中心线图层可以自动的在三维场景中铺路。
整个过程基本上可以分为三步:
第一步:把道理中心线图层导入三维场景中,检测中心线图层是否与地形相匹配,对于有问题的线进行修改,并导出新的道路中心线图层。
第二步:使用道路导入工具自动在三维场景中生成道路面。下面我会重点讲怎么根据道路中心线生成道路面,并附带样例代码。
第三步:把道路的道路面保存成Shp面图层,最后以流的方式导入道路面图层。关于道路面图层的保存可以参考SkyLine 开发(2)中的讲解。
链接地址: http://www.3snews.net/bbs/viewthread.php?tid=7892&extra=page%3D1
这里开始讲根据道路中心线生成三维场景中的道路面的方法,我们使用了SkyLine的接口和MapObject的接口进行开发。
首先对道路中心线进行解析,得到中心线的坐标串和属性(如道路等级,路宽等),再根据道路中心线的 空间信息把中心线扩展成具有一定宽度的面,
根据属性信息对道路的宽度和道路纹理进行赋值,然后在三维场景中生成道路。当然对于道路交叉口等复杂路段我们还需要手动调整。
下面提供相关样例代码,其中根据道路中心线生成面的方法稍微复杂,其实也就是根据线生成缓冲区的过程,其余都很容易看懂。
虽然MapObjct提供了缓冲计算的接口,可以根据线生产面,但是在线的两端也做了半圆缓冲,自然不符合生成三维场景中道路的要求,
所以我们使用SkyLine的相关接口进行缓冲计算。
//渲染道路
private void btnBuildRoad_Click(object sender, EventArgs e)
{
MapLayer lyrTemp = new MapLayer();
lyrTemp = (MapLayer)axMap1.Layers.Item(0);
TableDesc TabDesc = new TableDesc();
TabDesc = lyrTemp.Records.TableDesc;
Recordset recs = lyrTemp.Records;
Line lineTemp;
Points ptsTemp;
ESRI.MapObjects2.Core.Point ptTemp,ptBeg,ptEnd;
double douRoadWidth;//道路宽度
string strRoadSort;//道路类别
Polygon pgNew;
Line lineNew;
object[] ptsPolygon, ptPolygon;
for (int i = 0; i < recs.Count; i++)
{
if (recs.Fields.Item("Shape").Value != System.DBNull.Value)
{
lineTemp = (Line)recs.Fields.Item("Shape").Value;
}
else
{
return;
}
if (recs.Fields.Item("Width").Value != System.DBNull.Value)
{
douRoadWidth = Convert.ToDouble(recs.Fields.Item("Width").Value);
}
else
{
return;
}
for (int m = 0; m < lineTemp.Parts.Count; m++)
{
ptsTemp = (Points)lineTemp.Parts.Item(m);
ptsPolygon = new object[ptsTemp.Count * 6];
ptsPolygon = GetPolygonPoints(ptsTemp, douRoadWidth / 2);
for (int n = 0; n < ptsTemp.Count - 1; n++)
{
ptPolygon = new object[12];
ptPolygon[0] = ptsPolygon[n * 3];
ptPolygon[1] = ptsPolygon[n * 3+1];
ptPolygon[2] = ptsPolygon[n * 3+2];
ptPolygon[3] = ptsPolygon[(n+1) * 3];
ptPolygon[4] = ptsPolygon[(n+1) * 3+1];
ptPolygon[5] = ptsPolygon[(n+1) * 3+2];
ptPolygon[6] = ptsPolygon[(ptsTemp.Count * 2 - 2 - n) * 3];
ptPolygon[7] = ptsPolygon[(ptsTemp.Count * 2 - 2 - n) * 3+1];
ptPolygon[8] = ptsPolygon[(ptsTemp.Count * 2 - 2 - n) * 3+2];
ptPolygon[9] = ptsPolygon[(ptsTemp.Count * 2 - 1 - n) * 3];
ptPolygon[10] = ptsPolygon[(ptsTemp.Count * 2 - 1 - n) * 3+1];
ptPolygon[11] = ptsPolygon[(ptsTemp.Count * 2 - 1 - n) * 3+2];
//渲染道路
tePolyline = clsTE.ObjectManager.Create2DPolygon(ptPolygon, 16711680, 0.0, 16711680, HeightStyleCode.HS_ON_TERRAIN, 0, "ddddd");
tePolyline.TextureFileName = @"C:\Program Files\ Skyline\TerraExplorer Pro\Tools\FreeHand\RoadTextures\road-3-3.gif";
tePolyline.TextureTilingMethod = TilingMethodCode.TM_METERS_PER_TILE;
tePolyline.TextureScaleX = douRoadWidth;
tePolyline.TextureScaleY = douRoadWidth;
tePolyline.TextureRotateAngle = 90;
tePolyline.FgAlpha = 0.0;
}
}
recs.MoveNext();
}
}
/// <summary>
/// 获取多边形的顶点坐标数组 这个函数用来根据道路中心线的坐标串和道路宽度两个参数生成多边形节点坐标数组。
/// </summary>
private object[] GetPolygonPoints(Points ptsTemp,double douRoadWith)
{
double Alpha, douLength, dYaw;
object dXL, dYL, dHL, dXR, dYR, dHR;
object oYaw, oPich, oYaw1, oYaw2, oPich1, oPich2, oYawTemp;
ESRI.MapObjects2.Core.Point ptS,ptE;
object[] ptsPolygon=new object[ptsTemp.Count*6];
for (int i = 0; i < ptsTemp.Count; i++)
{
Alpha=0;
if (i == 0)
{
ptS = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i);
ptE = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i + 1);
clsTE.CoordSys.GetAimingAngles(ptS.X, ptS.Y, 1, ptE.X, ptE.Y, 1, out oYaw, out oPich);
dYaw = (double)oYaw;
}
else
{
if (i == ptsTemp.Count - 1)
{
ptS = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i-1);
ptE = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i);
clsTE.CoordSys.GetAimingAngles(ptS.X, ptS.Y, 1, ptE.X, ptE.Y, 1, out oYaw, out oPich);
dYaw = (double)oYaw;
}
else
{
ptS = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i - 1);
ptE = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i);
clsTE.CoordSys.GetAimingAngles(ptS.X, ptS.Y, 1, ptE.X, ptE.Y, 1, out oYaw1, out oPich1);
ptS = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i);
ptE = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i+1);
clsTE.CoordSys.GetAimingAngles(ptS.X, ptS.Y, 1, ptE.X, ptE.Y, 1, out oYaw2, out oPich2);
dYaw = Math.Abs((double)oYaw1 - (double)oYaw2);
Alpha = dYaw / 2;
if (dYaw > 180) Alpha = 180 - Alpha;
if (dYaw > 180)
{
dYaw = ((double)oYaw1 + (double)oYaw2) / 2 - 180;
}
else
{
dYaw = ((double)oYaw1 + (double)oYaw2) / 2;
}
}
}
douLength = douRoadWith / Math.Cos(Alpha*Math.PI/180);
if (douLength > douRoadWith * 6)
{
douLength = douRoadWith * 6;
}
dXL=dXR=(object)ptsTemp.Item(i).X;
dYL=dYR=(object)ptsTemp.Item(i).Y;
dHL=dHR=0;
oYawTemp = (object)(dYaw - 90);
clsTE.CoordSys.MoveCoordEx(ref dXL, ref dYL, ref dHL, ref oYawTemp, 0, 0, douLength, 0, 0);
dHL = (object)clsTE.Terrain.GetGroundHeight((double)dXL, (double)dYL, AccuracyLevel.ACCURACY_BEST_FROM_MPT);
oYawTemp = (object)(dYaw + 90);
clsTE.CoordSys.MoveCoordEx(ref dXR, ref dYR, ref dHR, ref oYawTemp, 0, 0, douLength, 0, 0);
dHR = (object)clsTE.Terrain.GetGroundHeight((double)dXR, (double)dYR, AccuracyLevel.ACCURACY_BEST_FROM_MPT);
ptsPolygon[i * 3] = dXL;
ptsPolygon[i * 3 + 1] = dHL;
ptsPolygon[i * 3 + 2] = dYL;
ptsPolygon[(ptsTemp.Count * 2 - 1 - i) * 3] = dXR;
ptsPolygon[(ptsTemp.Count * 2 - 1 - i) * 3 + 1] = dHR;
ptsPolygon[(ptsTemp.Count * 2 - 1 - i) * 3 + 2] = dYR;
}
return ptsPolygon;
}
如果我们有道路中心线矢量 图层,那么这一切将变得非常简单,我们根据道路中心线图层可以自动的在三维场景中铺路。
整个过程基本上可以分为三步:
第一步:把道理中心线图层导入三维场景中,检测中心线图层是否与地形相匹配,对于有问题的线进行修改,并导出新的道路中心线图层。
第二步:使用道路导入工具自动在三维场景中生成道路面。下面我会重点讲怎么根据道路中心线生成道路面,并附带样例代码。
第三步:把道路的道路面保存成Shp面图层,最后以流的方式导入道路面图层。关于道路面图层的保存可以参考SkyLine 开发(2)中的讲解。
链接地址: http://www.3snews.net/bbs/viewthread.php?tid=7892&extra=page%3D1
这里开始讲根据道路中心线生成三维场景中的道路面的方法,我们使用了SkyLine的接口和MapObject的接口进行开发。
首先对道路中心线进行解析,得到中心线的坐标串和属性(如道路等级,路宽等),再根据道路中心线的 空间信息把中心线扩展成具有一定宽度的面,
根据属性信息对道路的宽度和道路纹理进行赋值,然后在三维场景中生成道路。当然对于道路交叉口等复杂路段我们还需要手动调整。
下面提供相关样例代码,其中根据道路中心线生成面的方法稍微复杂,其实也就是根据线生成缓冲区的过程,其余都很容易看懂。
虽然MapObjct提供了缓冲计算的接口,可以根据线生产面,但是在线的两端也做了半圆缓冲,自然不符合生成三维场景中道路的要求,
所以我们使用SkyLine的相关接口进行缓冲计算。
//渲染道路
private void btnBuildRoad_Click(object sender, EventArgs e)
{
MapLayer lyrTemp = new MapLayer();
lyrTemp = (MapLayer)axMap1.Layers.Item(0);
TableDesc TabDesc = new TableDesc();
TabDesc = lyrTemp.Records.TableDesc;
Recordset recs = lyrTemp.Records;
Line lineTemp;
Points ptsTemp;
ESRI.MapObjects2.Core.Point ptTemp,ptBeg,ptEnd;
double douRoadWidth;//道路宽度
string strRoadSort;//道路类别
Polygon pgNew;
Line lineNew;
object[] ptsPolygon, ptPolygon;
for (int i = 0; i < recs.Count; i++)
{
if (recs.Fields.Item("Shape").Value != System.DBNull.Value)
{
lineTemp = (Line)recs.Fields.Item("Shape").Value;
}
else
{
return;
}
if (recs.Fields.Item("Width").Value != System.DBNull.Value)
{
douRoadWidth = Convert.ToDouble(recs.Fields.Item("Width").Value);
}
else
{
return;
}
for (int m = 0; m < lineTemp.Parts.Count; m++)
{
ptsTemp = (Points)lineTemp.Parts.Item(m);
ptsPolygon = new object[ptsTemp.Count * 6];
ptsPolygon = GetPolygonPoints(ptsTemp, douRoadWidth / 2);
for (int n = 0; n < ptsTemp.Count - 1; n++)
{
ptPolygon = new object[12];
ptPolygon[0] = ptsPolygon[n * 3];
ptPolygon[1] = ptsPolygon[n * 3+1];
ptPolygon[2] = ptsPolygon[n * 3+2];
ptPolygon[3] = ptsPolygon[(n+1) * 3];
ptPolygon[4] = ptsPolygon[(n+1) * 3+1];
ptPolygon[5] = ptsPolygon[(n+1) * 3+2];
ptPolygon[6] = ptsPolygon[(ptsTemp.Count * 2 - 2 - n) * 3];
ptPolygon[7] = ptsPolygon[(ptsTemp.Count * 2 - 2 - n) * 3+1];
ptPolygon[8] = ptsPolygon[(ptsTemp.Count * 2 - 2 - n) * 3+2];
ptPolygon[9] = ptsPolygon[(ptsTemp.Count * 2 - 1 - n) * 3];
ptPolygon[10] = ptsPolygon[(ptsTemp.Count * 2 - 1 - n) * 3+1];
ptPolygon[11] = ptsPolygon[(ptsTemp.Count * 2 - 1 - n) * 3+2];
//渲染道路
tePolyline = clsTE.ObjectManager.Create2DPolygon(ptPolygon, 16711680, 0.0, 16711680, HeightStyleCode.HS_ON_TERRAIN, 0, "ddddd");
tePolyline.TextureFileName = @"C:\Program Files\ Skyline\TerraExplorer Pro\Tools\FreeHand\RoadTextures\road-3-3.gif";
tePolyline.TextureTilingMethod = TilingMethodCode.TM_METERS_PER_TILE;
tePolyline.TextureScaleX = douRoadWidth;
tePolyline.TextureScaleY = douRoadWidth;
tePolyline.TextureRotateAngle = 90;
tePolyline.FgAlpha = 0.0;
}
}
recs.MoveNext();
}
}
/// <summary>
/// 获取多边形的顶点坐标数组 这个函数用来根据道路中心线的坐标串和道路宽度两个参数生成多边形节点坐标数组。
/// </summary>
private object[] GetPolygonPoints(Points ptsTemp,double douRoadWith)
{
double Alpha, douLength, dYaw;
object dXL, dYL, dHL, dXR, dYR, dHR;
object oYaw, oPich, oYaw1, oYaw2, oPich1, oPich2, oYawTemp;
ESRI.MapObjects2.Core.Point ptS,ptE;
object[] ptsPolygon=new object[ptsTemp.Count*6];
for (int i = 0; i < ptsTemp.Count; i++)
{
Alpha=0;
if (i == 0)
{
ptS = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i);
ptE = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i + 1);
clsTE.CoordSys.GetAimingAngles(ptS.X, ptS.Y, 1, ptE.X, ptE.Y, 1, out oYaw, out oPich);
dYaw = (double)oYaw;
}
else
{
if (i == ptsTemp.Count - 1)
{
ptS = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i-1);
ptE = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i);
clsTE.CoordSys.GetAimingAngles(ptS.X, ptS.Y, 1, ptE.X, ptE.Y, 1, out oYaw, out oPich);
dYaw = (double)oYaw;
}
else
{
ptS = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i - 1);
ptE = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i);
clsTE.CoordSys.GetAimingAngles(ptS.X, ptS.Y, 1, ptE.X, ptE.Y, 1, out oYaw1, out oPich1);
ptS = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i);
ptE = (ESRI.MapObjects2.Core.Point)ptsTemp.Item(i+1);
clsTE.CoordSys.GetAimingAngles(ptS.X, ptS.Y, 1, ptE.X, ptE.Y, 1, out oYaw2, out oPich2);
dYaw = Math.Abs((double)oYaw1 - (double)oYaw2);
Alpha = dYaw / 2;
if (dYaw > 180) Alpha = 180 - Alpha;
if (dYaw > 180)
{
dYaw = ((double)oYaw1 + (double)oYaw2) / 2 - 180;
}
else
{
dYaw = ((double)oYaw1 + (double)oYaw2) / 2;
}
}
}
douLength = douRoadWith / Math.Cos(Alpha*Math.PI/180);
if (douLength > douRoadWith * 6)
{
douLength = douRoadWith * 6;
}
dXL=dXR=(object)ptsTemp.Item(i).X;
dYL=dYR=(object)ptsTemp.Item(i).Y;
dHL=dHR=0;
oYawTemp = (object)(dYaw - 90);
clsTE.CoordSys.MoveCoordEx(ref dXL, ref dYL, ref dHL, ref oYawTemp, 0, 0, douLength, 0, 0);
dHL = (object)clsTE.Terrain.GetGroundHeight((double)dXL, (double)dYL, AccuracyLevel.ACCURACY_BEST_FROM_MPT);
oYawTemp = (object)(dYaw + 90);
clsTE.CoordSys.MoveCoordEx(ref dXR, ref dYR, ref dHR, ref oYawTemp, 0, 0, douLength, 0, 0);
dHR = (object)clsTE.Terrain.GetGroundHeight((double)dXR, (double)dYR, AccuracyLevel.ACCURACY_BEST_FROM_MPT);
ptsPolygon[i * 3] = dXL;
ptsPolygon[i * 3 + 1] = dHL;
ptsPolygon[i * 3 + 2] = dYL;
ptsPolygon[(ptsTemp.Count * 2 - 1 - i) * 3] = dXR;
ptsPolygon[(ptsTemp.Count * 2 - 1 - i) * 3 + 1] = dHR;
ptsPolygon[(ptsTemp.Count * 2 - 1 - i) * 3 + 2] = dYR;
}
return ptsPolygon;
}