三维可视域分析是在场景的模型数据表面,相对于某个观察点,基于一定的水平视角、垂直视角以及指定的范围半径,分析该区域内所有通视点的集合。分析结果正常用绿色区域表示观察点处可见,红色表示不可见。
参数一般包括:
观察点:观测位置,注意要能改,因为正常会有一定相对高度。不会有人趴在地面看事物的,一般来说。
方向角:相机方向与正北方向夹角,范围是-360到360
倾斜角:当前分析的相机方向与地平面的夹角。范围-360到360
水平视距垂直视距:设置水平方向和垂直方向的范围,水平默认90,垂直默认60,范围1-120
可视距离:设置可视域分析的长度范围,单位为米,非负
桌面界面如下:
可视域分析涉及supermap控件的属性和方法见(1),然后定义了可视域颜色的枚举如下,cb_ColorSetting控件集合定义
enum ColorShame
{
Standand,//标准(红/绿)
Custom,//自定义(黄/绿)
Random//随机
}
涉及的引用和全局变量如下:
using SuperMap.Data;
using SuperMap.Realspace;
using SuperMap.UI;
using SuperMap.Realspace.SpatialAnalyst;
private Workspace m_workSpace = null;
private SceneControl m_sceneControl = null;
private Viewshed3D m_viewShed3D = null; //建立可视区域分析并在指定的场景中显示分析结果
private AnalysisQuality m_Quality = AnalysisQuality.Medium;//定义分析质量,默认为中等
private Color m_hintLineColor = Color.White;//定义可视域分析提示线的颜色,默认白色
private ColorShame m_ColorShame = ColorShame.Standand;//定义可视域分析的颜色,默认为标准,红绿配,就是上面的枚举
private List m_ViewShed3DList = null; //保存所有的ViewShed的集合
private bool m_HasDone = true;//一次分析是否结束,true为结束,false为开始
private double m_viewDistance = 100.0; //可视域分析的可视距离默认值
private double m_horizontalFOV = 90; //1~120 deg. //水平视角默认值
private double m_vertialFOV = 60; //1~120 deg. //垂直视角默认值
private double m_direction = 0.0; //-360~360 //方向角默认值
private double m_pitch = 0.0; //俯仰角,也就是倾斜角
老样子子窗体实例化需要的:
public void setWorkSpace(Workspace workspace)
{
m_workSpace = workspace;
}
public void setSceneControl(SceneControl sceneControl)
{
m_sceneControl = sceneControl;
}
public DlgViewShedAnalysis()
{
InitializeComponent();
}
private void DlgViewShedAnalysis_Load(object sender, EventArgs e)
{
this.RegistTrackEvent(false); //注销Track事件
this.btn_EndAnalysis.Enabled = false; //结束分析button不可点
this.btn_Clear.Enabled = false; //清除分析button不可点
m_ViewShed3DList = new List();
this.cb_ColorSetting.SelectedIndex = 0;//注意控件一定要给默认值,防止异常
this.cb_AnalyticalQuality.SelectedIndex = 1;
}
然后定义注册Tracked和Tracking的方法
Tracking是在三维场景中鼠标交互绘制几何对象(在内存中跟踪绘制,结果在Scene.TrackingLayer)时触发该跟踪绘制事件。
Tracked在三维场景窗口的跟踪图层中鼠标交互绘制几何对象结束时触发该事件
///
/// 注销和绑定鼠标事件
///
///
private void RegistTrackEvent(bool isRegist)
{
if (isRegist)
{
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);
}
}
然后定义创建视域的方法
///
/// 创建视域
///
///
private Viewshed3D CreateViewShed()
{
Viewshed3D viewshed3D = new Viewshed3D(m_sceneControl.Scene);
UpdataParm(viewshed3D, false);//更新视域数据,true时用Viewshed3D更新属性,false时用界面参数更新viewshed3D
switch (m_ColorShame)
{//定义视域的颜色,visibleAreaColor为可视域的颜色,HiddenAreaColor为不可视域的颜色
case ColorShame.Standand:
{
viewshed3D.VisibleAreaColor = Color.Green;
viewshed3D.HiddenAreaColor = Color.Red;
}
break;
case ColorShame.Custom:
{
viewshed3D.VisibleAreaColor = Color.Yellow;
viewshed3D.HiddenAreaColor = Color.Blue;
}
break;
case ColorShame.Random:
{
Random rand = new Random();
viewshed3D.VisibleAreaColor = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
viewshed3D.HiddenAreaColor = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
}
break;
default:
viewshed3D.VisibleAreaColor = Color.Green;
viewshed3D.HiddenAreaColor = Color.Red;
break;
}
viewshed3D.HintLineColor = m_hintLineColor;//可视域的提示线颜色
m_ViewShed3DList.Add(viewshed3D);//将新的可视域保存到集合中
viewshed3D.Build();//执行分析,得出分析结果
return viewshed3D;
}
然后定义下更新视域相关数据的方法
///
/// 更新数据,判断是写入还是变更
/// true时用Viewshed3D更新属性,false时用界面参数更新viewshed3D
///
///
///
void UpdataParm(Viewshed3D viewshed , bool target)
{
if (target)
{
this.numericUD_Distance.Value = Convert.ToDecimal( viewshed.Distance);
this.numericUD_HorizontalFOV.Value = Convert.ToDecimal(viewshed.HorizontalFov);
this.numericUD_VerticalFOV.Value = Convert.ToDecimal(viewshed.VerticalFov);
this.numericUD_Direction.Value = Convert.ToDecimal(viewshed.Direction);
this.numericUD_Pitch.Value = Convert.ToDecimal(viewshed.Pitch);
}
else
{
viewshed.Distance = Convert.ToDouble(this.numericUD_Distance.Value);
viewshed.HorizontalFov = Convert.ToDouble(this.numericUD_HorizontalFOV.Value);
viewshed.VerticalFov = Convert.ToDouble(this.numericUD_VerticalFOV.Value);
viewshed.Direction = Convert.ToDouble(this.numericUD_Direction.Value);
viewshed.Pitch = Convert.ToDouble(this.numericUD_Pitch.Value);
}
}
///
/// 更新目标点
///
///
void updateObservePt(Viewshed3D viewshed)
{
this.tb_ObserveX.Text = viewshed.ViewerPosition.X.ToString();
this.tb_ObserveY.Text = viewshed.ViewerPosition.Y.ToString();
this.tb_ObserveZ.Text = viewshed.ViewerPosition.Z.ToString();
}
然后定义Track事件,便可开始分析了
private void m_sceneControl_Tracking(object sender, Tracking3DEventArgs e)
{
if (m_sceneControl.Action == Action3D.CreateLine)
{
if (m_HasDone)
{
m_viewShed3D = CreateViewShed();
m_HasDone = false;
}
if (m_viewShed3D != null)
{
GeoLine3D geoline3D = e.Geometry as GeoLine3D;
if (geoline3D.PartCount > 0)//子item数量
{
Point3Ds pts = geoline3D[0];
m_viewShed3D.ViewerPosition = pts[0];
updateObservePt(m_viewShed3D);
m_viewShed3D.SetDistDirByPoint(pts[1]);
this.UpdataParm(m_viewShed3D, true);
}
}
}
}
private void m_sceneControl_Tracked(object sender, Tracked3DEventArgs e)
{
//因为是Action为CreateLine,所以点两点Track便结束事件,调用Tracked了
// 通视分析SightLine那里是CreatePolyLine,是画折线,很多点需要右键结束
m_HasDone = true;
//下面部分是将可视域集合存到combobox里面,可以选择其中一个清除或修改,也可以选择ALL进行全部删除
this.cb_ViewShedItem.Items.Clear();
this.cb_ViewShedItem.Items.Add("ALL");
int i = 0;
for (i = 1; i <= m_ViewShed3DList.Count; i++)
{
String item = "{第" + i.ToString() + "个可视域}";
this.cb_ViewShedItem.Items.Add(item);
}
if (this.cb_ViewShedItem.Items.Count > 0)
{
this.cb_ViewShedItem.SelectedIndex = i - 1;
}
}
然后点击开始分析
///
/// 开始分析
///
///
///
private void btn_Analysis_Click(object sender, EventArgs e)
{
RegistTrackEvent(false);//保证事件不会被重复注册
RegistTrackEvent(true);
m_sceneControl.Action = Action3D.CreateLine;
this.btn_EndAnalysis.Enabled = true;
this.btn_Analysis.Enabled = false;
this.btn_Clear.Enabled = true;
this.m_HasDone = true;
}
至此可视域创建就结束了,接下来定义分析质量和改可视域颜色的方法
///
/// 分析结果质量
///
///
///
private void cb_AnalyticalQuality_SelectedIndexChanged(object sender, EventArgs e)
{
int QualityIndex = cb_AnalyticalQuality.SelectedIndex;
switch (QualityIndex)
{
case 0:
m_Quality = AnalysisQuality.Low;
break;
case 1:
m_Quality = AnalysisQuality.Medium;
break;
case 2:
m_Quality = AnalysisQuality.High;
break;
default:
m_Quality = AnalysisQuality.Medium;
break;
}
m_viewShed3D.Quality = m_Quality;
}
///
/// 颜色设置
///
///
///
private void cb_ColorSetting_SelectedIndexChanged(object sender, EventArgs e)
{
int index = this.cb_ColorSetting.SelectedIndex;
m_viewShed3D = m_ViewShed3DList[this.cb_ViewShedItem.SelectedIndex - 1];
switch (index)
{
case 0:
this.m_ColorShame = ColorShame.Standand;
if (m_viewShed3D != null)
{
m_viewShed3D.VisibleAreaColor = Color.Green;
m_viewShed3D.HiddenAreaColor = Color.Red;
}
break;
case 1:
this.m_ColorShame = ColorShame.Custom;
if (m_viewShed3D != null)
{
m_viewShed3D.VisibleAreaColor = Color.Yellow;
m_viewShed3D.HiddenAreaColor = Color.Blue;
}
break;
case 2:
this.m_ColorShame = ColorShame.Random;
if (m_viewShed3D != null)
{
Random rand = new Random();
m_viewShed3D.VisibleAreaColor = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
m_viewShed3D.HiddenAreaColor = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
}
break;
default:
this.m_ColorShame = ColorShame.Standand;
if (m_viewShed3D != null)
{
m_viewShed3D.VisibleAreaColor = Color.Green;
m_viewShed3D.HiddenAreaColor = Color.Red;
}
break;
}
}
然后定义可以选择可视域缓存的方法,通过选择第几次绘制的可视域,可以修改可视域的参数,颜色
///
/// 可视域缓存选择
///
///
///
private void cb_ViewShedItem_SelectedIndexChanged(object sender, EventArgs e)
{
Viewshed3D viewshed = null;
if (this.cb_ViewShedItem.SelectedIndex > 0)
{//如果存在可视域并且选中其中一条
viewshed = m_ViewShed3DList[cb_ViewShedItem.SelectedIndex - 1];
}
else if (this.cb_ViewShedItem.Items.Count > 0)
{//如果存在可视域,并且选中“ALL”,则选中的可视域为第一次创建的可视域
viewshed = m_ViewShed3DList[0];
}
if (viewshed != null)
{//让选中的可视域提示线变为橘黄色,未选中的其他可视域提示线为白色
for (int i = 0; i < m_ViewShed3DList.Count; i++)
{
m_viewShed3D = m_ViewShed3DList[i];
m_viewShed3D.HintLineColor = Color.White;
}
m_viewShed3D = viewshed;
m_viewShed3D.HintLineColor = Color.Orange;
updateObservePt(viewshed);//更新界面上可视域的参数,观测点等
this.UpdataParm(viewshed, true);
}
}
接下来比较麻烦的,清除选中的可视域的缓存,如果选中的是“ALL”则全部清除
///
/// 清除分析结果
///
///
///
private void btn_Clear_Click(object sender, EventArgs e)
{
this.RegistTrackEvent(false);//点击清除分析时,便不可继续创建可视域了,注销事件
int selection = this.cb_ViewShedItem.SelectedIndex;//获取选中的是第几个可视域
this.cb_ViewShedItem.Items.Clear();//清除comboBox,防止重复
if (selection == 0)
{//如果选中的是ALL,则全部清除
for (int i = 0; i < m_ViewShed3DList.Count; i++)
{
Viewshed3D viewshed3d = m_ViewShed3DList[i];
viewshed3d.Clear();
}
m_ViewShed3DList.Clear();
}
else if (selection > 0)
{//如果选中的是其中一条可视域
Viewshed3D viewshed3d = m_ViewShed3DList[selection - 1];
viewshed3d.Clear();
this.cb_ViewShedItem.Text = "";//将控件的文本清除,若不清除,items删除但控件还是有默认文本
m_ViewShed3DList.Remove(viewshed3d);//将该可视域从集合中清除
if (m_ViewShed3DList.Count > 0)
{//如果还剩下可视域
this.cb_ViewShedItem.Items.Add("ALL");
for (int i = 1; i <= m_ViewShed3DList.Count; i++)
{
String item = "{第" + i.ToString() + "个可视域}";
this.cb_ViewShedItem.Items.Add(item);
}
this.cb_ViewShedItem.SelectedIndex = m_ViewShed3DList.Count;//默认comboBox选中剩下的最后一条可视域
}
}
else
{//以防选中-1异常
MessageBox.Show("请选择清除第几个可视域缓存");
}
if (m_viewShed3D != null)
{
m_viewShed3D = null;
}
m_sceneControl.Action = Action3D.Pan;
this.btn_EndAnalysis.Enabled = true;
this.btn_Analysis.Enabled = true;
if (cb_ViewShedItem.Items.Count < 1)
{//如果可视域清除完了,清除分析button为不可用,结束分析也不可点击
this.cb_ViewShedItem.Items.Clear();
this.cb_ViewShedItem.Text = null;
this.btn_Clear.Enabled = false;
this.btn_EndAnalysis.Enabled = false;
}
}
然后定义结束分析
///
/// 结束分析
///
///
///
private void btn_EndAnalysis_Click(object sender, EventArgs e)
{
m_HasDone = false;
m_sceneControl.Action = Action3D.Pan;//注意一定要将Action改回来
this.m_sceneControl.Scene.TrackingLayer.Clear();
this.btn_EndAnalysis.Enabled = false;
this.btn_Analysis.Enabled = true;
this.btn_Clear.Enabled = true;
this.RegistTrackEvent(false);
}
最后定义下监视文本框以及可视域属性的那些框框的值变化的方法,然后还有关闭子窗体释放的事件
private void numericUD_Distance_ValueChanged(object sender, EventArgs e)
{
m_viewDistance = Convert.ToDouble(this.numericUD_Distance.Value);
if(m_viewShed3D != null)
{
m_viewShed3D.Distance = m_viewDistance;
}
}
private void numericUD_HorizontalFOV_ValueChanged(object sender, EventArgs e)
{
m_horizontalFOV = Convert.ToDouble(this.numericUD_HorizontalFOV.Value);
if (m_viewShed3D != null)
{
m_viewShed3D.HorizontalFov = m_horizontalFOV;
}
}
private void numericUD_VerticalFOV_ValueChanged(object sender, EventArgs e)
{
m_vertialFOV = Convert.ToDouble(this.numericUD_VerticalFOV.Value);
if (m_viewShed3D != null)
{
m_viewShed3D.VerticalFov = m_vertialFOV;
}
}
private void numericUD_Direction_ValueChanged(object sender, EventArgs e)
{
m_direction = Convert.ToDouble(this.numericUD_Direction.Value);
if (m_viewShed3D != null)
{
m_viewShed3D.Direction = m_direction;
}
}
private void numericUD_Pitch_ValueChanged(object sender, EventArgs e)
{
m_pitch = Convert.ToDouble(this.numericUD_Pitch.Value);
if (m_viewShed3D != null)
{
m_viewShed3D.Pitch = m_pitch;
}
}
private void DlgViewShedAnalysis_FormClosing(object sender, FormClosingEventArgs e)
{
this.RegistTrackEvent(false);
for (int i = 0; i < m_ViewShed3DList.Count; i++)
{
Viewshed3D viewshed3d = m_ViewShed3DList[i];
viewshed3d.Clear();
}
m_ViewShed3DList.Clear();
if (m_viewShed3D != null)
{
m_viewShed3D = null;
}
m_sceneControl.Action = Action3D.Pan;
}
o了,可视域分析结束了,下面附上成果图。三维分析还是挺有意思的