Skip to content

Commit 38ff7fc

Browse files
mlampertsliptonic
authored andcommitted
Added support for distances of edge end points.
1 parent 926d254 commit 38ff7fc

File tree

2 files changed

+104
-30
lines changed

2 files changed

+104
-30
lines changed

src/Mod/Path/App/VoronoiEdgePy.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,12 @@
9696
</Methode>
9797
<Methode Name="toGeom" Const="true">
9898
<Documentation>
99-
<UserDocu>Returns true if edge goes through endpoint of the segment site</UserDocu>
99+
<UserDocu>Returns a geom representation of the edge (line segment or arc of parabola)</UserDocu>
100+
</Documentation>
101+
</Methode>
102+
<Methode Name="getDistances" Const="true">
103+
<Documentation>
104+
<UserDocu>Returns the distance of the vertices to the input source</UserDocu>
100105
</Documentation>
101106
</Methode>
102107
</PythonExport>

src/Mod/Path/App/VoronoiEdgePyImp.cpp

Lines changed: 98 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,36 @@ namespace {
269269
Voronoi::diagram_type::cell_type::source_index_type index = cell->source_index() - dia->points.size();
270270
return dia->segments[index];
271271
}
272+
273+
Voronoi::point_type orthognalProjection(const Voronoi::point_type &point, const Voronoi::segment_type &segment) {
274+
// move segment so it goes through the origin (s)
275+
Voronoi::point_type offset;
276+
{
277+
offset.x(low(segment).x());
278+
offset.y(low(segment).y());
279+
}
280+
Voronoi::point_type s;
281+
{
282+
s.x(high(segment).x() - offset.x());
283+
s.y(high(segment).y() - offset.y());
284+
}
285+
// move point accordingly so it maintains it's relation to s (p)
286+
Voronoi::point_type p;
287+
{
288+
p.x(point.x() - offset.x());
289+
p.y(point.y() - offset.y());
290+
}
291+
// calculate the orthogonal projection of p onto s
292+
// ((p dot s) / (s dot s)) * s (https://en.wikibooks.org/wiki/Linear_Algebra/Orthogonal_Projection_Onto_a_Line)
293+
// and it back by original offset to get the projected point
294+
double proj = (p.x() * s.x() + p.y() * s.y()) / (s.x() * s.x() + s.y() * s.y());
295+
Voronoi::point_type pt;
296+
{
297+
pt.x(offset.x() + proj * s.x());
298+
pt.y(offset.y() + proj * s.y());
299+
}
300+
return pt;
301+
}
272302
}
273303

274304
PyObject* VoronoiEdgePy::toGeom(PyObject *args)
@@ -314,7 +344,7 @@ PyObject* VoronoiEdgePy::toGeom(PyObject *args)
314344
direction.y(dx);
315345
}
316346
}
317-
double k = 10.0;
347+
double k = 10.0; // <-- need something smarter here
318348
Voronoi::point_type begin;
319349
Voronoi::point_type end;
320350
if (e->ptr->vertex0()) {
@@ -343,35 +373,10 @@ PyObject* VoronoiEdgePy::toGeom(PyObject *args)
343373
// this is only the mid point of the segment if the parabola is symmetric
344374
Voronoi::point_type loc;
345375
{
346-
// move segment so it goes through the origin (s)
347-
Voronoi::point_type offset;
348-
{
349-
offset.x(low(segment).x());
350-
offset.y(low(segment).y());
351-
}
352-
Voronoi::point_type s;
353-
{
354-
s.x(high(segment).x() - offset.x());
355-
s.y(high(segment).y() - offset.y());
356-
}
357-
// move point accordingly so it maintains it's relation to s (p)
358-
Voronoi::point_type p;
359-
{
360-
p.x(point.x() - offset.x());
361-
p.y(point.y() - offset.y());
362-
}
363-
// calculate the orthogonal projection of p onto s
364-
// ((p dot s) / (s dot s)) * s (https://en.wikibooks.org/wiki/Linear_Algebra/Orthogonal_Projection_Onto_a_Line)
365-
double proj = (p.x() * s.x() + p.y() * s.y()) / (s.x() * s.x() + s.y() * s.y());
366-
Voronoi::point_type p1;
367-
{
368-
p1.x(proj * s.x());
369-
p1.y(proj * s.y());
370-
}
371-
// finally ...
376+
Voronoi::point_type proj = orthognalProjection(point, segment);
372377
// the location is the mid point between the projection on the segment and the point
373-
loc.x(((offset.x() + p1.x()) + point.x()) / 2);
374-
loc.y(((offset.y() + p1.y()) + point.y()) / 2);
378+
loc.x((proj.x() + point.x()) / 2);
379+
loc.y((proj.y() + point.y()) / 2);
375380
}
376381
Voronoi::point_type axis;
377382
{
@@ -409,6 +414,70 @@ PyObject* VoronoiEdgePy::toGeom(PyObject *args)
409414
return Py_None;
410415
}
411416

417+
418+
namespace {
419+
420+
double distanceBetween(const Voronoi::diagram_type::vertex_type &v0, const Voronoi::point_type &p1) {
421+
double x = v0.x() - p1.x();
422+
double y = v0.y() - p1.y();
423+
return sqrt(x * x + y * y);
424+
}
425+
426+
void addDistanceBetween(const Voronoi::diagram_type::vertex_type *v0, const Voronoi::point_type &p1, Py::List *list) {
427+
if (v0) {
428+
list->append(Py::Float(distanceBetween(*v0, p1)));
429+
} else {
430+
Py_INCREF(Py_None);
431+
list->append(Py::asObject(Py_None));
432+
}
433+
}
434+
435+
void addProjectedDistanceBetween(const Voronoi::diagram_type::vertex_type *v0, const Voronoi::segment_type &segment, Py::List *list) {
436+
if (v0) {
437+
Voronoi::point_type p0;
438+
{
439+
p0.x(v0->x());
440+
p0.y(v0->y());
441+
}
442+
Voronoi::point_type p1 = orthognalProjection(p0, segment);
443+
list->append(Py::Float(distanceBetween(*v0, p1)));
444+
} else {
445+
Py_INCREF(Py_None);
446+
list->append(Py::asObject(Py_None));
447+
}
448+
}
449+
450+
bool addDistancesToPoint(const VoronoiEdge *edge, Voronoi::point_type p, Py::List *list) {
451+
addDistanceBetween(edge->ptr->vertex0(), p, list);
452+
addDistanceBetween(edge->ptr->vertex1(), p, list);
453+
return true;
454+
}
455+
456+
bool retrieveDistances(const VoronoiEdge *edge, Py::List *list) {
457+
const Voronoi::diagram_type::cell_type *c0 = edge->ptr->cell();
458+
if (c0->contains_point()) {
459+
return addDistancesToPoint(edge, retrievePoint(edge->dia, c0), list);
460+
}
461+
const Voronoi::diagram_type::cell_type *c1 = edge->ptr->twin()->cell();
462+
if (c1->contains_point()) {
463+
return addDistancesToPoint(edge, retrievePoint(edge->dia, c1), list);
464+
}
465+
// at this point both cells are sourced from segments and it does not matter which one we use
466+
Voronoi::segment_type segment = retrieveSegment(edge->dia, c0);
467+
addProjectedDistanceBetween(edge->ptr->vertex0(), segment, list);
468+
addProjectedDistanceBetween(edge->ptr->vertex1(), segment, list);
469+
return false;
470+
}
471+
}
472+
473+
PyObject* VoronoiEdgePy::getDistances(PyObject *args)
474+
{
475+
VoronoiEdge *e = getVoronoiEdgeFromPy(this, args);
476+
Py::List list;
477+
retrieveDistances(e, &list);
478+
return Py::new_reference_to(list);
479+
}
480+
412481
// custom attributes get/set
413482

414483
PyObject* VoronoiEdgePy::getCustomAttributes(const char* /*attr*/) const

0 commit comments

Comments
 (0)