@@ -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
274304PyObject* 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
414483PyObject* VoronoiEdgePy::getCustomAttributes (const char * /* attr*/ ) const
0 commit comments