What define's Boost's svg_mapper scaling and translation? - c++

This code:
#include <fstream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
namespace bg = boost::geometry;
int main()
{
std::ofstream svg ( "test.svg" );
boost::geometry::svg_mapper<bg::model::d2::point_xy<double>, true, double> mapper ( svg, 6000, 3000 );
bg::model::polygon<bg::model::d2::point_xy<double>> square{
{{0, 0}, {0, 1000}, {1000, 1000}, {1000, 0}, {0, 0}}};
const std::string style{"fill-opacity:1.0;fill:rgb(128,128,128);stroke:rgb(0,0,0);stroke-width:5"};
mapper.add ( square );
mapper.map ( square, style, 1.0 );
}
Produces this svg:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g fill-rule="evenodd"><path d="M 1500,3000 L 1500,0 L 4500,0 L 4500,3000 L 1500,3000 z " style="fill-opacity:1.0;fill:rgb(128,128,128);stroke:rgb(0,0,0);stroke-width:5"/></g>
</svg>
The following conversions happen from the input polygon to the mapped svg geometries:
(0, 0) -> (1500,3000)
(0, 1000) -> (1500,0)
(1000, 1000) -> (4500,0)
(1000, 0) -> (4500,3000)
(0, 0) -> (1500,3000)
Staring at it a bit you see there is some transformation applied, something like this:
+1500 in x
+3000 in y
3x scale in x
-3x scale in y
My question is - What drives that transformation and can I prevent it? And if I can't prevent it, can I retrieve it or calculate it myself?
Reason being is I'm producing many complex SVG's and would like them to all be in the same frame. So if there is a circle at pixels (10,10) in one, I would like all the images to be of the same size with the circle in the exact same location. I tried to accomplish this with viewBox but the scaling and translation was too hard to predict to keep the images consistent.

svg_mapper calculates a bounding box from all add-ed geometries.
Then, a map_transformer is used to scale down to the desired width/height.
Contrary to what you might expect, add doesn't do anything besides expanding the bounding box. Likewise, after the first map call, no other add has any effect on the bounding-box used for the transformations.
In other words, you can use some kind of fixed bounding box, add only that, and then map your geometries into that "canvas":
Demo
#include <fstream>
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
namespace bg = boost::geometry;
using V = /*long*/ double;
using P = bg::model::d2::point_xy<V>;
using B = bg::model::box<P>;
int main()
{
auto verify = [](auto& g) {
if (std::string r; !bg::is_valid(g, r)) {
std::cout << "Correcting " << r << "\n";
bg::correct(g);
}
};
V side = 1000;
bg::model::polygon<P> square{
{{0, 0}, {0, side}, {side, side}, {side, 0}, {0, 0}},
};
verify(square);
std::array steps {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,};
for (unsigned i = 0; i < steps.size(); ++i) {
{
std::ofstream svg("test" + std::to_string(i) + ".svg");
bg::svg_mapper<P, true, V> mapper(svg, 400, 400);
auto clone = square;
V ofs = (steps[i] / 5. - 1.0) * side;
for (auto& p : boost::make_iterator_range(bg::points_begin(clone), bg::points_end(clone)))
bg::add_point(p, P{ofs, ofs});
std::cout << i << ": " << bg::wkt(square) << " " << bg::wkt(clone) << "\n";
mapper.add(B{{-side, -side}, {2 * side, 2 * side}});
//mapper.add(square); // no effect, already within bounding box
//mapper.add(clone); // no effect, already within bounding box
mapper.map(square, "fill-opacity:0.1;fill:rgb(128,0,0)", 1.0);
mapper.map(clone, "fill-opacity:0.1;fill:rgb(0,0,128)", 1.0);
}
}
}
Which creates a series of svgs that I can show as a poor man's animation to show that the positioning of the square is constant:

Related

Spheroid line_interpolate - but in the other direction

Using boost::geometry::line_interpolate with boost::geometry::srs::spheroid, I'm calculating great circle navigation points along the shortest distance between 2 geographic points. The code below calculates the navigation points for the shortest distance around the great circle. In some rare cases, I need to generate the longer distance that wraps around the globe in the wrong direction. For example, when interpolating between a lon/lat of (20, 20) to (30, 20), there only 10 degrees of difference in the shorter direction and 350 degrees in the other. In some cases I would like the ability to want to interpolate in the longer direction (e.g. 350 deg).
This 2d map shows shows the 10 degree longitude difference in red, and 350 degrees green. I drew the green line by hand to the line is only an approximation. How can I get the points for this green line?
This code is based on the example from boost.org, line_interpolate_4_with_strategy
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
int main()
{
typedef boost::geometry::model::d2::point_xy<double, boost::geometry::cs::geographic<boost::geometry::degree> > Point_Type;
using Segment_Type = boost::geometry::model::segment<Point_Type>;
using Multipoint_Type = boost::geometry::model::multi_point<Point_Type>;
boost::geometry::srs::spheroid<double> spheroid(6378137.0, 6356752.3142451793);
boost::geometry::strategy::line_interpolate::geographic<boost::geometry::strategy::vincenty> str(spheroid);
Segment_Type const start_end_points { {20, 20}, {30, 20} }; // lon/lat, interpolate between these two points
double distance { 50000 }; // plot a point ever 50km
Multipoint_Type mp;
boost::geometry::line_interpolate(start_end_points, distance, mp, str);
std::cout << "on segment : " << wkt(mp) << "\n";
return 0;
}
Note that line_interpolate interpolates points on a linestring where a segment between two points follows a geodesic.
Therefore, one workaround could be to create an antipodal point to the centroid of the original segment and create a linestring that follows the requested path. Then call line_interpolate with this linestring. The following code could do the trick.
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
int main()
{
namespace bg = boost::geometry;
using Point_Type = bg::model::d2::point_xy<double, bg::cs::geographic<bg::degree>>;
using Segment_Type = boost::geometry::model::segment<Point_Type>;
using Linstring_Type = bg::model::linestring<Point_Type>;
using Multipoint_Type = bg::model::multi_point<Point_Type>;
bg::srs::spheroid<double> spheroid(6378137.0, 6356752.3142451793);
bg::strategy::line_interpolate::geographic<bg::strategy::vincenty> str(spheroid);
Segment_Type const start_end_points { {20, 20}, {30, 20} };
Point_Type centroid;
bg::centroid(start_end_points, centroid);
Point_Type antipodal_centroid;
bg::set<0>(antipodal_centroid, bg::get<0>(centroid) + 180);
bg::set<1>(antipodal_centroid, bg::get<1>(centroid) * -1);
Linstring_Type line;
line.push_back(start_end_points.first);
line.push_back(antipodal_centroid);
line.push_back(start_end_points.second);
double distance { 50000 }; // plot a point ever 50km
Multipoint_Type mp;
bg::line_interpolate(line, distance, mp, str);
std::cout << "on segment : " << wkt(mp) << "\n";
return 0;
}
The result looks like this:
Note that since the spheroid you are constructing is non-spherical then there is no great circle (apart from equator and meridians) and the geodesic segment is not closed but looks like this. Therefore you will notice that the last interpolated point will be different from the segment's endpoint.

How to define a C++ function in VTK

I'm new with C++ and VTK. I'm trying to get cells ID into a rectilinearGrid basic example. I'm using this code, but the compiler say that is wrong with the error that I wrote in comment
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkFloatArray.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRectilinearGrid.h>
#include <vtkRectilinearGridGeometryFilter.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <array>
int main()
{
vtkNew<vtkNamedColors> colors;
std::array<int, 16> x = {
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
std::array<int, 16> y = {
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
std::array<int, 16> z = {
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
// Create a rectilinear grid by defining three arrays specifying the
// coordinates in the x-y-z directions.
vtkNew<vtkFloatArray> xCoords;
for (auto&& i : x)
{
xCoords->InsertNextValue(i);
}
vtkNew<vtkFloatArray> yCoords;
for (auto&& i : y)
{
yCoords->InsertNextValue(i);
}
vtkNew<vtkFloatArray> zCoords;
for (auto&& i : z)
{
zCoords->InsertNextValue(i);
}
// The coordinates are assigned to the rectilinear grid. Make sure that
// the number of values in each of the XCoordinates, YCoordinates,
// and ZCoordinates is equal to what is defined in SetDimensions().
//
vtkNew<vtkRectilinearGrid> rgrid;
rgrid->SetDimensions(int(x.size()), int(y.size()), int(z.size()));
rgrid->SetXCoordinates(xCoords);
rgrid->SetYCoordinates(yCoords);
rgrid->SetZCoordinates(zCoords);
vtkCell* GetCell(vtkRectilinearGrid * rgrid, int i, int j, int k) //I SHOULD INSERT IN HERE ";" FOR
{ //CLOSING THE STATEMENT. BUT IN
int dims[3]; //THIS WAY THE FUNCTION PARAMETER
rgrid->GetDimensions(dims); // BEHIND WOULDN'T BE CONNECTED.
if (i < 0 || i > dims[0] - 1 ||
j < 0 || j > dims[1] - 1 ||
k < 0 || k > dims[2] - 1)
{
return NULL; // out of bounds!
}
int pos[3];
pos[0] = i;
pos[1] = j;
pos[2] = k;
vtkIdType id;
id = vtkStructuredData::ComputeCellId(dims, pos);
return rgrid->GetCell(id);
};
// Extract a plane from the grid to see what we've got.
vtkNew<vtkRectilinearGridGeometryFilter> plane;
plane->SetInputData(rgrid);
plane->SetExtent(0, 46, 16, 16, 0, 43);
vtkNew<vtkPolyDataMapper> rgridMapper;
rgridMapper->SetInputConnection(plane->GetOutputPort());
vtkNew<vtkActor> wireActor;
wireActor->SetMapper(rgridMapper);
wireActor->GetProperty()->SetRepresentationToWireframe();
wireActor->GetProperty()->SetColor(colors->GetColor3d("Black").GetData());
// Create the usual rendering stuff.
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renWin;
renWin->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin);
renderer->AddActor(wireActor);
renderer->SetBackground(1, 1, 1);
renderer->ResetCamera();
renderer->GetActiveCamera()->Elevation(30.0);
renderer->GetActiveCamera()->Azimuth(15.0);
renderer->GetActiveCamera()->Zoom(1.0);
renderer->SetBackground(colors->GetColor3d("Beige").GetData());
renWin->SetSize(600, 600);
// interact with data
renWin->Render();
iren->Start();
return EXIT_SUCCESS;
}
How could be fixed?
UPDATE 1: I have inserted an image of the compiling error. Should be inserted ";" for closing the statement before {}
UPDATE 2: the exact error is
Errore (attivo) E0065 expected ';' RGrid C:\vtk\VTK-8.2.0\Examples\DataManipulation\Cxx\RGrid.cxx 73
I'm using Visual Studio. I have tried to drop the last ";" but nothing change
UPDATE 3: I have uploaded all the code
You have defined your GetCell function inside the body of the main function, which is not allowed in C++. Only a declaration would be allowed inside the body, hence the compiler expects a semicolon after the function header.
Move the whole GetCell function block outside the main function. If that leads to problems you cannot solve ask another question about them.

Adjust a detected 2D map to a reference 2D map

I have a map with some reference positions that correspond to the center (small cross) of some objects like this:
I take pictures to find my objects but in the pictures I have some noise so I can't always find all of the objects, it can be something like this:
From the few found positions I need to know where in the picture the other not found objects should be. I've being reading about this for the last couple of days and experimenting but I can't find a proper way of doing this. In some examples they start by calculating the center of masses and translating them together, then rotating, some other examples use least squares minimization and start by a rotation. I can't use OpenCV or any other APIs, just plain C++. I can use Eigen library if that helps. Can anyone give me some pointers on this?
EDIT:
I've solved the correspondence between points, the picture is never very different from the reference so for each found position I can search for its corresponding reference. In brief, I have one 2D matrix with reference points and another 2D matrix with found points. In the found matrix of points, the not found points are saved as NaN just to keep the same matrix size, the NaN points are not used in the calculations.
Since you have already matched the points to one another, finding the transform is straight forward:
Eigen::Affine2d findAffine(Eigen::Matrix2Xd const& refCloud, Eigen::Matrix2Xd const& targetCloud)
{
// get translation
auto refCom = centerOfMass(refCloud);
auto refAtOrigin = refCloud.colwise() - refCom;
auto targetCom = centerOfMass(targetCloud);
auto targetAtOrigin = targetCloud.colwise() - targetCom;
// get scale
auto scale = targetAtOrigin.rowwise().norm().sum() / refAtOrigin.rowwise().norm().sum();
// get rotation
auto covMat = refAtOrigin * targetAtOrigin.transpose();
auto svd = covMat.jacobiSvd(Eigen::ComputeFullU | Eigen::ComputeFullV);
auto rot = svd.matrixV() * svd.matrixU().transpose();
// combine the transformations
Eigen::Affine2d trans = Eigen::Affine2d::Identity();
trans.translate(targetCom).scale(scale).rotate(rot).translate(-refCom);
return trans;
}
refCloud is your reference point set and targetCloud is the set of points you have found in your image. It is important that the clouds match index wise, so refCloud[n] must be the corresponding point to targetCloud[n]. This means that you have to remove all NaNs from your matrix and cherry pick the correspondances in your reference point set.
Here is a full example. I'm using OpenCV to draw the stuff:
#include <Eigen/Dense>
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
using Point = Eigen::Vector2d;
template <typename TMatrix>
Point centerOfMass(TMatrix const& points)
{
return points.rowwise().sum() / points.cols();
}
Eigen::Affine2d findAffine(Eigen::Matrix2Xd const& refCloud, Eigen::Matrix2Xd const& targetCloud)
{
// get translation
auto refCom = centerOfMass(refCloud);
auto refAtOrigin = refCloud.colwise() - refCom;
auto targetCom = centerOfMass(targetCloud);
auto targetAtOrigin = targetCloud.colwise() - targetCom;
// get scale
auto scale = targetAtOrigin.rowwise().norm().sum() / refAtOrigin.rowwise().norm().sum();
// get rotation
auto covMat = refAtOrigin * targetAtOrigin.transpose();
auto svd = covMat.jacobiSvd(Eigen::ComputeFullU | Eigen::ComputeFullV);
auto rot = svd.matrixV() * svd.matrixU().transpose();
// combine the transformations
Eigen::Affine2d trans = Eigen::Affine2d::Identity();
trans.translate(targetCom).scale(scale).rotate(rot).translate(-refCom);
return trans;
}
void drawCloud(cv::Mat& img, Eigen::Matrix2Xd const& cloud, Point const& origin, Point const& scale, cv::Scalar const& color, int thickness = cv::FILLED)
{
for (int c = 0; c < cloud.cols(); c++)
{
auto p = origin + cloud.col(c).cwiseProduct(scale);
cv::circle(img, {int(p.x()), int(p.y())}, 5, color, thickness, cv::LINE_AA);
}
}
int main()
{
// generate sample reference
std::vector<Point> points = {{4, 9}, {4, 4}, {6, 9}, {6, 4}, {8, 9}, {8, 4}, {10, 9}, {10, 4}, {12, 9}, {12, 4}};
Eigen::Matrix2Xd fullRefCloud(2, points.size());
for (int i = 0; i < points.size(); i++)
fullRefCloud.col(i) = points[i];
// generate sample target
Eigen::Matrix2Xd refCloud = fullRefCloud.leftCols(fullRefCloud.cols() * 0.6);
Eigen::Affine2d refTransformation = Eigen::Affine2d::Identity();
refTransformation.translate(Point(8, -4)).rotate(4.3).translate(-centerOfMass(refCloud)).scale(1.5);
Eigen::Matrix2Xd targetCloud = refTransformation * refCloud;
// find the transformation
auto transform = findAffine(refCloud, targetCloud);
std::cout << "Original: \n" << refTransformation.matrix() << "\n\nComputed: \n" << transform.matrix() << "\n";
// apply the computed transformation
Eigen::Matrix2Xd queryCloud = fullRefCloud.rightCols(fullRefCloud.cols() - refCloud.cols());
queryCloud = transform * queryCloud;
// draw it
Point scale = {15, 15}, origin = {100, 300};
cv::Mat img(600, 600, CV_8UC3);
cv::line(img, {0, int(origin.y())}, {800, int(origin.y())}, {});
cv::line(img, {int(origin.x()), 0}, {int(origin.x()), 800}, {});
drawCloud(img, refCloud, origin, scale, {0, 255, 0});
drawCloud(img, fullRefCloud, origin, scale, {255, 0, 0}, 1);
drawCloud(img, targetCloud, origin, scale, {0, 0, 255});
drawCloud(img, queryCloud, origin, scale, {255, 0, 255}, 1);
cv::flip(img, img, 0);
cv::imshow("img", img);
cv::waitKey();
return 0;
}
I managed to make it work with the code from here:
https://github.com/oleg-alexandrov/projects/blob/master/eigen/Kabsch.cpp
I'm calling the Find3DAffineTransform function and passing it my 2D maps, as this function expects 3D maps I've made all z coordinates = 0 and it works. If I have some time I'll try to adapt it to 2D.
Meanwhile a fellow programmer (Regis :-) found also this, that should work:
https://eigen.tuxfamily.org/dox/group__Geometry__Module.html#gab3f5a82a24490b936f8694cf8fef8e60
Its the function umeyama() that returns the transformation between two point sets. Its part of Eigen library. Didn't have the time to test this.

How to Store some information at internal nodes of r-tree?

I am new to boost and c++. I am trying to code r tree using boost library. In my code, i want to store some information x at each internal node. I have two questions now.
1) How to perform traversing(depth-first) in the r star tree?
2) Suppose I can traverse the nodes of tree. There needs to be some member variables defined for the Box(INTERNAL node) class where I can store x at each node. What would be appropriate and efficient method for it?
From reading your comments I get an impression that you only want to store additional data in points stored in the R-tree and not to store additional data in the internal nodes of the R-tree. So here is an example showing how to store points with additional data and how to perform a query to get some of them. In the example I also show how to achieve the same with std::pair holding a point and some additional data which works by default and you do not have to register your own point type.
Includes:
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <vector>
#include <iostream>
Namespaces for convenience:
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
Definition of your own point type with 2-d coordinates and additional data (color):
enum color {red, green, blue};
struct my_point
{
double x, y;
color c;
};
Adaptation of my_point to Boost.Geometry Point concept with a macro so the library knows that this struct is a 2-d Point and how to get the coordinates:
BOOST_GEOMETRY_REGISTER_POINT_2D(my_point, double, bg::cs::cartesian, x, y)
Some Boost.Geometry models that will be used as well:
typedef bg::model::point<double, 2, bg::cs::cartesian> bg_point;
typedef bg::model::box<bg_point> bg_box;
Main:
int main()
{
{
Creation of the R-tree and insertion of several points:
bgi::rtree<my_point, bgi::rstar<4> > rtree;
rtree.insert(my_point{ 0, 0, red });
rtree.insert(my_point{ 1, 1, green });
rtree.insert(my_point{ 2, 5, blue });
rtree.insert(my_point{ 7, 3, red });
rtree.insert(my_point{ 8, 8, green });
rtree.insert(my_point{ 1, 9, blue });
Query for points that intersect the following box and are red:
std::vector<my_point> res;
rtree.query(bgi::intersects(bg_box{ {1, 1}, {8, 8} })
&& bgi::satisfies([](my_point const& p) {
return p.c == red;
}),
std::back_inserter(res));
Print the result:
for (my_point const& p : res)
std::cout << bg::wkt(p) << std::endl;
}
The same but std::pair<bg_point, color> is used instead of my_point so no registration is needed:
{
bgi::rtree<std::pair<bg_point, color>, bgi::rstar<4> > rtree;
rtree.insert(std::pair<bg_point, color>{ {0, 0}, red });
rtree.insert(std::pair<bg_point, color>{ {1, 1}, green });
rtree.insert(std::pair<bg_point, color>{ {2, 5}, blue });
rtree.insert(std::pair<bg_point, color>{ {7, 3}, red });
rtree.insert(std::pair<bg_point, color>{ {8, 8}, green });
rtree.insert(std::pair<bg_point, color>{ {1, 9}, blue });
std::vector<std::pair<bg_point, color> > res;
rtree.query(bgi::intersects(bg_box{ { 1, 1 },{ 8, 8 } })
&& bgi::satisfies([](std::pair<bg_point, color> const& p) {
return p.second == red;
}),
std::back_inserter(res));
for (std::pair<bg_point, color> const& p : res)
std::cout << bg::wkt(p.first) << std::endl;
}
}
The program above prints the following line two times:
POINT(7 3)
This is the only one red point which intersects the box.
Original answer (if you indeed want to modify the internal structure of the R-tree):
What you want to do is not supported from the public R-tree interface. You'd have to play with the internals which might change in the future.
Here is a thread explaining how you can write a visitor to traverse the R-tree nodes.
Using your own node types is harder. You'd have to:
add new node tag like this
specialize internal and leaf nodes (adding members you like in nodes) and all other required classes for this tag like in this file
implement your own R-tree parameters type, e.g. based on bgi::rstar, like this
specialize bgi::detail::rtree::options_type in order to tell the R-tree what nodes should be used for your parameters type like this
See also this node implementation used for R-tree testing. This is a node which can throw an exception on construction. It's used to test exception-safety.

GEOS OverlayOp intersection operation

I am using GEOS 3.6.2 to compute an intersection between two polygons. I was able to construct my polygons, but when I try to compute the intersection it won't work.
Compiling my program in Debug mode, I get the error message:
The inferior stopped because it received a signal from the operating
system.
Signal name : SIGSEG
Signal meaning : Segmentation fault
Any idea where I'm wrong?
Here is my code:
#include <geos/geom/Polygon.h>
#include <geos/geom/LinearRing.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Geometry.h>
#include <geos/operation/overlay/OverlayOp.h>
#include <iostream>
#include <array>
////////////////////////////////////////////////////////////////////////////////
geos::geom::Polygon* MakePoly(std::vector<std::vector<int>> const& polyCoords)
{
geos::geom::GeometryFactory* factory = geos::geom::GeometryFactory::create().get();
geos::geom::CoordinateSequence* temp = factory->getCoordinateSequenceFactory()->create((std::size_t) 0, 0);
std::vector<std::vector<int>>::const_iterator it_x = polyCoords.begin();
int size = it_x->size();
for (int i=0; i<size; i++)
{
temp->add(geos::geom::Coordinate(polyCoords[0][i], polyCoords[1][i]));
}
geos::geom::LinearRing *shell=factory->createLinearRing(temp);
//NULL in this case could instead be a collection of one or more holes
//in the interior of the polygon
return factory->createPolygon(shell,NULL);
}
////////////////////////////////////////////////////////////////////////////////
int main()
{
// Create geometry.
std::vector<std::vector<int>> polyCoords1 = {
{1, 1, 2, 2, 1, 1, 4, 5, 4, 1},
{1, 2, 2, 4, 4, 5, 5, 3, 1, 1}
};
geos::geom::Polygon* poly1 = MakePoly(polyCoords1);
std::vector<std::vector<int>> polyCoords2 = {
{4, 4, 6, 6, 4},
{1, 5, 5, 1, 1}
};
geos::geom::Polygon* poly2 = MakePoly(polyCoords2);
// Actually perform the operation.
geos::operation::overlay::OverlayOp intersection(poly1, poly2);
// Extracting the geometry of the intersection (position of the error).
geos::geom::Geometry* intersectionGeo = intersection.getResultGeometry( geos::operation::overlay::OverlayOp::OpCode::opINTERSECTION );
std::cout<<intersectionGeo->getArea()<<std::endl;
}
The problem in your code is getting the GeometryFactory pointer.
geos::geom::GeometryFactory::create() returns a smart pointer (std::unique_ptr) so after this line:
geos::geom::GeometryFactory* factory = geos::geom::GeometryFactory::create().get();
The unique_ptr returned by create is disposed.
Change that line with:
geos::geom::GeometryFactory::Ptr factory = geos::geom::GeometryFactory::create();
And the code works.