Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 7c3159d

Browse files
committed
[[ CanvasPathArcTo ]] Add tangent lines version of path "arc to ..." command.
1 parent 1d13d3b commit 7c3159d

File tree

5 files changed

+126
-0
lines changed

5 files changed

+126
-0
lines changed

engine/src/canvas.mlc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2675,6 +2675,7 @@ public foreign handler MCCanvasPathLineTo(in pPoint as Point, inout xPath as Pat
26752675
public foreign handler MCCanvasPathCurveThroughPoint(in pThrough as Point, in pTo as Point, inout xPath as Path) returns nothing binds to "<builtin>"
26762676
public foreign handler MCCanvasPathCurveThroughPoints(in pThroughA as Point, in pThroughB as Point, in pTo as Point, inout xPath as Path) returns nothing binds to "<builtin>"
26772677

2678+
public foreign handler MCCanvasPathArcTo(in pThrough as Point, in pTo as Point, in pRadius as CanvasFloat, inout xPath as Path) returns nothing binds to "<builtin>"
26782679
public foreign handler MCCanvasPathEllipticArcToWithRadiiAsList(in pTo as Point, in pRadii as List, in pRotation as CanvasFloat, inout xPath as Path) returns nothing binds to "<builtin>"
26792680
public foreign handler MCCanvasPathEllipticArcToWithFlagsWithRadiiAsList(in pTo as Point, in pRadii as List, in pRotation as CanvasFloat, in pLargest as bool, in pClockwise as bool, inout xPath as Path) returns nothing binds to "<builtin>"
26802681

@@ -2753,6 +2754,42 @@ begin
27532754
end syntax
27542755

27552756

2757+
/*
2758+
Summary: Adds an arc to a path.
2759+
2760+
mThrough: An expression which evaluates to a point.
2761+
mTo: An expression which evaluates to a point.
2762+
mRadius: An expression which evaluates to a number.
2763+
mPath: An expression which evaluates to a path.
2764+
2765+
Description: Adds an arc between the points of a circle with radius <mRadius> tangent to the lines from the current point to <mThrough>, and from <mThrough> to <mTo>.
2766+
2767+
Example:
2768+
// Construct a path tracing out a rectangle with rounded bottom corners.
2769+
variable tPath
2770+
put the empty path into tPath
2771+
2772+
// Begin a new subpath
2773+
move to point [0, 0] on tPath
2774+
2775+
// Continue path with an arc to the bottom edge
2776+
arc through point [0, my height] to point [25, my height] with radius 25 on tPath
2777+
2778+
// Continue path with an arc to the right edge
2779+
arc through point [my width, my height] to point [my width, 0] with radius 25 on tPath
2780+
2781+
// Close the path with a line back to the starting point
2782+
close path on tPath
2783+
2784+
Tags: Canvas
2785+
*/
2786+
syntax PathOperationArcTo is statement
2787+
"arc" "through" <mThrough: Expression> "to" <mTo: Expression> "with" "radius" <mRadius: Expression> "on" <mPath: Expression>
2788+
begin
2789+
MCCanvasPathArcTo(mThrough, mTo, mRadius, mPath)
2790+
end syntax
2791+
2792+
27562793
/*
27572794
Summary: Adds an arc to a path.
27582795

engine/src/module-canvas.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3690,6 +3690,32 @@ void MCCanvasPathClosePath(MCCanvasPathRef &x_path)
36903690
MCGPathRelease(t_path);
36913691
}
36923692

3693+
void MCCanvasPathArcTo(MCCanvasPointRef p_tangent, MCCanvasPointRef p_to, MCCanvasFloat p_radius, MCCanvasPathRef &x_path)
3694+
{
3695+
bool t_success;
3696+
t_success = true;
3697+
3698+
MCGPathRef t_path;
3699+
t_path = nil;
3700+
3701+
if (t_success)
3702+
{
3703+
MCGPathMutableCopy(*MCCanvasPathGet(x_path), t_path);
3704+
t_success = MCGPathIsValid(t_path);
3705+
}
3706+
3707+
if (t_success)
3708+
{
3709+
MCGPathArcToTangent(t_path, *MCCanvasPointGet(p_tangent), *MCCanvasPointGet(p_to), p_radius);
3710+
t_success = MCGPathIsValid(t_path);
3711+
}
3712+
3713+
if (t_success)
3714+
MCCanvasPathSetMCGPath(t_path, x_path);
3715+
3716+
MCGPathRelease(t_path);
3717+
}
3718+
36933719
void MCCanvasPathEllipticArcToWithFlagsWithRadiiAsList(MCCanvasPointRef p_to, MCProperListRef p_radii, MCCanvasFloat p_rotation, bool p_largest, bool p_clockwise, MCCanvasPathRef &x_path)
36943720
{
36953721
bool t_success;

engine/src/module-canvas.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ extern "C" MC_DLLEXPORT void MCCanvasPathCurveThroughPoint(MCCanvasPointRef p_th
441441
extern "C" MC_DLLEXPORT void MCCanvasPathCurveThroughPoints(MCCanvasPointRef p_through_a, MCCanvasPointRef p_through_b, MCCanvasPointRef p_to, MCCanvasPathRef &x_path);
442442
extern "C" MC_DLLEXPORT void MCCanvasPathClosePath(MCCanvasPathRef &x_path);
443443

444+
extern "C" MC_DLLEXPORT void MCCanvasPathArcTo(MCCanvasPointRef p_tangent, MCCanvasPointRef p_to, MCCanvasFloat p_radius, MCCanvasPathRef &x_path);
444445
extern "C" MC_DLLEXPORT void MCCanvasPathEllipticArcToWithFlagsWithRadiiAsList(MCCanvasPointRef p_to, MCProperListRef p_radii, MCCanvasFloat p_rotation, bool p_largest, bool p_clockwise, MCCanvasPathRef &x_path);
445446
extern "C" MC_DLLEXPORT void MCCanvasPathEllipticArcToWithRadiiAsList(MCCanvasPointRef p_to, MCProperListRef p_radii, MCCanvasFloat p_rotation, MCCanvasPathRef &x_path);
446447

libgraphics/include/graphics.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,7 @@ void MCGPathQuadraticTo(MCGPathRef path, MCGPoint control_point, MCGPoint end_po
783783
void MCGPathCubicTo(MCGPathRef path, MCGPoint first_control_point, MCGPoint second_control_point, MCGPoint end_point);
784784
void MCGPathArcTo(MCGPathRef path, MCGSize radii, MCGFloat rotation, bool large_arc, bool sweep, MCGPoint end_point);
785785
void MCGPathArcToBestFit(MCGPathRef path, MCGSize p_radii, MCGFloat p_rotation, MCGPoint p_end_point);
786+
void MCGPathArcToTangent(MCGPathRef path, const MCGPoint &p_tangent, const MCGPoint &p_end, MCGFloat p_radius);
786787
void MCGPathCloseSubpath(MCGPathRef path);
787788

788789
void MCGPathThicken(MCGPathRef path, const MCGStrokeAttr& attr, MCGPathRef& r_thick_path);

libgraphics/src/path.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,21 @@ static inline MCGPoint MCGVectorMake(const MCGPoint p_start, MCGPoint p_end)
757757
return MCGPointMake(p_end.x - p_start.x, p_end.y - p_start.y);
758758
}
759759

760+
static inline MCGPoint MCGVectorNormalize(const MCGPoint p_vector)
761+
{
762+
return MCGPointScale(p_vector, 1 / MCGVectorMagnitude(p_vector));
763+
}
764+
765+
static inline MCGPoint MCGVectorAdd(const MCGPoint &p_left, const MCGPoint &p_right)
766+
{
767+
return MCGPointMake(p_left.x + p_right.x, p_left.y + p_right.y);
768+
}
769+
770+
static inline MCGPoint MCGVectorScale(const MCGPoint &p_vector, MCGFloat p_scale)
771+
{
772+
return MCGPointMake(p_vector.x * p_scale, p_vector.y * p_scale);
773+
}
774+
760775
static inline MCGPoint MCGVectorRotate90(const MCGPoint &p_vector)
761776
{
762777
return MCGPointMake(-p_vector.y, p_vector.x);
@@ -1004,6 +1019,52 @@ void MCGPathArcToBestFit(MCGPathRef self, MCGSize p_radii, MCGFloat p_rotation,
10041019
self -> is_valid = t_success;
10051020
}
10061021

1022+
void MCGPathArcToTangent(MCGPathRef self, const MCGPoint &p_tangent, const MCGPoint &p_end, MCGFloat p_radius)
1023+
{
1024+
if (!MCGPathIsValid(self))
1025+
return;
1026+
1027+
bool t_success;
1028+
t_success = true;
1029+
1030+
if (t_success)
1031+
t_success = self -> is_mutable;
1032+
1033+
if (t_success)
1034+
{
1035+
MCGPoint t_start;
1036+
if (!MCGPathGetCurrentPoint(self, t_start))
1037+
t_start = MCGPointMake(0, 0);
1038+
1039+
t_success = !MCGPointIsEqual(t_start, p_tangent) && !MCGPointIsEqual(p_tangent, p_end) && !MCGPointIsEqual(p_end, t_start);
1040+
1041+
MCGPoint t_vec1, t_vec2;
1042+
t_vec1 = MCGVectorMake(p_tangent, t_start);
1043+
t_vec2 = MCGVectorMake(p_tangent, p_end);
1044+
1045+
MCGFloat t_angle;
1046+
t_angle = MCGAngleBetweenVectors(t_vec1, t_vec2);
1047+
1048+
MCGFloat t_dist;
1049+
t_dist = MCAbs(p_radius / tanf(t_angle / 2));
1050+
1051+
MCGPoint t_start_tangent, t_end_tangent;
1052+
if (MCGVectorMagnitude(t_vec1) > t_dist)
1053+
t_start_tangent = MCGVectorAdd(p_tangent, MCGVectorScale(MCGVectorNormalize(t_vec1), t_dist));
1054+
else
1055+
t_start_tangent = t_start;
1056+
1057+
if (MCGVectorMagnitude(t_vec2) > t_dist)
1058+
t_end_tangent = MCGVectorAdd(p_tangent, MCGVectorScale(MCGVectorNormalize(t_vec2), t_dist));
1059+
else
1060+
t_end_tangent = p_end;
1061+
1062+
MCGPathLineTo(self, t_start_tangent);
1063+
MCGPathArcTo(self, MCGSizeMake(p_radius, p_radius), 0, false, t_angle < 0, t_end_tangent);
1064+
MCGPathLineTo(self, p_end);
1065+
}
1066+
}
1067+
10071068
void MCGPathCloseSubpath(MCGPathRef self)
10081069
{
10091070
if (!MCGPathIsValid(self))

0 commit comments

Comments
 (0)