diff --git a/src/Mod/Path/App/VoronoiCellPy.xml b/src/Mod/Path/App/VoronoiCellPy.xml index dd57e44332..8a317a91bf 100644 --- a/src/Mod/Path/App/VoronoiCellPy.xml +++ b/src/Mod/Path/App/VoronoiCellPy.xml @@ -36,10 +36,16 @@ - Returns the index of the cell's source + Returns the cell's category as an integer + + + Returns the cell's category as a string + + + Incident edge of the cell - if exists diff --git a/src/Mod/Path/App/VoronoiCellPyImp.cpp b/src/Mod/Path/App/VoronoiCellPyImp.cpp index 319c084041..b338f0c9cf 100644 --- a/src/Mod/Path/App/VoronoiCellPyImp.cpp +++ b/src/Mod/Path/App/VoronoiCellPyImp.cpp @@ -137,6 +137,21 @@ Py::Int VoronoiCellPy::getSourceCategory(void) const return Py::Int(c->ptr->source_category()); } +Py::String VoronoiCellPy::getSourceCategoryName(void) const +{ + VoronoiCell *c = getVoronoiCellFromPy(this); + switch (c->ptr->source_category()) { + case boost::polygon::SOURCE_CATEGORY_SINGLE_POINT: return Py::String("SINGLE_POINT"); + case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT: return Py::String("SEGMENT_START_POINT"); + case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT: return Py::String("SEGMENT_END_POINT"); + case boost::polygon::SOURCE_CATEGORY_INITIAL_SEGMENT: return Py::String("INITIAL_SEGMENT"); + case boost::polygon::SOURCE_CATEGORY_REVERSE_SEGMENT: return Py::String("REVERSE_SEGMENT"); + case boost::polygon::SOURCE_CATEGORY_GEOMETRY_SHIFT: return Py::String("GEOMETRY_SHIFT"); + case boost::polygon::SOURCE_CATEGORY_BITMASK: return Py::String("BITMASK"); + } + return Py::String(""); +} + Py::Object VoronoiCellPy::getIncidentEdge(void) const { VoronoiCell *c = getVoronoiCellFromPy(this); diff --git a/src/Mod/Path/App/VoronoiEdgePy.xml b/src/Mod/Path/App/VoronoiEdgePy.xml index bce837524d..db36d4d547 100644 --- a/src/Mod/Path/App/VoronoiEdgePy.xml +++ b/src/Mod/Path/App/VoronoiEdgePy.xml @@ -100,6 +100,11 @@ Returns true if edge goes through endpoint of the segment site + + + Returns true if the point is on the segment + + Returns a shape for the edge diff --git a/src/Mod/Path/App/VoronoiEdgePyImp.cpp b/src/Mod/Path/App/VoronoiEdgePyImp.cpp index a99f53d152..3684ad85f8 100644 --- a/src/Mod/Path/App/VoronoiEdgePyImp.cpp +++ b/src/Mod/Path/App/VoronoiEdgePyImp.cpp @@ -39,7 +39,6 @@ #include "VoronoiVertex.h" #include "VoronoiVertexPy.h" - using namespace Path; namespace { @@ -164,6 +163,22 @@ namespace { return false; } + bool pointsMatch(const Voronoi::point_type &p0, const Voronoi::point_type &p1, double scale) { + return 1e-6 > distanceBetween(p0, p1, scale); + } + + bool isPointOnSegment(const Voronoi::point_type &point, const Voronoi::segment_type &segment, double scale) { + return pointsMatch(point, low(segment), scale) || pointsMatch(point, high(segment), scale); + } + + template + PyObject* makeLineSegment(const VoronoiEdge *e, const T &p0, double z0, const T &p1, double z1) { + Part::GeomLineSegment p; + p.setPoints(e->dia->scaledVector(p0, z0), e->dia->scaledVector(p1, z1)); + Handle(Geom_Curve) h = Handle(Geom_Curve)::DownCast(p.handle()); + BRepBuilderAPI_MakeEdge mkBuilder(h, h->FirstParameter(), h->LastParameter()); + return new Part::TopoShapeEdgePy(new Part::TopoShape(mkBuilder.Shape())); + } } std::ostream& operator<<(std::ostream& os, const Voronoi::vertex_type &v) { @@ -388,6 +403,21 @@ PyObject* VoronoiEdgePy::isSecondary(PyObject *args) return chk; } +PyObject* VoronoiEdgePy::isBorderline(PyObject *args) +{ + VoronoiEdge *e = getVoronoiEdgeFromPy(this, args); + PyObject *chk = Py_False; + if (e->isBound() && !e->ptr->is_linear()) { + Voronoi::point_type point = e->ptr->cell()->contains_point() ? e->dia->retrievePoint(e->ptr->cell()) : e->dia->retrievePoint(e->ptr->twin()->cell()); + Voronoi::segment_type segment = e->ptr->cell()->contains_point() ? e->dia->retrieveSegment(e->ptr->twin()->cell()) : e->dia->retrieveSegment(e->ptr->cell()); + if (isPointOnSegment(point, segment, e->dia->getScale())) { + chk = Py_True; + } + } + Py_INCREF(chk); + return chk; +} + PyObject* VoronoiEdgePy::toShape(PyObject *args) { double z0 = 0.0; @@ -406,11 +436,7 @@ PyObject* VoronoiEdgePy::toShape(PyObject *args) auto v0 = e->ptr->vertex0(); auto v1 = e->ptr->vertex1(); if (v0 && v1) { - Part::GeomLineSegment p; - p.setPoints(e->dia->scaledVector(*v0, z0), e->dia->scaledVector(*v1, z1)); - Handle(Geom_Curve) h = Handle(Geom_Curve)::DownCast(p.handle()); - BRepBuilderAPI_MakeEdge mkBuilder(h, h->FirstParameter(), h->LastParameter()); - return new Part::TopoShapeEdgePy(new Part::TopoShape(mkBuilder.Shape())); + return makeLineSegment(e, *v0, z0, *v1, z1); } } else { // infinite linear, need to clip somehow @@ -455,11 +481,7 @@ PyObject* VoronoiEdgePy::toShape(PyObject *args) end.x(origin.x() + direction.x() * k); end.y(origin.y() + direction.y() * k); } - Part::GeomLineSegment p; - p.setPoints(e->dia->scaledVector(begin, z0), e->dia->scaledVector(end, z1)); - Handle(Geom_Curve) h = Handle(Geom_Curve)::DownCast(p.handle()); - BRepBuilderAPI_MakeEdge mkBuilder(h, h->FirstParameter(), h->LastParameter()); - return new Part::TopoShapeEdgePy(new Part::TopoShape(mkBuilder.Shape())); + return makeLineSegment(e, begin, z0, end, z1); } } else { // parabolic curve, which is always formed by a point and an edge @@ -467,6 +489,11 @@ PyObject* VoronoiEdgePy::toShape(PyObject *args) Voronoi::segment_type segment = e->ptr->cell()->contains_point() ? e->dia->retrieveSegment(e->ptr->twin()->cell()) : e->dia->retrieveSegment(e->ptr->cell()); // the location is the mid point between the normal on the segment through point // this is only the mid point of the segment if the parabola is symmetric + + if (isPointOnSegment(point, segment, e->dia->getScale())) { + return makeLineSegment(e, low(segment), z0, high(segment), z1); + } + Voronoi::point_type loc; { Voronoi::point_type proj = orthognalProjection(point, segment); @@ -495,7 +522,7 @@ PyObject* VoronoiEdgePy::toShape(PyObject *args) double dist1 = distanceBetween(pt1, pt1x, e->dia->getScale()) * sideOf(pt1, xaxis); if (dist1 < dist0) { // if the parabola is traversed in the revere direction we need to use the points - // on the other side of the parabola - beauty of symmetric geometries + // on the other side of the parabola - 'beauty of symmetric geometries dist0 = -dist0; dist1 = -dist1; } @@ -521,6 +548,9 @@ PyObject* VoronoiEdgePy::toShape(PyObject *args) // focal length if parabola in the xy-plane is simply half the distance between the // point and segment - aka the distance between point and location, aka the length of axis focal = length(axis) / e->dia->getScale(); + if (dbg) { + std::cerr << "focal = " << length(axis) << "/" << e->dia->getScale() << "\n"; + } } else { // if the parabola is not in the xy-plane we need to find the // (x,y) coordinates of a point on the parabola in the parabola's @@ -555,6 +585,7 @@ PyObject* VoronoiEdgePy::toShape(PyObject *args) std::cerr << " loc" << loc << ", axis" << axis << std::endl; std::cerr << " dist0(" << dist0 << " : " << flenX0 << ", dist1(" << dist1 << " : " << flenX1 << ")" << std::endl; std::cerr << " z(" << z0 << ", " << zx << ", " << z1 << ")" << std::endl; + std::cerr << " focal = (" << flenX << " * " << flenX << ") / (4 * fabs(" << flenY << "))\n"; } // use new X values to set the parameters dist0 = dist0 >= 0 ? flenX0 : -flenX0;