Exists a dataset of all posible invalid geometries using c++ and boost::geometry libraries? or at least polygon coordinates of that invalid geomtries that i can to translate to boost::geometry
Example: Selfintersection, etc
I would like to test my application with a least all posibles invalid geometries.
Something like this:
https://knowledge.safe.com/articles/21674/invalid-ogc-geometry-examples.html
but with more test cases with inners and outer polygons.
I have created a library 'boost_geometry_make_valid' which allows correcting the errors described in this dataset:
https://github.com/kleunen/boost_geometry_make_valid
I use the dataset now for testing, the library is able to correct all the mentioned failures. Most important, remove self-intersection from polygons.
The Boost Geometry library implements the OGC standard. From the intro
The library follows existing conventions:
conventions from Boost
conventions from the std library
conventions and names from one of the OGC standards on geometry and, more specificly, from the OGC Simple Feature Specification
So the list that you used is relevant.
Besides, you can use the is_valid function with a reason parameter to interrogate the library about your geometry. I have several examples on this site showing how to do that. (Note: Not all constraints might be validatable)
Your Samples, Live
Let's adopt the outer ring orientation from the samples (not the BG default):
namespace bg = boost::geometry;
using pt = bg::model::d2::point_xy<double>;
using poly = bg::model::polygon<pt, false>;
using multi = bg::model::multi_polygon<poly>;
Let's create a generalized checker:
template <typename Geo = poly> void check(std::string wkt) {
Geo g;
bg::read_wkt(wkt, g);
std::string reason;
bool ok = bg::is_valid(g, reason);
std::cout << "Valid: " << std::boolalpha << ok << " (" << reason << ")\n";
bg::correct(g);
if (bg::is_valid(g, reason)) {
std::cout << "Autocorrected: " << bg::wkt(g) << "\n";
}
}
And run it for all the test cases:
//Hole Outside Shell
check("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (15 15, 15 20, 20 20, 20 15, 15 15))");
//Nested Holes
check("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2), (3 3, 3 7, 7 7, 7 3, 3 3))");
//Disconnected Interior
check("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (5 0, 10 5, 5 10, 0 5, 5 0))");
//Self Intersection
check("POLYGON((0 0, 10 10, 0 10, 10 0, 0 0))");
//Ring Self Intersection
check("POLYGON((5 0, 10 0, 10 10, 0 10, 0 0, 5 0, 3 3, 5 6, 7 3, 5 0))");
//Nested Shells
check<multi>("MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)),(( 2 2, 8 2, 8 8, 2 8, 2 2)))");
//Duplicated Rings
check<multi>("MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)),((0 0, 10 0, 10 10, 0 10, 0 0)))");
//Too Few Points
check("POLYGON((2 2, 8 2))");
//Invalid Coordinate
check("POLYGON((NaN 3, 3 4, 4 4, 4 3, 3 3))");
//Ring Not Closed
check("POLYGON((0 0, 0 10, 10 10, 10 0))");
Output
Live On Coliru
Prints
Valid: false (Geometry has interior rings defined outside the outer boundary)
Valid: false (Geometry has nested interior rings)
Valid: false (Geometry has wrong orientation)
Valid: false (Geometry has wrong orientation)
Valid: false (Geometry has invalid self-intersections. A self-intersection point was found at (5, 0); method: t; operations: i/i; segment IDs {source, multi, ring, segment}: {0, -1, -1, 4}/{0, -1, -1, 8})
Valid: false (Multi-polygon has intersecting interiors)
Valid: false (Geometry has invalid self-intersections. A self-intersection point was found at (10, 0); method: e; operations: c/c; segment IDs {source, multi, ring, segment}: {0, 0, -1, 0}/{0, 1, -1, 0})
Valid: false (Geometry has too few points)
Valid: false (Geometry has point(s) with invalid coordinate(s))
Valid: false (Geometry is defined as closed but is open)
Autocorrected: POLYGON((0 0,10 0,10 10,0 10,0 0))
Note: the bg::correct might in cases correct /part/ of the problem, but leave other issues, and this check function doesn't report on that.
Related
Like the title said, my code is reading a 2D array entirely wrong.
const int WINNING_ROWS[8][3] = { (0, 1, 2),
(3, 4, 5),
(6, 7, 8),
(0, 3, 6),
(1, 4, 7),
(2, 5, 8),
(0, 4, 8),
(2, 4, 6) };
Above is my 2D array of numbers.
My program doesn't seem to be able to read it properly.
For example, if I were to ask for row 2, item 1, I would expect 7, it, however, instead gives me 6.
Here is a list of rows and item requests I have done to try and figure out what has gone wrong here.
row 0, item 0, expected outcome 0, actual outcome 2
row 3, item 2, expected outcome 6, actual outcome 0
row 1, item 0, expected outcome 3, actual outcome 6
row 5, item 1, expected outcome 5, actual outcome 0
row 8, item 2, expected outcome 6, actual outcome 13629648
row 7, item 2, expected outcome 6, actual outcome 0
for reference, here is the code I have been using to call the items from the array
cout << WINNING_ROWS[7][2] << endl;
Edit 1: ignore the item in bold, that was a mistake on my part when testing my code.
Edit 2: my question has been answered.
const int WINNING_ROWS[8][3] = { (0, 1, 2),
(3, 4, 5),
(6, 7, 8),
(0, 3, 6),
(1, 4, 7),
(2, 5, 8),
(0, 4, 8),
(2, 4, 6) };
That doesn't mean what you think it does. The (0,1,2) is not a row of three elements, but a single integer computed using the comma operator. 0,1,2 evaluates to 2.
You need to use the proper {...} braces instead of parenthesis, or leave them out completely.
Suggest also you change const to constexpr.
WINNING_ROWS[8][2] is out of the array bounds, which means it will cause undefined behavior. If you want to get the last element, you should try cout << WINNING_ROWS[7][2] << endl; since they are 0-indexed.
What does the Combinations function do in ROOT/C++?
I only found this documentation
https://root.cern.ch/doc/master/namespaceROOT_1_1VecOps.html#a6d1d00c2ccb769cc48c6813dbeb132db
But I am still not sure what it does exactly.
Can someone provide an example showing how the answers in the documentation examples are computed?
Here is an example of what Combinations is doing:
Suppose you have a vector v{1., 2., 3., 4.,}
1, 2, 3, and 4 are the elements of the vector v
and 0, 1, 2, 3 are the indices of those elements.
If we write
Combinations (v, 2)
we get
{{ 0, 0, 0, 1, 1, 2} , { 1, 2, 3, 2, 3, 3}}.
That comes from looking at the different combinations of the vector elements.
Which are:
1, 2
1, 3
1, 4
2, 3
2, 4
3, 4
Which has the corresponding indices
0 1
0 2
0 3
1 2
1 3
2 3
Then, the left-side column makes the first vector in the answer and the right side column makes the second vector shown in the answer.
Sorry for the vague title, I'm not sure how to word it.
Say I have a vector:
vector<int> vec{{
1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14
}};
and a corresponding positions vector which occurs after a number is missed (like 5 to 7).
vector<int> positions{{
1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1
}};
How would I return a 2D vector running from each 1, up to but not including the next one: e.g.
1 2 3 4 5
7 8 9 10
12 13 14
Thanks in advance, I'd post my attempts, but they all led down blind avenues. I know it's an odd structure...
There are a few ways to solve this, but I believe this should work:
std::vector<std::vector<int>> vec2D;
int index = -1;
// Identify the indices of the position vector and use that to identify the
// correct indices of the vec.
for (int i = 0; i != position.size(); ++i)
{
// if the value at i of the position vector is 0,
// push_back the value at i of the vec vector into
// the correct vector of vector.
if (0 == position[i])
{
vec2D[index].push_back(vec[i])
}
else if (1 == position[i])
{
++index; //increment to the next vector
std::vector<int> temp;
vec2D.push_back(temp);
vec2D[index].push_back(vec[i])
}
}
I'm trying to do this operation in C++, but I cant wrap my head around it.
I tried looking in http://mathworks.com/help/matlab/ref/image.html but I still don't get it.
im is a matrix in Matlab. Width is 640
im(:,Width+(1:2),:) = im(:,1:2,:);
Is there anything similar to this operation in OpenCV Matrix or C++
Solution 1
You can use colRange function:
mat.colRange(0, 2).copyTo(mat.colRange(w, 2 + w));
Example:
//initilizes data
float data[2][4] = { { 1, 2, 3, 4}, { 5, 6, 7, 8 } };
Mat mat(2, 4, CV_32FC1, &data);
int w = 2; //w is equivelant to Width in your script, in this case I chose it to be 2
std::cout << "mat before: \n" << mat << std::endl;
mat.colRange(0, 2).copyTo(mat.colRange(w, 2 + w));
std::cout << "mat after: \n" << mat << std::endl;
Result:
mat before:
[1, 2, 3, 4;
5, 6, 7, 8]
mat after:
[1, 2, 1, 2;
5, 6, 5, 6]
Solution 2
Alternatively, use cv::Rect object, as follows:
cv::Mat roi = mat(cv::Rect(w, 0, 2, mat.rows));
mat(cv::Rect(0, 0, 2, mat.rows)).copyTo(roi);
There are several way to initialize a Rect, in my case I chose the following c-tor:
cv::Rect(int x, int y, int width, int height);
The result are the same as an in Solution 1.
Maybe you could also use Eigen that can serve the need. It has Block operations
Adapting the example provided under link you would need smth like:
Eigen::MatrixXf m(4, 4);
m << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16;
cout <<"original matrix \n" << m << endl;
m.block<2, 2>(1, 1) = m.block<2, 2>(2, 2);
cout <<"modified matrix \n" << m << endl;
Output:
original matrix
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
modified matrix
1 2 3 4
5 11 12 8
9 15 16 12
13 14 15 16
I'm trying to calculate a difference of two polygons using boost::geometry::difference with boost::geometry::model::polygon representing my polygons.
In case when the first polygon contains the second one result of the operation is a single boost::geometry::model::polygon with the inner and outer rings populated with coordinates of the source polygons.
How do I get a polygon (in the elementary geometry sense) from boost::geometry::model::polygon?
Clarification:
In elementary geometry, a polygon is a plane figure that is bounded by a finite chain of straight line segments closing in a loop to form a closed chain or circuit.
The outer ring of boost::geometry::model::polygon is a polygon, the inner rings are polygons too. As a whole boost::geometry::model::polygon is not a polygon.
So, what I'm asking: How to convert boost::geometry::model::polygon to a normal polygon (having a single chain of straight line segments), which represents the same area on a plane.
Here's what I'm trying to achieve:
polygon1 = (0,0), (0,8), (8,8), (8,0), (0,0)
polygon2 = (2,2), (2,6), (6,6), (6,2), (2,2)
Polygons 1 & 2 in green / oker:
difference = (0,0), (0,4), (2,4), (2,2), (6,2), (6,6), (2,6), (2,4), (0,4), (0,8), (8,8), (8,0), (0,0)
Expected difference in grey:
I know the same boost::geometry::model::polygon having inner rings could be represented by infinitely many different normal polygons. I don't care which one I get.
You can easily construct a ring that models your expected weak simple polygon. First:
Caveat
Note though that the result isn't valid for further use with the Boost Geometry library's algorithms.
Take your literal example:
std::string reason;
poly expected;
bg::read_wkt("POLYGON((0 0, 0 4, 2 4, 2 2, 6 2, 6 6, 2 6, 2 4, 0 4, 0 8, 8 8, 8 0, 0 0))", expected);
bool ok = bg::is_valid(expected, reason);
std::cout << "Expected: " << bg::dsv(expected) << (ok?" valid":" invalid: '" + reason + "'") << "\n";
Prints
Expected: (((0, 0), (0, 4), (2, 4), (2, 2), (6, 2), (6, 6), (2, 6), (2, 4), (0, 4), (0, 8), (8, 8), (8, 0), (0, 0))) invalid: 'Geometry has invalid self-intersections. A self-intersection point was found at (0, 4); method: t; operations: x/u; segment IDs {source, multi, ring, segment}: {0, -1, -1, 0}/{0, -1, -1, 7}'
Algorithm implementation
With that out of the way, here's a simple algorithm to construct the simple weak polygon from a given polygon:
ring weak_simple_ring(poly& p) {
ring r = p.outer();
for (auto& i: p.inners()) {
auto last = r.back();
r.insert(r.end(), i.rbegin(), i.rend());
r.insert(r.end(), last);
}
return r;
}
The only subtler point there is to reverse the direction (CW/CCW) of the inner rings to match that of the outer ring.
The algorithm doesn't attempt to be smart about finding a cut-point to the inner ring, which probably also means that it won't work nicely for the generic case with multiple inner rings.
DEMO
Here's a full live demo
Live On Coliru
Where the input is
bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 2, 2 6, 6 6, 6 2, 2 2))", b);
The transformation is
std::vector<poly> output;
bg::difference(a, b, output);
for (auto& p : output) {
ring r = weak_simple_ring(p);
bg::convert(r, p);
}
And the result becomes
More complicated sample
Consider when b had a hole:
bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 2, 2 6, 6 6, 6 2, 2 2)(3 3, 5 3, 5 5, 3 5, 3 3))", b);
The output with the same code becomes
This is the old answer. After edits to the question I've posted a simple implementation of an algorithm that suits the sample given
It already is.
If you mean, a "simple" non-holey polygon, the outer ring is all you want. Just discard the inner rings.
However, in the most generic case you can end up with multiple entirely disjunct polygons, which is why the output is a collection of polygons. You will have to consider this possibility too (optionally joining the different result polygons into one and discarding inner rings if that's what you desire, functionally).
A sample:
bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 -2,2 12,5 12,5 -2,2 -2))", b);
Here, b cuts a into two separate pieces. So you must be prepared to handle multiple, disjunct, output polygons:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/io/io.hpp>
#include <iostream>
#include <fstream>
namespace bg = boost::geometry;
using pt = bg::model::d2::point_xy<int>;
using poly = bg::model::polygon<pt>;
int main() {
poly a, b;
bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 -2,2 12,5 12,5 -2,2 -2))", b);
std::cout << bg::dsv(a) << "\n";
std::cout << bg::dsv(b) << "\n";
{
std::ofstream svg("/tmp/input.svg");
boost::geometry::svg_mapper<pt> mapper(svg, 400, 400);
mapper.add(a);
mapper.add(b);
mapper.map(a, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.map(b, "fill-opacity:0.5;fill:rgb(204,153,0);stroke:rgb(202,153,0);stroke-width:2");
}
std::vector<poly> output;
bg::difference(a, b, output);
for (auto& p : output)
std::cout << "\n\t" << bg::dsv(p);
{
std::ofstream svg("/tmp/output.svg");
boost::geometry::svg_mapper<pt> mapper(svg, 400, 400);
assert(output.size() == 2);
mapper.add(output[0]);
mapper.add(output[1]);
mapper.add(b);
mapper.map(output[0], "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.map(output[1], "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.map(b, "fill-opacity:0.15;fill:rgb(153,153,153);stroke-width:0");
}
}
Prints:
(((0, 0), (0, 10), (10, 10), (10, 0), (0, 0)))
(((2, -2), (2, 12), (5, 12), (5, -2), (2, -2)))
(((5, 10), (10, 10), (10, 0), (5, 0), (5, 10)))
(((2, 10), (2, 0), (0, 0), (0, 10), (2, 10)))
SVGs rendered: