Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delaunay from Voronoi with boost: missing triangle with non-integral point coordinates

Following this two resources:

  • Boost basic tutorial
  • SO Question

I wrote a Delaunay triangulation with boost. It works fine if the points coordinates are integral (I generated several random tests and I did not observed error). However if the points are non integral I found many incorrect triangulations with missing edges or wrong edges.

For example this image has been build with rounded value and is correct (see code below)

enter image description here

But this image as been build with raw values and is incorrect (see code below)

enter image description here

This code reproduce this two examples (without the display).

#include <boost/polygon/voronoi.hpp>
using boost::polygon::voronoi_builder;
using boost::polygon::voronoi_diagram;

struct Point
{
  double a;
  double b;
  Point(double x, double y) : a(x), b(y) {}
};

namespace boost
{
  namespace polygon
  {
    template <>
    struct geometry_concept<Point>
    {
      typedef point_concept type;
    };

    template <>
    struct point_traits<Point>
    {
      typedef double coordinate_type;

      static inline coordinate_type get(const Point& point, orientation_2d orient)
      {
        return (orient == HORIZONTAL) ? point.a : point.b;
      }
    };
  }  // polygon
}  // boost

int main()
{ 

 std::vector<double> xx = {8.45619987, 9.96573889, 0.26574428, 7.63918524, 8.15187618, 0.09100718};
 std::vector<double> yy = {9.2452883, 7.0843455, 0.4811701, 3.1193826, 5.1336435, 5.5368374};

 // std::vector<double> xx = {8, 10, 0, 8, 8, 0};
 // std::vector<double> yy = {9, 7, 0, 3, 5, 6};

  std::vector<Point> points;

  for (int i = 0 ; i < xx.size() ; i++)
  {
    points.push_back(Point(xx[i], yy[i]));
  }

  // Construction of the Voronoi Diagram.
  voronoi_diagram<double> vd;
  construct_voronoi(points.begin(), points.end(), &vd);

  for (const auto& vertex: vd.vertices())
  {
    std::vector<Point> triangle;
    auto edge = vertex.incident_edge();
    do
    {
      auto cell = edge->cell();
      assert(cell->contains_point());

      triangle.push_back(points[cell->source_index()]);
      if (triangle.size() == 3)
      {   
        // process output triangles
        std::cout << "Got triangle: (" << triangle[0].a << " " << triangle[0].b << ") (" << triangle[1].a << " " << triangle[1].b << ") (" << triangle[2].a << " " << triangle[2].b << ")" << std::endl;
        triangle.erase(triangle.begin() + 1);
      }

      edge = edge->rot_next();
    } while (edge != vertex.incident_edge());
  }

  return 0;
}
like image 639
JRR Avatar asked Jun 02 '18 14:06

JRR


1 Answers

It works fine if the points coordinates are not decimal

After playing around with your sample I suddenly realized you didn't mean "when the coordinates are not decimal". You meant "integral". Big difference.

Documentation: Point Concept

The coordinate type is expected to be integral

and

Floating point coordinate types are not supported by all the algorithms and generally not suitable for use with the library at present.

like image 141
sehe Avatar answered Sep 22 '22 08:09

sehe