这篇文章早在去年就写出来了,但是由于当时毕业论文有一段是直接引用了我的这篇文章,怕引起查重的麻烦就删掉了,在此,重新挂出来和大家一起分享。

要素的选择,也称为要素的捕捉,在CAD、计算机图形学和地理信息系统中占据着相当重要的作用。比如,用户要根据鼠标在屏幕上的点击判断出选择的是哪一个点、线和面,这是经常碰到的操作。这种操作可以很方便的进行要素的一些属性信息查看,要素的操作等等。

下面就分别说一些针对点、线和面的不同形状要素的选取。

点:点的捕捉就是计算点与点之间的距离,为了加快搜索速度,可以设置一个以当前的点为中心,一个合适的距离向四周扩散构成一个正方形进行搜索,然后根据搜索得到的结果集进行距离计算。但是计算距离必然会引起开方根运算,这样肯定会引起计算时间的加长。可以有x和y两个轴方向上的距离绝对值代替距离,只要fabs(y2-y1)<eps并且fabs(x2-x1)<eps就满足搜索的条件。这样就实现了点的捕捉。

线:线的捕捉可以首先理解为点与折线的最短距离的计算。点与折线段的距离可以先分解为点与线段的距离,然后求出这些距离的最小值。这样看起来还像不错,但是效率太低,计算量大,不适合做大规模数据的搜索。现在我们首先看点与线段的距离,也许有人会说,你傻啊,这不是很简单吗,就只要按照点与直线的距离求出距离就可以了吗?很遗憾的告诉你,可惜定义不是这样的。一般的解决办法如下:先求出线段起始点到这点的向量在线段始末点组成的向量上的投影proj,然后根据投影和线段的长度做比较,小于0,直接求出这点与线段起始点的距离作为最近距离。如果0<proj<length(AB),则垂线距离作为最短距离。如果proj> =length(AB),则求出这点与线段终点之间的距离作为最短距离。

代码如下:

double Point2Segment(const OGRPoint &point,OGRPoint& pt0,OGRPoint& pt1)
{
 OGRPoint vecD(pt1.getX()-pt0.getX(),
  pt1.getY()-pt0.getY());  //线段的向量
 OGRPoint vecP(point.getX()-pt0.getX(),point.getY()-pt0.getY());//点到线段起始点的向量
 double valueD = sqrt(vecD.getX()*vecD.getX()+vecD.getY()*vecD.getY());
 double valueP = sqrt(vecP.getX()*vecP.getX()+vecP.getY()*vecP.getY());
 double dotMultiplay = vecD.getX()*vecP.getX()+vecD.getY()*vecP.getY();

double t = dotMultiplay/valueD;  //计算向量的投影

//如果线段开始点接近点point
 if (t <= 0)
 {
  return valueP;
 }

//如果线段结束点接近点point
 if (t >= valueD)
 {
  OGRPoint vecP(point.getX()-pt1.getX(),point.getY()-pt1.getY());
  return sqrt(vecP.getX()*vecP.getX()+vecP.getY()*vecP.getY());
 }

//返回垂足距离
 return valueP - t*t/valueD;
}

第二步是求出点到所有线段的最小值。这个一次求出然后比较就可以了。可能大部分人会这么干,但我想说的是编程不只是实现功能,还要优化算法以及自己写过的代码。这里可以进行如下的优化:在每一条线段的搜索过程中,记录下上一次记录的最小的距离值,可以以当前点为矩形中心点,以上一次记录的最小距离向四周扩散组成一个矩形,这个矩形我暂且叫它安全矩形,如果某一个线段在这个矩形内或者与这个矩形相交,那么可以进行距离计算。如果不满足条件,则舍弃进入下一条线段的判断。这样就可以省去很多不必要的计算工作。

代码如下:

double Point2LineString(const OGRPoint& point,OGRLineString* poString)
{
 double distance = 65535;
 for (int i = 0; i < poString->getNumPoints()-1; i ++)
 {
  OGRPoint pt0, pt1;
  poString->getPoint(i,&pt0);
  poString->getPoint(i+1,&pt1);

//此处这个矩形作为搜索的一个工具
  OGREnvelope envSearch;
  envSearch.MinX = point.getX()-distance;
  envSearch.MaxX = point.getX()+distance;
  envSearch.MinY = point.getY()-distance;
  envSearch.MaxY = point.getY()+distance;
  OGREnvelope envSegment; //线段所在的矩形
  envSegment.MinX = min(pt0.getX(),pt1.getX());
  envSegment.MaxX = max(pt0.getX(),pt1.getX());
  envSegment.MinY = min(pt0.getY(),pt1.getY());
  envSegment.MaxY = max(pt0.getY(),pt1.getY());

//包含在或者与搜索矩形相交的线段才考虑求距离
  if (envSearch.Contains(envSegment) ||
   envSearch.Intersects(envSegment))
  {
   double dist = Point2Segment(point,pt0,pt1);
   if (distance >= dist)
   {
    distance = dist;
   }
  }
 }

return distance;
}

第三步:根据建立的空间索引进行搜索,找出符号条件的要素,然后再逐个比较距离大小,最后看是否小于阈值,在此需要转换为屏幕距离再作比较。

多边形(面):见我的另一篇博文(点与多边形关系(改进射线法))。

大家还有什么更好的优化方案可以一起进行探讨。

GIS中要素的捕捉以及C++实现的更多相关文章

  1. (十一)WebGIS中要素(Feature)的设计

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 在GIS中元素一般分为点元素,线元素,面元素以及symbol ...

  2. 地图四叉树一般用在GIS中,在游戏寻路中2D游戏中一般用2维数组就够了

    地图四叉树一般用在GIS中,在游戏寻路中2D游戏中一般用2维数组就够了 四叉树对于区域查询,效率比较高. 原理图

  3. 如何在视频处理控件TVideoGrabber中设置音频捕捉设备

    TVideoGrabber不仅可以捕捉视频,还可以作为多媒体播放器,并支持包括C#..NET.VB.NET.C++.Delphi.C++Builder和ActiveX平台,本文将剖析TVideoGra ...

  4. GIS中相交的定义(OGC相交的定义)

    我们常用GIS中的相交,比如在地图漫游的时候,屏幕显示的图形和屏幕这个包络线就是相交的关系.我们常用的GIS工具,拉框查询,这个用到的也是相交. 首先题目开起来很简单(开始的时候我是这样想的),但是做 ...

  5. 浅谈设计模式在GIS中的应用

    设计模式在GIS中的应用 一.设计模式概述 随着面向对象技术的广泛应用,软件复用在越来越多的开发工程中被采用.在研究软件复用的过程中,设计模式的概念被提了出来.所谓设计模式就是一些设计面向对象的软件的 ...

  6. android中全局异常捕捉

    android中全局异常捕捉 只要写代码就会有bug,但是我们要想办法收集到客户的bug.有第三方bugly或者友盟等可以收集.但是,android原生就提供了有关收集异常的api,所以我们来学习一下 ...

  7. GIS中的引擎:地图引擎

    什么是地图引擎?它和地图软件有什么区别? 引擎一词是英文单词engine的音译,通常指发动机,就是动力输出设备.诸如汽车.轮船.飞机的动力提供的核心设备就是引擎.IT领域中,常听说的有搜索引擎.图形引 ...

  8. GIS中栅格数据结构的显示与计算

    在GIS中,根据数据存储的表现形式不同,通常将空间数据分为矢量数据和栅格数据.最简单的区别是:当栅格数据放大到一定程度时,就会呈现出我们熟悉的讨厌的"马赛克". 栅格数据存储 最简 ...

  9. GIS中的数据库.gdb与.mdb的区别

    gdb是文件地理数据库,mdb是个人地理数据库,都是数据库文件类型. 个人地理数据库,是以access数据库为基础的个人将数据库格式mdb,可以存储不超过2G的文件,只适合Windows系统下: 文件 ...

随机推荐

  1. iTerm2配置

    1.颜色Solarized 首先下载 Solarized: $ git clone git://github.com/altercation/solarized.git Terminal/iTerm2 ...

  2. spring ioc 理解

    springIOC 作用 springIOC 是sprig的特性.称作控制反转.将对象的创建,初始化,销毁,交给spring容器管理. 原理 在spring容器启动的时候,通过反射的方式,主动加载(或 ...

  3. 通过手机音频口,实现与单片机通讯,做电子签名成功n

    手机端的Ukey便携产品, 可以管理证书.加密解密.电子签名 : 1.通讯稳定,生成签名成功率100% 2.证书固化,私钥安全 3.走手机音频接口,通用.跨平台 4.耗电少,自带电池可长期供电,且可充 ...

  4. Spark编程指南V1.4.0(翻译)

    Spark编程指南V1.4.0 ·        简单介绍 ·        接入Spark ·        Spark初始化 ·        使用Shell ·        在集群上部署代码 ...

  5. 获取android-5.0.2_r1代码6.7G

    获取 android-5.0.2_r1 源代码的坎坷路: 服务器相关 ====== * 国外服务器直接拉取,我一共有多个国外服务器,在获取android代码时下载速度都能到10MB/s的下载速度甚至更 ...

  6. JSON数据转换到POCO的代码

    转载:http://www.cnblogs.com/wintersun/archive/2012/09/14/2684708.html 在Visual Studio 2012中轻松把JSON数据转换到 ...

  7. find命令专辑

    find命令使用技巧 查找文件,移动到某个目录 使用find和xargs 15条 linux Find 命令实际使用方法 find 命令用法 find命令使用经验 find用法小结 find与xarg ...

  8. MySql_SQLyog+SQL Assistant实现智能提示

    相信用过sqlserver+SQL Assistant的同学都知道其智能提示多么方便,但是转到mysql后,无论是使用navicat还是webbench都无法实现较好的智能提示效果, 最终在网上找到使 ...

  9. FAQ:领域服务和应用服务的职责是什么?

    问答部分 问: 领域服务的职责是什么? 答: 夸聚合实例业务逻辑. 没办法合理放到实体中的其它业务逻辑. 问: 领域服务的设计原则是什么? 答: 用来组织业务逻辑. 面向业务逻辑. 细粒度. 内部视图 ...

  10. OAuth:OAuth概述

    OAuth addresses these issues by introducing an authorization layer and separating the role of the cl ...