0%

GEOS库的使用

这一篇文档将会对最近自己项目中使用的GEOS库做一个简单的使用介绍。GEOS库是一个开源的几何图形库,可以查看 GEOS官方网站 获得更多信息,不过不得不吐槽一下,这个库好像没多少人用,网上文档都没有,官网的文档页面也是404。下面,我将介绍一下利用这个库建立一些简单的几何图形,虽然官方说建议使用C API,因为其更加稳定,但是我在自己得项目中仍然采用C++ API,因为这样可以更好的利用C++11的一些特性。

在我的项目中,主要使用到的几何图形就是GEOS库中的多边形(Polygon),构造多边形,需要构造线环(LineRing),所以我就介绍一下这两者的构造以及一些简单的用法。

简单的几何图形构造

需要注意的是,我在几篇网络上的文档里面看到,在构造几何图形的时候,一个多边形在没有内环的情况下,和线环是一样的。但是,实际上这两者并不一样!

线环的构造

构造线环,需要给定一系列的坐标。但是线段的坐标序列需要注意起始点和终止点需要为同一个坐标。由于GEOS库的坐标(Coordinate)不方便直接初始化,所以我们封装一下。

1
2
3
using MyPos = std::pair<int, int>;
//定义一个全局的用于产生图形的对象
GeometryFactory::Ptr global_factory;//用的是智能指针,unique_ptr

上面的global_factory用于产生几何对象。我们接下来的所有几何对象都将由它构造。下面封装一个用于构造线环的函数,该函数接收一些列点,由vector保存,然后返回一个指向线环的unique_ptr智能指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//构造一个环
std::unique_ptr< LinearRing> create_linearring(const std::vector<MyPos>& poss)
{
//首先根据poss的内容,构造CoordinateArraySequence
CoordinateArraySequence cdseq;
//先假设poss给的数据是无误的,开始点和结束点一样。
for (const MyPos& p : poss)
{
cdseq.add(Coordinate(p.first, p.second));
}
auto res = global_factory->createLinearRing(CoordinateArraySequence::Ptr (new CoordinateArraySequence(cdseq)));
return res;

}

然后通过下列方式进行构造。

1
2
3
4
5
6
7
8
void test()
{
PrecisionModel* pm = new PrecisionModel(2.0, 0, 0);
global_factory = GeometryFactory::create(pm, -1);
delete pm;
vector<MyPos> outring_pos = { {0,0},{3,0},{3,3},{0,3},{0,0} };
auto outring = create_linearring(outring_pos);
}

多边形的构造

构造非空多边形 (Empty Polygon) ,我们需要给出多边形的外环(必需),内环(在没有内环的情况下可以为空)。在没有内环(holes)的情况下,我们封装下列函数:

1
2
3
4
std::unique_ptr< Polygon> create_polygon(const std::vector<MyPos>& poss)
{
return global_factory->createPolygon(create_linearring(poss));
}

可以发现,这个函数,就是首先构造一个线环,然后传给GeometryFactory对象构造多边形。当然,我们可以构造带有内环的多边形,构造方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
void test()
{
PrecisionModel* pm = new PrecisionModel(2.0, 0, 0);
global_factory = GeometryFactory::create(pm, -1);
delete pm;
vector<MyPos> outring_pos = { {0,0},{3,0},{3,3},{0,3},{0,0} };
vector<MyPos> inring_pos = { {1,1},{2,1},{2,2},{1,2},{1,1} };
auto outring = create_linearring(outring_pos);
auto inring = create_linearring(inring_pos);
vector<unique_ptr<LinearRing>> inring_vec;//可以存放多个不同的内环
inring_vec.push_back(move(inring));
auto poly = global_factory->createPolygon(move(outring), move(inring_vec));
}

线环与多边形的不同

前面说到,即使是在多边形没有内环的情况下,多边形与线环也是不一样的,个人的理解是:线环就只是那一个环上的点,而多边形则是包括了内环和外环所包围的点。因此,如果我们要判断一个三角形是不是在另一个大三角形里面,我们不能将三角形构造成一个线环,再使用within()函数来判断。