Incorrect work boost::geometry::union_ on C++ - c++

I want to use boost::geometry::union_ with polygons on picture, but it cannot see point E (says, that polygon ABCDE has area as ABCD). How can I fix it?

Here's how I'd write your exercise. I designed a similar scene (the points are probably named differently, but that's not the [sic] point):
Note: I've rounded the coordinates to the nearest integral number (and scaled x10 afterwards)
Live On Wandbox
#include <boost/geometry.hpp>
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <iostream>
#include <fstream>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using Point = bgm::d2::point_xy<int>;
using Polygon = bgm::polygon<Point>;
using Multi = bgm::multi_polygon<Polygon>;
int main() {
auto prepare = [](auto name, auto& geo) {
std::string r;
if (!bg::is_valid(geo, r)) {
std::cout << "Correcting " << name << ": " << bg::wkt(geo) << " (" << r << ")\n";
bg::correct(geo);
}
std::cout << name << ": " << bg::wkt(geo) << "\n";
};
Point A{-120, 50}, B{-60, 70}, C{-70, 50}, D{-40, 00}, E{-130, 10};
Point F{-20, -20}, G{40, -10}, H{80, 60}, I{50, 80}, J{-20, 50}, K{30, 30};
Polygon ABCDE({{A, B, C, D, E, A}});
Polygon DFGHIJK({{D, F, G, H, I, J, K, D}});
prepare("ABCDE", ABCDE);
prepare("DFGHIJK", DFGHIJK);
Multi out;
bg::union_(ABCDE, DFGHIJK, out);
prepare("union", out);
{
namespace bs = bg::strategy::buffer;
const double buffer_distance = 3;
bs::distance_symmetric<double> distance(buffer_distance);
bs::join_miter join;
bs::end_flat end;
bs::point_circle circle(6);
bs::side_straight side;
Multi outline;
bg::buffer(out, outline, distance, side, join, end, circle);
std::ofstream svg("output.svg");
boost::geometry::svg_mapper<Point> mapper(svg, 400, 400);
mapper.add(ABCDE);
mapper.add(DFGHIJK);
mapper.add(outline);
mapper.map(ABCDE,
"fill-opacity:0.3;fill:rgb(153,0,0);stroke:rgb(153,0,0);"
"stroke-width:1;stroke-dasharray:1 2");
mapper.map(DFGHIJK,
"fill-opacity:0.3;fill:rgb(0,0,153);stroke:rgb(0,0,153);"
"stroke-width:1;stroke-dasharray:1 2 2 1");
mapper.map(outline,
"fill-opacity:0.1;fill:rgb(153,204,0);stroke:rgb(153,204,0);"
"stroke-width:1");
}
std::cout << "Areas: " << bg::area(ABCDE) << " + " << bg::area(DFGHIJK)
<< " = " << bg::area(out) << "\n";
}
Which prints the expected:
ABCDE: POLYGON((-120 50,-60 70,-70 50,-40 0,-130 10,-120 50))
Correcting DFGHIJK: POLYGON((-40 0,-20 -20,40 -10,80 60,50 80,-20 50,30 30,-40 0)) (Geometry has wrong orie
ntation)
DFGHIJK: POLYGON((-40 0,30 30,-20 50,50 80,80 60,40 -10,-20 -20,-40 0))
union: MULTIPOLYGON(((-40 0,-130 10,-120 50,-60 70,-70 50,-40 0)),((-40 0,30 30,-20 50,50 80,80 60,40 -10,-
20 -20,-40 0)))
Areas: 3600 + 5800 = 9400
It also generates the following SVG:
I hope the way in which I approach it, and specifically the diagnostics code is helpful to you.

Related

eigen: create Vector-like Replicate (access with one index, LinearAccessBit)

I want to create an Eigen::Replicate object that can be accessed like a vector, i.e. with a single index. I got that to work with the fixed-size replicate<Index,Index>(), which I can't use in reality, the non-one factor is not a compile-time constant. It also works when manually creating a Replicate object, but I feel like I'm just overlooking the obvious way of using a replicate function to achieve this:
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
int main(){
Vector3i v (3);
v << 0,1,2;
constexpr int nReplications {2};
auto replDynamic { v.replicate(nReplications, 1) };
/* with a dynamic replication, two indexes are required to access a coeff */
std::cout << "5th entry: " << replDynamic(4,0) << '\n';
auto replFixed { v.replicate<nReplications, 1>() };
/* I want to use only one index, but I require the number of replications
* in one dimension to be dynamic */
std::cout << "5th entry: " << replFixed(4) << '\n';
/* don't know how to access the VectorwiseOp variant */
// auto replVector { v.replicate(nReplications) };
// std::cout << "5th entry: " << replVector(4) << '\n';
/* this function doesn't exist */
// auto replDefined { v.replicate<Dynamic,1>(nReplications, 1) };
// std::cout << "5th entry: " << replDefined(4) << '\n';
/* I'd rather not define it manually (it's not the intended way), but it works */
Replicate<Vector3i,Dynamic,1> replManual { v, nReplications, 1 };
std::cout << "5th entry: " << replManual(4) << '\n';
return 0;
}
The source code shows VectorwiseOp<...>::replicate(Index factor) in line 134, which sounds like what I need, but I don't seem to be able to access it.
And a function such as replicate<Index,Index>(Index,Index) doesn't exist.
Assuming I understand what you are asking, since a Vector3i is a one column Eigen::Matrix, you can get a VectorwiseOp<...> expression template from a Vector3i (say) by using the colwise() function and then call the one argument replicate with that.
That is,
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
int main() {
Vector3i v(3);
v << 0, 1, 2;
auto foo = v.colwise().replicate(2);
std::cout << "5th entry: " << foo(4) << '\n';
return 0;
}
Note though that using type deduction on a expression template, or "pseudo expression" as they are called in the Eigen documentation, is generally a bad idea i.e. writing Eigen::Matrix<int, 6, 1> foo = v.colwise().replicate(2) is safer; the Eigen documentation mentions the issue here.
By adding a .reshaped() after the replicate(...) call, the ColsAtCompileTime are set to 1, and therefore, the resulting object can be accessed like a vector:
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
int main(){
Vector3i v (3);
v << 0,1,2;
constexpr int nReplications {2};
auto replReshaped { v.replicate(nReplications, 1).reshaped() };
std::cout << "5th entry: " << replReshaped(4) << '\n';
return 0;
}

Boost geometry returning inconsistent results for intersects and intersection

In my application I'm using boost geometry to perform mainly intersection
and difference calculations. Unfortunately I noticed an inconsistency
in the results of:
bg::intersects and
bg::intersection
What I do is:
Calculate the intersection of polygon1 and polygon2 (= polygon3).
Remove (bg::difference) this intersection from polygon1 (= poly4)
The resulting polygon4 should not have any intersection with poly2.
#include <iostream>
#include <boost/geometry.hpp>
namespace bg = boost::geometry;
using point_t = bg::model::d2::point_xy<double>;
using polygon_t = bg::model::polygon<point_t>;
using mpolygon_t = bg::model::multi_polygon<polygon_t>;
int main()
{
polygon_t poly1, poly2;
mpolygon_t poly3, poly4, poly5;
bg::read_wkt("POLYGON(("
"12227.0 4967.0000000000009, 12238.0 4967.0000000000009, "
"12238.0 4813.0000000000009, 12227.0 4813.0000000000009, "
"12227.0 4967.0000000000009))", poly1);
bg::read_wkt("POLYGON(("
"12254.0 4947.0, 12219.0 4982.0, 12219.0 5020.0, 12254.0 5055.0, "
"12261.0 5055.0, 12263.0 5055.0, 12283.0 5055.0, 12283.0 4947.0, "
"12263.0 4947.0, 12261.0 4947.0, 12254.0 4947.0))", poly2);
bg::intersection(poly1, poly2, poly3);
bg::difference(poly1, poly3[0], poly4);
// b0 = true, b1 = false
bool b0 = bg::intersects(poly2, poly4[0]);
bool b1 = bg::intersection(poly2, poly4, poly5) && (poly5.size() != 0);
bool b2 = !bg::disjoint(poly2, poly4[0]) && !bg::touches(poly2, poly4[0]);
bool b3 = bg::overlaps(poly2, poly4[0]) || bg::within(poly4[0], poly2) || bg::within(poly2, poly4[0]);
std::cout << b0 << b1 << b2 << b3 << std::endl;
return 1;
}
The weird thing is that bg::intersects returns true while
bg::intersection returns an empty intersection.
Does anyone have an idea why this happens? (Maybe accuracy problem?) and
even more interesting: How can I avoid such problems?
I tried to avoid "intersects" by using other functions but the results were not helpful. Please see calculations for b2 and b3.
PS: Unfortunately the example seems cause a crash on coliru.
In fact the return value of the intersection function is unspecified: see
What does boost::geometry::intersection return
So, you need to look at the intersection itself:
Unlive On Coliru
Unlive On Compiler Explorer
Live On Wandbox (Yay!)
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/logic/tribool_io.hpp>
using boost::tribool;
using boost::indeterminate;
namespace bg = boost::geometry;
using Coord = double;
using point_t = bg::model::d2::point_xy<Coord>;
using polygon_t = bg::model::polygon<point_t>;
using mpolygon_t = bg::model::multi_polygon<polygon_t>;
int main() {
polygon_t a, b;
bg::read_wkt("POLYGON(("
"12227.0 4967.0000000000009, 12238.0 4967.0000000000009, "
"12238.0 4813.0000000000009, 12227.0 4813.0000000000009, "
"12227.0 4967.0000000000009))", a);
bg::read_wkt("POLYGON(("
"12254.0 4947.0, 12219.0 4982.0, 12219.0 5020.0, 12254.0 5055.0, "
"12261.0 5055.0, 12263.0 5055.0, 12283.0 5055.0, 12283.0 4947.0, "
"12263.0 4947.0, 12261.0 4947.0, 12254.0 4947.0))", b);
#define CHECK(expected, expr) \
do { \
auto const& actual = (expr); \
auto ok = ((expected) == actual); \
if (ok == true) { \
std::cout << "PASS"; \
} else if (ok == false) { \
std::cout << "FAIL"; \
} else { \
std::cout << "?"; \
} \
std::cout << "\t" << #expr << " -> " << std::boolalpha << actual \
<< "\n"; \
if (!(ok == true)) \
std::cout << " (expected value was " << (expected) << ")\n"; \
} while (false)
mpolygon_t ab_intersect;
auto dump = [](auto label, auto& geo) {
std::cout << label << " area " << bg::area(geo) << " " << bg::wkt(geo) << "\n";
};
CHECK(true, bg::intersection(a, b, ab_intersect));
CHECK(1, ab_intersect.size());
dump("a", a);
dump("b", b);
dump("ab_intersect", ab_intersect);
mpolygon_t a_minus_b, b_minus_a;
bg::difference(a, ab_intersect, a_minus_b);
bg::difference(b, ab_intersect, b_minus_a);
CHECK(1, a_minus_b.size());
CHECK(1, b_minus_a.size());
dump("a_minus_b", a_minus_b);
dump("b_minus_a", b_minus_a);
auto checks = [dump](auto& reduced, auto& other) {
CHECK(true, bg::intersects(reduced, other));
mpolygon_t check;
bg::intersection(reduced, other, check);
CHECK(true, check.empty());
dump("check", check);
};
std::cout << "-- reduced a vs b: -------\n";
checks(a_minus_b, b);
std::cout << "-- reduced b vs a: -------\n";
checks(b_minus_a, a);
}
Prints
PASS bg::intersection(a, b, ab_intersect) -> true
PASS ab_intersect.size() -> 1
a area 1694 POLYGON((12227 4967,12238 4967,12238 4813,12227 4813,12227 4967))
b area 5687 POLYGON((12254 4947,12219 4982,12219 5020,12254 5055,12261 5055,12263 5055,12283 5055,12283 4947,12263 4947,12261 4947,12254 4947))
ab_intersect area 8 MULTIPOLYGON(((12234 4967,12238 4967,12238 4963,12234 4967)))
PASS a_minus_b.size() -> 1
PASS b_minus_a.size() -> 1
a_minus_b area 1686 MULTIPOLYGON(((12234 4967,12238 4963,12238 4813,12227 4813,12227 4967,12234 4967)))
b_minus_a area 5679 MULTIPOLYGON(((12238 4963,12238 4967,12234 4967,12219 4982,12219 5020,12254 5055,12261 5055,12263 5055,12283 5055,12283 4947,12263 4947,12261 4947,12254 4947,12238 4963)))
-- reduced a vs b: -------
PASS bg::intersects(reduced, other) -> true
PASS check.empty() -> true
check area 0 MULTIPOLYGON()
-- reduced b vs a: -------
PASS bg::intersects(reduced, other) -> true
PASS check.empty() -> true
check area 0 MULTIPOLYGON()
The behavior I mentioned is not a bug but fully correct:
bg::intersection() returns an empty polygon BUT
if I call it with a linestring as output parameter:
using linestring_t = bg::model::linestring<point_t>;
linestring_t int1;
bg::intersection(poly2, poly4, int1);
std::cout << "int1: " << bg::wkt(int1) << std::endl;
it works.
TL;DR
The usage and my interpretation of bg::intersects() and bg::intersection() was wrong!

C++ Opencv: Mat.zeros get wrong shape

I defined and initialized a Mat variable using the Mat::zeros, when I print its shape, i.e. rows, cols, channels, it seems I get wrong values.
My code is shown as follows:
#include "opencv2/opencv.hpp"
#include <opencv2/core/core.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char const *argv[])
{
int n_Channel = 3;
int mySizes[3] = {100, 200, n_Channel};
Mat M = Mat::zeros(n_Channel, mySizes, CV_64F);
cout << M.rows << "," << M.cols << "," << M.channels() << endl;
return 0;
}
The printed message is :
-1,-1,1
What's wrong with this?
I also find that if I declare a Mat using the following code:
int n_Channel = 3;
Mat M(Size(100, 200), CV_32FC(n_Channel));
cout << M.rows << "," << M.cols << "," << M.channels() << endl;
the outcome is correct:
200,100,3
I'm confused about this. Thank you all for helping me!
You want to use a very special overloaded version of the cv::Mat::zeros method.
Let's have a look at the following code:
// Number of channels.
const int n_Channel = 3;
// Number of dimensions; must be 1 or 2?
const int n_Dimensions = 2;
// Create empty Mat using zeros, and output dimensions.
int mySizes[n_Dimensions] = { 200, 100 };
cv::Mat M1 = cv::Mat::zeros(n_Dimensions, mySizes, CV_64FC(n_Channel));
std::cout << "M1: " << M1.rows << "," << M1.cols << "," << M1.channels() << std::endl;
// Create empty Mat using constructor, and output dimensions.
cv::Mat M2 = cv::Mat(cv::Size(100, 200), CV_64FC(n_Channel), cv::Scalar(0, 0, 0));
std::cout << "M2: " << M2.rows << "," << M2.cols << "," << M2.channels() << std::endl;
which gives the following output:
M1: 200,100,3
M2: 200,100,3
So, basically you have to move the "channel number info" from mySizes to the cv::Mat::zeros method. Also, you have to pay attention to the order of the image dimensions provided in mySizes, since it seem to differ from the constructor using cv::Size. I guess the latter one is width x height, whereas the first one is number of rows x number of cols.
How to init CV mat :
cv::Mat test = cv::Mat::zeros(cv::Size(100, 200), CV_64F);
As you can see, the first parameter is the Size cf :
https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html

PCL zoom out functionality

I am new to Point Cloud Library (PCL) and C++ programming. I load multiple .ply files given as the arguments (say test0.ply,test1.ply...test99.ply) and visualize them one after another as if they are frames of videos.
Below is what I've tried so far. How can I get farther from the model during each frame (zoom out) ? The setCameraPosition function looks related, but the description is confusing.
UPDATE: We need to find the camera's current_position and play with it. Just like zoom in/out.
#include <iostream>
//#include <unistd.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_cloud.h>
#include <pcl/console/parse.h>
#include <pcl/common/transforms.h>
#include <pcl/visualization/pcl_visualizer.h>
// This function displays the help
void showHelp(char *program_name)
{
std::cout << std::endl;
std::cout << "Usage: " << program_name << " cloud_filename.[pcd|ply]" << std::endl;
std::cout << "-h: Show this help." << std::endl;
}
// Main function
int main(int argc, char **argv)
{
// Show help
if (pcl::console::find_switch(argc, argv, "-h") || pcl::console::find_switch(argc, argv, "--help"))
{
showHelp(argv[0]);
return 0;
}
// Fetch point cloud filename in arguments | Works with PLY files
std::vector<int> filenames;
filenames = pcl::console::parse_file_extension_argument(argc, argv, ".ply");
// Visualization
printf("\n Point cloud colors :\n"
" \t white \t = \t original point cloud \n");
pcl::visualization::PCLVisualizer viewer(" Point Cloud Visualizer");
viewer.setBackgroundColor(0.05, 0.05, 0.05, 0); // Set background to a dark grey
// Load file | Works with PLY files
pcl::PointCloud<pcl::PointXYZRGB>::Ptr source_cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
int i = 0;
while (1)
{
// int v1(0);
// viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1);
i++;
cout << argv[filenames[i % 10]] << endl;
if (pcl::io::loadPLYFile(argv[filenames[i % 10]], *source_cloud) < 0)
{
std::cout << "Error loading point cloud " << argv[filenames[(i % 10) + 1]] << std::endl << std::endl;
showHelp(argv[(i % 10) + 1]);
return -1;
}
// Define R,G,B colors for the point cloud
pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(source_cloud);
// We add the point cloud to the viewer and pass the color handler
viewer.addPointCloud(source_cloud, rgb, "original_cloud" + i);
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "original_cloud" + i);
viewer.spinOnce();
viewer.removePointCloud("original_cloud" + i);
}
return 0;
} // End main()
I think you are on the right track and setCameraPosition() should be what you are looking for. Here is some example code that focus the camera on a specific point and places the camera 5 meters away in the y dimension.
pcl::PointXYZI center = centerPoint(cloud);
viewer->setCameraPosition(center.x, center.y - 5, center.z, 0, 0, 1);
std::vector<pcl::visualization::Camera> cams;
viewer->getCameras(cams);
for (auto&& camera : cams)
{
camera.focal[0] = center.x;
camera.focal[1] = center.y;
camera.focal[2] = center.z;
}
viewer->setCameraParameters(cams[0]);

Boost::geometry Trouble in using within method on point and polygons?

It seems that I have trouble in using correctly the boost geometry library ( Boost::geometry : calculation of the centroid of a polygon ). I very much appreciated the help on my previous question and would like to ask something about the boost::geometry::within method, answering if one geometry is contained in another one.
I'm using it in my code to check if a point is contained in a polygon, and I'm encountering weird results where a point should definitely not be inside a polygon far away but the method still returns True when called.
I'm thinking about a subtlety I'm missing when declaring my polygon, and I would really like to pin down this trouble. Though looking at my code back and forth, I'm lacking ideas in debugging this, and it feels like a got tunnel vision. That's why I'd like to have an hint on this specific example:
My point has coordinates: 221.703 , 256
The polygon is coordinates are, point by point:
266.158 256
266.447 256.5
267.024 256.5
267.313 257
267.024 257.5
267.313 258
which clearly shouldn't contain the point given above.
I'm sorry to ask on something this pedantic, but I'd be really thankful to anyone willing to put their nose in this
My code:
#include <iostream>
#include <boost/geometry.hpp>
using namespace std;
namespace bg = boost::geometry;
typedef bg::model::point<float, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
typedef bg::model::polygon<point, false, true> polygon;
int main(int argc, char * argv[]){
polygon pol;
pol.outer().push_back(point(266.158,256));
pol.outer().push_back(point(266.447,256.5));
pol.outer().push_back(point(267.024,256.5));
pol.outer().push_back(point(267.313,257));
pol.outer().push_back(point(267.024,257.5));
pol.outer().push_back(point(267.313,258));
double x = atof(argv[1]);
double y = atof(argv[2]);
cout << "Is inside: " << ((bg::within(point(x,y),pol)) ? "yes" : "no") << endl;
return 0;
}
When you use bg::model::polygon<point, false, true> you are defining a polygon that uses point as its point type, that has its points in counter clockwise order and that is closed (meaning that its last point is equal to its first). If you either "close" your polygon or use an open polygon, the behaviour of bg::within seems to be what you expect:
Running on Coliru
#include <iostream>
#include <boost/geometry.hpp>
using std::cout;
using std::endl;
namespace bg = boost::geometry;
typedef bg::model::point<float, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
typedef bg::model::polygon<point, false, true> closed_polygon;
typedef bg::model::polygon<point, false, false> open_polygon;
int main(int argc, char * argv[])
{
{
closed_polygon pol;
pol.outer().push_back(point(266.158,256));
pol.outer().push_back(point(266.447,256.5));
pol.outer().push_back(point(267.024,256.5));
pol.outer().push_back(point(267.313,257));
pol.outer().push_back(point(267.024,257.5));
pol.outer().push_back(point(267.313,258));
pol.outer().push_back(point(266.158,256));//you need to close the polygon
double x = 222;
double y = 257;
cout << "Is " << bg::wkt<point>(point(x,y)) << " inside: " << ((bg::within(point(x,y),pol)) ? "yes" : "no") << endl;
x = 267;
y = 257;
cout << "Is " << bg::wkt<point>(point(x,y)) << " inside: " << ((bg::within(point(x,y),pol)) ? "yes" : "no") << endl;
}
{
open_polygon pol;
pol.outer().push_back(point(266.158,256));
pol.outer().push_back(point(266.447,256.5));
pol.outer().push_back(point(267.024,256.5));
pol.outer().push_back(point(267.313,257));
pol.outer().push_back(point(267.024,257.5));
pol.outer().push_back(point(267.313,258));
double x = 222;
double y = 257;
cout << "Is " << bg::wkt<point>(point(x,y)) << " inside: " << ((bg::within(point(x,y),pol)) ? "yes" : "no") << endl;
x = 267;
y = 257;
cout << "Is " << bg::wkt<point>(point(x,y)) << " inside: " << ((bg::within(point(x,y),pol)) ? "yes" : "no") << endl;
}
return 0;
}