I am trying to use boost's convex_hull algorithm with longitude/latitude coordinates.
From here: https://archive.fosdem.org/2017/schedule/event/geo_boost_geography/attachments/slides/1748/export/events/attachments/geo_boost_geography/slides/1748/FOSDEM17_vissarion.pdf
I can see that we can calculate the distance between two points and even find the area using longitude/latitude coordinates (see page 19 and 22 of the PDF document).
Combining that with https://www.boost.org/doc/libs/1_75_0/libs/geometry/doc/html/geometry/reference/algorithms/convex_hull.html
I came up with this: https://wandbox.org/permlink/2AGPUtHPWrlGFMTf, but it does not compile, code here for convenience:
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
namespace bg = boost::geometry;
int main()
{
typedef bg::model::point<double, 2, bg::cs::geographic<bg::degree>> point;
typedef boost::geometry::model::polygon<point> polygon;
polygon poly;
bg::read_wkt(" POLYGON ((4.346693 50.858306, 4.367945 50.852455, 4.366227 50.840809, 4.344961 50.833264, 4.338074 50.848677,4.346693 50.858306))",
poly );
polygon hull;
boost::geometry::convex_hull(poly, hull);
using boost::geometry::dsv;
std::cout << "polygon: " << dsv(poly) << std::endl << "hull: " << dsv(hull) << std::endl;
}
Any help is much appreciated.
Yeah, though you may be right that a strategy /can/ be made, that is not implemented.
A little side-by-side tester clearly shows that the strategy is not implemented for the geographical coordinate system:
template <typename cs> void test() {
using point = bg::model::point<double, 2, cs>;
using polygon = bg::model::polygon<point>;
polygon poly;
bg::read_wkt("POLYGON((4.346693 50.858306, 4.367945 50.852455, 4.366227 "
"50.840809, 4.344961 50.833264, 4.338074 50.848677,4.346693 "
"50.858306))",
poly);
std::cout << std::fixed;
std::cout << "Polygon: " << bg::dsv(poly) << std::endl;
std::cout << "Perimeter: " << bg::perimeter(poly) << std::endl;
std::cout << "Area: " << bg::area(poly) << std::endl;
using Strategy = typename bg::strategy_convex_hull<polygon, point>::type;
std::cout << "Strategy " << boost::core::demangle(typeid(Strategy).name()) << "\n";
if constexpr (not std::is_same_v<Strategy, bg::strategy::not_implemented>) {
polygon hull;
bg::convex_hull(poly, hull);
std::cout << "Hull: " << bg::dsv(hull) << std::endl;
}
}
It also demonstrates that some other strategies are implemented (e.g. distance).
See it Live On Coliru
int main() {
std::cout << "Cartesian:\n";
std::cout << "----------\n";
test<bg::cs::cartesian>();
std::cout << "\nGeographic:\n";
std::cout << "-----------\n";
test<bg::cs::geographic<bg::degree>>();
}
Simplifying the the typenames in the output:
Cartesian:
----------
Polygon: (((4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677), (4.346693, 50.858306)))
Perimeter: 0.086184
Area: 0.000488
Strategy bg::strategy::convex_hull::graham_andrew<polygon, point>
Hull: (((4.338074, 50.848677), (4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677)))
Geographic:
-----------
Polygon: (((4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677), (4.346693, 50.858306)))
Perimeter: 7663.398262
Area: 3848183.734567
Strategy bg::strategy::not_implemented
A look at the documented strategies suggests that graham_andrew is in fact the only one available.
You should probably find out what tweaks are required to get things to work. it is technically possible to force convex_hull to use the Graham/Andrew strategy, but that seems ill-advised as the trait implies that the strategy is specifically deselected based on the coordinate system:
/*!
\brief Traits class binding a convex hull calculation strategy to a coordinate system
\ingroup convex_hull
\tparam Tag tag of coordinate system
\tparam Geometry the geometry type (hull operates internally per hull over geometry)
\tparam Point point-type of output points
*/
template
<
typename Geometry1,
typename Point,
typename CsTag = typename cs_tag<Point>::type
>
struct strategy_convex_hull
{
typedef strategy::not_implemented type;
};
Digging into the implementation of the strategy here's a hopeful hint:
// TODO: User-defiend CS-specific side strategy
typename strategy::side::services::default_strategy<cs_tag>::type side;
Perhaps we could be "done" with "just" specializing the Side Strategy for your coordinate systems? And more interestingly: a strategy::side::geographic exists. I'm out of my depth understanding the parameters (e.g. what the geodetic solution policy means?), but maybe yourself can take it from there?
I'm convinced that if you know what needs to be done, the helpful devs over at the mailing list will be very willing to guide the technical questions on how to fit it into the library.
Related
I want to use the Efficient Ransac implementation of CGAL, but whenever I try to set my own parameters, the algorithm doesn't detect any shape anymore.
This work is related to the Polyfit implementation in CGAL. I want to fine tune the plane detection to see the influence it has on the algorithm. When I use the standard call to ransac.detect(), it works perfectly. However, when I want to set my own parameters it just doesn't find any plane, even if I set them manually to the default values.
Here is my code, strongly related to this example
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/IO/Writer_OFF.h>
#include <CGAL/property_map.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Shape_detection/Efficient_RANSAC.h>
#include <CGAL/Polygonal_surface_reconstruction.h>
#ifdef CGAL_USE_SCIP
#include <CGAL/SCIP_mixed_integer_program_traits.h>
typedef CGAL::SCIP_mixed_integer_program_traits<double> MIP_Solver;
#elif defined(CGAL_USE_GLPK)
#include <CGAL/GLPK_mixed_integer_program_traits.h>
typedef CGAL::GLPK_mixed_integer_program_traits<double> MIP_Solver;
#endif
#if defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP)
#include <CGAL/Timer.h>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
// Point with normal, and plane index
typedef boost::tuple<Point, Vector, int> PNI;
typedef std::vector<PNI> Point_vector;
typedef CGAL::Nth_of_tuple_property_map<0, PNI> Point_map;
typedef CGAL::Nth_of_tuple_property_map<1, PNI> Normal_map;
typedef CGAL::Nth_of_tuple_property_map<2, PNI> Plane_index_map;
typedef CGAL::Shape_detection::Efficient_RANSAC_traits<Kernel, Point_vector, Point_map, Normal_map> Traits;
typedef CGAL::Shape_detection::Efficient_RANSAC<Traits> Efficient_ransac;
typedef CGAL::Shape_detection::Plane<Traits> Plane;
typedef CGAL::Shape_detection::Point_to_shape_index_map<Traits> Point_to_shape_index_map;
typedef CGAL::Polygonal_surface_reconstruction<Kernel> Polygonal_surface_reconstruction;
typedef CGAL::Surface_mesh<Point> Surface_mesh;
int main(int argc, char ** argv)
{
Point_vector points;
// Loads point set from a file.
const std::string &input_file = argv[1];
//const std::string input_file(input);
std::ifstream input_stream(input_file.c_str());
if (input_stream.fail()) {
std::cerr << "failed open file \'" <<input_file << "\'" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Loading point cloud: " << input_file << "...";
CGAL::Timer t;
t.start();
if (!input_stream ||
!CGAL::read_xyz_points(input_stream,
std::back_inserter(points),
CGAL::parameters::point_map(Point_map()).normal_map(Normal_map())))
{
std::cerr << "Error: cannot read file " << input_file << std::endl;
return EXIT_FAILURE;
}
else
std::cout << " Done. " << points.size() << " points. Time: " << t.time() << " sec." << std::endl;
// Shape detection
Efficient_ransac ransac;
ransac.set_input(points);
ransac.add_shape_factory<Plane>();
std::cout << "Extracting planes...";
t.reset();
// Set parameters for shape detection.
Efficient_ransac::Parameters parameters;
// Set probability to miss the largest primitive at each iteration.
parameters.probability = 0.05;
// Detect shapes with at least 500 points.
parameters.min_points = 100;
// Set maximum Euclidean distance between a point and a shape.
parameters.epsilon = 0.01;
// Set maximum Euclidean distance between points to be clustered.
parameters.cluster_epsilon = 0.01;
// Set maximum normal deviation.
// 0.9 < dot(surface_normal, point_normal);
parameters.normal_threshold = 0.9;
// Detect shapes.
ransac.detect(parameters);
//ransac.detect();
Efficient_ransac::Plane_range planes = ransac.planes();
std::size_t num_planes = planes.size();
std::cout << " Done. " << num_planes << " planes extracted. Time: " << t.time() << " sec." << std::endl;
// Stores the plane index of each point as the third element of the tuple.
Point_to_shape_index_map shape_index_map(points, planes);
for (std::size_t i = 0; i < points.size(); ++i) {
// Uses the get function from the property map that accesses the 3rd element of the tuple.
int plane_index = get(shape_index_map, i);
points[i].get<2>() = plane_index;
}
//////////////////////////////////////////////////////////////////////////
std::cout << "Generating candidate faces...";
t.reset();
Polygonal_surface_reconstruction algo(
points,
Point_map(),
Normal_map(),
Plane_index_map()
);
std::cout << " Done. Time: " << t.time() << " sec." << std::endl;
//////////////////////////////////////////////////////////////////////////
Surface_mesh model;
std::cout << "Reconstructing...";
t.reset();
if (!algo.reconstruct<MIP_Solver>(model)) {
std::cerr << " Failed: " << algo.error_message() << std::endl;
return EXIT_FAILURE;
}
const std::string& output_file(input_file+"_result.off");
std::ofstream output_stream(output_file.c_str());
if (output_stream && CGAL::write_off(output_stream, model))
std::cout << " Done. Saved to " << output_file << ". Time: " << t.time() << " sec." << std::endl;
else {
std::cerr << " Failed saving file." << std::endl;
return EXIT_FAILURE;
}
//////////////////////////////////////////////////////////////////////////
// Also stores the candidate faces as a surface mesh to a file
Surface_mesh candidate_faces;
algo.output_candidate_faces(candidate_faces);
const std::string& candidate_faces_file(input_file+"_candidate_faces.off");
std::ofstream candidate_stream(candidate_faces_file.c_str());
if (candidate_stream && CGAL::write_off(candidate_stream, candidate_faces))
std::cout << "Candidate faces saved to " << candidate_faces_file << "." << std::endl;
return EXIT_SUCCESS;
}
#else
int main(int, char**)
{
std::cerr << "This test requires either GLPK or SCIP.\n";
return EXIT_SUCCESS;
}
#endif // defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP)
When launched, I have the following message:
Loading point cloud: Scene1/test.xyz... Done. 169064 points. Time: 0.428 sec.
Extracting planes... Done. 0 planes extracted. Time: 8.328 sec.
Generating candidate faces... Done. Time: 0.028 sec.
Reconstructing... Failed: at least 4 planes required to reconstruct a closed surface mesh (only 1 provided)
While I have this when launching the code the ransac detection function without parameters:
Loading point cloud: Scene1/test.xyz... Done. 169064 points. Time: 0.448 sec.
Extracting planes... Done. 18 planes extracted. Time: 3.088 sec.
Generating candidate faces... Done. Time: 94.536 sec.
Reconstructing... Done. Saved to Scene1/test.xyz_result.off. Time: 30.28 sec.
Can someone help me setting my own parameters for the ransac shape detection?
However, when I want to set my own parameters it just doesn't find any
plane, even if I set them manually to the default values.
Just to be sure: "setting them manually to the default values" is not what you are doing in the code you shared.
Default values are documented as:
1% of the total number of points for min_points, which should be around 1700 points in your case, not 100
1% of the bounding box diagonal for epsilon and cluster_epsilon. For that obviously I don't know if that is what you used (0.01) as I don't have access to your point set, but if you want to reproduce default values, you should use the CGAL::Bbox_3 object at some point
If you use these values, there's no reason why it should behave differently than with no parameters given (if it does not work, then please let me know because there may be a bug).
I have a problem. I would like to intersect a quad with a quad.
int main(){
typedef boost::geometry::model::point_xy<double> TBoostPoint;
typedef boost::geometry::model::polygon<TBoostPoint> TBoostPoly;
TBoostPoint point;
TBoostPoly firstPoly, secondPoly;
boost::geometry::read_wkt("POLYGON(
(1.504477611940313, 3.761194029850755),
(1.504477611940305, 3.573134328358203),
(1.316417910447765, 3.573134328358206),
(1.316417910447769, 3.761194029850752))", firstPoly);
boost::geometry::read_wkt("POLYGON(
(1.504477611940313, 3.761194029850755),
(1.504477611940305, 3.573134328358203),
(1.316417910447765, 3.573134328358206),
(1.316417910447751, 3.761194029850769))", secondPoly);
std::vector<TBoostPoly> outPoly;
boost::geometry::intersection(firstPoly,secondPoly,outPoly);
}
outPoly - is empty, but it not so.
There were 2 main issues.
The output is undefined because the input is invalid.
The input WKT specifies a lot of invalid inner rings (consisting of single points), instead of what you expected, a single outer ring of 5 points (excl. closing point). Fix it:
bg::read_wkt("POLYGON(( 1.504477611940313 3.761194029850755, 1.504477611940305 3.573134328358203, 1.316417910447765 3.573134328358206, 1.316417910447769 3.761194029850752))", first);
bg::read_wkt("POLYGON(( 1.504477611940313 3.761194029850755, 1.504477611940305 3.573134328358203, 1.316417910447765 3.573134328358206, 1.316417910447751 3.761194029850769))", second);
Boost Geometry assumes throughout that you never make errors against the documented preconditions. If you read in the polygon concept page and preconditions for intersection you'll see thew full list¹.
If you don't, you get no friendly errors, just silent failure, corruption or just wrong answers. Yeah. That's bad.
What's worse, BGeo didn't even have a is_valid facility to test the bulk of requirements until Boost 1_57 (IIRC). The good news is, if you upgrade to this version or later your life will be much simpler.
In this case you would have learned that the polygons weren't properly closed:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/io/io.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/algorithms/correct.hpp>
#include <boost/geometry/algorithms/is_valid.hpp>
namespace bg = boost::geometry;
int main(){
typedef bg::model::d2::point_xy<double> TPoint;
typedef bg::model::polygon<TPoint> TPoly;
TPoly first, second;
bg::read_wkt("POLYGON(( 1.504477611940313 3.761194029850755, 1.504477611940305 3.573134328358203, 1.316417910447765 3.573134328358206, 1.316417910447769 3.761194029850752))", first);
bg::read_wkt("POLYGON(( 1.504477611940313 3.761194029850755, 1.504477611940305 3.573134328358203, 1.316417910447765 3.573134328358206, 1.316417910447751 3.761194029850769))", second);
std::string reason;
// polys not closed!
if (!bg::is_valid(first, reason)) std::cout << "First polygon not valid: " << reason << "\n";
if (!bg::is_valid(second, reason)) std::cout << "Second polygon not valid: " << reason << "\n";
bg::correct(first);
bg::correct(second);
// no more output!
if (!bg::is_valid(first, reason)) std::cout << "First polygon not valid: " << reason << "\n";
if (!bg::is_valid(second, reason)) std::cout << "Second polygon not valid: " << reason << "\n";
std::vector<TPoly> out;
bg::intersection(first, second, out);
for (auto& g : out)
std::cout << "\nresult: " << bg::wkt(g) << "\n";
}
Prints:
First polygon not valid: Geometry is defined as closed but is open
Second polygon not valid: Geometry is defined as closed but is open
Oops. The geos weren't closed! correct(poly) fixes this for us on auto-pilot:
result: POLYGON((1.50448 3.57313,1.31642 3.57313,1.31642 3.76119,1.50448 3.76119,1.50448 3.57313))
¹ outer ring must be counter clockwise, inner cw, polys must be closed... stuff like that.
Good night. Has anyone encountered a similar problem?
Constructing Voronoi diagram has not caused problems. Voronoi cell is a polygon, at least for me. The library also allows you to find the distance from a point to a polygon. But the library function does not want to work with the cell. The compiler produces something in Elvish. Joke. In short, the compiler output can not help me.
Is there a way to make a polygon from the cell?
Voronoi diagram is constructed on vpoints. The program should calculate the distance from the qpoints element to the corresponding cell.
Here is my code:
#include <iostream>
#include <vector>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/polygon/voronoi.hpp>
namespace bg = boost::geometry;
using boost::polygon::voronoi_diagram;
typedef voronoi_diagram<double>::cell_type cell_type;
typedef voronoi_diagram<double>::edge_type edge_type;
typedef voronoi_diagram<double>::vertex_type vertex_type;
typedef boost::polygon::point_data<double> point_type;
using namespace std;
int main() {
vector< point_type > vpoints;
vpoints.push_back(point_type(0.0, 0.0));
vpoints.push_back(point_type(0.0, 4.0));
vpoints.push_back(point_type(4.0, 4.0));
vpoints.push_back(point_type(4.0, 0.0));
vpoints.push_back(point_type(2.0, 2.0));
vector< point_type > qpoints;
qpoints.push_back(point_type(0.0, 0.0));
qpoints.push_back(point_type(0.0, 2.0));
qpoints.push_back(point_type(3.0, 3.0));
qpoints.push_back(point_type(5.0, 5.0));
qpoints.push_back(point_type(5.0, 5.0));
voronoi_diagram<double> vd;
construct_voronoi(vpoints.begin(), vpoints.end(), &vd);
for (int i = 0; i < qpoints.size(); i++) {
for (voronoi_diagram<double>::const_cell_iterator it = vd.cells().begin();
it != vd.cells().end(); ++it) {
if (i == it->source_index()) {
cout << "v[i]=(" << vpoints[i].x() << "," << vpoints[i].y() << ")\t";
cout << "q[i]=(" << qpoints[i].x() << "," << qpoints[i].y() << ")\t";
cout << "Distance=";
cout << bg::distance(qpoints[i], *it) << endl;
cout << endl;
break;
}
}
}
return 0;
}
The message is
boost_1_57_0/boost/geometry/core/geometry_id.hpp|37 col 5| error: no matching function for call to ‘assertion_failed(mpl_::failed************ (boost::geometry::core_dispatch::geometry_id<void>::NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE::************)(mpl_::assert_::types<void, mpl_::na, mpl_::na, mpl_::na>))’
Which is the NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE assert. It happens doing geometry_id for reverse_dispatch:
/*!
\brief Meta-function returning the id of a geometry type
\details The meta-function geometry_id defines a numerical ID (based on
boost::mpl::int_<...> ) for each geometry concept. A numerical ID is
sometimes useful, and within Boost.Geometry it is used for the
reverse_dispatch metafuntion.
\note Used for e.g. reverse meta-function
\ingroup core
*/
template <typename Geometry>
struct geometry_id : core_dispatch::geometry_id<typename tag<Geometry>::type>
{};
The same warning is triggered when you do
cout << distance(qpoints[i], qpoints[i]) << endl;
So the problem is that your point type is not a reqistered geometry. Including
#include <boost/geometry/geometries/adapted/boost_polygon.hpp>
makes that compile, but of course
cout << distance(qpoints[i], *it) << endl;
still fails, this time because const boost::polygon::voronoi_cell<double> isn't a known geometry type to Boost Geometry.
I'd suggest not mixing the libraries unless you know why you want to.
It looks to me that a voronoi cell can be more than just a single thing (contains_segment() and contains_point() are indications). You may have to write some switching logic to handle the possible cases separately, and perhaps use euclidean_distance from Boost Polygon in the process (as opposed to boost::geometry::distance`)
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;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I tried to do this clipping example using Boost Geometry in the example here
But in the newest Boost library I can't find ...
boost/geometry/geometries/cartesian2d.hpp
Does anyone have any idea where I might find this file? Or is this tutorial too old, and the file now obsolete?
The tutorial is too old. Much has changed since that tutorial was written.
Anyhow, I've modified the code in your link above so that it compiles in Boost ver 1.53.0 ...
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>
using namespace boost::geometry;
typedef model::d2::point_xy<double> point;
typedef model::ring< point > ring;
typedef model::polygon< point > polygon;
typedef model::multi_polygon< polygon > polygons;
typedef model::box< point > box;
// Define a polygon and fill the outer ring.
// In most cases you will read it from a file or database
polygon poly;
{
read_wkt("POLYGON((2.0 1.3, 2.4 1.7, 2.8 1.8, 3.4 1.2, 3.7 1.6, \
3.4 2.0, 4.1 3.0, 5.3 2.6, 5.4 1.2, 4.9 0.8, 2.9 0.7, \
2.0 1.3))", poly);
}
// Polygons should be closed, and directed clockwise. If you're not sure if that is the case,
// call the correct algorithm
correct(poly);
// Polygons can be streamed as text
// (or more precisely: as DSV (delimiter separated values))
std::cout << dsv(poly) << std::endl;
// As with lines, bounding box of polygons can be calculated
box b;
envelope(poly, b);
std::cout << dsv(b) << std::endl;
// The area of the polygon can be calulated
std::cout << "area: " << area(poly) << std::endl;
// And the centroid, which is the center of gravity
point cent;
centroid(poly, cent);
std::cout << "centroid: " << dsv(cent) << std::endl;
// The number of points have to called per ring separately
std::cout << "number of points in outer ring: " << poly.outer().size() << std::endl;
// Polygons can have one or more inner rings, also called holes, donuts, islands, interior rings.
// Let's add one
{
poly.inners().resize(1);
ring& inner = poly.inners().back();
read_wkt("POLYGON((4.0 2.0, 4.2 1.4, 4.8 1.9, 4.4 2.2, 4.0 2.0))", inner);
}
correct(poly);
std::cout << "with inner ring:" << dsv(poly) << std::endl;
// The area of the polygon is changed of course
std::cout << "new area of polygon: " << area(poly) << std::endl;
centroid(poly, cent);
std::cout << "new centroid: " << dsv(cent) << std::endl;
// You can test whether points are within a polygon
std::cout << "point in polygon:"
<< " p1: " << (within(make<point>(3.0, 2.0), poly)?"true":"false")
<< " p2: " << (within(make<point>(3.7, 2.0), poly)?"true":"false")
<< " p3: " << (within(make<point>(4.4, 2.0), poly)?"true":"false")
<< std::endl;
// As with linestrings and points, you can derive from polygon to add, for example,
// fill color and stroke color. Or SRID (spatial reference ID). Or Z-value. Or a property map.
// We don't show this here.
// Clip the polygon using a bounding box
box cb(make<point>(1.5, 1.5), make<point>(4.5, 2.5));
polygons v;
intersection(cb, poly, v);
std::cout << "Clipped output polygons" << std::endl;
for (polygons::const_iterator it = v.begin(); it != v.end(); ++it)
{
std::cout << dsv(*it) << std::endl;
}
union_(cb, poly, v);
polygon hull;
convex_hull(poly, hull);
std::cout << "Convex hull:" << dsv(hull) << std::endl;
// If you really want:
// You don't have to use a vector, you can define a polygon with a deque
// You can specify the container for the points and for the inner rings independently
typedef model::polygon<point, true, true, std::vector, std::deque> polygon_deq;
polygon_deq poly2;
polygon_deq::ring_type& r = poly2.outer();
append(r, make<point>(2.8, 1.9));
append(r, make<point>(2.9, 2.4));
append(r, make<point>(3.3, 2.2));
append(r, make<point>(3.2, 1.8));
append(r, make<point>(2.8, 1.9));
std::cout << dsv(poly2) << std::endl;