Override floating point tolerance with boost intersection - boost

Is it possible to introduce some tolerance with the intersection algorithm, such that close points or almost colinear lines are considered parallel?
To be concrete:
I have two line segments that should be considered parallel, however, due to some accuracy problems while doing floating point calculations, the line segments are not entirely parallel, the error is 3.78e-14 which should - by all means - be considered parallel in my case: so boost's intersection should give me two points.
However this is not the case and intersection regards those lines as not parallel. Example:
This is very similar to this question. This post is old and doesn't seem to satisfy me needs though. I'm confused as to how the intersection algorithm works in boost, too. I tried to find the code in boosts library but without success. Boosts code base is terrifying.
struct Point {
double x, y;
Point(double x_, double y_) : x(x_), y(y_) {};
}
BOOST_GEOMETRY_REGISTER_POINT_2D(Point, double, boost::geometry::cs::cartesian, x, y);
typedef boost::geometry::model::segment<Point> Segment;
Segment seg1({ -1012600, 9641189 }, { -935132, 9595186.14285714179277420043945 });
Segment seg2({ -1012600, 9641189 }, { -877031, 9560684 });
std::vector<Point> out;
boost::geometry::intersection(seg1, seg2, out);
Since I consider both segments as parallel, the expected output should be:
{ -1012600, 9641189 }, { -935132, 9595186.14285714179277420043945 }
Intersection indeed gives two points in a parallel case:
See for example:
Segment seg1({0, 0}, {6, 6});
Segment seg2({2, 2}, {3, 3});
boost::geometry::intersection(seg1, seg2, out);
Will give:
{2, 2}, {3, 3}

What do you expect the outcome to be? The segments still start in the same point.
And the resulting intersection is that point when I test it:
Live On Coliru
#include <boost/geometry.hpp>
#include <iostream>
#include <boost/geometry/geometries/register/point.hpp>
struct Point {
double x, y;
Point(double x_= 0, double y_= 0) : x(x_), y(y_) {};
};
BOOST_GEOMETRY_REGISTER_POINT_2D(Point, double, boost::geometry::cs::cartesian,
x, y)
typedef boost::geometry::model::segment<Point> Segment;
int main() {
Point P1{-1012600, 9641189};
std::cout << std::fixed;
Segment seg1(P1, {-935132, 9595186.14285714179277420043945});
Segment seg2(P1, {-877031, 9560684});
std::vector<Point> out;
boost::geometry::intersection(seg1, seg2, out);
for (auto& p : out) {
std::cout << boost::geometry::wkt(p) << "\n";
}
}
Print
POINT(-1012600.000000 9641189.000000)
On Precision
Otherwise, I've had success replacing double with long double or Boost Multiprecision types: https://stackoverflow.com/search?tab=newest&q=user%3a85371%20geometry%20multiprecision

Related

Boost Geometry: segments intersection not yet implemented?

I am trying a simple test: compute the intersection of 2 segments with Boost Geometry. It does not compile. I also tried with some variations (int points instead of float points, 2D instead of 3D) with no improvement.
Is it really possible that boost doesn't implement segment intersection ? Or what did I do wrong ? Missing some hpp ? Confusion between algorithms "intersects" & "intersection" ?
The code is very basic:
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
typedef boost::geometry::model::point<float, 3, boost::geometry::cs::cartesian> testPoint;
typedef boost::geometry::model::segment<testPoint> testSegment;
testSegment s1(
testPoint(-1.f, 0.f, 0.f),
testPoint(1.f, 0.f, 0.f)
);
testSegment s2(
testPoint(0.f, -1.f, 0.f),
testPoint(0.f, 1.f, 0.f)
);
std::vector<testPoint> output;
bool intersectionExists = boost::geometry::intersects(s1, s2, output);
But I got the following errors at compile time by Visual:
- Error C2039 'apply' n'est pas membre de 'boost::geometry::dispatch::disjoint<Geometry1,Geometry2,3,boost::geometry::segment_tag,boost::geometry::segment_tag,false>' CDCadwork C:\Program Files\Boost\boost_1_75_0\boost\geometry\algorithms\detail\disjoint\interface.hpp 54
- Error C2338 This operation is not or not yet implemented. CDCadwork C:\Program Files\Boost\boost_1_75_0\boost\geometry\algorithms\not_implemented.hpp 47
There are indeed two problems:
you're intersecting 3D geometries. That's not implemented
Instead you can do the same operation on a projection.
you're passing an "output" geometry to intersects (which indeed only returns the true/false value as your chosen name intersectionExists suggested). In the presence of a third parameter, it would be used as a Strategy - a concept for which output obviously doesn't satisfy.
Note intersection always returns true: What does boost::geometry::intersection return - although that's not part of the documented interface
Since your geometries are trivially projected onto 2d plane Z=0:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <iostream>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using Point = bgm::point<float, 2, bg::cs::cartesian>;
using Segment = bgm::segment<Point>;
int main() {
Segment s1{{-1, 0}, {1, 0}};
Segment s2{{0, -1}, {0, 1}};
bool exists = bg::intersects(s1, s2);
std::vector<Point> output;
/*bool alwaysTrue = */ bg::intersection(s1, s2, output);
std::cout << bg::wkt(s1) << "\n";
std::cout << bg::wkt(s2) << "\n";
for (auto& p : output) {
std::cout << bg::wkt(p) << "\n";
}
return exists? 0:1;
}
Prints
LINESTRING(-1 0,1 0)
LINESTRING(0 -1,0 1)
POINT(0 0)

Properly generate convex hull and get plane equations

I am completely new to Computational Geometry. I want to generate convex hull of a set of points and then get plane equations for the generated convex polyhedron so that I can check inclusion/exclusion of points. I have followed the docs and tried the whole procedure probably a dozen times but there is always some issue. Maybe I'm missing some subtle point here. The whole procedure is as follows. I have the following plot, generated in Mathematica.
I want to include every point that is on the plot inside a convex hull. So I take all the points lying on all corners of both planes and the origin (Maybe that's the problem. Maybe there is a way to properly choose points so that all points on the plot are covered). The points for this specific plot are as follows. Note that the points are generated using infinite precision so they are exact values.
pts = {
{-24298771/25000000000,-223461425901/50000000000,0},
{11285077/10000000000,-223461425901/50000000000,0},
{-24298771/25000000000,0,0},
{-24298771/25000000000,-11285077/10000000000,0},
{-24298771/25000000000,120551411529/25000000000,-24298771/25000000000},
{11285077/10000000000,120551411529/25000000000,11285077/10000000000},
{11285077/10000000000,0,11285077/10000000000},
{-24298771/25000000000,24298771/25000000000,-24298771/25000000000},
{0,0,0}
};
Then, I use the following CGAL program to generate the convex hull and plane equations. Again, trying to keep things in infinite precision.
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/GMP/Gmpq_type.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/convex_hull_3.h>
#include <CGAL/Side_of_triangle_mesh.h>
#include <CGAL/number_utils.h>
#include <unistd.h>
#include <iomanip>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron_3;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Plane_3 Plane_3;
typedef Kernel::Vector_3 Vector_3;
typedef CGAL::Side_of_triangle_mesh<Polyhedron_3, Kernel> Point_inside;
struct Plane_equation {
template <class Facet>
typename Facet::Plane_3 operator()( Facet& f) {
typename Facet::Halfedge_handle h = f.halfedge();
typedef typename Facet::Plane_3 Plane;
return Plane( h->vertex()->point(),
h->next()->vertex()->point(),
h->next()->next()->vertex()->point());
}
};
Point_3 create_point(std::vector<std::string> points) {
auto x = points[0], y = points[1], z = points[2];
Point_3 p;
std::istringstream input(x + " " + y + " " + z);
input >> p;
return p;
}
std::vector<std::string> create_coords_from_line(std::string line) {
std::vector<std::string> points;
std::istringstream stream(line);
std::string pt;
getline(stream, pt, ' ');
points.push_back(pt);
getline(stream, pt, ' ');
points.push_back(pt);
getline(stream, pt);
points.push_back(pt);
return points;
}
int main() {
std::vector<Point_3> points;
std::string line;
for (auto i = 0; i < 9; ++i) {
getline(std::cin, line);
points.push_back(create_point(create_coords_from_line(line)));
}
Polyhedron_3 poly;
CGAL::convex_hull_3(points.begin(), points.end(), poly);
// CGAL::draw(poly);
std::transform(poly.facets_begin(), poly.facets_end(), poly.planes_begin(), Plane_equation());
CGAL::set_pretty_mode(std::cout);
for (auto it = poly.planes_begin(); it != poly.planes_end(); ++it) {
if (isatty(fileno(stdin))) {
std::cout << "A = " << it->a().exact() << "\n";
std::cout << "B = " << it->b().exact() << "\n";
std::cout << "C = " << it->c().exact() << "\n";
std::cout << "D = " << it->d().exact() << "\n";
std::cout << "\n";
} else {
std::cout << it->a().exact() << " " << it->b().exact() << " "
<< it->c().exact() << " " << it->d().exact() << "\n";
}
}
return EXIT_SUCCESS;
}
Now, in order to make sure that the generated equations are correct and cover all the points, I create a Z3py script. In that, f is the function used to generate the plot, g is the conjunction of all plane equations with proper inequality (<, =, >). Then I check if f ---> g. I use the theory of reals for infinite precision. But it always comes up with a counter-example. And these counter examples are always on some edge of the plane. Here are a couple of pictures where red circle indicates the location of counterexample. This is a different plot from the one above but the process is the same. Just the input values to f is different.
Now, I don't really need infinite precision for my problem. But I would like to make sure that the procedure works with infinite precision so that I can be confident about correctness. But then I tried with CPLEX, which uses only 64-bits, and with that too, counterexamples were generated, in similar fashion to Z3. Here's an example
Now I have no idea in which step of the process am I making a mistake. My suspicion is the selection of initial points for convex hull. It would be great if someone can help me find the convex hull properly. As far as I have read, the convex hull algorithms are exact if infinite precision is used. That's why I didn't use Mathematica's convex hull feature, because it is not using infinite precision.
EDIT: There are two smaller planes which Mathematica is failing to show, as shown below. I want all points on those planes to be selected too. But the endpoints of the smaller planes coincide with the endpoints of larger planes. That's why I have taken only the corners of larger planes.
EDIT 2: Due to the range of y being so large compared to the other two variables, the convex hull generated for the above specified points looks just like a single line.
However, after diving the y values by 1000, we can see a clearer picture.

program that converts spelled out numbers in to its digit form. (c++)

I am trying to make a program that converts numbers in digit form to spelled out numbers, and also from spelled-out numbers in to digit numbers (numbers from 0-10). So far my program can do the digit to spelled-out convertion, but I am not sure how to do it the other way around. I am grateful for any help. This is my code so far:
#include "std_lib_facilities.h"
using namespace std;
int main()
{
vector <string> string_val = {"zeroe","one","two","three","four","five","six","seven" ,"eight","nine"};
int integer =0;
string spelled_integer;
cout<<"Enter a number bethween '0' and '10'\n";
while(cin>>integer)
{
if(integer<10)
cout<<"your number in spelled out form is: "<<string_val[integer] <<'\n';
else
cout<<"your number is either to low, or to big, try again.\n";
}
}
As #pm100 suggested in a comment, an std::map is the perfect solution for you. Here is a sample:
int main()
{
std::map<std::string, int> numbers {
{"zero", 0},
{"one", 1},
{"two", 2}
};
std::cout << numbers["two"];
}
The above sample prints 2. For the other way around (the one you've already done) I would also suggest using a map. They are very powerful containers worth exploring.

Finding which parallel edge was used in a path in a BGL graph?

Can anyone show, with a working example, how one might determine the actual edges used by path obtained from an astar_search() on a graph of type: adjacency_list<multisetS,vecS,directedS,location,route> when parallel edges (multiple routes between the same adjacent source and target vertex) are likely to be present (with different "costs")?
location and route are custom structures that I have as bundled properties for vertices and edges.
I originally was going to use a listS (specifically a std::list) as the type for the outEdgesList but I understand that if I wanted to use out_edge_range(source, target, graph) to retrieve all the edges linking source and target, it needs to be a multisetS (an "ordered set" which permits duplicate values?) - in the worst case I would have to step back through the vertexes of the found path from destination to start, and use the current and previous vertexes with that to recall all the possible edges involved and then pick the one with the lowest "cost" - but that seems a bit non-optimal if the search has already done just that to find the path...!
I am led to believe an edge_predecessor_recorder visitor might be a way to note down the particular edge selected but I have not been able to find a code sample that shows it in use - can that particular visitor even be used on the predecessor map from an A* search?
I should say that I am not totally familiar with the boost libraries - and I'm not that strong on C++ (C: yes, C++: gulp !) The way that the BGL typedefs things and provides some data structures automagically may, indeed, maximise the flexibility to utilise it - but it is a little confusing for the inexperienced (me, for example) to pin down the actual types of elements used or needed for a particular use IMVHO.
I think you're on the right track. This worked for me:
struct location_t { // vertex properties
std::string name;
};
struct route_t { // edge properties
std::size_t distance;
};
typedef adjacency_list<listS,vecS,directedS,location_t,route_t> graph_t;
typedef graph_traits<graph_t>::edge_descriptor edge_t;
typedef graph_traits<graph_t>::vertex_descriptor vertex_t;
struct heuristic {
heuristic(vertex_t dest) : dest_(dest) {}
std::size_t operator()(vertex_t src) {
// only needs to be "optimistic", so:
return (src == dest_) ? 0 : 1 ;
}
private:
vertex_t dest_;
};
typedef std::map<vertex_t, edge_t> pred_edge_map_t;
typedef associative_property_map<pred_edge_map_t> pred_edge_pmap_t;
int main() {
graph_t g;
// insert four vertices and a mix of singular and parallel edges
vertex_t zero = add_vertex(location_t{"A"}, g); // source
vertex_t one = add_vertex(location_t{"B"}, g);
vertex_t two = add_vertex(location_t{"C"}, g);
vertex_t three = add_vertex(location_t{"D"}, g); // sink
// optimal path: 0->2->3 (cost 6)
add_edge(zero, one, route_t{3}, g);
add_edge(zero, one, route_t{5}, g); // parallel to previous edge
add_edge(zero, two, route_t{4}, g);
add_edge(one, three, route_t{4}, g);
add_edge(two, three, route_t{2}, g);
add_edge(two, three, route_t{4}, g); // parallel to previous edge
// construct predecessor map
pred_edge_map_t pred;
pred_edge_pmap_t pred_pmap(pred);
// construct visitor that uses it
auto recorder = record_edge_predecessors(pred_pmap, on_edge_relaxed());
astar_visitor<decltype(recorder)> visitor(recorder);
astar_search(g, zero, heuristic(three),
weight_map(get(&route_t::distance, g)).
visitor(visitor));
// extract route (in reverse order)
for (vertex_t v = three; v != zero; v = source(pred_pmap[v], g)) {
auto e = pred_pmap[v];
std::cout << g[source(e, g)].name << "->" << g[target(e, g)].name << " with weight " << g[pred_pmap[v]].distance << std::endl;
}
}

Boost::geometry::intersection performance in Debug mode

I have a question about boost::geometry::intersection performance in Debug configuration. One part of my project has a lot(millions) of intersections of polygon-polygon kind. And it is very-very slow in debug comparing to release. So I need to wait a lot of time to debug problems after this 'intersection' part. What can I do to speed up it in Debug mode?
Code example of simple Win32 console project in VS2010:
#include "stdafx.h"
#include <time.h>
#include <deque>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/foreach.hpp>
bool get_poly_intersection_area_S_2d( const double *poly_x_1, const int poly_n_1, const double *poly_x_2, const int poly_n_2, double *S)
{
// intersects two 2d polygons using boost::geometry library
// polygons are in 3d format [(x0, y0, 0.0) (x1, y1, 0.0) .... (xn, yn, 0.0) ]
// S is resulting area of intersection
// returns true if intersection exists (area > DBL_EPSILON) and false otherwise
typedef boost::geometry::model::d2::point_xy<double> bg_point;
typedef boost::geometry::model::polygon< bg_point, false, false > bg_polygon;
*S = 0.0;
bg_polygon bg_poly_1, bg_poly_2;
// init boost 2d polygons by our double 3D polygons
for(int i=0; i<poly_n_1; i++)
bg_poly_1.outer().push_back(bg_point(poly_x_1[i*3], poly_x_1[i*3+1]));
for(int i=0; i<poly_n_2; i++)
bg_poly_2.outer().push_back(bg_point(poly_x_2[i*3], poly_x_2[i*3+1]));
// correct polygons
boost::geometry::correct(bg_poly_1);
boost::geometry::correct(bg_poly_2);
// call intersection
std::deque<bg_polygon> output;
bool res = boost::geometry::intersection(bg_poly_1, bg_poly_2, output);
if(!res)
return false;
// for each polygon of intersection we add area
BOOST_FOREACH(bg_polygon const& p, output)
{
double s = boost::geometry::area(p);
*S += s;
}
// no intersection
if(fabs(*S) <= DBL_EPSILON)
return false;
// intersection > DBL_EPSILON
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
double p1[4 * 3] = {0,0,0, 2,0,0, 2,2,0, 0,2,0};
double p2[4 * 3] = {1,1,0, 3,1,0, 3,3,0, 1,3,0};
clock_t start_t, finish_t;
start_t = clock();
for(int i=0;i<5000; i++)
{
double s;
for(int k=0; k<4; k++)
{
p1[k*4] += i;
p2[k*4] += i;
}
get_poly_intersection_area_S_2d(p1, 4, p2, 4, &s);
}
finish_t = clock();
printf("time=%.3f s\n", double(finish_t - start_t)/1000.);
return 0;
}
In Debug it takes 15 seconds, in Release 0.1 seconds. And here only 5000 polygons intersections. For millions it will be much slower.
The Boost.Geometry speed is heavily influenced by the speed of stl (vector, deque, map) which is considerably slower in Debug Mode.
You might try to solve that, e.g. by this links:
Why does my STL code run so slowly when I have the debugger/IDE attached?
Why is this code 100 times slower in debug?
Especially the second link suggests setting _HAS_ITERATOR_DEBUGGING to 0 which might help a lot because iterators are heavily used inside Boost.Geometry
Alternatively you might try using stl port.
The best way is to work out a way to reproduce the problem you are debugging using a small dataset. This helps in MANY ways, especially when creating a regression test when you have solved the problem.
You write: "debug problems after this 'intersection' part "
This suggests to me that you should optionally save the output from the intersection part, so that you need run it only once, and then have an option to load the saved partial result and run the rest of the program from there in debug mode.

Resources