Skip to content

Commit 9ede2de

Browse files
committed
VirtualPath: Export tangent from findClosestPointTo()
The tangent vector is essential for the move parallel tool where we want to calculate the distance of the cursor from the tangent line touching the path in question. Please note that we are generating a "pseudo tangent" for corners and line ends to enable sensible behavior during mouse drag events.
1 parent 20065ec commit 9ede2de

File tree

3 files changed

+40
-6
lines changed

3 files changed

+40
-6
lines changed

src/core/objects/object.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,7 @@ ClosestPathCoord PathObject::findClosestPointTo(
11601160

11611161
using distance_type = decltype(ClosestPathCoord::distance_squared);
11621162
return std::accumulate(begin(path_parts), end(path_parts),
1163-
ClosestPathCoord { {}, std::numeric_limits<distance_type>::max() },
1163+
ClosestPathCoord { {}, {}, std::numeric_limits<distance_type>::max() },
11641164
op);
11651165
}
11661166

src/core/path_coord.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,17 @@ class PathCoord
158158

159159

160160
/**
161-
* The structure returned when looking for closest coordinates on a path.
161+
* The structure returned when looking for the closest coordinates on a path.
162+
* The tangent element is defined even on corners and line ends. Following the
163+
* intuitive view, the tangent line touches the corner, dividing the plane into
164+
* the part with the corner and the part without it. At the line ends, the
165+
* "tangent" is the direction of the neighboring segment. The "pseudo tangent"
166+
* is generated to define the direction for mouse drag actions.
162167
*/
163168
struct ClosestPathCoord
164169
{
165170
PathCoord path_coord;
171+
MapCoordF tangent;
166172
double distance_squared;
167173
};
168174

src/core/virtual_path.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)