diff --git a/src/Mod/Path/App/VoronoiEdgePy.xml b/src/Mod/Path/App/VoronoiEdgePy.xml
index ab55c6ced0..c05f273e52 100644
--- a/src/Mod/Path/App/VoronoiEdgePy.xml
+++ b/src/Mod/Path/App/VoronoiEdgePy.xml
@@ -96,7 +96,12 @@
- Returns true if edge goes through endpoint of the segment site
+ Returns a geom representation of the edge (line segment or arc of parabola)
+
+
+
+
+ Returns the distance of the vertices to the input source
diff --git a/src/Mod/Path/App/VoronoiEdgePyImp.cpp b/src/Mod/Path/App/VoronoiEdgePyImp.cpp
index cd2013384a..0a3e062db5 100644
--- a/src/Mod/Path/App/VoronoiEdgePyImp.cpp
+++ b/src/Mod/Path/App/VoronoiEdgePyImp.cpp
@@ -269,6 +269,36 @@ namespace {
Voronoi::diagram_type::cell_type::source_index_type index = cell->source_index() - dia->points.size();
return dia->segments[index];
}
+
+ Voronoi::point_type orthognalProjection(const Voronoi::point_type &point, const Voronoi::segment_type &segment) {
+ // move segment so it goes through the origin (s)
+ Voronoi::point_type offset;
+ {
+ offset.x(low(segment).x());
+ offset.y(low(segment).y());
+ }
+ Voronoi::point_type s;
+ {
+ s.x(high(segment).x() - offset.x());
+ s.y(high(segment).y() - offset.y());
+ }
+ // move point accordingly so it maintains it's relation to s (p)
+ Voronoi::point_type p;
+ {
+ p.x(point.x() - offset.x());
+ p.y(point.y() - offset.y());
+ }
+ // calculate the orthogonal projection of p onto s
+ // ((p dot s) / (s dot s)) * s (https://en.wikibooks.org/wiki/Linear_Algebra/Orthogonal_Projection_Onto_a_Line)
+ // and it back by original offset to get the projected point
+ double proj = (p.x() * s.x() + p.y() * s.y()) / (s.x() * s.x() + s.y() * s.y());
+ Voronoi::point_type pt;
+ {
+ pt.x(offset.x() + proj * s.x());
+ pt.y(offset.y() + proj * s.y());
+ }
+ return pt;
+ }
}
PyObject* VoronoiEdgePy::toGeom(PyObject *args)
@@ -314,7 +344,7 @@ PyObject* VoronoiEdgePy::toGeom(PyObject *args)
direction.y(dx);
}
}
- double k = 10.0;
+ double k = 10.0; // <-- need something smarter here
Voronoi::point_type begin;
Voronoi::point_type end;
if (e->ptr->vertex0()) {
@@ -343,35 +373,10 @@ PyObject* VoronoiEdgePy::toGeom(PyObject *args)
// this is only the mid point of the segment if the parabola is symmetric
Voronoi::point_type loc;
{
- // move segment so it goes through the origin (s)
- Voronoi::point_type offset;
- {
- offset.x(low(segment).x());
- offset.y(low(segment).y());
- }
- Voronoi::point_type s;
- {
- s.x(high(segment).x() - offset.x());
- s.y(high(segment).y() - offset.y());
- }
- // move point accordingly so it maintains it's relation to s (p)
- Voronoi::point_type p;
- {
- p.x(point.x() - offset.x());
- p.y(point.y() - offset.y());
- }
- // calculate the orthogonal projection of p onto s
- // ((p dot s) / (s dot s)) * s (https://en.wikibooks.org/wiki/Linear_Algebra/Orthogonal_Projection_Onto_a_Line)
- double proj = (p.x() * s.x() + p.y() * s.y()) / (s.x() * s.x() + s.y() * s.y());
- Voronoi::point_type p1;
- {
- p1.x(proj * s.x());
- p1.y(proj * s.y());
- }
- // finally ...
+ Voronoi::point_type proj = orthognalProjection(point, segment);
// the location is the mid point between the projection on the segment and the point
- loc.x(((offset.x() + p1.x()) + point.x()) / 2);
- loc.y(((offset.y() + p1.y()) + point.y()) / 2);
+ loc.x((proj.x() + point.x()) / 2);
+ loc.y((proj.y() + point.y()) / 2);
}
Voronoi::point_type axis;
{
@@ -409,6 +414,70 @@ PyObject* VoronoiEdgePy::toGeom(PyObject *args)
return Py_None;
}
+
+namespace {
+
+ double distanceBetween(const Voronoi::diagram_type::vertex_type &v0, const Voronoi::point_type &p1) {
+ double x = v0.x() - p1.x();
+ double y = v0.y() - p1.y();
+ return sqrt(x * x + y * y);
+ }
+
+ void addDistanceBetween(const Voronoi::diagram_type::vertex_type *v0, const Voronoi::point_type &p1, Py::List *list) {
+ if (v0) {
+ list->append(Py::Float(distanceBetween(*v0, p1)));
+ } else {
+ Py_INCREF(Py_None);
+ list->append(Py::asObject(Py_None));
+ }
+ }
+
+ void addProjectedDistanceBetween(const Voronoi::diagram_type::vertex_type *v0, const Voronoi::segment_type &segment, Py::List *list) {
+ if (v0) {
+ Voronoi::point_type p0;
+ {
+ p0.x(v0->x());
+ p0.y(v0->y());
+ }
+ Voronoi::point_type p1 = orthognalProjection(p0, segment);
+ list->append(Py::Float(distanceBetween(*v0, p1)));
+ } else {
+ Py_INCREF(Py_None);
+ list->append(Py::asObject(Py_None));
+ }
+ }
+
+ bool addDistancesToPoint(const VoronoiEdge *edge, Voronoi::point_type p, Py::List *list) {
+ addDistanceBetween(edge->ptr->vertex0(), p, list);
+ addDistanceBetween(edge->ptr->vertex1(), p, list);
+ return true;
+ }
+
+ bool retrieveDistances(const VoronoiEdge *edge, Py::List *list) {
+ const Voronoi::diagram_type::cell_type *c0 = edge->ptr->cell();
+ if (c0->contains_point()) {
+ return addDistancesToPoint(edge, retrievePoint(edge->dia, c0), list);
+ }
+ const Voronoi::diagram_type::cell_type *c1 = edge->ptr->twin()->cell();
+ if (c1->contains_point()) {
+ return addDistancesToPoint(edge, retrievePoint(edge->dia, c1), list);
+ }
+ // at this point both cells are sourced from segments and it does not matter which one we use
+ Voronoi::segment_type segment = retrieveSegment(edge->dia, c0);
+ addProjectedDistanceBetween(edge->ptr->vertex0(), segment, list);
+ addProjectedDistanceBetween(edge->ptr->vertex1(), segment, list);
+ return false;
+ }
+}
+
+PyObject* VoronoiEdgePy::getDistances(PyObject *args)
+{
+ VoronoiEdge *e = getVoronoiEdgeFromPy(this, args);
+ Py::List list;
+ retrieveDistances(e, &list);
+ return Py::new_reference_to(list);
+}
+
// custom attributes get/set
PyObject* VoronoiEdgePy::getCustomAttributes(const char* /*attr*/) const