37#include "ompl/extensions/triangle/TriangularDecomposition.h"
38#include "ompl/base/State.h"
39#include "ompl/base/StateSampler.h"
40#include "ompl/base/spaces/RealVectorBounds.h"
41#include "ompl/control/planners/syclop/Decomposition.h"
42#include "ompl/control/planners/syclop/GridDecomposition.h"
43#include "ompl/util/RandomNumbers.h"
44#include "ompl/util/Hash.h"
45#include "ompl/util/String.h"
51#include <unordered_map>
58#define ANSI_DECLARATORS
65 struct hash<ompl::control::TriangularDecomposition::Vertex>
67 size_t operator()(
const ompl::control::TriangularDecomposition::Vertex &v)
const
69 std::size_t hash = std::hash<double>()(v.x);
70 ompl::hash_combine(hash, v.y);
77 std::vector<Polygon> holes,
78 std::vector<Polygon> intRegs)
80 , holes_(
std::move(holes))
81 , intRegs_(
std::move(intRegs))
89ompl::control::TriangularDecomposition::~TriangularDecomposition() =
default;
91void ompl::control::TriangularDecomposition::setup()
93 int numTriangles = createTriangles();
98void ompl::control::TriangularDecomposition::addHole(
const Polygon &hole)
100 holes_.push_back(hole);
103void ompl::control::TriangularDecomposition::addRegionOfInterest(
const Polygon ®ion)
105 intRegs_.push_back(region);
108int ompl::control::TriangularDecomposition::getNumHoles()
const
110 return holes_.size();
113int ompl::control::TriangularDecomposition::getNumRegionsOfInterest()
const
115 return intRegs_.size();
118const std::vector<ompl::control::TriangularDecomposition::Polygon> &
119ompl::control::TriangularDecomposition::getHoles()
const
124const std::vector<ompl::control::TriangularDecomposition::Polygon> &
125ompl::control::TriangularDecomposition::getAreasOfInterest()
const
142 tri.volume = 0.5 * ((tri.pts[0].x - tri.pts[2].x) * (tri.pts[1].y - tri.pts[0].y) -
143 (tri.pts[0].x - tri.pts[1].x) * (tri.pts[2].y - tri.pts[0].y));
150 neighbors = triangles_[triID].neighbors;
155 std::vector<double> coord(2);
157 const std::vector<int> &gridTriangles = locator.locateTriangles(s);
159 for (
int triID : gridTriangles)
161 if (triContains(triangles_[triID], coord))
164 OMPL_WARN(
"Decomposition space coordinate (%f,%f) is somehow contained by multiple triangles. \
165 This can happen if the coordinate is located exactly on a triangle segment.\n",
177 const Triangle &tri = triangles_[triID];
181 coord[0] = (1 - r1) * tri.pts[0].x + r1 * (1 - r2) * tri.pts[1].x + r1 * r2 * tri.pts[2].x;
182 coord[1] = (1 - r1) * tri.pts[0].y + r1 * (1 - r2) * tri.pts[1].y + r1 * r2 * tri.pts[2].y;
185void ompl::control::TriangularDecomposition::print(std::ostream &out)
const
192 for (
unsigned int i = 0; i < triangles_.size(); ++i)
195 const Triangle &tri = triangles_[i];
196 for (
int v = 0; v < 3; ++v)
197 out << tri.pts[v].x <<
" " << tri.pts[v].y <<
" ";
198 if (intRegInfo_[i] > -1)
199 out << intRegInfo_[i] <<
" ";
200 out <<
"-1" << std::endl;
204ompl::control::TriangularDecomposition::Vertex::Vertex(
double vx,
double vy) : x(vx), y(vy)
208bool ompl::control::TriangularDecomposition::Vertex::operator==(
const Vertex &v)
const
210 return x == v.x && y == v.y;
219 const double maxTriangleArea = bounds.getVolume() * triAreaPct_;
220 std::string triswitches =
"pDznQA -a" +
ompl::toString(maxTriangleArea);
221 struct triangulateio in;
229 std::unordered_map<Vertex, int> pointIndex;
232 pointIndex[
Vertex(bounds.low[0], bounds.low[1])] = 0;
233 pointIndex[
Vertex(bounds.high[0], bounds.low[1])] = 1;
234 pointIndex[
Vertex(bounds.high[0], bounds.high[1])] = 2;
235 pointIndex[
Vertex(bounds.low[0], bounds.high[1])] = 3;
240 in.numberofpoints = 4;
241 in.numberofsegments = 4;
244 for (
auto &p : holes_)
246 for (
auto &pt : p.pts)
248 ++in.numberofsegments;
251 if (pointIndex.find(pt) == pointIndex.end())
252 pointIndex[pt] = in.numberofpoints++;
258 for (
auto &p : intRegs_)
260 for (
auto &pt : p.pts)
262 ++in.numberofsegments;
263 if (pointIndex.find(pt) == pointIndex.end())
264 pointIndex[pt] = in.numberofpoints++;
269 in.pointlist = (REAL *)malloc(2 * in.numberofpoints *
sizeof(REAL));
272 for (
const auto &i : pointIndex)
274 const Vertex &v = i.first;
275 int index = i.second;
276 in.pointlist[2 * index] = v.x;
277 in.pointlist[2 * index + 1] = v.y;
282 in.segmentlist = (
int *)malloc(2 * in.numberofsegments *
sizeof(
int));
285 for (
int i = 0; i < 4; ++i)
287 in.segmentlist[2 * i] = i;
288 in.segmentlist[2 * i + 1] = (i + 1) % 4;
297 for (
auto &p : holes_)
299 for (
unsigned int j = 0; j < p.pts.size(); ++j)
301 in.segmentlist[2 * segIndex] = pointIndex[p.pts[j]];
302 in.segmentlist[2 * segIndex + 1] = pointIndex[p.pts[(j + 1) % p.pts.size()]];
309 for (
auto &p : intRegs_)
311 for (
unsigned int j = 0; j < p.pts.size(); ++j)
313 in.segmentlist[2 * segIndex] = pointIndex[p.pts[j]];
314 in.segmentlist[2 * segIndex + 1] = pointIndex[p.pts[(j + 1) % p.pts.size()]];
322 in.numberofholes = holes_.size();
323 in.holelist =
nullptr;
324 if (in.numberofholes > 0)
328 in.holelist = (REAL *)malloc(2 * in.numberofholes *
sizeof(REAL));
329 for (
int i = 0; i < in.numberofholes; ++i)
331 Vertex v = getPointInPoly(holes_[i]);
332 in.holelist[2 * i] = v.x;
333 in.holelist[2 * i + 1] = v.y;
340 in.numberofregions = intRegs_.size();
341 in.regionlist =
nullptr;
342 if (in.numberofregions > 0)
348 in.regionlist = (REAL *)malloc(4 * in.numberofregions *
sizeof(REAL));
349 for (
unsigned int i = 0; i < intRegs_.size(); ++i)
351 Vertex v = getPointInPoly(intRegs_[i]);
352 in.regionlist[4 * i] = v.x;
353 in.regionlist[4 * i + 1] = v.y;
356 in.regionlist[4 * i + 2] = (REAL)(i + 1);
357 in.regionlist[4 * i + 3] = -1.;
362 in.segmentmarkerlist = (
int *)
nullptr;
363 in.numberofpointattributes = 0;
364 in.pointattributelist =
nullptr;
365 in.pointmarkerlist =
nullptr;
368 struct triangulateio out;
369 out.pointlist = (REAL *)
nullptr;
370 out.pointattributelist = (REAL *)
nullptr;
371 out.pointmarkerlist = (
int *)
nullptr;
372 out.trianglelist = (
int *)
nullptr;
373 out.triangleattributelist = (REAL *)
nullptr;
374 out.neighborlist = (
int *)
nullptr;
375 out.segmentlist = (
int *)
nullptr;
376 out.segmentmarkerlist = (
int *)
nullptr;
377 out.edgelist = (
int *)
nullptr;
378 out.edgemarkerlist = (
int *)
nullptr;
379 out.pointlist = (REAL *)
nullptr;
380 out.pointattributelist = (REAL *)
nullptr;
381 out.trianglelist = (
int *)
nullptr;
382 out.triangleattributelist = (REAL *)
nullptr;
385 triangulate(
const_cast<char *
>(triswitches.c_str()), &in, &out,
nullptr);
387 triangles_.resize(out.numberoftriangles);
389 for (
int i = 0; i < out.numberoftriangles; ++i)
392 for (
int j = 0; j < 3; ++j)
394 t.pts[j].x = out.pointlist[2 * out.trianglelist[3 * i + j]];
395 t.pts[j].y = out.pointlist[2 * out.trianglelist[3 * i + j] + 1];
396 if (out.neighborlist[3 * i + j] >= 0)
397 t.neighbors.push_back(out.neighborlist[3 * i + j]);
401 if (in.numberofregions > 0)
403 auto attribute = (int)out.triangleattributelist[i];
405 intRegInfo_[i] = (attribute > 0 ? attribute - 1 : -1);
409 trifree(in.pointlist);
410 trifree(in.segmentlist);
411 if (in.numberofholes > 0)
412 trifree(in.holelist);
413 if (in.numberofregions > 0)
414 trifree(in.regionlist);
415 trifree(out.pointlist);
416 trifree(out.pointattributelist);
417 trifree(out.pointmarkerlist);
418 trifree(out.trianglelist);
419 trifree(out.triangleattributelist);
420 trifree(out.neighborlist);
421 trifree(out.edgelist);
422 trifree(out.edgemarkerlist);
423 trifree(out.segmentlist);
424 trifree(out.segmentmarkerlist);
426 return out.numberoftriangles;
429void ompl::control::TriangularDecomposition::LocatorGrid::buildTriangleMap(
const std::vector<Triangle> &triangles)
431 regToTriangles_.resize(getNumRegions());
432 std::vector<double> bboxLow(2);
433 std::vector<double> bboxHigh(2);
434 std::vector<int> gridCoord[2];
435 for (
unsigned int i = 0; i < triangles.size(); ++i)
439 const Triangle &tri = triangles[i];
440 bboxLow[0] = tri.pts[0].x;
441 bboxLow[1] = tri.pts[0].y;
442 bboxHigh[0] = bboxLow[0];
443 bboxHigh[1] = bboxLow[1];
445 for (
int j = 1; j < 3; ++j)
447 if (tri.pts[j].x < bboxLow[0])
448 bboxLow[0] = tri.pts[j].x;
449 else if (tri.pts[j].x > bboxHigh[0])
450 bboxHigh[0] = tri.pts[j].x;
451 if (tri.pts[j].y < bboxLow[1])
452 bboxLow[1] = tri.pts[j].y;
453 else if (tri.pts[j].y > bboxHigh[1])
454 bboxHigh[1] = tri.pts[j].y;
459 coordToGridCoord(bboxLow, gridCoord[0]);
460 coordToGridCoord(bboxHigh, gridCoord[1]);
464 std::vector<int> c(2);
465 for (
int x = gridCoord[0][0]; x <= gridCoord[1][0]; ++x)
467 for (
int y = gridCoord[0][1]; y <= gridCoord[1][1]; ++y)
471 int cellID = gridCoordToRegion(c);
472 regToTriangles_[cellID].push_back(i);
478void ompl::control::TriangularDecomposition::buildLocatorGrid()
480 locator.buildTriangleMap(triangles_);
483bool ompl::control::TriangularDecomposition::triContains(
const Triangle &tri,
const std::vector<double> &coord)
485 for (
int i = 0; i < 3; ++i)
489 const double ax = tri.pts[i].x;
490 const double ay = tri.pts[i].y;
491 const double bx = tri.pts[(i + 1) % 3].x;
492 const double by = tri.pts[(i + 1) % 3].y;
495 if ((coord[0] - ax) * (by - ay) - (bx - ax) * (coord[1] - ay) > 0.)
501ompl::control::TriangularDecomposition::Vertex
502ompl::control::TriangularDecomposition::getPointInPoly(
const Polygon &poly)
507 for (
auto pt : poly.pts)
512 p.x /= poly.pts.size();
513 p.y /= poly.pts.size();
Random number generation. An instance of this class cannot be used by multiple threads at once (membe...
double uniform01()
Generate a random real between 0 and 1.
The lower and upper bounds for an Rn space.
Definition of an abstract state.
Decomposition(int dim, const base::RealVectorBounds &b)
Constructor. Creates a Decomposition with a given dimension and a given set of bounds....
virtual void project(const base::State *s, std::vector< double > &coord) const =0
Project a given State to a set of coordinates in R^k, where k is the dimension of this Decomposition.
virtual const base::RealVectorBounds & getBounds() const
Returns the bounds of this Decomposition.
TriangularDecomposition(const base::RealVectorBounds &bounds, std::vector< Polygon > holes=std::vector< Polygon >(), std::vector< Polygon > intRegs=std::vector< Polygon >())
Creates a TriangularDecomposition over the given bounds, which must be 2-dimensional....
int locateRegion(const base::State *s) const override
Returns the index of the region containing a given State. Most often, this is obtained by first calli...
virtual int createTriangles()
Helper method to triangulate the space and return the number of triangles.
std::vector< int > intRegInfo_
Maps from triangle ID to index of Polygon in intReg_ that contains the triangle ID....
int getRegionOfInterestAt(int triID) const
Returns the region of interest that contains the given triangle ID. Returns -1 if the triangle ID is ...
void sampleFromRegion(int triID, RNG &rng, std::vector< double > &coord) const override
Samples a projected coordinate from a given region.
void getNeighbors(int triID, std::vector< int > &neighbors) const override
Stores a given region's neighbors into a given vector.
double getRegionVolume(int triID) override
Returns the volume of a given region in this Decomposition.
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
std::string toString(float val)
convert float to string using classic "C" locale semantics