-module(svg_path@transform).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/svg_path/transform.gleam").
-export([matrix/6, from_tuple/1, identity/0, multiply/2, chain/2, translate/2, about_point/2, scale_xy/2, scale/1, rotate/1, skew_x/1, skew_y/1, to_tuple/1, point/2, translate_point/3, scale_point/2, scale_xy_point/3, rotate_point/2, skew_x_point/2, skew_y_point/2, segment/2, segment_about_point/3, segment_about_anchor/3, translate_segment/3, scale_segment/2, scale_xy_segment/3, rotate_segment/2, skew_x_segment/2, skew_y_segment/2, segment_gracefully/2, segment_gracefully2/2, subpath/2, subpath_about_point/3, subpath_about_anchor/3, translate_subpath/3, scale_subpath/2, scale_xy_subpath/3, rotate_subpath/2, skew_x_subpath/2, skew_y_subpath/2, subpath_gracefully/2, path/2, path_about_point/3, path_about_anchor/3, translate_path/3, scale_path/2, scale_xy_path/3, rotate_path/2, skew_x_path/2, skew_y_path/2]).
-export_type([matrix/0, anchor/0, error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Transform paths and path segments with 2D affine matrices.\n"
"\n"
" Matrices use SVG's six-value affine form `matrix(a b c d e f)` and are\n"
" applied to column vectors. Use `chain(first:, then:)` when thinking in\n"
" transform application order, and `multiply(left:, right:)` when thinking in\n"
" algebraic matrix multiplication order.\n"
).
-opaque matrix() :: {matrix,
float(),
float(),
float(),
float(),
float(),
float()}.
-type anchor() :: top_left |
top_center |
top_right |
center_left |
center |
center_right |
bottom_left |
bottom_center |
bottom_right.
-type error() :: degenerate_arc_transform |
invalid_matrix |
{core, svg_path:error()}.
-file("src/svg_path/transform.gleam", 50).
?DOC(" Create an affine matrix from SVG's six matrix values.\n").
-spec matrix(float(), float(), float(), float(), float(), float()) -> matrix().
matrix(A, B, C, D, E, F) ->
{matrix, A, B, C, D, E, F}.
-file("src/svg_path/transform.gleam", 62).
?DOC(" Create an affine matrix from SVG's six matrix values as a tuple.\n").
-spec from_tuple({float(), float(), float(), float(), float(), float()}) -> matrix().
from_tuple(Values) ->
{A, B, C, D, E, F} = Values,
matrix(A, B, C, D, E, F).
-file("src/svg_path/transform.gleam", 71).
?DOC(" The identity transform.\n").
-spec identity() -> matrix().
identity() ->
matrix(1.0, +0.0, +0.0, 1.0, +0.0, +0.0).
-file("src/svg_path/transform.gleam", 86).
?DOC(
" Multiply two matrices in algebraic order.\n"
"\n"
" `multiply(left: a, right: b)` returns `a * b`.\n"
).
-spec multiply(matrix(), matrix()) -> matrix().
multiply(Left, Right) ->
matrix(
(erlang:element(2, Left) * erlang:element(2, Right)) + (erlang:element(
4,
Left
)
* erlang:element(3, Right)),
(erlang:element(3, Left) * erlang:element(2, Right)) + (erlang:element(
5,
Left
)
* erlang:element(3, Right)),
(erlang:element(2, Left) * erlang:element(4, Right)) + (erlang:element(
4,
Left
)
* erlang:element(5, Right)),
(erlang:element(3, Left) * erlang:element(4, Right)) + (erlang:element(
5,
Left
)
* erlang:element(5, Right)),
((erlang:element(2, Left) * erlang:element(6, Right)) + (erlang:element(
4,
Left
)
* erlang:element(7, Right)))
+ erlang:element(6, Left),
((erlang:element(3, Left) * erlang:element(6, Right)) + (erlang:element(
5,
Left
)
* erlang:element(7, Right)))
+ erlang:element(7, Left)
).
-file("src/svg_path/transform.gleam", 79).
?DOC(
" Chain two transforms in application order.\n"
"\n"
" `chain(first: a, then: b)` creates a matrix that applies `a` first and `b`\n"
" second. In algebraic matrix order, this is `b * a`.\n"
).
-spec chain(matrix(), matrix()) -> matrix().
chain(First, Second) ->
multiply(Second, First).
-file("src/svg_path/transform.gleam", 108).
?DOC(" Create a translation matrix.\n").
-spec translate(float(), float()) -> matrix().
translate(X, Y) ->
matrix(1.0, +0.0, +0.0, 1.0, X, Y).
-file("src/svg_path/transform.gleam", 98).
?DOC(" Create a matrix that applies a transform about a point.\n").
-spec about_point(matrix(), vec@vec2:vec2(float())) -> matrix().
about_point(Transform, Point) ->
_pipe = translate(
+0.0 - erlang:element(2, Point),
+0.0 - erlang:element(3, Point)
),
_pipe@1 = chain(_pipe, Transform),
chain(
_pipe@1,
translate(erlang:element(2, Point), erlang:element(3, Point))
).
-file("src/svg_path/transform.gleam", 118).
?DOC(" Create a non-uniform scale matrix.\n").
-spec scale_xy(float(), float()) -> matrix().
scale_xy(X, Y) ->
matrix(X, +0.0, +0.0, Y, +0.0, +0.0).
-file("src/svg_path/transform.gleam", 113).
?DOC(" Create a uniform scale matrix.\n").
-spec scale(float()) -> matrix().
scale(Factor) ->
scale_xy(Factor, Factor).
-file("src/svg_path/transform.gleam", 884).
-spec degrees_to_radians(float()) -> float().
degrees_to_radians(Degrees) ->
(Degrees * gleam_community@maths:pi()) / 180.0.
-file("src/svg_path/transform.gleam", 123).
?DOC(" Create a rotation matrix from an angle in degrees.\n").
-spec rotate(float()) -> matrix().
rotate(Degrees) ->
Radians = degrees_to_radians(Degrees),
Cosine = gleam_community@maths:cos(Radians),
Sine = gleam_community@maths:sin(Radians),
matrix(Cosine, Sine, +0.0 - Sine, Cosine, +0.0, +0.0).
-file("src/svg_path/transform.gleam", 132).
?DOC(" Create an x-axis skew matrix from an angle in degrees.\n").
-spec skew_x(float()) -> matrix().
skew_x(Degrees) ->
matrix(
1.0,
+0.0,
gleam_community@maths:tan(degrees_to_radians(Degrees)),
1.0,
+0.0,
+0.0
).
-file("src/svg_path/transform.gleam", 144).
?DOC(" Create a y-axis skew matrix from an angle in degrees.\n").
-spec skew_y(float()) -> matrix().
skew_y(Degrees) ->
matrix(
1.0,
gleam_community@maths:tan(degrees_to_radians(Degrees)),
+0.0,
1.0,
+0.0,
+0.0
).
-file("src/svg_path/transform.gleam", 156).
?DOC(" Return SVG's six matrix values as `#(a, b, c, d, e, f)`.\n").
-spec to_tuple(matrix()) -> {float(),
float(),
float(),
float(),
float(),
float()}.
to_tuple(Transform) ->
{erlang:element(2, Transform),
erlang:element(3, Transform),
erlang:element(4, Transform),
erlang:element(5, Transform),
erlang:element(6, Transform),
erlang:element(7, Transform)}.
-file("src/svg_path/transform.gleam", 170).
?DOC(" Transform a point by a matrix.\n").
-spec point(vec@vec2:vec2(float()), matrix()) -> vec@vec2:vec2(float()).
point(Point, Transform) ->
svg_path:point(
((erlang:element(2, Transform) * erlang:element(2, Point)) + (erlang:element(
4,
Transform
)
* erlang:element(3, Point)))
+ erlang:element(6, Transform),
((erlang:element(3, Transform) * erlang:element(2, Point)) + (erlang:element(
5,
Transform
)
* erlang:element(3, Point)))
+ erlang:element(7, Transform)
).
-file("src/svg_path/transform.gleam", 178).
?DOC(" Translate a point.\n").
-spec translate_point(vec@vec2:vec2(float()), float(), float()) -> vec@vec2:vec2(float()).
translate_point(Input, X, Y) ->
point(Input, translate(X, Y)).
-file("src/svg_path/transform.gleam", 187).
?DOC(" Scale a point uniformly.\n").
-spec scale_point(vec@vec2:vec2(float()), float()) -> vec@vec2:vec2(float()).
scale_point(Input, Factor) ->
point(Input, scale(Factor)).
-file("src/svg_path/transform.gleam", 195).
?DOC(" Scale a point non-uniformly.\n").
-spec scale_xy_point(vec@vec2:vec2(float()), float(), float()) -> vec@vec2:vec2(float()).
scale_xy_point(Input, X, Y) ->
point(Input, scale_xy(X, Y)).
-file("src/svg_path/transform.gleam", 204).
?DOC(" Rotate a point around the origin.\n").
-spec rotate_point(vec@vec2:vec2(float()), float()) -> vec@vec2:vec2(float()).
rotate_point(Input, Degrees) ->
point(Input, rotate(Degrees)).
-file("src/svg_path/transform.gleam", 212).
?DOC(" Skew a point along the x axis.\n").
-spec skew_x_point(vec@vec2:vec2(float()), float()) -> vec@vec2:vec2(float()).
skew_x_point(Input, Degrees) ->
point(Input, skew_x(Degrees)).
-file("src/svg_path/transform.gleam", 220).
?DOC(" Skew a point along the y axis.\n").
-spec skew_y_point(vec@vec2:vec2(float()), float()) -> vec@vec2:vec2(float()).
skew_y_point(Input, Degrees) ->
point(Input, skew_y(Degrees)).
-file("src/svg_path/transform.gleam", 880).
-spec determinant(matrix()) -> float().
determinant(Transform) ->
(erlang:element(2, Transform) * erlang:element(5, Transform)) - (erlang:element(
3,
Transform
)
* erlang:element(4, Transform)).
-file("src/svg_path/transform.gleam", 873).
-spec transformed_sweep(boolean(), matrix()) -> boolean().
transformed_sweep(Sweep, Transform) ->
case determinant(Transform) < +0.0 of
true ->
not Sweep;
false ->
Sweep
end.
-file("src/svg_path/transform.gleam", 750).
-spec from_ellipse_point(svg_path@ellipse:point()) -> vec@vec2:vec2(float()).
from_ellipse_point(Point) ->
svg_path:point(erlang:element(2, Point), erlang:element(3, Point)).
-file("src/svg_path/transform.gleam", 735).
-spec affine(matrix()) -> svg_path@ellipse:affine().
affine(Transform) ->
svg_path@ellipse:ellipse_affine(
erlang:element(2, Transform),
erlang:element(3, Transform),
erlang:element(4, Transform),
erlang:element(5, Transform),
erlang:element(6, Transform),
erlang:element(7, Transform)
).
-file("src/svg_path/transform.gleam", 746).
-spec to_ellipse_point(vec@vec2:vec2(float())) -> svg_path@ellipse:point().
to_ellipse_point(Point) ->
{point, erlang:element(2, Point), erlang:element(3, Point)}.
-file("src/svg_path/transform.gleam", 645).
-spec transform_valid_segment(svg_path:segment(), matrix()) -> {ok,
svg_path:segment()} |
{error, error()}.
transform_valid_segment(Segment, Transform) ->
case Segment of
{line, Start, End} ->
{ok, {line, point(Start, Transform), point(End, Transform)}};
{quadratic_bezier, Start@1, Control, End@1} ->
{ok,
{quadratic_bezier,
point(Start@1, Transform),
point(Control, Transform),
point(End@1, Transform)}};
{cubic_bezier, Start@2, Control1, Control2, End@2} ->
{ok,
{cubic_bezier,
point(Start@2, Transform),
point(Control1, Transform),
point(Control2, Transform),
point(End@2, Transform)}};
{arc, Start@3, Radius, X_axis_rotation, Large_arc, Sweep, End@3} ->
case svg_path@ellipse:transformed_axes(
to_ellipse_point(Radius),
X_axis_rotation,
affine(Transform)
) of
{error, _} ->
{error, degenerate_arc_transform};
{ok, {Radius@1, X_axis_rotation@1}} ->
{ok,
{arc,
point(Start@3, Transform),
from_ellipse_point(Radius@1),
X_axis_rotation@1,
Large_arc,
transformed_sweep(Sweep, Transform),
point(End@3, Transform)}}
end
end.
-file("src/svg_path/transform.gleam", 791).
-spec is_nan(float()) -> boolean().
is_nan(Value) ->
not ((Value < +0.0) orelse (Value >= +0.0)).
-file("src/svg_path/transform.gleam", 787).
-spec is_finite(float()) -> boolean().
is_finite(Value) ->
not is_nan(Value - Value).
-file("src/svg_path/transform.gleam", 695).
-spec validate_matrix(matrix()) -> {ok, nil} | {error, error()}.
validate_matrix(Transform) ->
case ((((is_finite(erlang:element(2, Transform)) andalso is_finite(
erlang:element(3, Transform)
))
andalso is_finite(erlang:element(4, Transform)))
andalso is_finite(erlang:element(5, Transform)))
andalso is_finite(erlang:element(6, Transform)))
andalso is_finite(erlang:element(7, Transform)) of
true ->
{ok, nil};
false ->
{error, invalid_matrix}
end.
-file("src/svg_path/transform.gleam", 232).
?DOC(
" Transform a segment by a matrix.\n"
"\n"
" Degenerate arc transforms return `DegenerateArcTransform`; use\n"
" `segment_gracefully` or `segment_gracefully2` to convert collapsed arcs into\n"
" line-based representations when possible.\n"
).
-spec segment(svg_path:segment(), matrix()) -> {ok, svg_path:segment()} |
{error, error()}.
segment(Segment, Transform) ->
case validate_matrix(Transform) of
{error, Error} ->
{error, Error};
{ok, nil} ->
transform_valid_segment(Segment, Transform)
end.
-file("src/svg_path/transform.gleam", 243).
?DOC(" Transform a segment about a point.\n").
-spec segment_about_point(svg_path:segment(), matrix(), vec@vec2:vec2(float())) -> {ok,
svg_path:segment()} |
{error, error()}.
segment_about_point(Input, Transform, Point) ->
segment(Input, about_point(Transform, Point)).
-file("src/svg_path/transform.gleam", 718).
-spec anchor_point(svg_path:bounding_box(), anchor()) -> vec@vec2:vec2(float()).
anchor_point(Box, Anchor) ->
{bounding_box, Min, Max} = Box,
Center = svg_path:bounding_box_center(Box),
case Anchor of
top_left ->
Min;
top_center ->
svg_path:point(erlang:element(2, Center), erlang:element(3, Min));
top_right ->
svg_path:point(erlang:element(2, Max), erlang:element(3, Min));
center_left ->
svg_path:point(erlang:element(2, Min), erlang:element(3, Center));
center ->
Center;
center_right ->
svg_path:point(erlang:element(2, Max), erlang:element(3, Center));
bottom_left ->
svg_path:point(erlang:element(2, Min), erlang:element(3, Max));
bottom_center ->
svg_path:point(erlang:element(2, Center), erlang:element(3, Max));
bottom_right ->
Max
end.
-file("src/svg_path/transform.gleam", 252).
?DOC(" Transform a segment about an anchor on its bounding box.\n").
-spec segment_about_anchor(svg_path:segment(), matrix(), anchor()) -> {ok,
svg_path:segment()} |
{error, error()}.
segment_about_anchor(Input, Transform, Anchor) ->
case svg_path:segment_bounding_box(Input) of
{error, Error} ->
{error, {core, Error}};
{ok, Box} ->
segment_about_point(Input, Transform, anchor_point(Box, Anchor))
end.
-file("src/svg_path/transform.gleam", 269).
?DOC(" Translate a segment.\n").
-spec translate_segment(svg_path:segment(), float(), float()) -> {ok,
svg_path:segment()} |
{error, error()}.
translate_segment(Input, X, Y) ->
segment(Input, translate(X, Y)).
-file("src/svg_path/transform.gleam", 278).
?DOC(" Scale a segment uniformly.\n").
-spec scale_segment(svg_path:segment(), float()) -> {ok, svg_path:segment()} |
{error, error()}.
scale_segment(Input, Factor) ->
segment(Input, scale(Factor)).
-file("src/svg_path/transform.gleam", 286).
?DOC(" Scale a segment non-uniformly.\n").
-spec scale_xy_segment(svg_path:segment(), float(), float()) -> {ok,
svg_path:segment()} |
{error, error()}.
scale_xy_segment(Input, X, Y) ->
segment(Input, scale_xy(X, Y)).
-file("src/svg_path/transform.gleam", 295).
?DOC(" Rotate a segment around the origin.\n").
-spec rotate_segment(svg_path:segment(), float()) -> {ok, svg_path:segment()} |
{error, error()}.
rotate_segment(Input, Degrees) ->
segment(Input, rotate(Degrees)).
-file("src/svg_path/transform.gleam", 303).
?DOC(" Skew a segment along the x axis.\n").
-spec skew_x_segment(svg_path:segment(), float()) -> {ok, svg_path:segment()} |
{error, error()}.
skew_x_segment(Input, Degrees) ->
segment(Input, skew_x(Degrees)).
-file("src/svg_path/transform.gleam", 311).
?DOC(" Skew a segment along the y axis.\n").
-spec skew_y_segment(svg_path:segment(), float()) -> {ok, svg_path:segment()} |
{error, error()}.
skew_y_segment(Input, Degrees) ->
segment(Input, skew_y(Degrees)).
-file("src/svg_path/transform.gleam", 322).
?DOC(
" Transform a segment, converting collapsed arcs into lines when possible.\n"
"\n"
" This returns a single segment. If a collapsed arc needs multiple line\n"
" segments to preserve its motion, use `segment_gracefully2`.\n"
).
-spec segment_gracefully(svg_path:segment(), matrix()) -> {ok,
svg_path:segment()} |
{error, error()}.
segment_gracefully(Input, Transform) ->
case segment(Input, Transform) of
{ok, Segment} ->
{ok, Segment};
{error, degenerate_arc_transform} ->
case Input of
{arc, Start, Radius, X_axis_rotation, Large_arc, Sweep, End} ->
case svg_path@ellipse:collapsed_arc_line(
to_ellipse_point(Start),
to_ellipse_point(Radius),
X_axis_rotation,
Large_arc,
Sweep,
to_ellipse_point(End),
affine(Transform)
) of
{ok, Line} ->
{Start@1, End@1} = Line,
{ok,
{line,
from_ellipse_point(Start@1),
from_ellipse_point(End@1)}};
{error, _} ->
{error, degenerate_arc_transform}
end;
_ ->
{error, degenerate_arc_transform}
end;
{error, Error} ->
{error, Error}
end.
-file("src/svg_path/transform.gleam", 709).
-spec map_core_error({ok, svg_path:subpath()} | {error, svg_path:error()}) -> {ok,
svg_path:subpath()} |
{error, error()}.
map_core_error(Result) ->
case Result of
{ok, Subpath} ->
{ok, Subpath};
{error, Error} ->
{error, {core, Error}}
end.
-file("src/svg_path/transform.gleam", 768).
-spec lines_between_rest(
svg_path@ellipse:point(),
list(svg_path@ellipse:point()),
list(svg_path:segment())
) -> list(svg_path:segment()).
lines_between_rest(Previous, Points, Lines) ->
case Points of
[] ->
lists:reverse(Lines);
[First | Rest] ->
lines_between_rest(
First,
Rest,
[{line, from_ellipse_point(Previous), from_ellipse_point(First)} |
Lines]
)
end.
-file("src/svg_path/transform.gleam", 754).
-spec lines_between(list(svg_path@ellipse:point())) -> list(svg_path:segment()).
lines_between(Points) ->
case Points of
[] ->
[];
[_] ->
[];
[First, Second | Rest] ->
lines_between_rest(
Second,
Rest,
[{line, from_ellipse_point(First), from_ellipse_point(Second)}]
)
end.
-file("src/svg_path/transform.gleam", 369).
?DOC(
" Transform a segment, returning a subpath for graceful collapsed arc handling.\n"
"\n"
" This can represent collapsed arcs as multiple line segments when needed.\n"
).
-spec segment_gracefully2(svg_path:segment(), matrix()) -> {ok,
svg_path:subpath()} |
{error, error()}.
segment_gracefully2(Input, Transform) ->
case segment(Input, Transform) of
{ok, Segment} ->
_pipe = svg_path:subpath([Segment]),
map_core_error(_pipe);
{error, degenerate_arc_transform} ->
case Input of
{arc, Start, Radius, X_axis_rotation, Large_arc, Sweep, End} ->
case svg_path@ellipse:collapsed_arc_subpath(
to_ellipse_point(Start),
to_ellipse_point(Radius),
X_axis_rotation,
Large_arc,
Sweep,
to_ellipse_point(End),
affine(Transform)
) of
{ok, Points} ->
_pipe@1 = svg_path:subpath(lines_between(Points)),
map_core_error(_pipe@1);
{error, _} ->
{error, degenerate_arc_transform}
end;
_ ->
{error, degenerate_arc_transform}
end;
{error, Error} ->
{error, Error}
end.
-file("src/svg_path/transform.gleam", 857).
-spec close_transformed_subpath(svg_path:subpath()) -> {ok, svg_path:subpath()} |
{error, error()}.
close_transformed_subpath(Subpath) ->
case svg_path:set_closed(Subpath, true) of
{ok, Subpath@1} ->
{ok, Subpath@1};
{error, _} ->
case svg_path:set_closed_with(Subpath, true, wiggle) of
{ok, Subpath@2} ->
{ok, Subpath@2};
{error, Error} ->
{error, {core, Error}}
end
end.
-file("src/svg_path/transform.gleam", 527).
-spec finalize_transformed_subpath(
svg_path:subpath(),
list(svg_path:segment()),
matrix()
) -> {ok, svg_path:subpath()} | {error, error()}.
finalize_transformed_subpath(Original, Segments, Transform) ->
Start@1 = case svg_path:start(Original) of
{ok, Start} -> Start;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/transform"/utf8>>,
function => <<"finalize_transformed_subpath"/utf8>>,
line => 532,
value => _assert_fail,
start => 13739,
'end' => 13786,
pattern_start => 13750,
pattern_end => 13759})
end,
Start@2 = point(Start@1, Transform),
case Segments of
[] ->
Subpath = svg_path:empty_subpath(Start@2),
case svg_path:is_closed(Original) of
true ->
_pipe = svg_path:set_closed(Subpath, true),
map_core_error(_pipe);
false ->
{ok, Subpath}
end;
_ ->
case svg_path:subpath(Segments) of
{error, Error} ->
{error, {core, Error}};
{ok, Transformed} ->
case svg_path:is_closed(Original) of
true ->
close_transformed_subpath(Transformed);
false ->
{ok, Transformed}
end
end
end.
-file("src/svg_path/transform.gleam", 795).
-spec transform_segments(
list(svg_path:segment()),
matrix(),
list(svg_path:segment())
) -> {ok, list(svg_path:segment())} | {error, error()}.
transform_segments(Segments, Transform, Transformed) ->
case Segments of
[] ->
{ok, lists:reverse(Transformed)};
[First | Rest] ->
case segment(First, Transform) of
{error, Error} ->
{error, Error};
{ok, First@1} ->
transform_segments(Rest, Transform, [First@1 | Transformed])
end
end.
-file("src/svg_path/transform.gleam", 413).
?DOC(
" Transform a subpath by a matrix.\n"
"\n"
" Closed subpaths remain semantically closed when the transformed endpoints can\n"
" be reconciled.\n"
).
-spec subpath(svg_path:subpath(), matrix()) -> {ok, svg_path:subpath()} |
{error, error()}.
subpath(Subpath, Transform) ->
case validate_matrix(Transform) of
{error, Error} ->
{error, Error};
{ok, nil} ->
case transform_segments(svg_path:segments(Subpath), Transform, []) of
{error, Error@1} ->
{error, Error@1};
{ok, Segments} ->
finalize_transformed_subpath(Subpath, Segments, Transform)
end
end.
-file("src/svg_path/transform.gleam", 430).
?DOC(" Transform a subpath about a point.\n").
-spec subpath_about_point(svg_path:subpath(), matrix(), vec@vec2:vec2(float())) -> {ok,
svg_path:subpath()} |
{error, error()}.
subpath_about_point(Input, Transform, Point) ->
subpath(Input, about_point(Transform, Point)).
-file("src/svg_path/transform.gleam", 439).
?DOC(" Transform a subpath about an anchor on its bounding box.\n").
-spec subpath_about_anchor(svg_path:subpath(), matrix(), anchor()) -> {ok,
svg_path:subpath()} |
{error, error()}.
subpath_about_anchor(Input, Transform, Anchor) ->
case svg_path:subpath_bounding_box(Input) of
{error, Error} ->
{error, {core, Error}};
{ok, Box} ->
subpath_about_point(Input, Transform, anchor_point(Box, Anchor))
end.
-file("src/svg_path/transform.gleam", 456).
?DOC(" Translate a subpath.\n").
-spec translate_subpath(svg_path:subpath(), float(), float()) -> {ok,
svg_path:subpath()} |
{error, error()}.
translate_subpath(Input, X, Y) ->
subpath(Input, translate(X, Y)).
-file("src/svg_path/transform.gleam", 465).
?DOC(" Scale a subpath uniformly.\n").
-spec scale_subpath(svg_path:subpath(), float()) -> {ok, svg_path:subpath()} |
{error, error()}.
scale_subpath(Input, Factor) ->
subpath(Input, scale(Factor)).
-file("src/svg_path/transform.gleam", 473).
?DOC(" Scale a subpath non-uniformly.\n").
-spec scale_xy_subpath(svg_path:subpath(), float(), float()) -> {ok,
svg_path:subpath()} |
{error, error()}.
scale_xy_subpath(Input, X, Y) ->
subpath(Input, scale_xy(X, Y)).
-file("src/svg_path/transform.gleam", 482).
?DOC(" Rotate a subpath around the origin.\n").
-spec rotate_subpath(svg_path:subpath(), float()) -> {ok, svg_path:subpath()} |
{error, error()}.
rotate_subpath(Input, Degrees) ->
subpath(Input, rotate(Degrees)).
-file("src/svg_path/transform.gleam", 490).
?DOC(" Skew a subpath along the x axis.\n").
-spec skew_x_subpath(svg_path:subpath(), float()) -> {ok, svg_path:subpath()} |
{error, error()}.
skew_x_subpath(Input, Degrees) ->
subpath(Input, skew_x(Degrees)).
-file("src/svg_path/transform.gleam", 498).
?DOC(" Skew a subpath along the y axis.\n").
-spec skew_y_subpath(svg_path:subpath(), float()) -> {ok, svg_path:subpath()} |
{error, error()}.
skew_y_subpath(Input, Degrees) ->
subpath(Input, skew_y(Degrees)).
-file("src/svg_path/transform.gleam", 831).
-spec prepend_all(list(svg_path:segment()), list(svg_path:segment())) -> list(svg_path:segment()).
prepend_all(Segments, Transformed) ->
case Segments of
[] ->
Transformed;
[First | Rest] ->
prepend_all(Rest, [First | Transformed])
end.
-file("src/svg_path/transform.gleam", 811).
-spec transform_segments_gracefully(
list(svg_path:segment()),
matrix(),
list(svg_path:segment())
) -> {ok, list(svg_path:segment())} | {error, error()}.
transform_segments_gracefully(Segments, Transform, Transformed) ->
case Segments of
[] ->
{ok, lists:reverse(Transformed)};
[First | Rest] ->
case segment_gracefully2(First, Transform) of
{error, Error} ->
{error, Error};
{ok, First@1} ->
Transformed@1 = prepend_all(
svg_path:segments(First@1),
Transformed
),
transform_segments_gracefully(
Rest,
Transform,
Transformed@1
)
end
end.
-file("src/svg_path/transform.gleam", 509).
?DOC(
" Transform a subpath, gracefully converting collapsed arcs when possible.\n"
"\n"
" This uses the core path wiggle helpers to preserve continuity after\n"
" collapsed arcs are converted to line-based subpaths.\n"
).
-spec subpath_gracefully(svg_path:subpath(), matrix()) -> {ok,
svg_path:subpath()} |
{error, error()}.
subpath_gracefully(Subpath, Transform) ->
case validate_matrix(Transform) of
{error, Error} ->
{error, Error};
{ok, nil} ->
case transform_segments_gracefully(
svg_path:segments(Subpath),
Transform,
[]
) of
{error, Error@1} ->
{error, Error@1};
{ok, Segments} ->
finalize_transformed_subpath(Subpath, Segments, Transform)
end
end.
-file("src/svg_path/transform.gleam", 841).
-spec transform_subpaths(
list(svg_path:subpath()),
matrix(),
list(svg_path:subpath())
) -> {ok, list(svg_path:subpath())} | {error, error()}.
transform_subpaths(Subpaths, Transform, Transformed) ->
case Subpaths of
[] ->
{ok, lists:reverse(Transformed)};
[First | Rest] ->
case subpath(First, Transform) of
{error, Error} ->
{error, Error};
{ok, First@1} ->
transform_subpaths(Rest, Transform, [First@1 | Transformed])
end
end.
-file("src/svg_path/transform.gleam", 558).
?DOC(" Transform every subpath in a path by a matrix.\n").
-spec path(svg_path:path(), matrix()) -> {ok, svg_path:path()} |
{error, error()}.
path(Path, Transform) ->
case validate_matrix(Transform) of
{error, Error} ->
{error, Error};
{ok, nil} ->
case transform_subpaths(svg_path:subpaths(Path), Transform, []) of
{error, Error@1} ->
{error, Error@1};
{ok, Subpaths} ->
{ok, {path, Subpaths}}
end
end.
-file("src/svg_path/transform.gleam", 574).
?DOC(" Transform a path about a point.\n").
-spec path_about_point(svg_path:path(), matrix(), vec@vec2:vec2(float())) -> {ok,
svg_path:path()} |
{error, error()}.
path_about_point(Input, Transform, Point) ->
path(Input, about_point(Transform, Point)).
-file("src/svg_path/transform.gleam", 583).
?DOC(" Transform a path about an anchor on its bounding box.\n").
-spec path_about_anchor(svg_path:path(), matrix(), anchor()) -> {ok,
svg_path:path()} |
{error, error()}.
path_about_anchor(Input, Transform, Anchor) ->
case svg_path:path_bounding_box(Input) of
{error, Error} ->
{error, {core, Error}};
{ok, Box} ->
path_about_point(Input, Transform, anchor_point(Box, Anchor))
end.
-file("src/svg_path/transform.gleam", 596).
?DOC(" Translate a path.\n").
-spec translate_path(svg_path:path(), float(), float()) -> {ok, svg_path:path()} |
{error, error()}.
translate_path(Input, X, Y) ->
path(Input, translate(X, Y)).
-file("src/svg_path/transform.gleam", 605).
?DOC(" Scale a path uniformly.\n").
-spec scale_path(svg_path:path(), float()) -> {ok, svg_path:path()} |
{error, error()}.
scale_path(Input, Factor) ->
path(Input, scale(Factor)).
-file("src/svg_path/transform.gleam", 613).
?DOC(" Scale a path non-uniformly.\n").
-spec scale_xy_path(svg_path:path(), float(), float()) -> {ok, svg_path:path()} |
{error, error()}.
scale_xy_path(Input, X, Y) ->
path(Input, scale_xy(X, Y)).
-file("src/svg_path/transform.gleam", 622).
?DOC(" Rotate a path around the origin.\n").
-spec rotate_path(svg_path:path(), float()) -> {ok, svg_path:path()} |
{error, error()}.
rotate_path(Input, Degrees) ->
path(Input, rotate(Degrees)).
-file("src/svg_path/transform.gleam", 630).
?DOC(" Skew a path along the x axis.\n").
-spec skew_x_path(svg_path:path(), float()) -> {ok, svg_path:path()} |
{error, error()}.
skew_x_path(Input, Degrees) ->
path(Input, skew_x(Degrees)).
-file("src/svg_path/transform.gleam", 638).
?DOC(" Skew a path along the y axis.\n").
-spec skew_y_path(svg_path:path(), float()) -> {ok, svg_path:path()} |
{error, error()}.
skew_y_path(Input, Degrees) ->
path(Input, skew_y(Degrees)).