DE-9IM 空间关系模型 与Boost Geometry Lib

DE-9IM 空间关系模型

 注:文章转载自https://www.cnblogs.com/oloroso/p/14298258.html#2727310410,如有侵权,请联系删除!

DE-9IM 空间关系模型

 

 

简述#

DE-9IM 是Dimensionally Extended 9-Intersection Model 的缩写,直接翻译为 维度扩展的 9 相交模型好像比较别扭,但一时也找不到比较好的翻译。

DE-9IM 模型是用于描述两个 二维几何对象(点、线、面) 之间的空间关系的一种模型,它使用一个 3 x 3 的矩阵来描述几何关系类别(相交部分的维度)。

网上很多关于 DE-9IM 的介绍都是翻译自 https://en.wikipedia.org/wiki/DE-9IM 或者 GeoTools/userguide/dim9 等文档的,我这里就不做这些翻译了。

因为要给别人讲述清楚这个东西,所以自己总结了下,在这里做个记录。

空间关系#

这里主要是说二维平面下的两个几何对象之间的空间关系。

主要有两种关系:

  • 相交(Intersects)
  • 相离(Disjoint)

相离 关系很简单,就是两个几何对象相互独立,之间没有任何相接触到的地方。形象的说,比如一张纸上画了两个多边形(或者点或线),你可以再画一条线把它们分开,而且这条画的线可以不碰到这两个多边形。

DE-9IM-disjoint

相交(Intersects)关系图解#

相交(Intersects)关系就比较复杂一点了,它又可以分为好几类。

下面对相交(Intersects)的各种情况进行分类介绍,包括点、线、面相互之间形成相应关系的9种情况的图像说明(图是网上找的,来自一个国外的网站)。

下面的关系又称为空间谓词,下面的图式中都说明的是 红色 几何对象 相对于 蓝色 几何对象的空间关系(方向不能反)。

包含(Contains )#

包含表示一个几何对象完全在另一个几何对象内部。

下面图是红色几何对象包含(Contains)蓝色几何对象的在其里头的示意图。

不可能包含线线也不可能包含在里头,所以有三个位置是 X

DE-9IM-contains

横跨(Crosses)#

横跨关系一般又叫做交叉或者跨立,这里我还是觉得横跨比较合适。

横跨关系一定是建立在线线或者线之间(可以理解为线才能够横在别的形状上嘛)。

下面图是红色几何对象横跨(Crosses)蓝色几何对象的上面的示意图。

DE-9IM-crosses

等于(Equals)#

等于(Equals)表示两几何对象完全一致(包括形状和位置),是一种完全重合的情况。

下面图是红色几何对象等于(Equals) 蓝色几何对象的示意图。

DE-9IM-equals

重叠(Overlaps)#

重叠(Overlaps)表示两个几何对象对象之间有一部分是重合的情况(完全重合就是 Equals 了)。

重叠只发生在 线-线面-面 之间,线只能是CrossesWithin或者Touches,点没有长度和面积(就是不存在部分,不可以分割),不可能Overlaps

下面图是红色几何对象重叠(Overlaps)蓝色几何对象上的示意图。

DE-9IM-overlaps

触碰(Touches)#

触碰(Touches)这个一般又叫做接触或者触及,表示两个几何对象的边界部分有重合部分的情况,也就是说两个几何对象有公共点或者公共边线的情况。

之间是没有Touches关系,线的触碰关系一定是在线的端点或者面的边上。

线两种形状之间的Touches关系可能是有公共点,也可能是有公共边。

DE-9IM-touches

被包含(Within)#

被包含(Within)一般也描述为在什么内部(所以也有用 inside 的),表示一个几何对象完全处于另一个几何对象内部。这个其实就是包含(Contains)的反向关系。

就是说 A Within B 就等于是 B Contains A

下面图是红色几何对象被包含(Within)蓝色几何对象里头的示意图。

DE-9IM-within

DE-9IM 模型#

DE-9IM 模型把几何对象分为 内部边界外部 三个部分,两个几何对象这三个部分两两之间的关系,就可以组合为一个3X3大小(就是 9 个值)的矩阵,这9个值的组合,就表示两个几何对象的空间关系。

DE-9IM-matrix

如上图所示,淡紫色的多边形为条件几何对象(A),淡红色的多边形为 测试几何对象(B),图中的 黑色 部分表示两个几何对象对应的部分(内部、边界、外部)之间的相交(或者说重合)部分( A.[I/B/E] intersection B.[I/B/E])。

DE-9IM 用数值来表示相交(重合)部分的情况(维度),是点还是线还是面,或者是没有。

  • -1 没有重合部分
  • 0 重合部分为(零维)
  • 1 重合部分为线(一维)
  • 2 重合部分为(二维)

如上面图中,它的 DE-9IM 计算值(在 GeoTools/GEOS 中使用 relate 计算)就是 2 1 2 1 0 1 2 1 2

使用下面的方式来表示矩阵中①~⑨的值是以下的任意一种空间关系:

  • T = 相交部分维度为 012
  • F = 相交部分维度 < 0
  • * = 相交部分维度为任意值。
  • 0 = 相交部分维度为 0
  • 1 = 相交部分维度为 1
  • 2 = 相交部分维度为 2

而两个几何对象具有什么空间关系(就是上面所说的IntersectsDisjointContains...等),就可以通过两个几何对象的 DE-9IM 值来确定。

根据上面对各个空间谓词的定义,可以得到每个空间谓词对于的 DE-9IM 关系表示。一般我们写程序的时候不直接使用 relate 计算的结果去判断两个几何对象的空间关系,而是直接使用相应的空间谓词去判断。

空间谓词DE-9IM值说明等价于
Equals T*F**FFF* 如果两个几何对象的内部相交,并且一个几何对象的内部或边界没有任何部分与另一个几何对象的外部相交,那么这两个几何对象在拓扑上是相等的 Within & Contains
Disjoint FF*FF**** 两个几何对象它们没有公共点。 它们形成了一组不连续的几何形状。 not Intersects
Touches FT******* 或
F**T***** 或
F***T****
两个几何对象它们至少有一个公共点,但它们的内部不相交。  
Contains T*****FF* 被测试几何对象B位于条件几何对象A内部(A Contains B)。 Within(B,A)
Within(Inside) T*F**F*** 上面的 Contains 操作对象调换下方向就是。 Contains(B,A)
Crosses 线 Corsses  = T*T******
 Corsses 线 = T*****T**
线 Corsses 线 = 0********
A Contains B:它们有一些但不是全部的内部点是相同的,并且相交部分的维度数小于A或B中至少一个的维度数。  
Overlaps  Overlaps  = T*T***T**
线 Overlaps 线 = 1*T***T**
A Overlaps B:它们有一些但不是所有的点是相同的,它们有相同的维数,两个几何内部的交点和这些几何本身的维数是相同的。  
Intersects T******** 
*T*******
***T***** 或
****T****
两个几何对象它们至少有一个公共点。 not Disjoint
Covers
(涵盖了)
T*****FF* 或
*T****FF* 或
***T**FF* 或
****T*FF*
A Covers B:A的至少一个点位于B,A的任何点都不位于B的外部 CoveredBy(B,A)
CoveredBy
(被涵盖)
T*F**F*** 
*TF**F*** 或
**FT*F*** 或
**F*TF***
A CoveredBy B:A上至少有一个点在 B 上,而 A 上没有一个点在b的外部 Covers(B,A)
  
 
 
 

最在项目中要用到计算几何的东西,计算三维空间中面片与六面体的相交判断,通过各种搜索发现boost库中的Geometry模块还不错,可以比较容易地实现。这里记录一下这个库的基本情况。

1、常见几何对象

#include <boost/geometry.hpp>

#include <boost/geometry/geometries/point_xy.hpp>

#include <boost/geometry/geometries/point.hpp>

#include <boost/geometry/geometries/multi_point.hpp>

#include <boost/geometry/geometries/segment.hpp>

#include <boost/geometry/geometries/polygon.hpp>

#include <boost/geometry/geometries/multi_polygon.hpp>

#include <boost/geometry/geometries/linestring.hpp>

#include <boost/geometry/geometries/multi_linestring.hpp>

#include <boost/geometry/geometries/box.hpp>

#include <boost/geometry/geometries/ring.hpp>

#include <boost/geometry/geometries/variant.hpp>

Boost.Geometry的model有point_xy, point, multi_point, ,segment,linestring,multi_linestring, box,ring,polygon,multi_polygon, variant.

model::point

model::d2::point_xy

model::linestring

model::polygon

model::multi_point

model::multi_linestring

model::multi_polygon

model::box,

model::ring

model::segment

model::referring_segment

model::point

Basic point class, having coordinates defined in a neutral way.

Description

Defines a neutral point class, fulfilling the Point Concept. Library users can use this point class, or use their own point classes. This point class is used in most of the samples and tests of Boost.Geometry This point class is used occasionally within the library, where a temporary point class is necessary.

 model::d2::point_xy

2D point in Cartesian coordinate system

 model::linestring

A linestring (named so by OGC) is a collection (default a vector) of points.

 model::polygon

The polygon contains an outer ring and zero or more inner rings.

 

2、常见算法

提供的算法有:面积、长度、周长、质心、凸壳、交集(剪裁)、内(多边形中的点)、距离、包络线(边界框)、简化、变换等。

area

assign

append

buffer

centroid

clear

convert

convex_hull

correct

covered_by

crosses

densify

difference

discrete_frechet_distance

discrete_hausdorff_distance

disjoint

distance

envelope

equals

expand

for_each

intersection

intersects

is_empty

is_simple

is_valid

length

make

num_geometries

num_interior_rings

num_points

num_segments

overlaps

perimeter

relate

relation

reverse

simplify

sym_difference

touches

transform

union_

unique

within

常见的有以下几种:

计算面积

Boost::Geometry::area(obj1)

计算距离

Boost::Geometry::distance(obj1, obj2)

判断是否相交

Boost::Geometry::intersects(obj1, obj2)

计算交点

Boost::Geometry::intersection(obj1, obj2, result)

判断是否在box内

Boost::Geometry::within(obj1, obj2)

  

3、几何图形的输入输出

DSV (Delimiter-Separated Values)

WKT (Well-Known Text)

SVG (Scalable Vector Graphics)

前两种是文本格式数据流,第三种是图形化输入和输出。

 

4、几何图形的算术运算

add_point

add_value

assign_point

assign_value

cross_product

cross_product

divide_point

divide_value

dot_product

multiply_point

multiply_value

subtract_point

subtract_value

 

6、官方示例

https://www.boost.org/doc/libs/1_69_0/libs/geometry/doc/html/geometry/spatial_indexes/rtree_examples/index_of_polygons_stored_in_vector.html

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <cmath>
#include <vector>
#include <iostream>
#include <boost/foreach.hpp>

namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;

int main()

{

typedef bg::model::point<float, 2, bg::cs::cartesian> point; //define point 2 dimension

typedef bg::model::box<point> box;

typedef bg::model::polygon<point, false, false> polygon; // ccw, open polygon

typedef std::pair<box, unsigned> value;

 

// polygons

std::vector<polygon> polygons;

// create some polygons

for ( unsigned i = 0 ; i < 10 ; ++i )

{

// create a polygon

polygon p;

for ( float a = 0 ; a < 6.28316f ; a += 1.04720f )

{

float x = i + int(10*::cos(a))*0.1f;

float y = i + int(10*::sin(a))*0.1f;

p.outer().push_back(point(x, y));

}

// add polygon

polygons.push_back(p);

}

// display polygons

std::cout << "generated polygons:" << std::endl;

BOOST_FOREACH(polygon const& p, polygons)

std::cout << bg::wkt<polygon>(p) << std::endl;

 

// create the rtree using default constructor

bgi::rtree< value, bgi::rstar<16, 4> > rtree;

 

// fill the spatial index

for ( unsigned i = 0 ; i < polygons.size() ; ++i )

{

// calculate polygon bounding box

box b = bg::return_envelope<box>(polygons[i]);

// insert new value

rtree.insert(std::make_pair(b, i));

}

 

// find values intersecting some area defined by a box

box query_box(point(0, 0), point(5, 5));

std::vector<value> result_s;

rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));

 

// find 5 nearest values to a point

std::vector<value> result_n;

rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n));

 

// note: in Boost.Geometry the WKT representation of a box is polygon

 

// note: the values store the bounding boxes of polygons

// the polygons aren't used for querying but are printed

 
// display results

std::cout << "spatial query box:" << std::endl;

std::cout << bg::wkt<box>(query_box) << std::endl;

std::cout << "spatial query result:" << std::endl;

BOOST_FOREACH(value const& v, result_s)

std::cout << bg::wkt<polygon>(polygons[v.second]) << std::endl;

 
std::cout << "knn query point:" << std::endl;

std::cout << bg::wkt<point>(point(0, 0)) << std::endl;

std::cout << "knn query result:" << std::endl;

BOOST_FOREACH(value const& v, result_n)

std::cout << bg::wkt<polygon>(polygons[v.second]) << std::endl;

return 0;

}

 

posted @ 2022-07-29 15:21  SuperVan  阅读(720)  评论(0编辑  收藏  举报