基于3D路口安全系数的导航决策系统--三维行车模拟版块实现
时间:2011-03-10 来源:@龙飞凤舞@
注:此篇文章最早发布于ESRI中国社区上,现在想把博客园作为自己发布文章的主战场,故原篇Copy过来。
恭贺论坛3D技术版块版开版,顺便拿出09年GIS开发竞赛作品“基于3D路口安全系数的导航决策系统”中的三维模拟导航功能版块和大家分享。 三维行车模拟功能展现:
系统的实时模拟功能实现了将行走过程中的行走速度、行车方式(开车、自行车、步行)、浏览视角改变(开车视角、俯视视角)、语音安全提示、缩略地图实时显示所处位置、最近/最安全路径分析选择等种功能相互结合,将实施行走模拟功能展示出来;更可贵的是系统将三维行走过程同行走道路的安全状况相互结合起来,并且可以在道路拐弯处提前给出道路口的安全状况语音动态提示,以此提高城市交通安全状况,实现系统价值体现。
实现技术:
在三维实时安全导航,每到交叉路口处,提示此路口安全系数、道路状况及开车注意等。此功能我们就是根据速度计算出当前所在点的坐标,通过查询过滤器IQueryFilter判断,若满足坐标与已知路口点的坐标x、y相差都在10m范围之内,则读取此路口属性进行提示,否则提示未知。
系统三维中实现第一视角开车比较复杂,首先就是视点camera的Target和Observer的角度、位置都必须恰到好处,才能给人以身临其境之感。让汽车实现转向,是通过取当前汽车点与路径上相邻一点的连线的坐标方位角,根据其计算公式得到汽车的角度,即实现了汽车转弯技术。
部分实现代码
public void fly()
{
if ((xtraTabControl1.SelectedTabPageIndex == 0))
{
this.xtraTabControl1.SelectedTabPageIndex = 1;
}
//得到路径Polyline
if (ShortPathSolveCommand.m_NAContext == null)
{
return;
}
try
{
IFeatureClass routesFC = ShortPathSolveCommand.m_NAContext.NAClasses.get_ItemByName("Routes") as IFeatureClass;
IFeature feature = routesFC.GetFeature(1);
IPolyline pPolyline = feature.Shape as IPolyline;
//将路径添加到鹰眼窗口
//鹰眼中画线
ChangeLineStyle(pPolyline, 200, 0, 0);
this.axMapControl2.Extent = pPolyline.Envelope;
//将路径添加到Scene窗口
//Scene中缩放到路径范围
ICamera camera = axSceneControl1.Scene.SceneGraph.ActiveViewer.Camera;
IEnvelope pEnv = new EnvelopeClass();
pEnv = pPolyline.Envelope;
pEnv.ZMax = axSceneControl1.Scene.Extent.ZMax; ;
pEnv.ZMin = axSceneControl1.Scene.Extent.ZMin;
camera.SetDefaultsMBB(pEnv);
this.axSceneControl1.SceneGraph.RefreshViewers();
ISceneGraph pSG = axSceneControl1.SceneGraph;
FlashGeometry(pPolyline, pSG);
//开始行走
double d = pPolyline.Length;
IPoint point1 = new PointClass();
IPoint point2 = new PointClass();
IPoint point11 = new PointClass();
IPoint point12 = new PointClass();
int fly_v = 30;
string fly_eye = "开车";
double m = d / fly_v;
double t = 0;
IPoint tempPoint = new PointClass();
for (int i = 0; i < (int)d; i = i + fly_v)
{
pPolyline.QueryPoint(esriSegmentExtension.esriNoExtension, i, false, point1);
pPolyline.QueryPoint(esriSegmentExtension.esriExtendAtFrom, i - 27, false, point2);
pPolyline.QueryPoint(esriSegmentExtension.esriNoExtension, i - 19, false, point12);
pPolyline.QueryPoint(esriSegmentExtension.esriNoExtension, i - 20, false, point11);
switch (fly_eye)
{
case "开车":
point12.Z = 0;
point2.Z = point12.Z + 5;
point1.Z = point12.Z + 4;
break;
case "俯视":
pPolyline.QueryPoint(esriSegmentExtension.esriExtendAtFrom, i - 100, false, point2);
pPolyline.QueryPoint(esriSegmentExtension.esriNoExtension, i + 4, false, point12);
point12.Z = 0;
point2.Z = point12.Z + 190;
point1.Z = point12.Z + 0;
break;
}
camera.Target = point1;//目标点
camera.Observer = point2;//观察点
IPoint point_now = new PointClass();
pPolyline.QueryPoint(esriSegmentExtension.esriNoExtension, i + 200, false, point_now);
//汽车转弯代码
double x = (int)point1.X - (int)point11.X;
double y = (int)point1.Y - (int)point11.Y;
double angle = 180 / 3.1415 * Math.Atan(y / x);
if (angle < 0)
{
angle = angle + 360;
}
if (x < 0 && y < 0)
{
angle = angle + 180;
}
if (x < 0 && y > 0)
{
angle = angle - 180;
}
angle = angle + 90;
// filename = @"..\..\Res\style\汽车3.3Ds";
string path = @"..\..\Res\style\汽车3.3Ds";
point12.Z = 1;
Add3DSymbolToScene(point12, path, angle);
//鹰眼里面行走
pPolyline.QueryPoint(esriSegmentExtension.esriExtendTangentAtTo, t, true, tempPoint);
int nFlashes = 2;
int flashInterval = 310;
object missing = Type.Missing;
ISimpleMarkerSymbol ipSimpleMarkersymbol;
ipSimpleMarkersymbol = new SimpleMarkerSymbol();
IRgbColor ipColor;
ipColor = new RgbColor();
ipColor.Red = 128;
ipSimpleMarkersymbol.Color = ipColor;
ipSimpleMarkersymbol.Size = 8;
this.axMapControl2.FlashShape(tempPoint, nFlashes, flashInterval, ipSimpleMarkersymbol);
t = t + 1 / m;
}
this.axMapControl2.Extent = this.axMapControl2.FullExtent;
}
catch
{
m_ErrorHandle.DisplayInformation("模拟失败!!!", false, "确定", "取消");
}
}