3

I am trying to calculate distance between a point and a line segment. But the following code terminates during runtime abruptly (@comparable_distance).

using namespace std;
namespace bg = boost::geometry;

class Vertex {
public:
    Vertex(int px, int py):x(px), y(py){}
    int x;
    int y;
};

BOOST_GEOMETRY_REGISTER_POINT_2D(Vertex, double, cs::cartesian, x, y)

typedef Vertex* vertref;

typedef bg::model::segment<vertref> segment_type;

std::vector<segment_type> segments;

int main()
{
    segment_type l(new Vertex(1,2), new Vertex(2,2));
    Vertex p(4,5);
    double comp_dist = 0;
    comp_dist = bg::comparable_distance(p, l);

    cout<<comp_dist<<endl;

    return 0;
}

If I replace bg::model::segment with linestring; add two points to it, it works without any error as in below ...

using namespace std;
namespace bg = boost::geometry;

class Vertex {
public:
    Vertex(int px, int py):x(px), y(py){}
    int x;
    int y;
};

BOOST_GEOMETRY_REGISTER_POINT_2D(Vertex, double, cs::cartesian, x, y)

typedef Vertex* vertref;

typedef bg::model::linestring<vertref> segment_type;

std::vector<segment_type> segments;

int main()
{
    segment_type l;
    l.push_back(new Vertex(1,2));
    l.push_back(new Vertex(2,2));
    Vertex p(4,5);
    double comp_dist = 0;
    comp_dist = bg::comparable_distance(p, l);

    cout<<comp_dist<<endl;

    return 0;
}

Any ideas what I am doing wrong in the first code using segment?

Thanks!

Call Stack ...

#0 0x40486f boost::geometry::traits::access<Vertex, 0u, void>::set(p=..., value=@0x63fde8: 1) (C:\Projects\test\main.cpp:17)
#1 0x403e14 boost::geometry::core_dispatch::access<boost::geometry::point_tag, Vertex, double, 0u, boost::integral_constant<bool, true> >::set(p=0x77b12580, value=@0x63fde8: 1) (C:/boost_1_68_0/boost/geometry/core/access.hpp:187)
#2 0x404182 boost::geometry::set<0u, Vertex*>(geometry=@0x63fe34: 0x77b12580, value=@0x63fde8: 1, dummy=0x0) (C:/boost_1_68_0/boost/geometry/core/access.hpp:321)
#3 0x40469a boost::geometry::detail::assign::assign_point_from_index<boost::geometry::model::segment<Vertex*>, Vertex*, 0u, 0u, 2u>::apply(geometry=..., point=@0x63fe34: 0x77b12580) (C:/boost_1_68_0/boost/geometry/algorithms/detail/assign_values.hpp:195)
#4 0x4045de boost::geometry::detail::assign_point_from_index<0u, Vertex*, boost::geometry::model::segment<Vertex*> >(geometry=..., point=@0x63fe34: 0x77b12580) (C:/boost_1_68_0/boost/geometry/algorithms/detail/assign_indexed_point.hpp:80)
#5 0x4049fc boost::geometry::dispatch::distance<Vertex, boost::geometry::model::segment<Vertex*>, boost::geometry::strategy::distance::projected_point<void, boost::geometry::strategy::distance::comparable::pythagoras<void> >, boost::geometry::point_tag, boost::geometry::segment_tag, boost::geometry::strategy_tag_distance_point_segment, false>::apply(point=..., segment=..., strategy=...) (C:/boost_1_68_0/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp:419)
#6 0x403f9b boost::geometry::resolve_strategy::comparable_distance::apply<Vertex, boost::geometry::model::segment<Vertex*> >(geometry1=..., geometry2=...) (C:/boost_1_68_0/boost/geometry/algorithms/detail/comparable_distance/interface.hpp:83)
#7 0x403f38 boost::geometry::resolve_variant::comparable_distance<Vertex, boost::geometry::model::segment<Vertex*> >::apply<boost::geometry::default_strategy>(geometry1=..., geometry2=..., strategy=...) (C:/boost_1_68_0/boost/geometry/algorithms/detail/comparable_distance/interface.hpp:106)
#8 0x403ff5 boost::geometry::comparable_distance<Vertex, boost::geometry::model::segment<Vertex*>, boost::geometry::default_strategy>(geometry1=..., geometry2=..., strategy=...) (C:/boost_1_68_0/boost/geometry/algorithms/detail/comparable_distance/interface.hpp:328)
#9 0x403fc9 boost::geometry::comparable_distance<Vertex, boost::geometry::model::segment<Vertex*> >(geometry1=..., geometry2=...) (C:/boost_1_68_0/boost/geometry/algorithms/detail/comparable_distance/interface.hpp:356)
#10 0x401518    main() (C:\Projects\test\main.cpp:30)
Bhupen
  • 891
  • 1
  • 8
  • 23

1 Answers1

3

The Segment Concept is modeled by model::segment, which takes a template parameter that models a Point.

Now you used:

typedef Vertex *vertref;

typedef bg::model::segment<vertref> segment_type;

Note that vertref does not in fact model the Point concept. So, by contrast, consider:

Live On Coliru

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <iostream>
namespace bg = boost::geometry;

struct Vertex {
    double x;
    double y;
};

BOOST_GEOMETRY_REGISTER_POINT_2D(Vertex, double, bg::cs::cartesian, x, y)

typedef bg::model::segment<Vertex> segment_type;

int main() {
    segment_type l({1, 2}, {2, 2});
    Vertex p {4, 5};

    auto comp_dist = bg::comparable_distance(p, l);

    std::cout << comp_dist << "\n";
}

Prints:

13

Indeed 13 is the square of the actual distance: enter image description here

BONUS

In response to the comment, yes there's even an out-of-the-box model for segments referring to points (from other geometries). Here's how to use referring_segment<>:

Live On Coliru

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <iostream>
namespace bg = boost::geometry;

struct Vertex {
    double x;
    double y;
};

BOOST_GEOMETRY_REGISTER_POINT_2D(Vertex, double, bg::cs::cartesian, x, y)

typedef bg::model::referring_segment<Vertex> segment_type;

int main() {
    Vertex A{1,2},
           B{2,2};
    segment_type l(A, B);
    Vertex p {4, 5};

    std::cout << bg::distance(p, l) << "\n";

    bg::multiply_value(A, -1);
    bg::multiply_value(B, -1);
    std::cout << bg::distance(p, l) << "\n";
}

Which prints distance before and after mutation:

3.60555
8.60233

Again this matches what you'd expect to see:enter image description here

Notes:

  1. using new in C++ is almost always a mistake. This mistake is most often made by beginners coming from garbage-collected languages like Java or C# (Why should C++ programmers minimize use of 'new'?)
  2. there was an inconsistency of types (the members x, y were ints)
sehe
  • 328,274
  • 43
  • 416
  • 565
  • Thanks for the reply @sehe. Why I needed a reference was to keep the point list in some other container. So when I update the points, the distance also gets updated. I am able to do that using linestring. Can I use reference somehow here? – Bhupen Oct 26 '18 at 23:34
  • Sure just use the `referring_segment` model listed from that [concept doc]() I linked. See it **[Live On Coliru](http://coliru.stacked-crooked.com/a/4049f963a687d8d2)**. Will update the answer. – sehe Oct 26 '18 at 23:48
  • Done. Threw in [more cute graphics](https://i.stack.imgur.com/h99A5.png) (credits to Geogebra) – sehe Oct 26 '18 at 23:51
  • 1
    Thanks again! I am like a guy using an assault rifle who is not qualified to use a hammer. I need to delete java/python programming from my head and relearn C++. – Bhupen Oct 26 '18 at 23:57
  • Ok one last silly question :D ... these points are to be generated dynamically throughout the program (user clicking on screen)... how do I do that without using dynamic memory? – Bhupen Oct 27 '18 at 00:23
  • By assigning to A / B from that code. Although you might very well use dynamic allocation (`vector` would do fine, again, no need to use `new`). Because it seems to me that you wouldn't really have a segment if the endpoints don't exist yet. E.g.: [Live On Coliru](http://coliru.stacked-crooked.com/a/3a6f86b159752882) which puts user input into a circular-buffer of two points, and the `line` is initialized to refer to those as soon as the buffer is valid. – sehe Oct 27 '18 at 00:56
  • Honestly, points are just a POD of two values, it's likely to be more efficient to just do [a new segment each time](http://coliru.stacked-crooked.com/a/33c39dc90e913f54). Simpler code is easier to maintain, and often easier for the compiler to optimize (see [Godbolt](https://github.com/mattgodbolt/compiler-explorer)) https://i.imgur.com/7FsFKnd.png – sehe Oct 27 '18 at 01:11
  • I somehow forgot to mention that this kind of program seems an odd fit for C++. Instead, make some nice UI in, say, Python + Qt and then implement the hard-core algorithms in a C++ extension, if you need it – sehe Oct 27 '18 at 01:18
  • thanks i got some idea ... [coliru](http://coliru.stacked-crooked.com/a/2a535d4cd69bc6ec) ... let me know if this looks good (it works and i think u'll like that i used shared_ptr :D) – Bhupen Oct 27 '18 at 01:19
  • I am trying out some cloth simulations and with python i got like .1 frames per second ... if i have to goto cython, its better i use c++ – Bhupen Oct 27 '18 at 01:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/182621/discussion-between-sehe-and-bhupen). – sehe Oct 27 '18 at 01:23