@@ -347,9 +347,11 @@ ClosestPathCoord VirtualPath::findClosestPointTo(
347347 size_type start_index,
348348 size_type end_index ) const
349349{
350- Q_ASSERT (! path_coords.empty () );
350+ Q_ASSERT (path_coords.size () > 1 );
351351
352- auto result = ClosestPathCoord { path_coords.front (), distance_bound_squared };
352+ auto result = ClosestPathCoord { path_coords.front (),
353+ path_coords[1 ].pos - path_coords[0 ].pos ,
354+ distance_bound_squared };
353355
354356 // Find upper bound for distance.
355357 for (const auto & path_coord : path_coords)
@@ -364,6 +366,27 @@ ClosestPathCoord VirtualPath::findClosestPointTo(
364366 if (dist_sq < result.distance_squared )
365367 {
366368 result.distance_squared = dist_sq;
369+ // Here we create predictable behavior for corners and handle
370+ // the ends. Although corners do not have a tangent in
371+ // the mathematical sense, the humans intuitively expect the
372+ // "tangent" to go across the corner and divide the plane into the
373+ // inner and outer parts.
374+ bool in_ok = false ;
375+ bool out_ok = false ;
376+ auto const incoming = calculateIncomingTangent (path_coord.index , in_ok);
377+ auto const outgoing = calculateOutgoingTangent (path_coord.index , out_ok);
378+ if (in_ok && out_ok)
379+ {
380+ result.tangent = incoming + outgoing;
381+ }
382+ else if (in_ok)
383+ {
384+ result.tangent = incoming;
385+ }
386+ else if (out_ok)
387+ {
388+ result.tangent = outgoing;
389+ }
367390 result.path_coord = path_coord;
368391 }
369392 }
@@ -391,6 +414,7 @@ ClosestPathCoord VirtualPath::findClosestPointTo(
391414 if (to_coord.lengthSquared () < result.distance_squared )
392415 {
393416 result.distance_squared = to_coord.lengthSquared ();
417+ result.tangent = tangent;
394418 result.path_coord = *pc;
395419 }
396420 continue ;
@@ -402,6 +426,7 @@ ClosestPathCoord VirtualPath::findClosestPointTo(
402426 if (coord.distanceSquaredTo (next_pos) < result.distance_squared )
403427 {
404428 result.distance_squared = coord.distanceSquaredTo (next_pos);
429+ result.tangent = tangent;
405430 result.path_coord = *next_pc;
406431 }
407432 continue ;
@@ -425,13 +450,16 @@ ClosestPathCoord VirtualPath::findClosestPointTo(
425450 if (coords.flags [result.path_coord .index ].isCurveStart ())
426451 {
427452 MapCoordF unused;
453+ MapCoordF curve2_control_point1;
428454 PathCoord::splitBezierCurve (MapCoordF (coords.flags [result.path_coord .index ]), MapCoordF (coords.flags [result.path_coord .index +1 ]),
429455 MapCoordF (coords.flags [result.path_coord .index +2 ]), MapCoordF (coords.flags [result.path_coord .index +3 ]),
430- result.path_coord .param , unused, unused, result.path_coord .pos , unused, unused);
456+ result.path_coord .param , unused, unused, result.path_coord .pos , curve2_control_point1, unused);
457+ result.tangent = curve2_control_point1 - result.path_coord .pos ;
431458 }
432459 else
433460 {
434- result.path_coord .pos = pos + (next_pos - pos) * double (factor);
461+ result.tangent = next_pos - pos;
462+ result.path_coord .pos = pos + result.tangent * double (factor);
435463 }
436464 }
437465 }
0 commit comments