三维可视分析包括通视分析和可视域分析。前者用来判断两点之间是否通视,后者用于对观察点的可视范围进行分析。
涉及到的控件:
sceneControl相关事件:Tracking,Tracked
Scene属性:TrackingLayer
SightLine(通视线)相关方法:Build,Clear,AddTargetPoint,GetSightLineResult,SetTargetPoint,GetTargetPoint,GetTargetPointCount,RemoveAllTargetPoint。涉及属性:BarrierPoint,HiddenColor,TargetPoint,ViewerPosition,ViewPosition。
ViewShed3D(通视域)相关方法:Build,Clear,SetDistDirBypoint。涉及属性:Direction,Distance,HiddenAreaColor,HintLineColor,HorizontalFov,VerticalFov,ViewerPosition,VisibleAreaColor。
涉及引用:supermap.Data;supermap.Realspace;supermap.UI;supermap.Realspace.SpatialAnalyst;
一:通视分析
通视分析是三维GIS常用的分析功能,用于判断三维场景中任意两点之间的通视情况。
通视分析需要用户指定观察点和目标点,分析结果保存在VisibleResult3D对象中,包含了是否通视,通视线对象,障碍点和不通视线对象的信息。
判断两点是否通视,并保存分析结果到通视分析结果对象。viewPoint为观察点,TargetPoint为目标点。
VisibleResult3D visible = VisibilityAnalyst3D.IsVisible(viewPoint,TargetPoint);
首先子窗口实例化
private Workspace m_WorkSpace = null;
private SceneControl m_SceneControl = null;
private Sightline m_Sightline = null;
public DlgSightLineAnalysis()
{
InitializeComponent();
}
public void setWorkSpace(Workspace workspace)
{
m_WorkSpace = workspace;
}
public void setSceneControl(SceneControl sceneControl)
{
m_SceneControl = sceneControl;
}
private void DlgSightLineAnalysis_Load(object sender, EventArgs e)
{
this.btn_Clear.Enabled = false;//清除分析button
this.btn_EndAnalysis.Enabled = false;//结束分析button
this.btn_GetBarrierPoints.Enabled = false;//获取障碍点button
this.cb_ColorScheme.SelectedIndex = 0;
this.cb_TargetPointsIndex.Items.Clear();
m_Sightline.VisibleColor = Color.FromArgb(108, 231, 27);//设置通视线可视和不可视的颜色
m_Sightline.HiddenColor = Color.FromArgb(244, 52, 4);
}
然后定义创建可视线的方法
///
/// 根据指定的Scene对象,构造一个新的Sightline对象。
///
///
private Sightline CreateSightLine()
{
Sightline sightline = new Sightline(m_SceneControl.Scene);
this.cb_TargetPointsIndex.Items.Clear();//清除目标点集合
sightline.Build();//执行视线分析。 成功返回true 失败返回false
return sightline;
}
定义可视线颜色
///
/// 设置视线颜色,可见区域颜色/不可见区域颜色
///
///
///
private void cb_ColorScheme_SelectedIndexChanged(object sender, EventArgs e)
{
int index = this.cb_ColorScheme.SelectedIndex;
switch (index)
{
case 0:
if (m_Sightline != null)
{
m_Sightline.VisibleColor = Color.FromArgb(108, 231, 27);
m_Sightline.HiddenColor = Color.FromArgb(244, 52, 4);
}
break;
case 1:
if (m_Sightline != null)
{
m_Sightline.VisibleColor = Color.Yellow;
m_Sightline.HiddenColor = Color.Blue;
}
break;
case 2:
if (m_Sightline != null)
{
Random rand = new Random();
m_Sightline.VisibleColor = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
m_Sightline.HiddenColor = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
}
break;
default:
if (m_Sightline != null)
{
m_Sightline.VisibleColor = Color.Green;
m_Sightline.HiddenColor = Color.Red;
}
break;
}
}
然后就可以开始重头戏啦。首先先要为SceneControl绑定读取鼠标的事件
Tracking是在三维场景中鼠标交互绘制几何对象(在内存中跟踪绘制,结果在Scene.TrackingLayer)时触发该跟踪绘制事件。
Tracked在三维场景窗口的跟踪图层中鼠标交互绘制几何对象结束时触发该事件
///
/// 创建或者注销画线事件 true为注册,false为注销
///
///
private void RegisterTrackEvents(bool register)
{
if (register)
{
m_SceneControl.Tracking += new Tracking3DEventHandler(m_SceneControl_Tracking);
m_SceneControl.Tracked += new Tracked3DEventHandler(m_SceneControl_Tracked);
}
else
{
m_SceneControl.Tracking -= new Tracking3DEventHandler(m_SceneControl_Tracking);
m_SceneControl.Tracked -= new Tracked3DEventHandler(m_SceneControl_Tracked);
}
}
///
/// 跟踪图层中鼠标交互绘制几何对象时会触发该事件
/// tracking是读取鼠标移动,所以打断点时鼠标一动便会读取一次相应
///
///
///
private void m_SceneControl_Tracking(object sender, Tracking3DEventArgs e)
{
m_SceneControl.Scene.TrackingLayer.Clear();//清除跟踪图层
//判断是否是创建折线
if (m_SceneControl.Action == Action3D.CreatePolyline)
{
if (m_Sightline != null)//判断sightlight是否实例化
{
//线对象由一个或多个部分组成,每个部分称为线对象的一个子对象。每个子对象用一个三维点对象集合来表示。
//通过该类可以对子对象进行添加、删除和修改等操作。
GeoLine3D geoLine3D = e.Geometry as GeoLine3D;
if (geoLine3D != null && geoLine3D.PartCount > 0)
{
//此类管理三维线对象或三维线对象的子对象上的所有节点。
//由于三维线对象或三维线对象的子对象都是有向的,所以其三维点集合对象为有序的三维点的集合。
Point3Ds point3Ds = geoLine3D[0];
m_Sightline.ViewerPosition = point3Ds[0];//取得第一条折线的第一个节点,即为最初的观察点
UpDataToForm(point3Ds[0]);//tracking时可能会延迟显示是因为还没来得及相应
m_Sightline.RemoveAllTargetPoints();
for (int i = 1; i < point3Ds.Count; i++)
{
m_Sightline.AddTargetPoint(point3Ds[i]);
}
}
}
}
}
///
/// 创建可视线的方法。 根据指定的Scene对象,构造一个新的Sightline对象。
///
///
private Sightline CreateSightLine()
{
Sightline sightline = new Sightline(m_SceneControl.Scene);
sightline.Build();//执行视线分析。 成功返回true 失败返回false
return sightline;
}
///
/// 将观察点打印到窗体上
///
///
private void UpDataToForm(Point3D point)
{
this.textBox_ViewPosition_X.Text = String.Format("{0}",Math.Round(point.X,8));
this.textBox_ViewPosition_Y.Text = String.Format("{0}",Math.Round(point.Y,8));
this.textBox_ViewPosition_Z.Text = String.Format("{0}", Math.Round(point.Z,8));
}
然后定义Tracked绘制结束事件的方法
///
/// 绘制几何对象结束
///
///
///
private void m_SceneControl_Tracked(object sender, Tracked3DEventArgs e)
{
this.cb_TargetPointsIndex.Items.Clear();//防止目标点item有数据
if (m_SceneControl.Action == Action3D.CreatePolyline)
{
GeoLine3D geoline3D = e.Geometry as GeoLine3D;
if (geoline3D != null && geoline3D.PartCount > 0)//判断是画了折线并且子项数目大于0
{
Point3Ds pts = geoline3D[0];
m_Sightline.ViewerPosition = pts[0];
UpDataToForm(pts[0]);
m_Sightline.RemoveAllTargetPoints();
for (int i = 1; i < pts.Count; ++i)
{
m_Sightline.AddTargetPoint(pts[i]);
this.cb_TargetPointsIndex.Items.Add(i);
}
}
}
if (this.cb_TargetPointsIndex.Items.Count > 0)
{
this.cb_TargetPointsIndex.SelectedIndex = 0;
}
}
到此,通视分析基本功能已经实现,接下来定义了读取和修改目标点和观测点的方法
///
/// 修改观测点
///
///
///
private void btn_modiftObservePt_Click(object sender, EventArgs e)
{
if (m_Sightline != null)
{
Point3D point = m_Sightline.ViewerPosition;
point.X = Convert.ToDouble(this.textBox_ViewPosition_X.Text);
point.Y = Convert.ToDouble(this.textBox_ViewPosition_Y.Text);
point.Z = Convert.ToDouble(this.textBox_ViewPosition_Z.Text);
m_Sightline.ViewerPosition = point;
m_SceneControl.Scene.TrackingLayer.Clear();
}
}
///
/// 读取目标点
///
///
///
private void cb_TargetPointsIndex_SelectedIndexChanged(object sender, EventArgs e)
{
int Index_TargetPoint = this.cb_TargetPointsIndex.SelectedIndex;
Point3D point = m_Sightline.GetTargetPoint(Index_TargetPoint);
this.textBox_TargetX.Text = String.Format("{0}",Math.Round(point.X, 8));
this.textBox_TargetY.Text = String.Format("{0}", Math.Round(point.Y, 8));
this.textBox_TargetZ.Text = String.Format("{0}", Math.Round(point.Z, 8));
}
///
/// 修改目标点
///
///
///
private void btn_modifyTargetPt_Click(object sender, EventArgs e)
{
int index = this.cb_TargetPointsIndex.SelectedIndex;
if (m_Sightline != null && index >=0)
{
Point3D point = m_Sightline.ViewerPosition;
point.X = Convert.ToDouble(this.textBox_TargetX.Text);
point.Y = Convert.ToDouble(this.textBox_TargetY.Text);
point.Z = Convert.ToDouble(this.textBox_TargetZ.Text);
m_Sightline.SetTargetPoint(index, point);
m_SceneControl.Scene.TrackingLayer.Clear();
}
}
紧接着,我们定义一个获取障碍点的方法
///
/// 获取障碍点
///
///
///
private void btn_GetBarrierPoints_Click(object sender, EventArgs e)
{
GeoStyle3D geoStyle = new GeoStyle3D();//障碍点定义以及其属性
geoStyle.MarkerSize = 20;
geoStyle.AltitudeMode = AltitudeMode.Absolute;
geoStyle.MarkerFile = @"D:\My_Test\三维测试\三维测试\Resources\toolStripPan.png";
geoStyle.MarkerAnchorPoint = new Point2D(0.5, 0.5);
int count = m_Sightline.GetTargetPointCount() > 0? m_Sightline.GetTargetPointCount():0;//确定是否存在通视线,这一句没有意义只是好玩才写的
if (m_Sightline != null && count != 0)
{
for (int i = 0; i < count; i++)
{
Sightline.SightlineResult result = m_Sightline.GetSightlineResult(i);
Point3D point = result.BarrierPoint;
GeoPoint3D geoPoint = new GeoPoint3D(point);
geoPoint.Style3D = geoStyle;
String Tag = "BarrierPoint{" + i.ToString() + "}";
//判断是否已经存过了
int index = m_SceneControl.Scene.TrackingLayer.IndexOf(Tag);
if (index < 0)
{
m_SceneControl.Scene.TrackingLayer.Add(geoPoint, Tag);
}
else
{
m_SceneControl.Scene.TrackingLayer.Set(index, geoPoint);
}
}
}
}
最后定义结束分析和清除分析结果button的方法
///
/// 清除分析结果
///
///
///
private void btn_Clear_Click(object sender, EventArgs e)
{
if (m_Sightline != null)
{
m_Sightline.Clear();
m_Sightline = null;
}
m_SceneControl.Scene.TrackingLayer.Clear();
this.cb_TargetPointsIndex.Items.Clear();
this.textBox_ViewPosition_X.Text = "0.0";
this.textBox_ViewPosition_Y.Text = "0.0";
this.textBox_ViewPosition_Z.Text = "0.0";
this.textBox_TargetX.Text = "";
this.textBox_TargetY.Text = "";
this.textBox_TargetZ.Text = "";
this.RegisterTrackEvents(false);//注销track事件
m_SceneControl.Action = Action3D.Pan;
this.btn_Analysis.Enabled = true;
this.btn_Clear.Enabled = false;
this.btn_EndAnalysis.Enabled = false;
this.cb_ColorScheme.Enabled = true;
}
///
/// 结束分析
///
///
///
private void btn_EndAnalysis_Click(object sender, EventArgs e)
{
this.RegisterTrackEvents(false);
m_SceneControl.Scene.TrackingLayer.Clear();
m_SceneControl.Action = Action3D.Pan;
this.btn_EndAnalysis.Enabled = false;
this.btn_GetBarrierPoints.Enabled = true;
}
最后附上结果图