Help us understand the problem. What is going on with this article?

# GEOSによる図形演算

More than 3 years have passed since last update.

Siv3D Advent Calendar 2017 23 日目の記事です。

# 導入

GEOS - Geometry Engine, Open Source とは、ジオメトリ計算を行うためのライブラリです。

ダウンロードは https://trac.osgeo.org/geos から行えます。

Siv3D 用にビルドするのが少し面倒なので、VS2015 でビルド済みのライブラリファイルを GitHub に上げました（GEOS のヘッダファイルは入っていません）。
https://github.com/agehama/geos_build_VS2015

# 0. 図形の作成

geos_example0.cpp
```#include "GeosSiv3DHelper.hpp"

void Main()
{
while (System::Update())
{
gg::Polygon* poly = ToGeosPoly(Rect(100, 50).setCenter(Window::Center()).asPolygon());

ToSivPoly(*poly).draw();

delete poly;
}
}
```

# 1. 図形の接触判定

geos_example1.cpp
```#include "GeosSiv3DHelper.hpp"

void Main()
{
Font font(30);

gg::Polygon* star = ToGeosPoly(Geometry2D::CreateNStar(5, 100, 50).movedBy(Window::Size()*0.5));

while (System::Update())
{
gg::Polygon* plus = ToGeosPoly(Geometry2D::CreatePlus(30.0, 10.0).movedBy(Mouse::Pos()));

gg::IntersectionMatrix* relation = star->relate(*plus);

font(CharacterSet::Widen(relation->toString())).draw();

ToSivPoly(*star).draw(Color(255, 0, 0));
ToSivPoly(*plus).draw(Color(0, 255, 0));

delete plus;
delete relation;
}

delete star;
}
```

# 2. ブーリアン演算

geos_example2.cpp
```#include "GeosSiv3DHelper.hpp"

void Main()
{
gg::Polygon* star = ToGeosPoly(Geometry2D::CreateNStar(5, 100, 50).movedBy(Window::Size()*0.5));

double angle = 0.0;
while (System::Update())
{
angle += 0.01;
gg::Polygon* plus = ToGeosPoly(Geometry2D::CreatePlus(30.0, 10.0).rotated(angle).movedBy(Window::Size()*0.5));

gg::Geometry* resultGPoly = plus->symDifference(star);
const MultiPolygon resultSPoly = ToSivPoly(*resultGPoly);

resultSPoly.draw();
resultSPoly.drawWireframe(1.0, Palette::Black);

ToSivPoly(*plus).drawFrame();
ToSivPoly(*star).drawFrame();

delete plus;
delete resultGPoly;
}

delete star;
}
```

# 3. バッファ演算

geos_example3.cpp
```#include "GeosSiv3DHelper.hpp"

void Main()
{
const double pos = 150.0;

gg::Polygon* star = ToGeosPoly(Geometry2D::CreateNStar(5, 100, 50).movedBy(pos, Window::Height()*0.5));
gg::Polygon* plus = ToGeosPoly(Geometry2D::CreatePlus(100.0, 50.0).movedBy(Window::Width() - pos, Window::Height()*0.5));

while (System::Update())
{
gg::Geometry* resultGStar = star->buffer(15.0, 10);
gg::Geometry* resultGPlus = plus->buffer(-15.0, 10);

const MultiPolygon resultSStar = ToSivPoly(*resultGStar);
const MultiPolygon resultSPlus = ToSivPoly(*resultGPlus);

resultSStar.draw();
resultSStar.drawWireframe(1.0, Palette::Gray);

resultSPlus.draw();
resultSPlus.drawWireframe(1.0, Palette::Gray);

ToSivPoly(*star).drawFrame(1.0, Palette::Cyan);
ToSivPoly(*plus).drawFrame(1.0, Palette::Cyan);

delete resultGStar;
delete resultGPlus;
}

delete star;
delete plus;
}
```

# 4. 折れ線からポリゴンの生成

geos_example4.cpp
```#include "GeosSiv3DHelper.hpp"

void Main()
{
gg::CoordinateArraySequence points;
std::vector<LineString> lines;

while (System::Update())
{
if (Input::MouseL.clicked)
{
}

if (Input::MouseL.pressed && !points.empty() && 30.0 < points.back().distance(gg::Coordinate(Mouse::Pos().x, Mouse::Pos().y)))
{
}

if (Input::MouseL.released)
{
gg::GeometryFactory::unique_ptr factory = gg::GeometryFactory::create();

gg::PrecisionModel model(gg::PrecisionModel::Type::FLOATING);

gob::BufferParameters param(10, gob::BufferParameters::CAP_ROUND, gob::BufferParameters::JOIN_BEVEL, 10.0);
//gob::BufferParameters param(10, gob::BufferParameters::CAP_FLAT, gob::BufferParameters::JOIN_BEVEL, 10.0);

gob::OffsetCurveBuilder builder(&model, param);

std::vector<gg::CoordinateSequence*> result;

builder.getLineCurve(&points, 15.0, result);
//builder.getSingleSidedLineCurve(&points, 10.0, result, true, false);

for (gg::CoordinateSequence* p : result)
{
std::vector<Vec2> ps;
for (size_t i = 0; i < p->size(); ++i)
{
ps.emplace_back(p->getX(i), p->getY(i));
}

lines.emplace_back(ps);
}

points.clear();
}

if (!points.empty())
{
for (size_t i = 0; i+1 < points.size(); ++i)
{
const double x0 = points.getX(i);
const double y0 = points.getY(i);
const double x1 = points.getX(i + 1);
const double y1 = points.getY(i + 1);
Line(x0, y0, x1, y1).draw();
}
}

for (const auto& l : lines)
{
l.draw();
}
}
}
```

# 5. 図形同士の距離、最近接点

geos_example5.cpp
```#include "GeosSiv3DHelper.hpp"

void Main()
{
gg::CoordinateArraySequence points;
std::vector<LineString> lines;

gg::Polygon* star = ToGeosPoly(Geometry2D::CreateNStar(5, 100, 50).movedBy(Window::Size()*0.5));

while (System::Update())
{
std::vector<Vec2> points;

gg::Polygon* plus = ToGeosPoly(Geometry2D::CreatePlus(40.0, 20.0).movedBy(Mouse::Pos()));
god::DistanceOp distanceOp(*star, *plus);

gg::CoordinateSequence* ps = distanceOp.closestPoints();

for (size_t i = 0; i < ps->size(); ++i)
{
const double x0 = ps->getX(i);
const double y0 = ps->getY(i);
points.emplace_back(x0, y0);
}

LineString(points).draw(1.0, Palette::Red);

ToSivPoly(*star).drawFrame();
ToSivPoly(*plus).drawFrame();

delete plus;
}

delete star;
}
```

# 6. 凸包、ボロノイ分割

geos_example6.cpp
```#include "GeosSiv3DHelper.hpp"

void Main()
{
double angle = 0.0;

while (System::Update())
{
angle += 0.02;
gg::Polygon* star = ToGeosPoly(Geometry2D::CreatePlus(100.0, 20.0).rotated(angle).movedBy(Window::Size()*0.5));

gt::VoronoiDiagramBuilder builder;
builder.setSites(*star->getCoordinates());

gg::GeometryFactory::unique_ptr factory = gg::GeometryFactory::create();
std::auto_ptr<gg::Geometry> edges = builder.getDiagramEdges(*factory);

gg::CoordinateSequence* cs = edges->getCoordinates();

ToSivPoly(*star).draw();

for (size_t i = 0; i + 1 < cs->size(); ++i)
{
const double x0 = cs->getX(i);
const double y0 = cs->getY(i);
const double x1 = cs->getX(i + 1);
const double y1 = cs->getY(i + 1);
Line(x0, y0, x1, y1).draw(1.0, Palette::Cyan);
}

ToSivPoly(*edges->getEnvelope()).drawFrame(1.0, Palette::Cyan);

delete star;
}
}
```

# 終わりに

Why not register and get more from Qiita?
1. We will deliver articles that match you
By following users and tags, you can catch up information on technical fields that you are interested in as a whole
2. you can read useful information later efficiently
By "stocking" the articles you like, you can search right away