-module(svg_path@convex_hull).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/svg_path/convex_hull.gleam").
-export([segment_hull/1, subpath_hull/1, path_hull/1, points_hull/1, test_segment_support/2, test_brute_segment_support/2, test_point_chord_polygon_loop_separation/2, test_point_chord_polygon_tangent_subpaths/2, test_point_exact_loop_tangent_subpaths/2, test_loop_plus_point_hull/2, test_loop_plus_points_hull/2, test_path_hull_with_repair_mode/2, test_ambitious_repair_loop_with_loop/2, test_find_seeded_worst_direction/4, test_loop_initial_sample_angles/2, test_loop_union_segments_with_seed_angles/3, test_segment_tangent_monotone/2, test_point_loop_view/5]).
-export_type([support_sample/0, run/0, run_endpoint/0, loop_support/0, loop_param/0, loop/0, convex_polygon/0, convex_loop/0, union_piece/0, loop_winner/0, loop_sample/0, loop_boundary/0, hull_piece/0, tangent_candidate/0, loop_tangent_candidate/0, point_loop_view/0, hull_error/0, tangent_search_orientation/0, tangent_orientation/0, tangent_orientation_evidence/0, loop_dominance/0, seeded_worst_direction_state/0, refinement_scan/0, loop_orientation/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(
" Convex hull helpers for paths, subpaths, segments, and points.\n"
"\n"
" This module computes closed hulls. Lines, quadratic Beziers, and arcs have\n"
" semantic hulls: the primitive itself plus the chord joining its endpoints,\n"
" with tiny/point-like cases collapsed to lines. Cubic Beziers use a\n"
" cubic-specific support/event solver.\n"
).
-type support_sample() :: {support_sample,
float(),
float(),
vec@vec2:vec2(float()),
float()}.
-type run() :: {run, list(float())}.
-type run_endpoint() :: {point_endpoint, float()} |
{curve_endpoint, float(), float()}.
-type loop_support() :: {loop_support,
loop_param(),
vec@vec2:vec2(float()),
float()}.
-type loop_param() :: {loop_param, integer(), float()}.
-type loop() :: {loop, list(svg_path:segment())}.
-type convex_polygon() :: {convex_polygon, list(vec@vec2:vec2(float()))}.
-type convex_loop() :: {convex_loop, loop(), convex_polygon()}.
-type union_piece() :: {hull_line_a_b, loop_param(), loop_param()} |
{hull_line_b_a, loop_param(), loop_param()} |
{loop_piece_a, loop_param(), loop_param()} |
{loop_piece_b, loop_param(), loop_param()}.
-type loop_winner() :: loop_a | loop_b.
-type loop_sample() :: {loop_sample,
float(),
loop_winner(),
loop_support(),
loop_support(),
float()}.
-type loop_boundary() :: {loop_boundary,
float(),
loop_support(),
loop_support(),
loop_winner(),
loop_winner()}.
-type hull_piece() :: {hull_curve, float(), float()} |
{hull_line, float(), float()}.
-type tangent_candidate() :: {tangent_candidate,
integer(),
vec@vec2:vec2(float())}.
-type loop_tangent_candidate() :: {loop_tangent_candidate,
loop_param(),
vec@vec2:vec2(float())}.
-type point_loop_view() :: tangent_point | outside_point | inside_point.
-type hull_error() :: {path_error, svg_path:error()} |
consecutive_curves |
duplicate_adjacent_t_values |
{refinement_reached_max_iterations, integer()} |
{purification_reached_max_iterations, integer()} |
loop_union_collapsed |
tangent_search_degenerate_loop |
{tangent_search_non_convex_vertex, integer()} |
{tangent_search_expected_two_tangencies, integer()} |
{seeded_worst_direction_exceeded_threshold, float(), float()}.
-type tangent_search_orientation() :: {exact_search_orientation,
loop_orientation()} |
{line_like_search_orientation, loop_orientation()} |
degenerate_search_orientation.
-type tangent_orientation() :: {found_tangent_orientation, loop_orientation()} |
no_tangent_orientation |
conflicting_tangent_orientation.
-type tangent_orientation_evidence() :: no_tangent_orientation_evidence |
{tangent_orientation_evidence, loop_orientation()} |
conflicting_tangent_orientation_evidence.
-type loop_dominance() :: loop_a_dominates |
loop_b_dominates |
no_loop_dominates.
-type seeded_worst_direction_state() :: {seeded_worst_direction_state,
float(),
float()}.
-type refinement_scan() :: {done, float()} |
{continue, {float(), float(), float(), float()}}.
-type loop_orientation() :: counter_clockwise |
clockwise |
degenerate_orientation.
-file("src/svg_path/convex_hull.gleam", 3858).
-spec turn_against_orientation_amount(float(), float(), loop_orientation()) -> float().
turn_against_orientation_amount(Turn, Scale, Orientation) ->
Tolerance = 0.000000001 * Scale,
case Orientation of
counter_clockwise ->
gleam@float:max(+0.0, (+0.0 - Tolerance) - Turn);
clockwise ->
gleam@float:max(+0.0, Turn - Tolerance);
degenerate_orientation ->
+0.0
end.
-file("src/svg_path/convex_hull.gleam", 3977).
-spec dot(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> float().
dot(A, B) ->
(erlang:element(2, A) * erlang:element(2, B)) + (erlang:element(3, A) * erlang:element(
3,
B
)).
-file("src/svg_path/convex_hull.gleam", 3880).
-spec point_length(vec@vec2:vec2(float())) -> float().
point_length(Point) ->
Length@1 = case gleam@float:square_root(dot(Point, Point)) of
{ok, Length} -> Length;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"point_length"/utf8>>,
line => 3881,
value => _assert_fail,
start => 101292,
'end' => 101352,
pattern_start => 101303,
pattern_end => 101313})
end,
Length@1.
-file("src/svg_path/convex_hull.gleam", 3936).
-spec cross(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> float().
cross(A, B) ->
(erlang:element(2, A) * erlang:element(3, B)) - (erlang:element(3, A) * erlang:element(
2,
B
)).
-file("src/svg_path/convex_hull.gleam", 3729).
-spec segment_derivative_sample(svg_path:segment(), integer(), integer()) -> {ok,
vec@vec2:vec2(float())} |
{error, svg_path:error()}.
segment_derivative_sample(Segment, Index, Sample_count) ->
T = case erlang:float(Sample_count) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(Index) / Gleam@denominator
end,
svg_path:segment_derivative(Segment, T).
-file("src/svg_path/convex_hull.gleam", 1893).
-spec segment_tangent_turn_numerical_loop(
svg_path:segment(),
loop_orientation(),
integer(),
integer(),
vec@vec2:vec2(float()),
float()
) -> {ok, nil} | {error, float()}.
segment_tangent_turn_numerical_loop(
Segment,
Orientation,
Sample_count,
Sample_index,
Previous,
Worst
) ->
case Sample_index > Sample_count of
true ->
case Worst =:= +0.0 of
true ->
{ok, nil};
false ->
{error, Worst}
end;
false ->
case segment_derivative_sample(Segment, Sample_index, Sample_count) of
{error, _} ->
{ok, nil};
{ok, Current} ->
Turn = cross(Previous, Current),
Scale = point_length(Previous) * point_length(Current),
Amount = turn_against_orientation_amount(
Turn,
Scale,
Orientation
),
segment_tangent_turn_numerical_loop(
Segment,
Orientation,
Sample_count,
Sample_index + 1,
Current,
gleam@float:max(Worst, Amount)
)
end
end.
-file("src/svg_path/convex_hull.gleam", 1869).
-spec segment_tangent_turn_numerical(svg_path:segment(), loop_orientation()) -> {ok,
nil} |
{error, float()}.
segment_tangent_turn_numerical(Segment, Orientation) ->
case Segment of
{line, _, _} ->
{ok, nil};
_ ->
Sample_count = 24,
case segment_derivative_sample(Segment, 0, Sample_count) of
{error, _} ->
{ok, nil};
{ok, First} ->
segment_tangent_turn_numerical_loop(
Segment,
Orientation,
Sample_count,
1,
First,
+0.0
)
end
end.
-file("src/svg_path/convex_hull.gleam", 3889).
-spec segment_kind(svg_path:segment()) -> binary().
segment_kind(Segment) ->
case Segment of
{line, _, _} ->
<<"Line"/utf8>>;
{quadratic_bezier, _, _, _} ->
<<"QuadraticBezier"/utf8>>;
{cubic_bezier, _, _, _, _} ->
<<"CubicBezier"/utf8>>;
{arc, _, _, _, _, _, _} ->
<<"Arc"/utf8>>
end.
-file("src/svg_path/convex_hull.gleam", 3707).
-spec diagnose_segment_tangent_turn_result(
svg_path:segment(),
integer(),
binary(),
{ok, nil} | {error, float()}
) -> nil.
diagnose_segment_tangent_turn_result(Segment, Segment_index, Check, Result) ->
case Result of
{ok, _} ->
nil;
{error, Amount} ->
gleam_stdlib:println(
<<<<<<<<<<<<<<"[convex_hull diagnostic] "/utf8, Check/binary>>/binary,
" segment tangent reversal at segment "/utf8>>/binary,
(erlang:integer_to_binary(Segment_index))/binary>>/binary,
" ("/utf8>>/binary,
(segment_kind(Segment))/binary>>/binary,
") amount="/utf8>>/binary,
(gleam_stdlib:float_to_string(Amount))/binary>>
)
end.
-file("src/svg_path/convex_hull.gleam", 1974).
-spec curvature_wrong_way_amount(float(), loop_orientation()) -> float().
curvature_wrong_way_amount(Value, Orientation) ->
case Orientation of
counter_clockwise ->
gleam@float:max(+0.0, +0.0 - Value);
clockwise ->
gleam@float:max(+0.0, Value);
degenerate_orientation ->
gleam@float:absolute_value(Value)
end.
-file("src/svg_path/convex_hull.gleam", 1958).
-spec curvature_violation(list(float()), loop_orientation()) -> {ok, nil} |
{error, float()}.
curvature_violation(Values, Orientation) ->
Violation = begin
_pipe = Values,
gleam@list:fold(
_pipe,
+0.0,
fun(Worst, Value) ->
gleam@float:max(
Worst,
curvature_wrong_way_amount(Value, Orientation)
)
end
)
end,
case Violation =:= +0.0 of
true ->
{ok, nil};
false ->
{error, Violation}
end.
-file("src/svg_path/convex_hull.gleam", 3932).
-spec scale_point(vec@vec2:vec2(float()), float()) -> vec@vec2:vec2(float()).
scale_point(A, Factor) ->
svg_path:point(erlang:element(2, A) * Factor, erlang:element(3, A) * Factor).
-file("src/svg_path/convex_hull.gleam", 3928).
-spec subtract(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> vec@vec2:vec2(float()).
subtract(A, B) ->
svg_path:point(
erlang:element(2, A) - erlang:element(2, B),
erlang:element(3, A) - erlang:element(3, B)
).
-file("src/svg_path/convex_hull.gleam", 3924).
-spec add_points(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> vec@vec2:vec2(float()).
add_points(A, B) ->
svg_path:point(
erlang:element(2, A) + erlang:element(2, B),
erlang:element(3, A) + erlang:element(3, B)
).
-file("src/svg_path/convex_hull.gleam", 1928).
-spec cubic_curvature_values(
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
vec@vec2:vec2(float())
) -> list(float()).
cubic_curvature_values(Start, Control1, Control2, End) ->
A = subtract(Control1, Start),
B = subtract(Control2, Control1),
C = subtract(End, Control2),
U = A,
V = scale_point(subtract(B, A), 2.0),
W = add_points(subtract(A, scale_point(B, 2.0)), C),
Qa = cross(V, W),
Qb = 2.0 * cross(U, W),
Qc = cross(U, V),
Candidates = case Qa =:= +0.0 of
true ->
[+0.0, 1.0];
false ->
Critical = case (2.0 * Qa) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> (+0.0 - Qb) / Gleam@denominator
end,
case (Critical > +0.0) andalso (Critical < 1.0) of
true ->
[+0.0, 1.0, Critical];
false ->
[+0.0, 1.0]
end
end,
_pipe = Candidates,
gleam@list:map(_pipe, fun(T) -> (((Qa * T) * T) + (Qb * T)) + Qc end).
-file("src/svg_path/convex_hull.gleam", 1836).
-spec segment_tangent_turn_algebraic(svg_path:segment(), loop_orientation()) -> {ok,
nil} |
{error, float()}.
segment_tangent_turn_algebraic(Segment, Orientation) ->
case Segment of
{line, _, _} ->
{ok, nil};
{quadratic_bezier, Start, Control, End} ->
Arriving = subtract(Control, Start),
Leaving = subtract(End, Control),
curvature_violation([cross(Arriving, Leaving)], Orientation);
{cubic_bezier, Start@1, Control1, Control2, End@1} ->
_pipe = cubic_curvature_values(Start@1, Control1, Control2, End@1),
curvature_violation(_pipe, Orientation);
{arc, _, _, _, _, Sweep, _} ->
case Orientation of
counter_clockwise ->
case Sweep of
true ->
{ok, nil};
false ->
{error, 1.0}
end;
clockwise ->
case Sweep of
true ->
{error, 1.0};
false ->
{ok, nil}
end;
degenerate_orientation ->
{error, 1.0}
end
end.
-file("src/svg_path/convex_hull.gleam", 3688).
-spec diagnose_segment_tangent_turn(
svg_path:segment(),
loop_orientation(),
integer()
) -> nil.
diagnose_segment_tangent_turn(Segment, Orientation, Segment_index) ->
diagnose_segment_tangent_turn_result(
Segment,
Segment_index,
<<"algebraic"/utf8>>,
segment_tangent_turn_algebraic(Segment, Orientation)
),
diagnose_segment_tangent_turn_result(
Segment,
Segment_index,
<<"numerical"/utf8>>,
segment_tangent_turn_numerical(Segment, Orientation)
).
-file("src/svg_path/convex_hull.gleam", 3674).
-spec diagnose_segment_tangent_turns_loop(
list(svg_path:segment()),
loop_orientation(),
integer()
) -> nil.
diagnose_segment_tangent_turns_loop(Segments, Orientation, Index) ->
case Segments of
[] ->
nil;
[Segment | Rest] ->
diagnose_segment_tangent_turn(Segment, Orientation, Index),
diagnose_segment_tangent_turns_loop(Rest, Orientation, Index + 1)
end.
-file("src/svg_path/convex_hull.gleam", 3667).
-spec diagnose_segment_tangent_turns(
list(svg_path:segment()),
loop_orientation()
) -> nil.
diagnose_segment_tangent_turns(Segments, Orientation) ->
diagnose_segment_tangent_turns_loop(Segments, Orientation, 0).
-file("src/svg_path/convex_hull.gleam", 3885).
-spec point_string(vec@vec2:vec2(float())) -> binary().
point_string(Point) ->
<<<<<<<<"("/utf8,
(gleam_stdlib:float_to_string(erlang:element(2, Point)))/binary>>/binary,
", "/utf8>>/binary,
(gleam_stdlib:float_to_string(erlang:element(3, Point)))/binary>>/binary,
")"/utf8>>.
-file("src/svg_path/convex_hull.gleam", 3850).
-spec turn_is_against_orientation(float(), float(), loop_orientation()) -> boolean().
turn_is_against_orientation(Turn, Scale, Orientation) ->
turn_against_orientation_amount(Turn, Scale, Orientation) > +0.0.
-file("src/svg_path/convex_hull.gleam", 3634).
-spec diagnose_endpoint_turns_loop(
list(vec@vec2:vec2(float())),
loop_orientation(),
integer()
) -> nil.
diagnose_endpoint_turns_loop(Points, Orientation, Index) ->
case Points of
[A, B, C | Rest] ->
Ab = subtract(B, A),
Bc = subtract(C, B),
Turn = cross(Ab, Bc),
Scale = point_length(Ab) * point_length(Bc),
case turn_is_against_orientation(Turn, Scale, Orientation) of
true ->
gleam_stdlib:println(
<<<<<<<<<<<<<<"[convex_hull diagnostic] endpoint right turn at vertex "/utf8,
(erlang:integer_to_binary(
Index
))/binary>>/binary,
" turn="/utf8>>/binary,
(gleam_stdlib:float_to_string(Turn))/binary>>/binary,
" scale="/utf8>>/binary,
(gleam_stdlib:float_to_string(Scale))/binary>>/binary,
" point="/utf8>>/binary,
(point_string(B))/binary>>
);
false ->
nil
end,
diagnose_endpoint_turns_loop([B, C | Rest], Orientation, Index + 1);
_ ->
nil
end.
-file("src/svg_path/convex_hull.gleam", 3875).
-spec point_distance_squared(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> float().
point_distance_squared(A, B) ->
Difference = subtract(A, B),
dot(Difference, Difference).
-file("src/svg_path/convex_hull.gleam", 3871).
-spec points_near(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> boolean().
points_near(A, B) ->
point_distance_squared(A, B) =< (0.000000001 * 0.000000001).
-file("src/svg_path/convex_hull.gleam", 3804).
-spec remove_near_adjacent_duplicates_loop(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
list(vec@vec2:vec2(float()))
) -> list(vec@vec2:vec2(float())).
remove_near_adjacent_duplicates_loop(Points, Previous, Kept) ->
case Points of
[] ->
lists:reverse(Kept);
[Point | Rest] ->
case points_near(Previous, Point) of
true ->
remove_near_adjacent_duplicates_loop(Rest, Previous, Kept);
false ->
remove_near_adjacent_duplicates_loop(
Rest,
Point,
[Point | Kept]
)
end
end.
-file("src/svg_path/convex_hull.gleam", 3794).
-spec remove_near_adjacent_duplicates(list(vec@vec2:vec2(float()))) -> list(vec@vec2:vec2(float())).
remove_near_adjacent_duplicates(Points) ->
case Points of
[] ->
[];
[First | Rest] ->
remove_near_adjacent_duplicates_loop(Rest, First, [First])
end.
-file("src/svg_path/convex_hull.gleam", 3991).
-spec drop_last(list(MQP)) -> list(MQP).
drop_last(Items) ->
case Items of
[] ->
[];
[_] ->
[];
[First | Rest] ->
[First | drop_last(Rest)]
end.
-file("src/svg_path/convex_hull.gleam", 3776).
-spec remove_closing_duplicate(list(vec@vec2:vec2(float()))) -> list(vec@vec2:vec2(float())).
remove_closing_duplicate(Points) ->
case Points of
[] ->
[];
[First | _] ->
case gleam@list:last(Points) of
{ok, Last} ->
case points_near(First, Last) of
true ->
drop_last(Points);
false ->
Points
end;
_ ->
Points
end
end.
-file("src/svg_path/convex_hull.gleam", 3766).
-spec segment_endpoints(list(svg_path:segment())) -> list(vec@vec2:vec2(float())).
segment_endpoints(Segments) ->
case Segments of
[] ->
[];
[Segment | Rest] ->
[svg_path:segment_end(Segment) | segment_endpoints(Rest)]
end.
-file("src/svg_path/convex_hull.gleam", 3751).
-spec loop_vertices(list(svg_path:segment())) -> list(vec@vec2:vec2(float())).
loop_vertices(Segments) ->
case Segments of
[] ->
[];
[First | _] ->
Points = [svg_path:segment_start(First) |
segment_endpoints(Segments)],
_pipe = Points,
_pipe@1 = remove_closing_duplicate(_pipe),
remove_near_adjacent_duplicates(_pipe@1)
end.
-file("src/svg_path/convex_hull.gleam", 3620).
-spec diagnose_endpoint_turns(list(svg_path:segment()), loop_orientation()) -> nil.
diagnose_endpoint_turns(Segments, Orientation) ->
case loop_vertices(Segments) of
[] ->
nil;
[_] ->
nil;
[_, _] ->
nil;
[First, Second | _] = Vertices ->
_pipe = Vertices,
_pipe@1 = lists:append(_pipe, [First, Second]),
diagnose_endpoint_turns_loop(_pipe@1, Orientation, 0)
end.
-file("src/svg_path/convex_hull.gleam", 3832).
-spec signed_area_loop(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
float()
) -> float().
signed_area_loop(Points, First, Previous, Area) ->
case Points of
[] ->
(Area + cross(Previous, First)) / 2.0;
[Point | Rest] ->
signed_area_loop(Rest, First, Point, Area + cross(Previous, Point))
end.
-file("src/svg_path/convex_hull.gleam", 3824).
-spec signed_area(list(vec@vec2:vec2(float()))) -> float().
signed_area(Points) ->
case Points of
[] ->
+0.0;
[_] ->
+0.0;
[_, _] ->
+0.0;
[First | Rest] ->
signed_area_loop(Rest, First, First, +0.0)
end.
-file("src/svg_path/convex_hull.gleam", 3738).
-spec loop_orientation(list(svg_path:segment())) -> loop_orientation().
loop_orientation(Segments) ->
Vertices = loop_vertices(Segments),
Area = signed_area(Vertices),
case gleam@float:absolute_value(Area) =< (0.000000001 * 0.000000001) of
true ->
degenerate_orientation;
false ->
case Area > +0.0 of
true ->
counter_clockwise;
false ->
clockwise
end
end.
-file("src/svg_path/convex_hull.gleam", 3605).
-spec diagnose_closed_loop(list(svg_path:segment())) -> nil.
diagnose_closed_loop(Segments) ->
case false of
false ->
nil;
true ->
case loop_orientation(Segments) of
degenerate_orientation ->
nil;
Orientation ->
diagnose_endpoint_turns(Segments, Orientation),
diagnose_segment_tangent_turns(Segments, Orientation)
end
end.
-file("src/svg_path/convex_hull.gleam", 3981).
-spec map_path_error({ok, MQK} | {error, svg_path:error()}) -> {ok, MQK} |
{error, hull_error()}.
map_path_error(Result) ->
gleam@result:map_error(Result, fun(Field@0) -> {path_error, Field@0} end).
-file("src/svg_path/convex_hull.gleam", 2306).
-spec build_closed_subpath(list(svg_path:segment())) -> {ok, svg_path:subpath()} |
{error, hull_error()}.
build_closed_subpath(Segments) ->
gleam@result:'try'(
begin
_pipe = svg_path:subpath_with(Segments, wiggle_then_bridge),
map_path_error(_pipe)
end,
fun(Subpath) ->
case begin
_pipe@1 = svg_path:set_closed_with(
Subpath,
true,
wiggle_then_bridge
),
map_path_error(_pipe@1)
end of
{error, Error} ->
{error, Error};
{ok, Subpath@1} ->
diagnose_closed_loop(svg_path:segments(Subpath@1)),
{ok, Subpath@1}
end
end
).
-file("src/svg_path/convex_hull.gleam", 2983).
-spec segment_is_point_like(svg_path:segment()) -> boolean().
segment_is_point_like(Segment) ->
case svg_path:segment_bounding_box(Segment) of
{error, _} ->
true;
{ok, Box} ->
svg_path:bounding_box_diameter(Box) =< 0.000000001
end.
-file("src/svg_path/convex_hull.gleam", 1737).
-spec remove_point_like_segments(list(svg_path:segment())) -> list(svg_path:segment()).
remove_point_like_segments(Segments) ->
_pipe = Segments,
gleam@list:filter(
_pipe,
fun(Segment) -> segment_is_point_like(Segment) =:= false end
).
-file("src/svg_path/convex_hull.gleam", 3999).
-spec nth(list(MQS), integer()) -> {ok, MQS} | {error, nil}.
nth(Items, Index) ->
case {Items, Index} of
{[], _} ->
{error, nil};
{[Item | _], 0} ->
{ok, Item};
{[_ | Rest], _} ->
nth(Rest, Index - 1)
end.
-file("src/svg_path/convex_hull.gleam", 2830).
-spec loop_point(loop(), loop_param()) -> vec@vec2:vec2(float()).
loop_point(Loop, Param) ->
{loop, Segments} = Loop,
{loop_param, Segment_index, T} = Param,
Segment@1 = case nth(Segments, Segment_index) of
{ok, Segment} -> Segment;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"loop_point"/utf8>>,
line => 2833,
value => _assert_fail,
start => 75071,
'end' => 75124,
pattern_start => 75082,
pattern_end => 75093})
end,
Point@1 = case svg_path:segment_point(Segment@1, T) of
{ok, Point} -> Point;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"loop_point"/utf8>>,
line => 2834,
value => _assert_fail@1,
start => 75127,
'end' => 75188,
pattern_start => 75138,
pattern_end => 75147})
end,
Point@1.
-file("src/svg_path/convex_hull.gleam", 2907).
-spec loop_partial_segment(svg_path:segment(), float(), float()) -> svg_path:segment().
loop_partial_segment(Segment, From, To) ->
Part@1 = case svg_path:sub_segment(Segment, From, To) of
{ok, Part} -> Part;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"loop_partial_segment"/utf8>>,
line => 2912,
value => _assert_fail,
start => 77246,
'end' => 77317,
pattern_start => 77257,
pattern_end => 77265})
end,
Part@1.
-file("src/svg_path/convex_hull.gleam", 2916).
-spec segment_at(list(svg_path:segment()), integer()) -> svg_path:segment().
segment_at(Segments, Index) ->
Segment@1 = case nth(Segments, Index) of
{ok, Segment} -> Segment;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"segment_at"/utf8>>,
line => 2920,
value => _assert_fail,
start => 77419,
'end' => 77464,
pattern_start => 77430,
pattern_end => 77441})
end,
Segment@1.
-file("src/svg_path/convex_hull.gleam", 2940).
-spec next_index(integer(), integer()) -> integer().
next_index(Index, Count) ->
case (Index + 1) >= Count of
true ->
0;
false ->
Index + 1
end.
-file("src/svg_path/convex_hull.gleam", 2924).
-spec walk_segment_indices(integer(), integer(), integer(), list(integer())) -> list(integer()).
walk_segment_indices(Current, Target, Count, Indices) ->
case Current =:= Target of
true ->
[Current | Indices];
false ->
walk_segment_indices(
next_index(Current, Count),
Target,
Count,
[Current | Indices]
)
end.
-file("src/svg_path/convex_hull.gleam", 2884).
-spec loop_wrapped_same_segment_piece(
list(svg_path:segment()),
integer(),
float(),
float()
) -> list(svg_path:segment()).
loop_wrapped_same_segment_piece(Segments, Index, From, To) ->
Count = erlang:length(Segments),
Middle = begin
_pipe = walk_segment_indices(next_index(Index, Count), Index, Count, []),
_pipe@1 = lists:reverse(_pipe),
_pipe@2 = drop_last(_pipe@1),
gleam@list:map(
_pipe@2,
fun(Index@1) ->
loop_partial_segment(segment_at(Segments, Index@1), +0.0, 1.0)
end
)
end,
lists:append(
[loop_partial_segment(segment_at(Segments, Index), From, 1.0)],
lists:append(
Middle,
[loop_partial_segment(segment_at(Segments, Index), +0.0, To)]
)
).
-file("src/svg_path/convex_hull.gleam", 2838).
-spec loop_piece_segments(loop(), loop_param(), loop_param()) -> list(svg_path:segment()).
loop_piece_segments(Loop, From, To) ->
{loop, Segments} = Loop,
{loop_param, From_index, From_t} = From,
{loop_param, To_index, To_t} = To,
case (From_index =:= To_index) andalso (gleam@float:absolute_value(
From_t - To_t
)
=< 0.000001) of
true ->
Segments;
false ->
case From_index =:= To_index of
true ->
case From_t =< To_t of
true ->
[loop_partial_segment(
segment_at(Segments, From_index),
From_t,
To_t
)];
false ->
loop_wrapped_same_segment_piece(
Segments,
From_index,
From_t,
To_t
)
end;
false ->
_pipe = walk_segment_indices(
From_index,
To_index,
erlang:length(Segments),
[]
),
_pipe@1 = lists:reverse(_pipe),
gleam@list:map(
_pipe@1,
fun(Index) ->
Segment = segment_at(Segments, Index),
case {Index =:= From_index, Index =:= To_index} of
{true, _} ->
loop_partial_segment(Segment, From_t, 1.0);
{_, true} ->
loop_partial_segment(Segment, +0.0, To_t);
{_, _} ->
loop_partial_segment(Segment, +0.0, 1.0)
end
end
)
end
end.
-file("src/svg_path/convex_hull.gleam", 2420).
-spec union_piece_segments(list(union_piece()), loop(), loop()) -> list(svg_path:segment()).
union_piece_segments(Pieces, Loop_a, Loop_b) ->
_pipe = Pieces,
_pipe@1 = gleam@list:flat_map(_pipe, fun(Piece) -> case Piece of
{loop_piece_a, From, To} ->
loop_piece_segments(Loop_a, From, To);
{loop_piece_b, From@1, To@1} ->
loop_piece_segments(Loop_b, From@1, To@1);
{hull_line_a_b, A, B} ->
[{line, loop_point(Loop_a, A), loop_point(Loop_b, B)}];
{hull_line_b_a, B@1, A@1} ->
[{line, loop_point(Loop_b, B@1), loop_point(Loop_a, A@1)}]
end end),
remove_point_like_segments(_pipe@1).
-file("src/svg_path/convex_hull.gleam", 2784).
-spec loop_points_far(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> boolean().
loop_points_far(A, B) ->
Dx = erlang:element(2, A) - erlang:element(2, B),
Dy = erlang:element(3, A) - erlang:element(3, B),
((Dx * Dx) + (Dy * Dy)) > (0.000001 * 0.000001).
-file("src/svg_path/convex_hull.gleam", 2764).
-spec compact_loop_pieces(list(union_piece()), loop(), loop()) -> list(union_piece()).
compact_loop_pieces(Pieces, Loop_a, Loop_b) ->
_pipe = Pieces,
gleam@list:filter(_pipe, fun(Piece) -> case Piece of
{loop_piece_a, From, To} ->
loop_points_far(
loop_point(Loop_a, From),
loop_point(Loop_a, To)
);
{loop_piece_b, From@1, To@1} ->
loop_points_far(
loop_point(Loop_b, From@1),
loop_point(Loop_b, To@1)
);
{hull_line_a_b, A, B} ->
loop_points_far(
loop_point(Loop_a, A),
loop_point(Loop_b, B)
);
{hull_line_b_a, B@1, A@1} ->
loop_points_far(
loop_point(Loop_b, B@1),
loop_point(Loop_a, A@1)
)
end end).
-file("src/svg_path/convex_hull.gleam", 2954).
-spec circular_pairs_loop(list(MNK), MNK, list({MNK, MNK})) -> list({MNK, MNK}).
circular_pairs_loop(Items, First, Pairs) ->
case Items of
[] ->
_pipe = Pairs,
lists:reverse(_pipe);
[Last] ->
_pipe@1 = [{Last, First} | Pairs],
lists:reverse(_pipe@1);
[Left, Right | Rest] ->
circular_pairs_loop([Right | Rest], First, [{Left, Right} | Pairs])
end.
-file("src/svg_path/convex_hull.gleam", 2947).
-spec circular_pairs(list(MNH)) -> list({MNH, MNH}).
circular_pairs(Items) ->
case Items of
[] ->
[];
[_] ->
[];
[First | _] ->
circular_pairs_loop(Items, First, [])
end.
-file("src/svg_path/convex_hull.gleam", 2743).
-spec loop_pieces_from_boundaries(list(loop_boundary())) -> list(union_piece()).
loop_pieces_from_boundaries(Boundaries) ->
_pipe = Boundaries,
_pipe@1 = circular_pairs(_pipe),
_pipe@2 = gleam@list:map(
_pipe@1,
fun(Boundary_pair) ->
{Start_boundary, End_boundary} = Boundary_pair,
Loop_piece = case erlang:element(6, Start_boundary) of
loop_a ->
{loop_piece_a,
erlang:element(2, erlang:element(3, Start_boundary)),
erlang:element(2, erlang:element(3, End_boundary))};
loop_b ->
{loop_piece_b,
erlang:element(2, erlang:element(4, Start_boundary)),
erlang:element(2, erlang:element(4, End_boundary))}
end,
Line_piece = case {erlang:element(5, End_boundary),
erlang:element(6, End_boundary)} of
{loop_a, loop_b} ->
{hull_line_a_b,
erlang:element(2, erlang:element(3, End_boundary)),
erlang:element(2, erlang:element(4, End_boundary))};
{loop_b, loop_a} ->
{hull_line_b_a,
erlang:element(2, erlang:element(4, End_boundary)),
erlang:element(2, erlang:element(3, End_boundary))};
{_, _} ->
Loop_piece
end,
[Loop_piece, Line_piece]
end
),
lists:append(_pipe@2).
-file("src/svg_path/convex_hull.gleam", 2791).
-spec all_one_loop(list(loop_sample())) -> list(union_piece()).
all_one_loop(Samples) ->
case Samples of
[] ->
[];
[First | _] ->
case erlang:element(3, First) of
loop_a ->
[{loop_piece_a,
erlang:element(2, erlang:element(4, First)),
erlang:element(2, erlang:element(4, First))}];
loop_b ->
[{loop_piece_b,
erlang:element(2, erlang:element(5, First)),
erlang:element(2, erlang:element(5, First))}]
end
end.
-file("src/svg_path/convex_hull.gleam", 2655).
-spec loop_winner(float()) -> loop_winner().
loop_winner(Difference) ->
case Difference >= +0.0 of
true ->
loop_a;
false ->
loop_b
end.
-file("src/svg_path/convex_hull.gleam", 3972).
-spec angle_direction(float()) -> vec@vec2:vec2(float()).
angle_direction(Angle) ->
Radians = (Angle * gleam_community@maths:pi()) / 180.0,
svg_path:point(
gleam_community@maths:cos(Radians),
gleam_community@maths:sin(Radians)
).
-file("src/svg_path/convex_hull.gleam", 3470).
-spec brute_segment_support(svg_path:segment(), float()) -> {ok,
support_sample()} |
{error, svg_path:error()}.
brute_segment_support(Segment, Angle) ->
Direction = angle_direction(Angle),
gleam@result:'try'(
svg_path:segment_minimize(
Segment,
fun(Point) -> +0.0 - dot(Point, Direction) end
),
fun(T) ->
gleam@result:'try'(
svg_path:segment_point(Segment, T),
fun(Point@1) ->
{ok,
{support_sample,
Angle,
T,
Point@1,
dot(Point@1, Direction)}}
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 3507).
-spec support_candidate(svg_path:segment(), float(), float()) -> {ok,
support_sample()} |
{error, svg_path:error()}.
support_candidate(Segment, Angle, T) ->
Direction = angle_direction(Angle),
gleam@result:'try'(
svg_path:segment_point(Segment, T),
fun(Point) ->
{ok, {support_sample, Angle, T, Point, dot(Point, Direction)}}
end
).
-file("src/svg_path/convex_hull.gleam", 3489).
-spec best_segment_support(svg_path:segment(), float(), list(float())) -> {ok,
support_sample()} |
{error, svg_path:error()}.
best_segment_support(Segment, Angle, Candidates) ->
{First@1, Rest@1} = case Candidates of
[First | Rest] -> {First, Rest};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"best_segment_support"/utf8>>,
line => 3494,
value => _assert_fail,
start => 91807,
'end' => 91846,
pattern_start => 91818,
pattern_end => 91833})
end,
gleam@result:'try'(
support_candidate(Segment, Angle, First@1),
fun(First@2) -> _pipe = Rest@1,
gleam@list:fold(
_pipe,
{ok, First@2},
fun(Best, T) ->
gleam@result:'try'(
Best,
fun(Best@1) ->
gleam@result:'try'(
support_candidate(Segment, Angle, T),
fun(Candidate) ->
case erlang:element(5, Candidate) > erlang:element(
5,
Best@1
) of
true ->
{ok, Candidate};
false ->
{ok, Best@1}
end
end
)
end
)
end
) end
).
-file("src/svg_path/convex_hull.gleam", 3940).
-spec quadratic_roots(float(), float(), float()) -> list(float()).
quadratic_roots(A, B, C) ->
case gleam@float:absolute_value(A) < 0.000000000001 of
true ->
case gleam@float:absolute_value(B) < 0.000000000001 of
true ->
[];
false ->
[case B of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> (+0.0 - C) / Gleam@denominator
end]
end;
false ->
Discriminant = (B * B) - ((4.0 * A) * C),
case Discriminant < +0.0 of
true ->
[];
false ->
Root@1 = case gleam@float:square_root(Discriminant) of
{ok, Root} -> Root;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"quadratic_roots"/utf8>>,
line => 3952,
value => _assert_fail,
start => 103355,
'end' => 103408,
pattern_start => 103366,
pattern_end => 103374})
end,
[case (2.0 * A) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator@1 -> ((+0.0 - B) - Root@1) / Gleam@denominator@1
end, case (2.0 * A) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator@2 -> ((+0.0 - B) + Root@1) / Gleam@denominator@2
end]
end
end.
-file("src/svg_path/convex_hull.gleam", 3419).
-spec segment_support(svg_path:segment(), float()) -> {ok, support_sample()} |
{error, svg_path:error()}.
segment_support(Segment, Angle) ->
Direction = angle_direction(Angle),
case Segment of
{line, Start, End} ->
Start_value = dot(Start, Direction),
End_value = dot(End, Direction),
case End_value > Start_value of
true ->
{ok, {support_sample, Angle, 1.0, End, End_value}};
false ->
{ok, {support_sample, Angle, +0.0, Start, Start_value}}
end;
{quadratic_bezier, Start@1, Control, End@1} ->
P0 = dot(Start@1, Direction),
P1 = dot(Control, Direction),
P2 = dot(End@1, Direction),
A = (P0 - (2.0 * P1)) + P2,
B = (-2.0 * P0) + (2.0 * P1),
Candidates = begin
_pipe = [+0.0, 1.0 | quadratic_roots(+0.0, 2.0 * A, B)],
gleam@list:filter(
_pipe,
fun(T) -> (T >= +0.0) andalso (T =< 1.0) end
)
end,
best_segment_support(Segment, Angle, Candidates);
{cubic_bezier, Start@2, Control1, Control2, End@2} ->
P0@1 = dot(Start@2, Direction),
P1@1 = dot(Control1, Direction),
P2@1 = dot(Control2, Direction),
P3 = dot(End@2, Direction),
A@1 = (((+0.0 - P0@1) + (3.0 * P1@1)) - (3.0 * P2@1)) + P3,
B@1 = ((3.0 * P0@1) - (6.0 * P1@1)) + (3.0 * P2@1),
C = (-3.0 * P0@1) + (3.0 * P1@1),
Candidates@1 = begin
_pipe@1 = [+0.0, 1.0 | quadratic_roots(3.0 * A@1, 2.0 * B@1, C)],
gleam@list:filter(
_pipe@1,
fun(T@1) -> (T@1 >= +0.0) andalso (T@1 =< 1.0) end
)
end,
best_segment_support(Segment, Angle, Candidates@1);
{arc, _, _, _, _, _, _} ->
brute_segment_support(Segment, Angle)
end.
-file("src/svg_path/convex_hull.gleam", 2817).
-spec segment_loop_support(svg_path:segment(), integer(), float()) -> loop_support().
segment_loop_support(Segment, Index, Angle) ->
Sample@1 = case segment_support(Segment, Angle) of
{ok, Sample} -> Sample;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"segment_loop_support"/utf8>>,
line => 2822,
value => _assert_fail,
start => 74740,
'end' => 74802,
pattern_start => 74751,
pattern_end => 74761})
end,
{loop_support,
{loop_param, Index, erlang:element(3, Sample@1)},
erlang:element(4, Sample@1),
erlang:element(5, Sample@1)}.
-file("src/svg_path/convex_hull.gleam", 2803).
-spec loop_support(loop(), float()) -> loop_support().
loop_support(Loop, Angle) ->
{loop, Segments} = Loop,
{First@1, Rest@1} = case Segments of
[First | Rest] -> {First, Rest};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"loop_support"/utf8>>,
line => 2805,
value => _assert_fail,
start => 74300,
'end' => 74337,
pattern_start => 74311,
pattern_end => 74326})
end,
First_support = segment_loop_support(First@1, 0, Angle),
_pipe = Rest@1,
gleam@list:index_fold(
_pipe,
First_support,
fun(Best, Segment, Index) ->
Candidate = segment_loop_support(Segment, Index + 1, Angle),
case erlang:element(4, Candidate) > erlang:element(4, Best) of
true ->
Candidate;
false ->
Best
end
end
).
-file("src/svg_path/convex_hull.gleam", 2521).
-spec loop_sample(loop(), loop(), float()) -> loop_sample().
loop_sample(Loop_a, Loop_b, Angle) ->
A = loop_support(Loop_a, Angle),
B = loop_support(Loop_b, Angle),
Difference = erlang:element(4, A) - erlang:element(4, B),
{loop_sample, Angle, loop_winner(Difference), A, B, Difference}.
-file("src/svg_path/convex_hull.gleam", 2974).
-spec normalize_angle(float()) -> float().
normalize_angle(Angle) ->
Turns = math:floor(Angle / 360.0),
Normalized = Angle - (Turns * 360.0),
case Normalized < +0.0 of
true ->
Normalized + 360.0;
false ->
Normalized
end.
-file("src/svg_path/convex_hull.gleam", 2718).
-spec loop_bisect_boundary(
loop(),
loop(),
loop_sample(),
loop_sample(),
integer()
) -> loop_sample().
loop_bisect_boundary(Loop_a, Loop_b, Left, Right, Remaining) ->
case (Remaining =< 0) orelse (gleam@float:absolute_value(
erlang:element(6, Left)
)
=< 0.0000001) of
true ->
Left;
false ->
Middle_angle = (erlang:element(2, Left) + erlang:element(2, Right))
/ 2.0,
Middle = loop_sample(Loop_a, Loop_b, Middle_angle),
case erlang:element(3, Middle) =:= erlang:element(3, Left) of
true ->
loop_bisect_boundary(
Loop_a,
Loop_b,
Middle,
Right,
Remaining - 1
);
false ->
loop_bisect_boundary(
Loop_a,
Loop_b,
Left,
Middle,
Remaining - 1
)
end
end.
-file("src/svg_path/convex_hull.gleam", 2967).
-spec unwrap_angle_after(float(), float()) -> float().
unwrap_angle_after(Left, Right) ->
case Right =< Left of
true ->
Right + 360.0;
false ->
Right
end.
-file("src/svg_path/convex_hull.gleam", 2684).
-spec loop_refine_boundary(loop(), loop(), float(), float(), loop_winner()) -> loop_boundary().
loop_refine_boundary(Loop_a, Loop_b, Left_angle, Right_angle, Left_winner) ->
Right_angle@1 = unwrap_angle_after(Left_angle, Right_angle),
Left = loop_sample(Loop_a, Loop_b, Left_angle),
Right = loop_sample(Loop_a, Loop_b, Right_angle@1),
Refined = loop_bisect_boundary(Loop_a, Loop_b, Left, Right, 32),
Angle = normalize_angle(erlang:element(2, Refined)),
At_boundary = loop_sample(Loop_a, Loop_b, Angle),
To = case Left_winner of
loop_a ->
loop_b;
loop_b ->
loop_a
end,
{loop_boundary,
Angle,
erlang:element(4, At_boundary),
erlang:element(5, At_boundary),
Left_winner,
To}.
-file("src/svg_path/convex_hull.gleam", 2662).
-spec loop_transition_boundaries(loop(), loop(), list(loop_sample())) -> list(loop_boundary()).
loop_transition_boundaries(Loop_a, Loop_b, Samples) ->
_pipe = circular_pairs(Samples),
gleam@list:filter_map(
_pipe,
fun(Pair) ->
{Left, Right} = Pair,
case erlang:element(3, Left) =:= erlang:element(3, Right) of
true ->
{error, nil};
false ->
{ok,
loop_refine_boundary(
Loop_a,
Loop_b,
erlang:element(2, Left),
erlang:element(2, Right),
erlang:element(3, Left)
)}
end
end
).
-file("src/svg_path/convex_hull.gleam", 2508).
-spec remove_loop_sample_angle_wrap_duplicate(list(float())) -> list(float()).
remove_loop_sample_angle_wrap_duplicate(Angles) ->
case Angles of
[] ->
Angles;
[_] ->
Angles;
[First | _] ->
Last@1 = case gleam@list:last(Angles) of
{ok, Last} -> Last;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"remove_loop_sample_angle_wrap_duplicate"/utf8>>,
line => 2512,
value => _assert_fail,
start => 67099,
'end' => 67138,
pattern_start => 67110,
pattern_end => 67118})
end,
case ((First + 360.0) - Last@1) < 0.02 of
true ->
drop_last(Angles);
false ->
Angles
end
end.
-file("src/svg_path/convex_hull.gleam", 2474).
-spec unique_loop_sample_angles_loop(
list(float()),
gleam@option:option(float()),
list(float())
) -> list(float()).
unique_loop_sample_angles_loop(Angles, Previous, Kept) ->
case Angles of
[] ->
lists:reverse(Kept);
[Angle | Rest] ->
case Previous of
{some, Previous@1} ->
case (Angle - Previous@1) < 0.02 of
true ->
unique_loop_sample_angles_loop(
Rest,
{some, Previous@1},
Kept
);
false ->
unique_loop_sample_angles_loop(
Rest,
{some, Angle},
[Angle | Kept]
)
end;
none ->
unique_loop_sample_angles_loop(
Rest,
{some, Angle},
[Angle | Kept]
)
end
end.
-file("src/svg_path/convex_hull.gleam", 2470).
-spec unique_loop_sample_angles(list(float())) -> list(float()).
unique_loop_sample_angles(Angles) ->
unique_loop_sample_angles_loop(Angles, none, []).
-file("src/svg_path/convex_hull.gleam", 2462).
-spec uniform_sample_angles(integer()) -> list(float()).
uniform_sample_angles(Sample_count) ->
_pipe = gleam@int:range(
0,
Sample_count,
[],
fun(Angles, I) ->
Angle = case erlang:float(Sample_count) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(I) * 360.0 / Gleam@denominator
end,
[Angle | Angles]
end
),
lists:reverse(_pipe).
-file("src/svg_path/convex_hull.gleam", 2451).
-spec loop_initial_sample_angles(integer(), list(float())) -> list(float()).
loop_initial_sample_angles(Sample_count, Seed_angles) ->
_pipe = lists:append(uniform_sample_angles(Sample_count), Seed_angles),
_pipe@1 = gleam@list:map(_pipe, fun normalize_angle/1),
_pipe@2 = gleam@list:sort(_pipe@1, fun gleam@float:compare/2),
_pipe@3 = unique_loop_sample_angles(_pipe@2),
remove_loop_sample_angle_wrap_duplicate(_pipe@3).
-file("src/svg_path/convex_hull.gleam", 2441).
-spec loop_initial_samples(loop(), loop(), integer(), list(float())) -> list(loop_sample()).
loop_initial_samples(Loop_a, Loop_b, Sample_count, Seed_angles) ->
_pipe = loop_initial_sample_angles(Sample_count, Seed_angles),
gleam@list:map(
_pipe,
fun(_capture) -> loop_sample(Loop_a, Loop_b, _capture) end
).
-file("src/svg_path/convex_hull.gleam", 2402).
-spec loop_union(loop(), loop(), integer(), list(float())) -> list(union_piece()).
loop_union(Loop_a, Loop_b, Sample_count, Seed_angles) ->
Samples = loop_initial_samples(Loop_a, Loop_b, Sample_count, Seed_angles),
Boundaries = loop_transition_boundaries(Loop_a, Loop_b, Samples),
case Boundaries of
[] ->
all_one_loop(Samples);
_ ->
_pipe = loop_pieces_from_boundaries(Boundaries),
compact_loop_pieces(_pipe, Loop_a, Loop_b)
end.
-file("src/svg_path/convex_hull.gleam", 1102).
-spec seeded_loop_union_segments(loop(), loop(), list(float())) -> list(svg_path:segment()).
seeded_loop_union_segments(Current, Addition, Seed_angles) ->
_pipe = loop_union(Current, Addition, 360, Seed_angles),
union_piece_segments(_pipe, Current, Addition).
-file("src/svg_path/convex_hull.gleam", 2651).
-spec loop_b_advantage(loop(), loop(), float()) -> float().
loop_b_advantage(Loop_a, Loop_b, Angle) ->
+0.0 - erlang:element(6, loop_sample(Loop_a, Loop_b, Angle)).
-file("src/svg_path/convex_hull.gleam", 2627).
-spec seeded_worst_direction_candidate(
loop(),
loop(),
float(),
float(),
seeded_worst_direction_state(),
float()
) -> seeded_worst_direction_state().
seeded_worst_direction_candidate(
Loop_a,
Loop_b,
Origin,
Candidate_direction,
Best,
Max_drift
) ->
case gleam@float:absolute_value(Candidate_direction - Origin) > (Max_drift + 0.000000001) of
true ->
Best;
false ->
Advantage = loop_b_advantage(Loop_a, Loop_b, Candidate_direction),
case Advantage > erlang:element(3, Best) of
true ->
{seeded_worst_direction_state,
Candidate_direction,
Advantage};
false ->
Best
end
end.
-file("src/svg_path/convex_hull.gleam", 2600).
-spec seeded_worst_direction_best_step(
loop(),
loop(),
float(),
seeded_worst_direction_state(),
float(),
float()
) -> seeded_worst_direction_state().
seeded_worst_direction_best_step(
Loop_a,
Loop_b,
Origin,
Current,
Step,
Max_drift
) ->
Upper = seeded_worst_direction_candidate(
Loop_a,
Loop_b,
Origin,
erlang:element(2, Current) + Step,
Current,
Max_drift
),
seeded_worst_direction_candidate(
Loop_a,
Loop_b,
Origin,
erlang:element(2, Current) - Step,
Upper,
Max_drift
).
-file("src/svg_path/convex_hull.gleam", 2566).
-spec seeded_worst_direction_local_search(
loop(),
loop(),
float(),
seeded_worst_direction_state(),
float(),
float()
) -> seeded_worst_direction_state().
seeded_worst_direction_local_search(
Loop_a,
Loop_b,
Origin,
Current,
Step,
Max_drift
) ->
Candidate = seeded_worst_direction_best_step(
Loop_a,
Loop_b,
Origin,
Current,
Step,
Max_drift
),
case Candidate of
{seeded_worst_direction_state, Direction, _} when Direction =:= erlang:element(
2,
Current
) ->
Current;
_ ->
seeded_worst_direction_local_search(
Loop_a,
Loop_b,
Origin,
Candidate,
Step,
Max_drift
)
end.
-file("src/svg_path/convex_hull.gleam", 2528).
-spec find_seeded_worst_direction(loop(), loop(), float(), float()) -> {ok,
{float(), float()}} |
{error, hull_error()}.
find_seeded_worst_direction(Loop_a, Loop_b, Direction, Threshold) ->
Max_drift = Threshold,
Initial = {seeded_worst_direction_state,
Direction,
loop_b_advantage(Loop_a, Loop_b, Direction)},
Coarse = seeded_worst_direction_local_search(
Loop_a,
Loop_b,
Direction,
Initial,
0.1,
Max_drift
),
Refined = seeded_worst_direction_local_search(
Loop_a,
Loop_b,
Direction,
Coarse,
0.01,
Max_drift
),
{ok,
{normalize_angle(erlang:element(2, Refined)),
normalize_angle(erlang:element(2, Refined))}}.
-file("src/svg_path/convex_hull.gleam", 3968).
-spec direction_angle(vec@vec2:vec2(float())) -> float().
direction_angle(Direction) ->
normalize_angle(case gleam_community@maths:pi() of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> gleam_community@maths:atan2(
erlang:element(3, Direction),
erlang:element(2, Direction)
)
* 180.0
/ Gleam@denominator
end).
-file("src/svg_path/convex_hull.gleam", 3985).
-spec clamp(float(), float(), float()) -> float().
clamp(Value, Minimum, Maximum) ->
_pipe = Value,
_pipe@1 = gleam@float:max(_pipe, Minimum),
gleam@float:min(_pipe@1, Maximum).
-file("src/svg_path/convex_hull.gleam", 2190).
-spec closest_point_on_segment(
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
vec@vec2:vec2(float())
) -> vec@vec2:vec2(float()).
closest_point_on_segment(A, B, Point) ->
Ab = subtract(B, A),
Length_squared = dot(Ab, Ab),
case Length_squared =< (0.000000001 * 0.000000001) of
true ->
A;
false ->
T = case Length_squared of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> dot(subtract(Point, A), Ab) / Gleam@denominator
end,
add_points(A, scale_point(Ab, clamp(T, +0.0, 1.0)))
end.
-file("src/svg_path/convex_hull.gleam", 2169).
-spec closest_point_on_polyline_loop(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
vec@vec2:vec2(float())
) -> vec@vec2:vec2(float()).
closest_point_on_polyline_loop(Vertices, Point, Closest) ->
case Vertices of
[A, B | Rest] ->
Candidate = closest_point_on_segment(A, B, Point),
Closest@1 = case point_distance_squared(Candidate, Point) < point_distance_squared(
Closest,
Point
) of
true ->
Candidate;
false ->
Closest
end,
closest_point_on_polyline_loop([B | Rest], Point, Closest@1);
_ ->
Closest
end.
-file("src/svg_path/convex_hull.gleam", 2155).
-spec closest_point_on_polyline(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float())
) -> vec@vec2:vec2(float()).
closest_point_on_polyline(Vertices, Point) ->
case Vertices of
[] ->
Point;
[Only] ->
Only;
[A, B | Rest] ->
First = closest_point_on_segment(A, B, Point),
closest_point_on_polyline_loop([B | Rest], Point, First)
end.
-file("src/svg_path/convex_hull.gleam", 2147).
-spec closest_point_on_polygon(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float())
) -> vec@vec2:vec2(float()).
closest_point_on_polygon(Vertices, Point) ->
First@1 = case gleam@list:first(Vertices) of
{ok, First} -> First;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"closest_point_on_polygon"/utf8>>,
line => 2151,
value => _assert_fail,
start => 57557,
'end' => 57600,
pattern_start => 57568,
pattern_end => 57577})
end,
closest_point_on_polyline(lists:append(Vertices, [First@1]), Point).
-file("src/svg_path/convex_hull.gleam", 2134).
-spec point_is_inside_edge(float(), float(), loop_orientation()) -> boolean().
point_is_inside_edge(Turn, Scale, Orientation) ->
Tolerance = 0.000000001 * Scale,
case Orientation of
counter_clockwise ->
Turn >= (+0.0 - Tolerance);
clockwise ->
Turn =< Tolerance;
degenerate_orientation ->
false
end.
-file("src/svg_path/convex_hull.gleam", 2113).
-spec convex_polygon_contains_point_loop(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
loop_orientation()
) -> boolean().
convex_polygon_contains_point_loop(Points, Point, Orientation) ->
case Points of
[A, B | Rest] ->
Edge = subtract(B, A),
Offset = subtract(Point, A),
Turn = cross(Edge, Offset),
Scale = point_length(Edge) * point_length(Offset),
case point_is_inside_edge(Turn, Scale, Orientation) of
true ->
convex_polygon_contains_point_loop(
[B | Rest],
Point,
Orientation
);
false ->
false
end;
_ ->
true
end.
-file("src/svg_path/convex_hull.gleam", 2097).
-spec convex_polygon_contains_point(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
loop_orientation()
) -> boolean().
convex_polygon_contains_point(Vertices, Point, Orientation) ->
case Vertices of
[] ->
false;
[_] ->
false;
[_, _] ->
false;
[First | _] ->
convex_polygon_contains_point_loop(
lists:append(Vertices, [First]),
Point,
Orientation
)
end.
-file("src/svg_path/convex_hull.gleam", 793).
-spec point_chord_polyline_separation(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float())
) -> gleam@option:option({float(), vec@vec2:vec2(float())}).
point_chord_polyline_separation(Vertices, Point) ->
Closest = closest_point_on_polyline(Vertices, Point),
case points_near(Closest, Point) of
true ->
none;
false ->
{some, {direction_angle(subtract(Point, Closest)), Closest}}
end.
-file("src/svg_path/convex_hull.gleam", 707).
-spec convex_polygon_orientation(convex_polygon()) -> loop_orientation().
convex_polygon_orientation(Polygon) ->
{convex_polygon, Vertices} = Polygon,
Area = signed_area(Vertices),
case gleam@float:absolute_value(Area) =< (0.000000001 * 0.000000001) of
true ->
degenerate_orientation;
false ->
case Area > +0.0 of
true ->
counter_clockwise;
false ->
clockwise
end
end.
-file("src/svg_path/convex_hull.gleam", 771).
-spec point_chord_polygon_separation(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float())
) -> gleam@option:option({float(), vec@vec2:vec2(float())}).
point_chord_polygon_separation(Vertices, Point) ->
Orientation = convex_polygon_orientation({convex_polygon, Vertices}),
case Orientation of
degenerate_orientation ->
point_chord_polyline_separation(Vertices, Point);
_ ->
case convex_polygon_contains_point(Vertices, Point, Orientation) of
true ->
none;
false ->
Closest = closest_point_on_polygon(Vertices, Point),
case points_near(Closest, Point) of
true ->
none;
false ->
{some,
{direction_angle(subtract(Point, Closest)),
Closest}}
end
end
end.
-file("src/svg_path/convex_hull.gleam", 759).
-spec point_segment_separation(
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
vec@vec2:vec2(float())
) -> gleam@option:option({float(), vec@vec2:vec2(float())}).
point_segment_separation(A, B, Point) ->
Closest = closest_point_on_segment(A, B, Point),
case points_near(Closest, Point) of
true ->
none;
false ->
{some, {direction_angle(subtract(Point, Closest)), Closest}}
end.
-file("src/svg_path/convex_hull.gleam", 749).
-spec point_point_separation(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> gleam@option:option({float(),
vec@vec2:vec2(float())}).
point_point_separation(Only, Point) ->
case points_near(Only, Point) of
true ->
none;
false ->
{some, {direction_angle(subtract(Point, Only)), Only}}
end.
-file("src/svg_path/convex_hull.gleam", 733).
-spec point_chord_polygon_loop_separation(loop(), vec@vec2:vec2(float())) -> gleam@option:option({float(),
vec@vec2:vec2(float())}).
point_chord_polygon_loop_separation(Loop, Point) ->
{loop, Segments} = Loop,
Vertices = loop_vertices(Segments),
case Vertices of
[] ->
none;
[Only] ->
point_point_separation(Only, Point);
[A, B] ->
point_segment_separation(A, B, Point);
_ ->
point_chord_polygon_separation(Vertices, Point)
end.
-file("src/svg_path/convex_hull.gleam", 432).
-spec point_segment(vec@vec2:vec2(float())) -> svg_path:segment().
point_segment(Point) ->
{line, Point, Point}.
-file("src/svg_path/convex_hull.gleam", 990).
-spec union_loop_with_point(loop(), vec@vec2:vec2(float())) -> {ok, loop()} |
{error, hull_error()}.
union_loop_with_point(Loop, Point) ->
Point_loop = {loop, [point_segment(Point)]},
case point_chord_polygon_loop_separation(Loop, Point) of
none ->
{ok, Loop};
{some, {Direction, _}} ->
gleam@result:'try'(
find_seeded_worst_direction(Loop, Point_loop, Direction, 1.0),
fun(Refined) ->
{Lower, Upper} = Refined,
case seeded_loop_union_segments(
Loop,
Point_loop,
[Lower, Upper]
) of
[] ->
{ok, Loop};
Segments ->
{ok, {loop, Segments}}
end
end
)
end.
-file("src/svg_path/convex_hull.gleam", 1129).
-spec subpath_end(svg_path:subpath()) -> vec@vec2:vec2(float()).
subpath_end(Subpath) ->
Point@1 = case svg_path:'end'(Subpath) of
{ok, Point} -> Point;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"subpath_end"/utf8>>,
line => 1130,
value => _assert_fail,
start => 29774,
'end' => 29818,
pattern_start => 29785,
pattern_end => 29794})
end,
Point@1.
-file("src/svg_path/convex_hull.gleam", 1124).
-spec subpath_start(svg_path:subpath()) -> vec@vec2:vec2(float()).
subpath_start(Subpath) ->
Point@1 = case svg_path:start(Subpath) of
{ok, Point} -> Point;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"subpath_start"/utf8>>,
line => 1125,
value => _assert_fail,
start => 29652,
'end' => 29698,
pattern_start => 29663,
pattern_end => 29672})
end,
Point@1.
-file("src/svg_path/convex_hull.gleam", 838).
-spec opposite_signs(float(), float()) -> boolean().
opposite_signs(A, B) ->
((A < +0.0) andalso (B > +0.0)) orelse ((A > +0.0) andalso (B < +0.0)).
-file("src/svg_path/convex_hull.gleam", 804).
-spec point_loop_view(
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
loop_orientation()
) -> point_loop_view().
point_loop_view(Point, Q, Arriving, Leaving, Orientation) ->
Sight = subtract(Q, Point),
Arriving_turn = cross(Sight, Arriving),
Leaving_turn = cross(Sight, Leaving),
case ((Arriving_turn =:= +0.0) orelse (Leaving_turn =:= +0.0)) orelse opposite_signs(
Arriving_turn,
Leaving_turn
) of
true ->
tangent_point;
false ->
case Orientation of
counter_clockwise ->
case Arriving_turn < +0.0 of
true ->
outside_point;
false ->
inside_point
end;
clockwise ->
case Arriving_turn > +0.0 of
true ->
outside_point;
false ->
inside_point
end;
degenerate_orientation ->
tangent_point
end
end.
-file("src/svg_path/convex_hull.gleam", 1744).
-spec segment_chain_is_outside(
list(svg_path:segment()),
vec@vec2:vec2(float()),
loop_orientation()
) -> boolean().
segment_chain_is_outside(Segments, Point, Orientation) ->
case Segments of
[] ->
false;
[Segment | _] ->
Q@1 = case svg_path:segment_point(Segment, 0.5) of
{ok, Q} -> Q;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"segment_chain_is_outside"/utf8>>,
line => 1752,
value => _assert_fail,
start => 47051,
'end' => 47110,
pattern_start => 47062,
pattern_end => 47067})
end,
Tangent@1 = case svg_path:segment_derivative(Segment, 0.5) of
{ok, Tangent} -> Tangent;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"segment_chain_is_outside"/utf8>>,
line => 1753,
value => _assert_fail@1,
start => 47117,
'end' => 47187,
pattern_start => 47128,
pattern_end => 47139})
end,
point_loop_view(Point, Q@1, Tangent@1, Tangent@1, Orientation) =:= outside_point
end.
-file("src/svg_path/convex_hull.gleam", 1725).
-spec build_open_subpath_from_segments(list(svg_path:segment())) -> {ok,
svg_path:subpath()} |
{error, hull_error()}.
build_open_subpath_from_segments(Segments) ->
Segments@1 = remove_point_like_segments(Segments),
case Segments@1 of
[] ->
{error, tangent_search_degenerate_loop};
_ ->
_pipe = svg_path:subpath_with(Segments@1, wiggle_then_bridge),
map_path_error(_pipe)
end.
-file("src/svg_path/convex_hull.gleam", 1701).
-spec loop_tangent_chains_to_subpaths(
loop(),
loop_tangent_candidate(),
loop_tangent_candidate(),
vec@vec2:vec2(float()),
loop_orientation()
) -> {ok, {svg_path:subpath(), svg_path:subpath()}} | {error, hull_error()}.
loop_tangent_chains_to_subpaths(Loop, First, Second, Point, Orientation) ->
{loop_tangent_candidate, First_param, _} = First,
{loop_tangent_candidate, Second_param, _} = Second,
First_segments = loop_piece_segments(Loop, First_param, Second_param),
Second_segments = loop_piece_segments(Loop, Second_param, First_param),
gleam@result:'try'(
build_open_subpath_from_segments(First_segments),
fun(First_subpath) ->
gleam@result:'try'(
build_open_subpath_from_segments(Second_segments),
fun(Second_subpath) ->
case segment_chain_is_outside(
First_segments,
Point,
Orientation
) of
true ->
{ok, {First_subpath, Second_subpath}};
false ->
{ok, {Second_subpath, First_subpath}}
end
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 1672).
-spec unique_sorted_ts_loop(
list(float()),
gleam@option:option(float()),
list(float())
) -> list(float()).
unique_sorted_ts_loop(Values, Previous, Kept) ->
case Values of
[] ->
lists:reverse(Kept);
[Value | Rest] ->
case Previous of
{some, Previous@1} ->
case gleam@float:absolute_value(Value - Previous@1) =< 0.000001 of
true ->
unique_sorted_ts_loop(
Rest,
{some, Previous@1},
Kept
);
false ->
unique_sorted_ts_loop(
Rest,
{some, Value},
[Value | Kept]
)
end;
_ ->
unique_sorted_ts_loop(Rest, {some, Value}, [Value | Kept])
end
end.
-file("src/svg_path/convex_hull.gleam", 1666).
-spec unique_sorted_ts(list(float())) -> list(float()).
unique_sorted_ts(Values) ->
_pipe = Values,
_pipe@1 = gleam@list:sort(_pipe, fun gleam@float:compare/2),
unique_sorted_ts_loop(_pipe@1, none, []).
-file("src/svg_path/convex_hull.gleam", 1513).
-spec arc_angle_progresses(svg_path@ellipse:center_arc_data(), float()) -> list(float()).
arc_angle_progresses(Arc, Angle) ->
gleam@int:range(
-1,
1,
[],
fun(Progresses, Turn) ->
Shifted = Angle + ((erlang:float(Turn) * 2.0) * gleam_community@maths:pi(
)),
[case erlang:element(6, Arc) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> (Shifted - erlang:element(5, Arc)) / Gleam@denominator
end | Progresses]
end
).
-file("src/svg_path/convex_hull.gleam", 1541).
-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/convex_hull.gleam", 1523).
-spec ellipse_local_point(
vec@vec2:vec2(float()),
svg_path@ellipse:center_arc_data()
) -> vec@vec2:vec2(float()).
ellipse_local_point(Point, Arc) ->
Translated = subtract(Point, from_ellipse_point(erlang:element(2, Arc))),
Radians = +0.0 - ((erlang:element(4, Arc) * gleam_community@maths:pi()) / 180.0),
Cosine = gleam_community@maths:cos(Radians),
Sine = gleam_community@maths:sin(Radians),
svg_path:point(
(Cosine * erlang:element(2, Translated)) - (Sine * erlang:element(
3,
Translated
)),
(Sine * erlang:element(2, Translated)) + (Cosine * erlang:element(
3,
Translated
))
).
-file("src/svg_path/convex_hull.gleam", 1537).
-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/convex_hull.gleam", 1465).
-spec arc_point_tangent_roots(
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
float(),
boolean(),
boolean(),
vec@vec2:vec2(float()),
vec@vec2:vec2(float())
) -> {ok, list(float())} | {error, hull_error()}.
arc_point_tangent_roots(
Start,
Radius,
X_axis_rotation,
Large_arc,
Sweep,
End,
Point
) ->
Endpoint = svg_path@ellipse:endpoint_arc_data(
to_ellipse_point(Start),
to_ellipse_point(Radius),
X_axis_rotation,
Large_arc,
Sweep,
to_ellipse_point(End)
),
gleam@result:'try'(
begin
_pipe = svg_path@ellipse:endpoint_to_center(Endpoint),
gleam@result:map_error(
_pipe,
fun(_) -> {path_error, degenerate_arc} end
)
end,
fun(Arc) ->
Local = ellipse_local_point(Point, Arc),
A = erlang:element(2, Local) * erlang:element(
3,
erlang:element(3, Arc)
),
B = +0.0 - (erlang:element(3, Local) * erlang:element(
2,
erlang:element(3, Arc)
)),
C = erlang:element(2, erlang:element(3, Arc)) * erlang:element(
3,
erlang:element(3, Arc)
),
Magnitude@1 = case gleam@float:square_root((A * A) + (B * B)) of
{ok, Magnitude} -> Magnitude;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"arc_point_tangent_roots"/utf8>>,
line => 1492,
value => _assert_fail,
start => 39984,
'end' => 40046,
pattern_start => 39995,
pattern_end => 40008})
end,
case (Magnitude@1 =< 0.000000001) orelse (C > (Magnitude@1 + 0.000000001)) of
true ->
{ok, []};
false ->
Ratio = clamp(case Magnitude@1 of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> C / Gleam@denominator
end, -1.0, 1.0),
Base = gleam_community@maths:atan2(B, A),
gleam@result:'try'(
begin
_pipe@1 = gleam_community@maths:acos(Ratio),
gleam@result:map_error(
_pipe@1,
fun(_) -> {path_error, degenerate_arc} end
)
end,
fun(Offset) ->
{ok,
begin
_pipe@2 = [Base - Offset, Base + Offset],
_pipe@3 = gleam@list:flat_map(
_pipe@2,
fun(_capture) ->
arc_angle_progresses(Arc, _capture)
end
),
_pipe@4 = gleam@list:filter(
_pipe@3,
fun(T) ->
(T >= (+0.0 - 0.000001)) andalso (T
=< (1.0 + 0.000001))
end
),
gleam@list:map(
_pipe@4,
fun(T@1) -> clamp(T@1, +0.0, 1.0) end
)
end}
end
)
end
end
).
-file("src/svg_path/convex_hull.gleam", 3415).
-spec same_sign(float(), float()) -> boolean().
same_sign(A, B) ->
((A < +0.0) andalso (B < +0.0)) orelse ((A > +0.0) andalso (B > +0.0)).
-file("src/svg_path/convex_hull.gleam", 1640).
-spec point_tangent_value(svg_path:segment(), vec@vec2:vec2(float()), float()) -> float().
point_tangent_value(Segment, Point, T) ->
Q@1 = case svg_path:segment_point(Segment, T) of
{ok, Q} -> Q;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"point_tangent_value"/utf8>>,
line => 1645,
value => _assert_fail,
start => 44038,
'end' => 44095,
pattern_start => 44049,
pattern_end => 44054})
end,
Tangent@1 = case svg_path:segment_derivative(Segment, T) of
{ok, Tangent} -> Tangent;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"point_tangent_value"/utf8>>,
line => 1646,
value => _assert_fail@1,
start => 44098,
'end' => 44166,
pattern_start => 44109,
pattern_end => 44120})
end,
cross(subtract(Q@1, Point), Tangent@1).
-file("src/svg_path/convex_hull.gleam", 1600).
-spec bisect_point_tangent_loop(
svg_path:segment(),
vec@vec2:vec2(float()),
float(),
float(),
float(),
integer()
) -> float().
bisect_point_tangent_loop(Segment, Point, Left, Left_value, Right, Remaining) ->
Midpoint = Left + ((Right - Left) / 2.0),
Midpoint_value = point_tangent_value(Segment, Point, Midpoint),
case ((Remaining =< 0) orelse (gleam@float:absolute_value(Midpoint_value) < 0.00000000000001))
orelse (gleam@float:absolute_value(Right - Left) < 0.000000000001) of
true ->
Midpoint;
false ->
case same_sign(Left_value, Midpoint_value) of
true ->
bisect_point_tangent_loop(
Segment,
Point,
Midpoint,
Midpoint_value,
Right,
Remaining - 1
);
false ->
bisect_point_tangent_loop(
Segment,
Point,
Left,
Left_value,
Midpoint,
Remaining - 1
)
end
end.
-file("src/svg_path/convex_hull.gleam", 1583).
-spec bisect_point_tangent(
svg_path:segment(),
vec@vec2:vec2(float()),
float(),
float()
) -> float().
bisect_point_tangent(Segment, Point, Left, Right) ->
Left_value = point_tangent_value(Segment, Point, Left),
bisect_point_tangent_loop(Segment, Point, Left, Left_value, Right, 80).
-file("src/svg_path/convex_hull.gleam", 1654).
-spec insert_near_unique_float(list(float()), float()) -> list(float()).
insert_near_unique_float(Values, Value) ->
case begin
_pipe = Values,
gleam@list:any(
_pipe,
fun(Existing) ->
gleam@float:absolute_value(Existing - Value) =< 0.000001
end
)
end of
true ->
Values;
false ->
[Value | Values]
end.
-file("src/svg_path/convex_hull.gleam", 1650).
-spec near_zero(float()) -> boolean().
near_zero(Value) ->
gleam@float:absolute_value(Value) =< 0.000000000001.
-file("src/svg_path/convex_hull.gleam", 1545).
-spec segment_point_tangent_numeric_roots(
svg_path:segment(),
vec@vec2:vec2(float())
) -> list(float()).
segment_point_tangent_numeric_roots(Segment, Point) ->
Sample_count = 720,
First = point_tangent_value(Segment, Point, +0.0),
_pipe = gleam@int:range(
1,
Sample_count,
{+0.0, First, []},
fun(State, Index) ->
{Previous_t, Previous_value, Roots} = State,
T = case erlang:float(Sample_count) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(Index) / Gleam@denominator
end,
Value = point_tangent_value(Segment, Point, T),
Roots@1 = case {near_zero(Previous_value), near_zero(Value)} of
{true, _} ->
insert_near_unique_float(Roots, Previous_t);
{_, true} ->
insert_near_unique_float(Roots, T);
{false, false} ->
case same_sign(Previous_value, Value) of
true ->
Roots;
false ->
insert_near_unique_float(
Roots,
bisect_point_tangent(
Segment,
Point,
Previous_t,
T
)
)
end
end,
{T, Value, Roots@1}
end
),
_pipe@1 = (fun(State@1) ->
{_, _, Roots@2} = State@1,
Roots@2
end)(_pipe),
lists:reverse(_pipe@1).
-file("src/svg_path/convex_hull.gleam", 1435).
-spec segment_point_tangent_roots(svg_path:segment(), vec@vec2:vec2(float())) -> {ok,
list(float())} |
{error, hull_error()}.
segment_point_tangent_roots(Segment, Point) ->
case Segment of
{line, _, _} ->
{ok, []};
{quadratic_bezier, Start, Control, End} ->
S = subtract(Start, Point),
A = subtract(Control, Start),
B = add_points(subtract(Start, scale_point(Control, 2.0)), End),
{ok,
begin
_pipe = quadratic_roots(
cross(A, B),
cross(S, B),
cross(S, A)
),
gleam@list:filter(
_pipe,
fun(T) -> (T >= +0.0) andalso (T =< 1.0) end
)
end};
{cubic_bezier, _, _, _, _} ->
{ok, segment_point_tangent_numeric_roots(Segment, Point)};
{arc, Start@1, Radius, X_axis_rotation, Large_arc, Sweep, End@1} ->
arc_point_tangent_roots(
Start@1,
Radius,
X_axis_rotation,
Large_arc,
Sweep,
End@1,
Point
)
end.
-file("src/svg_path/convex_hull.gleam", 1410).
-spec exact_loop_interior_tangent_candidates(
list(svg_path:segment()),
integer(),
vec@vec2:vec2(float()),
loop_orientation()
) -> {ok, list(loop_tangent_candidate())} | {error, hull_error()}.
exact_loop_interior_tangent_candidates(Segments, Index, Point, _) ->
Segment = segment_at(Segments, Index),
gleam@result:'try'(
segment_point_tangent_roots(Segment, Point),
fun(Roots) -> _pipe = Roots,
_pipe@1 = gleam@list:filter(
_pipe,
fun(T) -> (T > 0.000001) andalso (T < (1.0 - 0.000001)) end
),
_pipe@2 = unique_sorted_ts(_pipe@1),
gleam@list:fold(
_pipe@2,
{ok, []},
fun(Candidates, T@1) ->
gleam@result:'try'(
Candidates,
fun(Candidates@1) ->
gleam@result:'try'(
begin
_pipe@3 = svg_path:segment_point(
Segment,
T@1
),
map_path_error(_pipe@3)
end,
fun(Q) ->
{ok,
lists:append(
Candidates@1,
[{loop_tangent_candidate,
{loop_param, Index, T@1},
Q}]
)}
end
)
end
)
end
) end
).
-file("src/svg_path/convex_hull.gleam", 2086).
-spec previous_index(integer(), integer()) -> integer().
previous_index(Index, Count) ->
case Index =< 0 of
true ->
Count - 1;
false ->
Index - 1
end.
-file("src/svg_path/convex_hull.gleam", 1386).
-spec exact_loop_endpoint_tangent_candidate(
list(svg_path:segment()),
integer(),
vec@vec2:vec2(float()),
loop_orientation()
) -> {ok, list(loop_tangent_candidate())} | {error, hull_error()}.
exact_loop_endpoint_tangent_candidate(Segments, Index, Point, Orientation) ->
Count = erlang:length(Segments),
Segment = segment_at(Segments, Index),
Previous = segment_at(Segments, previous_index(Index, Count)),
gleam@result:'try'(
begin
_pipe = svg_path:segment_derivative(Previous, 1.0),
map_path_error(_pipe)
end,
fun(Arriving) ->
gleam@result:'try'(
begin
_pipe@1 = svg_path:segment_derivative(Segment, +0.0),
map_path_error(_pipe@1)
end,
fun(Leaving) ->
Q = svg_path:segment_start(Segment),
case point_loop_view(
Point,
Q,
Arriving,
Leaving,
Orientation
) of
tangent_point ->
{ok,
[{loop_tangent_candidate,
{loop_param, Index, +0.0},
Q}]};
_ ->
{ok, []}
end
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 1357).
-spec point_exact_loop_tangent_candidates(
loop(),
vec@vec2:vec2(float()),
loop_orientation()
) -> {ok, list(loop_tangent_candidate())} | {error, hull_error()}.
point_exact_loop_tangent_candidates(Loop, Point, Orientation) ->
{loop, Segments} = Loop,
gleam@int:range(
0,
erlang:length(Segments) - 1,
{ok, []},
fun(Candidates, Index) ->
gleam@result:'try'(
Candidates,
fun(Candidates@1) ->
gleam@result:'try'(
exact_loop_endpoint_tangent_candidate(
Segments,
Index,
Point,
Orientation
),
fun(Endpoint) ->
gleam@result:'try'(
exact_loop_interior_tangent_candidates(
Segments,
Index,
Point,
Orientation
),
fun(Interior) ->
{ok,
lists:append(
Candidates@1,
lists:append(Endpoint, Interior)
)}
end
)
end
)
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 1338).
-spec validate_loop_segment_convexity(
list(svg_path:segment()),
loop_orientation()
) -> {ok, nil} | {error, hull_error()}.
validate_loop_segment_convexity(Segments, Orientation) ->
gleam@int:range(
0,
erlang:length(Segments) - 1,
{ok, nil},
fun(State, Index) ->
gleam@result:'try'(
State,
fun(_) ->
Segment = segment_at(Segments, Index),
case segment_tangent_turn_algebraic(Segment, Orientation) of
{ok, _} ->
{ok, nil};
{error, _} ->
{error, {tangent_search_non_convex_vertex, Index}}
end
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 2081).
-spec vertex_at(list(vec@vec2:vec2(float())), integer()) -> vec@vec2:vec2(float()).
vertex_at(Vertices, Index) ->
Vertex@1 = case nth(Vertices, Index) of
{ok, Vertex} -> Vertex;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"vertex_at"/utf8>>,
line => 2082,
value => _assert_fail,
start => 55954,
'end' => 55998,
pattern_start => 55965,
pattern_end => 55975})
end,
Vertex@1.
-file("src/svg_path/convex_hull.gleam", 1820).
-spec chord_polygon_vertex_is_convex(
list(vec@vec2:vec2(float())),
integer(),
loop_orientation()
) -> boolean().
chord_polygon_vertex_is_convex(Vertices, Index, Orientation) ->
Count = erlang:length(Vertices),
Previous = vertex_at(Vertices, previous_index(Index, Count)),
Q = vertex_at(Vertices, Index),
Next = vertex_at(Vertices, next_index(Index, Count)),
Arriving = subtract(Q, Previous),
Leaving = subtract(Next, Q),
Turn = cross(Arriving, Leaving),
Scale = point_length(Arriving) * point_length(Leaving),
turn_is_against_orientation(Turn, Scale, Orientation) =:= false.
-file("src/svg_path/convex_hull.gleam", 1759).
-spec validate_chord_polygon_convex(
list(vec@vec2:vec2(float())),
loop_orientation()
) -> {ok, nil} | {error, hull_error()}.
validate_chord_polygon_convex(Vertices, Orientation) ->
gleam@int:range(
0,
erlang:length(Vertices) - 1,
{ok, nil},
fun(State, Index) ->
gleam@result:'try'(
State,
fun(_) ->
case chord_polygon_vertex_is_convex(
Vertices,
Index,
Orientation
) of
true ->
{ok, nil};
false ->
{error, {tangent_search_non_convex_vertex, Index}}
end
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 1330).
-spec validate_loop_endpoint_convexity(
list(svg_path:segment()),
loop_orientation()
) -> {ok, nil} | {error, hull_error()}.
validate_loop_endpoint_convexity(Segments, Orientation) ->
_pipe = loop_vertices(Segments),
validate_chord_polygon_convex(_pipe, Orientation).
-file("src/svg_path/convex_hull.gleam", 1315).
-spec loop_vertex_param_loop(
list(svg_path:segment()),
vec@vec2:vec2(float()),
integer()
) -> {ok, loop_param()} | {error, hull_error()}.
loop_vertex_param_loop(Segments, Point, Index) ->
case Segments of
[] ->
{error, tangent_search_degenerate_loop};
[Segment | Rest] ->
case points_near(svg_path:segment_start(Segment), Point) of
true ->
{ok, {loop_param, Index, +0.0}};
false ->
loop_vertex_param_loop(Rest, Point, Index + 1)
end
end.
-file("src/svg_path/convex_hull.gleam", 1308).
-spec loop_vertex_param(list(svg_path:segment()), vec@vec2:vec2(float())) -> {ok,
loop_param()} |
{error, hull_error()}.
loop_vertex_param(Segments, Point) ->
loop_vertex_param_loop(Segments, Point, 0).
-file("src/svg_path/convex_hull.gleam", 1286).
-spec line_like_loop_tangent_subpaths(
loop(),
vec@vec2:vec2(float()),
loop_orientation()
) -> {ok, {svg_path:subpath(), svg_path:subpath()}} | {error, hull_error()}.
line_like_loop_tangent_subpaths(Loop, Point, Orientation) ->
{loop, Segments} = Loop,
case loop_vertices(Segments) of
[A, B] ->
gleam@result:'try'(
loop_vertex_param(Segments, A),
fun(A_param) ->
gleam@result:'try'(
loop_vertex_param(Segments, B),
fun(B_param) ->
loop_tangent_chains_to_subpaths(
Loop,
{loop_tangent_candidate, A_param, A},
{loop_tangent_candidate, B_param, B},
Point,
Orientation
)
end
)
end
);
_ ->
{error, tangent_search_degenerate_loop}
end.
-file("src/svg_path/convex_hull.gleam", 1274).
-spec orientation_from_turn(float(), float()) -> loop_orientation().
orientation_from_turn(Turn, Scale) ->
Tolerance = 0.000000001 * Scale,
case Turn > Tolerance of
true ->
counter_clockwise;
false ->
case Turn < (+0.0 - Tolerance) of
true ->
clockwise;
false ->
degenerate_orientation
end
end.
-file("src/svg_path/convex_hull.gleam", 1254).
-spec line_like_orientation(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float())
) -> loop_orientation().
line_like_orientation(Vertices, Point) ->
case Vertices of
[A, B] ->
Edge = subtract(B, A),
Offset = subtract(Point, A),
Turn = cross(Edge, Offset),
Scale = point_length(Edge) * point_length(Offset),
case orientation_from_turn(Turn, Scale) of
counter_clockwise ->
clockwise;
clockwise ->
counter_clockwise;
degenerate_orientation ->
counter_clockwise
end;
_ ->
degenerate_orientation
end.
-file("src/svg_path/convex_hull.gleam", 1223).
-spec tangent_orientation_evidence_result(tangent_orientation_evidence()) -> tangent_orientation().
tangent_orientation_evidence_result(Evidence) ->
case Evidence of
{tangent_orientation_evidence, Orientation} ->
{found_tangent_orientation, Orientation};
no_tangent_orientation_evidence ->
no_tangent_orientation;
conflicting_tangent_orientation_evidence ->
conflicting_tangent_orientation
end.
-file("src/svg_path/convex_hull.gleam", 1234).
-spec endpoint_tangent_orientation(list(svg_path:segment()), integer()) -> loop_orientation().
endpoint_tangent_orientation(Segments, Index) ->
Count = erlang:length(Segments),
Segment = segment_at(Segments, Index),
Previous = segment_at(Segments, previous_index(Index, Count)),
case {svg_path:segment_derivative(Previous, 1.0),
svg_path:segment_derivative(Segment, +0.0)} of
{{ok, Arriving}, {ok, Leaving}} ->
Turn = cross(Arriving, Leaving),
Scale = point_length(Arriving) * point_length(Leaving),
orientation_from_turn(Turn, Scale);
{_, _} ->
degenerate_orientation
end.
-file("src/svg_path/convex_hull.gleam", 1205).
-spec add_tangent_orientation_evidence(
tangent_orientation_evidence(),
loop_orientation()
) -> tangent_orientation_evidence().
add_tangent_orientation_evidence(Evidence, Orientation) ->
case {Evidence, Orientation} of
{conflicting_tangent_orientation_evidence, _} ->
conflicting_tangent_orientation_evidence;
{_, degenerate_orientation} ->
Evidence;
{no_tangent_orientation_evidence, Orientation@1} ->
{tangent_orientation_evidence, Orientation@1};
{{tangent_orientation_evidence, Existing}, Orientation@2} ->
case Existing =:= Orientation@2 of
true ->
Evidence;
false ->
conflicting_tangent_orientation_evidence
end
end.
-file("src/svg_path/convex_hull.gleam", 1172).
-spec loop_tangent_orientation_loop(
list(svg_path:segment()),
integer(),
integer(),
tangent_orientation_evidence()
) -> tangent_orientation_evidence().
loop_tangent_orientation_loop(Segments, Index, Count, Evidence) ->
case Index >= Count of
true ->
Evidence;
false ->
loop_tangent_orientation_loop(
Segments,
Index + 1,
Count,
add_tangent_orientation_evidence(
Evidence,
endpoint_tangent_orientation(Segments, Index)
)
)
end.
-file("src/svg_path/convex_hull.gleam", 1160).
-spec loop_tangent_orientation(list(svg_path:segment())) -> tangent_orientation().
loop_tangent_orientation(Segments) ->
_pipe = loop_tangent_orientation_loop(
Segments,
0,
erlang:length(Segments),
no_tangent_orientation_evidence
),
tangent_orientation_evidence_result(_pipe).
-file("src/svg_path/convex_hull.gleam", 1134).
-spec tangent_search_orientation(
list(svg_path:segment()),
vec@vec2:vec2(float())
) -> tangent_search_orientation().
tangent_search_orientation(Segments, Point) ->
case loop_orientation(Segments) of
degenerate_orientation ->
case loop_tangent_orientation(Segments) of
{found_tangent_orientation, Orientation} ->
{exact_search_orientation, Orientation};
no_tangent_orientation ->
case line_like_orientation(loop_vertices(Segments), Point) of
degenerate_orientation ->
degenerate_search_orientation;
Orientation@1 ->
{line_like_search_orientation, Orientation@1}
end;
conflicting_tangent_orientation ->
degenerate_search_orientation
end;
Orientation@2 ->
{exact_search_orientation, Orientation@2}
end.
-file("src/svg_path/convex_hull.gleam", 871).
-spec point_exact_loop_tangent_subpaths(loop(), vec@vec2:vec2(float())) -> {ok,
{svg_path:subpath(), svg_path:subpath()}} |
{error, hull_error()}.
point_exact_loop_tangent_subpaths(Loop, Point) ->
{loop, Segments} = Loop,
case tangent_search_orientation(Segments, Point) of
degenerate_search_orientation ->
{error, tangent_search_degenerate_loop};
{line_like_search_orientation, Orientation} ->
line_like_loop_tangent_subpaths(Loop, Point, Orientation);
{exact_search_orientation, Orientation@1} ->
gleam@result:'try'(
validate_loop_endpoint_convexity(Segments, Orientation@1),
fun(_) ->
gleam@result:'try'(
validate_loop_segment_convexity(Segments, Orientation@1),
fun(_) ->
gleam@result:'try'(
point_exact_loop_tangent_candidates(
Loop,
Point,
Orientation@1
),
fun(Tangents) -> case Tangents of
[First, Second] ->
loop_tangent_chains_to_subpaths(
Loop,
First,
Second,
Point,
Orientation@1
);
_ ->
{error,
{tangent_search_expected_two_tangencies,
erlang:length(Tangents)}}
end end
)
end
)
end
)
end.
-file("src/svg_path/convex_hull.gleam", 910).
-spec loop_plus_point_hull(loop(), vec@vec2:vec2(float())) -> {ok, loop()} |
{error, hull_error()}.
loop_plus_point_hull(Loop, Point) ->
gleam@result:'try'(
point_exact_loop_tangent_subpaths(Loop, Point),
fun(Split) ->
{_, Kept} = Split,
Start = subpath_start(Kept),
End = subpath_end(Kept),
Segments = lists:append(
svg_path:segments(Kept),
[{line, End, Point}, {line, Point, Start}]
),
gleam@result:'try'(
begin
_pipe = svg_path:subpath_with(Segments, wiggle_then_bridge),
map_path_error(_pipe)
end,
fun(Subpath) ->
gleam@result:'try'(
begin
_pipe@1 = svg_path:set_closed_with(
Subpath,
true,
wiggle_then_bridge
),
map_path_error(_pipe@1)
end,
fun(Closed) ->
{ok, {loop, svg_path:segments(Closed)}}
end
)
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 977).
-spec dumb_repair_loop_with_point(loop(), vec@vec2:vec2(float())) -> {ok,
loop()} |
{error, hull_error()}.
dumb_repair_loop_with_point(Loop, Point) ->
case loop_plus_point_hull(Loop, Point) of
{ok, Loop@1} ->
{ok, Loop@1};
{error, {tangent_search_expected_two_tangencies, _}} ->
union_loop_with_point(Loop, Point);
{error, tangent_search_degenerate_loop} ->
union_loop_with_point(Loop, Point);
{error, Error} ->
{error, Error}
end.
-file("src/svg_path/convex_hull.gleam", 963).
-spec repair_loop_with_points(loop(), list(vec@vec2:vec2(float()))) -> {ok,
loop()} |
{error, hull_error()}.
repair_loop_with_points(Loop, Points) ->
_pipe = Points,
gleam@list:fold(
_pipe,
{ok, Loop},
fun(Current, Point) ->
gleam@result:'try'(
Current,
fun(Current@1) ->
case point_chord_polygon_loop_separation(Current@1, Point) of
none ->
{ok, Current@1};
{some, _} ->
dumb_repair_loop_with_point(Current@1, Point)
end
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 474).
-spec add_distinct_point(list(vec@vec2:vec2(float())), vec@vec2:vec2(float())) -> list(vec@vec2:vec2(float())).
add_distinct_point(Points, Point) ->
case begin
_pipe = Points,
gleam@list:any(_pipe, fun(Existing) -> points_near(Existing, Point) end)
end of
true ->
Points;
false ->
[Point | Points]
end.
-file("src/svg_path/convex_hull.gleam", 946).
-spec dumb_repair_loop_with_point_groups(
loop(),
list(list(vec@vec2:vec2(float())))
) -> {ok, loop()} | {error, hull_error()}.
dumb_repair_loop_with_point_groups(Loop, Point_groups) ->
Repair_points = begin
_pipe = Point_groups,
_pipe@2 = gleam@list:fold(
_pipe,
[],
fun(Points, Group) -> _pipe@1 = Group,
gleam@list:fold(
_pipe@1,
Points,
fun(Points@1, Point) ->
add_distinct_point(Points@1, Point)
end
) end
),
lists:reverse(_pipe@2)
end,
repair_loop_with_points(Loop, lists:append(Repair_points, Repair_points)).
-file("src/svg_path/convex_hull.gleam", 465).
-spec segment_endpoints_for_repair(list(svg_path:segment())) -> list(vec@vec2:vec2(float())).
segment_endpoints_for_repair(Segments) ->
_pipe = Segments,
gleam@list:fold(
_pipe,
[],
fun(Points, Segment) ->
[svg_path:segment_start(Segment),
svg_path:segment_end(Segment) |
Points]
end
).
-file("src/svg_path/convex_hull.gleam", 1116).
-spec loop_endpoints(loop()) -> list(vec@vec2:vec2(float())).
loop_endpoints(Loop) ->
{loop, Segments} = Loop,
_pipe = Segments,
_pipe@1 = segment_endpoints_for_repair(_pipe),
_pipe@2 = gleam@list:fold(
_pipe@1,
[],
fun(Points, Point) -> add_distinct_point(Points, Point) end
),
lists:reverse(_pipe@2).
-file("src/svg_path/convex_hull.gleam", 1078).
-spec ambitious_repair_seed_angles(loop(), loop()) -> {ok, list(float())} |
{error, hull_error()}.
ambitious_repair_seed_angles(Current, Addition) ->
_pipe = loop_endpoints(Addition),
_pipe@1 = gleam@list:fold(
_pipe,
{ok, []},
fun(Seed_angles, Point) ->
gleam@result:'try'(
Seed_angles,
fun(Seed_angles@1) ->
case point_chord_polygon_loop_separation(Current, Point) of
none ->
{ok, Seed_angles@1};
{some, {Direction, _}} ->
gleam@result:'try'(
find_seeded_worst_direction(
Current,
Addition,
Direction,
1.0
),
fun(Refined) ->
{Lower, Upper} = Refined,
{ok, [Lower, Upper | Seed_angles@1]}
end
)
end
end
)
end
),
gleam@result:map(_pipe@1, fun lists:reverse/1).
-file("src/svg_path/convex_hull.gleam", 1060).
-spec ambitious_repair_loop_with_loop(loop(), loop()) -> {ok, loop()} |
{error, hull_error()}.
ambitious_repair_loop_with_loop(Current, Addition) ->
gleam@result:'try'(
ambitious_repair_seed_angles(Current, Addition),
fun(Seed_angles) -> case Seed_angles of
[] ->
{ok, Current};
_ ->
Segments = seeded_loop_union_segments(
Current,
Addition,
Seed_angles
),
case Segments of
[] ->
{ok, Current};
_ ->
{ok, {loop, Segments}}
end
end end
).
-file("src/svg_path/convex_hull.gleam", 1048).
-spec ambitious_repair_loop_with_loops(loop(), list(convex_loop())) -> {ok,
loop()} |
{error, hull_error()}.
ambitious_repair_loop_with_loops(Current, Additions) ->
_pipe = Additions,
gleam@list:fold(
_pipe,
{ok, Current},
fun(Current@1, Addition) ->
gleam@result:'try'(
Current@1,
fun(Current@2) ->
{convex_loop, Addition@1, _} = Addition,
ambitious_repair_loop_with_loop(Current@2, Addition@1)
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 1018).
-spec final_repair_loop(
loop(),
list(convex_loop()),
list(list(vec@vec2:vec2(float()))),
binary()
) -> {ok, loop()} | {error, hull_error()}.
final_repair_loop(Loop, Source_loops, Repair_point_groups, Repair_mode) ->
case Repair_mode of
Mode when Mode =:= <<"ambitious"/utf8>> ->
ambitious_repair_loop_with_loops(Loop, Source_loops);
Mode@1 when Mode@1 =:= <<"dumb"/utf8>> ->
dumb_repair_loop_with_point_groups(Loop, Repair_point_groups);
Mode@2 when Mode@2 =:= <<"none"/utf8>> ->
{ok, Loop};
_ ->
{ok, Loop}
end.
-file("src/svg_path/convex_hull.gleam", 2255).
-spec bounding_box_polygon(svg_path:bounding_box()) -> convex_polygon().
bounding_box_polygon(Box) ->
{convex_polygon,
[svg_path:point(
erlang:element(2, erlang:element(2, Box)),
erlang:element(3, erlang:element(2, Box))
),
svg_path:point(
erlang:element(2, erlang:element(3, Box)),
erlang:element(3, erlang:element(2, Box))
),
svg_path:point(
erlang:element(2, erlang:element(3, Box)),
erlang:element(3, erlang:element(3, Box))
),
svg_path:point(
erlang:element(2, erlang:element(2, Box)),
erlang:element(3, erlang:element(3, Box))
)]}.
-file("src/svg_path/convex_hull.gleam", 2239).
-spec combine_boxes(svg_path:bounding_box(), svg_path:bounding_box()) -> svg_path:bounding_box().
combine_boxes(First, Second) ->
{bounding_box,
svg_path:point(
gleam@float:min(
erlang:element(2, erlang:element(2, First)),
erlang:element(2, erlang:element(2, Second))
),
gleam@float:min(
erlang:element(3, erlang:element(2, First)),
erlang:element(3, erlang:element(2, Second))
)
),
svg_path:point(
gleam@float:max(
erlang:element(2, erlang:element(3, First)),
erlang:element(2, erlang:element(3, Second))
),
gleam@float:max(
erlang:element(3, erlang:element(3, First)),
erlang:element(3, erlang:element(3, Second))
)
)}.
-file("src/svg_path/convex_hull.gleam", 2226).
-spec loop_bounding_box_loop(list(svg_path:segment()), svg_path:bounding_box()) -> {ok,
svg_path:bounding_box()} |
{error, svg_path:error()}.
loop_bounding_box_loop(Segments, Box) ->
case Segments of
[] ->
{ok, Box};
[Segment | Rest] ->
gleam@result:'try'(
svg_path:segment_bounding_box(Segment),
fun(Next) ->
loop_bounding_box_loop(Rest, combine_boxes(Box, Next))
end
)
end.
-file("src/svg_path/convex_hull.gleam", 2214).
-spec loop_bounding_box(list(svg_path:segment())) -> {ok,
svg_path:bounding_box()} |
{error, svg_path:error()}.
loop_bounding_box(Segments) ->
case Segments of
[] ->
{error, empty_subpath};
[First | Rest] ->
gleam@result:'try'(
svg_path:segment_bounding_box(First),
fun(Box) -> loop_bounding_box_loop(Rest, Box) end
)
end.
-file("src/svg_path/convex_hull.gleam", 2206).
-spec loop_enclosure(loop()) -> convex_polygon().
loop_enclosure(Loop) ->
{loop, Segments} = Loop,
case loop_bounding_box(Segments) of
{error, _} ->
{convex_polygon, loop_vertices(Segments)};
{ok, Box} ->
bounding_box_polygon(Box)
end.
-file("src/svg_path/convex_hull.gleam", 450).
-spec convex_loop(list(svg_path:segment())) -> convex_loop().
convex_loop(Segments) ->
Loop = {loop, Segments},
{convex_loop, Loop, loop_enclosure(Loop)}.
-file("src/svg_path/convex_hull.gleam", 1034).
-spec configured_repair_loop_with_loop(loop(), loop(), binary()) -> {ok, loop()} |
{error, hull_error()}.
configured_repair_loop_with_loop(Current, Addition, Repair_mode) ->
case Repair_mode of
Mode when Mode =:= <<"ambitious"/utf8>> ->
ambitious_repair_loop_with_loop(Current, Addition);
Mode@1 when Mode@1 =:= <<"dumb"/utf8>> ->
{ok, Current};
Mode@2 when Mode@2 =:= <<"none"/utf8>> ->
{ok, Current};
_ ->
{ok, Current}
end.
-file("src/svg_path/convex_hull.gleam", 2378).
-spec loop_support_dominance(loop(), loop(), integer()) -> loop_dominance().
loop_support_dominance(Loop_a, Loop_b, Sample_count) ->
Initial = {true, true},
{A_contains_b@1, B_contains_a@1} = gleam@int:range(
0,
Sample_count - 1,
Initial,
fun(State, I) ->
{A_contains_b, B_contains_a} = State,
Angle = case erlang:float(Sample_count) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(I) * 360.0 / Gleam@denominator
end,
Sample = loop_sample(Loop_a, Loop_b, Angle),
{A_contains_b andalso (erlang:element(6, Sample) >= (+0.0 - 0.0000001)),
B_contains_a andalso (erlang:element(6, Sample) =< 0.0000001)}
end
),
case {A_contains_b@1, B_contains_a@1} of
{true, _} ->
loop_a_dominates;
{false, true} ->
loop_b_dominates;
{false, false} ->
no_loop_dominates
end.
-file("src/svg_path/convex_hull.gleam", 2355).
-spec dominant_loop_segments(loop(), loop()) -> {ok, list(svg_path:segment())} |
{error, hull_error()}.
dominant_loop_segments(Loop_a, Loop_b) ->
case loop_support_dominance(Loop_a, Loop_b, 360) of
loop_a_dominates ->
{loop, Segments} = Loop_a,
{ok, Segments};
loop_b_dominates ->
{loop, Segments@1} = Loop_b,
{ok, Segments@1};
no_loop_dominates ->
{error, loop_union_collapsed}
end.
-file("src/svg_path/convex_hull.gleam", 2329).
-spec union_loop_segments(list(svg_path:segment()), list(svg_path:segment())) -> {ok,
list(svg_path:segment())} |
{error, hull_error()}.
union_loop_segments(Left, Right) ->
Loop_a = {loop, Left},
Loop_b = {loop, Right},
Pieces = loop_union(Loop_a, Loop_b, 360, []),
case union_piece_segments(Pieces, Loop_a, Loop_b) of
[] ->
gleam@result:'try'(
dominant_loop_segments(Loop_a, Loop_b),
fun(Segments) ->
diagnose_closed_loop(Segments),
{ok, Segments}
end
);
Segments@1 ->
diagnose_closed_loop(Segments@1),
{ok, Segments@1}
end.
-file("src/svg_path/convex_hull.gleam", 499).
-spec union_convex_loops(convex_loop(), convex_loop(), binary()) -> {ok,
convex_loop()} |
{error, hull_error()}.
union_convex_loops(Left, Right, Repair_mode) ->
{convex_loop, {loop, Left_segments}, _} = Left,
{convex_loop, {loop, Right_segments}, _} = Right,
gleam@result:'try'(
union_loop_segments(Left_segments, Right_segments),
fun(Segments) ->
gleam@result:'try'(
configured_repair_loop_with_loop(
{loop, Segments},
{loop, Right_segments},
Repair_mode
),
fun(Repaired) ->
{loop, Segments@1} = Repaired,
{ok, convex_loop(Segments@1)}
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 484).
-spec union_convex_loop_list(list(convex_loop()), binary()) -> {ok,
convex_loop()} |
{error, hull_error()}.
union_convex_loop_list(Loops, Repair_mode) ->
case Loops of
[] ->
{error, loop_union_collapsed};
[First | Rest] ->
_pipe = Rest,
gleam@list:fold(
_pipe,
{ok, First},
fun(Hull, Loop) ->
gleam@result:'try'(
Hull,
fun(Hull@1) ->
union_convex_loops(Hull@1, Loop, Repair_mode)
end
)
end
)
end.
-file("src/svg_path/convex_hull.gleam", 455).
-spec convex_loop_endpoint_groups(list(convex_loop())) -> list(list(vec@vec2:vec2(float()))).
convex_loop_endpoint_groups(Loops) ->
_pipe = Loops,
gleam@list:map(
_pipe,
fun(Loop) ->
{convex_loop, Loop@1, _} = Loop,
loop_endpoints(Loop@1)
end
).
-file("src/svg_path/convex_hull.gleam", 694).
-spec point_is_strictly_inside_edge(float(), float(), loop_orientation()) -> boolean().
point_is_strictly_inside_edge(Turn, Scale, Orientation) ->
Tolerance = 0.000000001 * Scale,
case Orientation of
counter_clockwise ->
Turn > Tolerance;
clockwise ->
Turn < (+0.0 - Tolerance);
degenerate_orientation ->
false
end.
-file("src/svg_path/convex_hull.gleam", 669).
-spec convex_polygon_strictly_contains_point_loop(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
loop_orientation()
) -> boolean().
convex_polygon_strictly_contains_point_loop(Points, Point, Orientation) ->
case Points of
[A, B | Rest] ->
Edge = subtract(B, A),
Offset = subtract(Point, A),
Turn = cross(Edge, Offset),
Scale = point_length(Edge) * point_length(Offset),
case point_is_strictly_inside_edge(Turn, Scale, Orientation) of
true ->
convex_polygon_strictly_contains_point_loop(
[B | Rest],
Point,
Orientation
);
false ->
false
end;
_ ->
true
end.
-file("src/svg_path/convex_hull.gleam", 652).
-spec convex_polygon_strictly_contains_point(
convex_polygon(),
vec@vec2:vec2(float()),
loop_orientation()
) -> boolean().
convex_polygon_strictly_contains_point(Polygon, Point, Orientation) ->
{convex_polygon, Vertices} = Polygon,
case Vertices of
[] ->
false;
[_] ->
false;
[_, _] ->
false;
[First | _] ->
convex_polygon_strictly_contains_point_loop(
lists:append(Vertices, [First]),
Point,
Orientation
)
end.
-file("src/svg_path/convex_hull.gleam", 637).
-spec convex_loop_strictly_inside(
convex_loop(),
convex_polygon(),
loop_orientation()
) -> boolean().
convex_loop_strictly_inside(Convex_loop, Envelope, Orientation) ->
{convex_loop, _, {convex_polygon, Vertices}} = Convex_loop,
case Vertices of
[] ->
false;
_ ->
gleam@list:all(
Vertices,
fun(Point) ->
convex_polygon_strictly_contains_point(
Envelope,
Point,
Orientation
)
end
)
end.
-file("src/svg_path/convex_hull.gleam", 720).
-spec convex_polygon_support_value(convex_polygon(), float()) -> float().
convex_polygon_support_value(Polygon, Angle) ->
{convex_polygon, Vertices} = Polygon,
Direction = angle_direction(Angle),
case Vertices of
[] ->
+0.0;
[First | Rest] ->
_pipe = Rest,
gleam@list:fold(
_pipe,
dot(First, Direction),
fun(Best, Point) ->
gleam@float:max(Best, dot(Point, Direction))
end
)
end.
-file("src/svg_path/convex_hull.gleam", 611).
-spec convex_loop_support(convex_loop(), float(), float()) -> {ok,
loop_support()} |
{error, nil}.
convex_loop_support(Convex_loop, Angle, Value_to_beat) ->
{convex_loop, Loop, Enclosure} = Convex_loop,
case convex_polygon_support_value(Enclosure, Angle) =< Value_to_beat of
true ->
{error, nil};
false ->
Support = loop_support(Loop, Angle),
case erlang:element(4, Support) > Value_to_beat of
true ->
{ok, Support};
false ->
{error, nil}
end
end.
-file("src/svg_path/convex_hull.gleam", 590).
-spec convex_loop_family_support_loop(
list(convex_loop()),
float(),
{ok, loop_support()} | {error, nil},
float()
) -> {ok, loop_support()} | {error, nil}.
convex_loop_family_support_loop(Loops, Angle, Best, Value_to_beat) ->
case Loops of
[] ->
Best;
[Loop | Rest] ->
{Best@1, Value_to_beat@1} = case convex_loop_support(
Loop,
Angle,
Value_to_beat
) of
{error, _} ->
{Best, Value_to_beat};
{ok, Candidate} ->
{{ok, Candidate}, erlang:element(4, Candidate)}
end,
convex_loop_family_support_loop(
Rest,
Angle,
Best@1,
Value_to_beat@1
)
end.
-file("src/svg_path/convex_hull.gleam", 629).
-spec convex_loop_exact_support(convex_loop(), float()) -> loop_support().
convex_loop_exact_support(Convex_loop, Angle) ->
{convex_loop, Loop, _} = Convex_loop,
loop_support(Loop, Angle).
-file("src/svg_path/convex_hull.gleam", 570).
-spec convex_loop_family_support(list(convex_loop()), float()) -> {ok,
loop_support()} |
{error, nil}.
convex_loop_family_support(Loops, Angle) ->
case Loops of
[] ->
{error, nil};
[First | Rest] ->
First@1 = convex_loop_exact_support(First, Angle),
convex_loop_family_support_loop(
Rest,
Angle,
{ok, First@1},
erlang:element(4, First@1)
)
end.
-file("src/svg_path/convex_hull.gleam", 547).
-spec first_pass_envelope(list(convex_loop())) -> convex_polygon().
first_pass_envelope(Loops) ->
Points@1 = begin
_pipe = gleam@int:range(
0,
36 - 1,
[],
fun(Points, I) ->
Angle = case erlang:float(36) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(I) * 360.0 / Gleam@denominator
end,
case convex_loop_family_support(Loops, Angle) of
{ok, Support} ->
[erlang:element(3, Support) | Points];
{error, _} ->
Points
end
end
),
_pipe@1 = lists:reverse(_pipe),
_pipe@2 = remove_closing_duplicate(_pipe@1),
remove_near_adjacent_duplicates(_pipe@2)
end,
{convex_polygon, Points@1}.
-file("src/svg_path/convex_hull.gleam", 523).
-spec prefilter_convex_loops(list(convex_loop())) -> list(convex_loop()).
prefilter_convex_loops(Loops) ->
case Loops of
[] ->
Loops;
[_] ->
Loops;
_ ->
Envelope = first_pass_envelope(Loops),
case convex_polygon_orientation(Envelope) of
degenerate_orientation ->
Loops;
Orientation ->
Filtered = begin
_pipe = Loops,
gleam@list:filter(
_pipe,
fun(Loop) ->
convex_loop_strictly_inside(
Loop,
Envelope,
Orientation
)
=:= false
end
)
end,
case Filtered of
[] ->
Loops;
_ ->
Filtered
end
end
end.
-file("src/svg_path/convex_hull.gleam", 516).
-spec maybe_prefilter_convex_loops(list(convex_loop())) -> list(convex_loop()).
maybe_prefilter_convex_loops(Loops) ->
case true of
true ->
prefilter_convex_loops(Loops);
false ->
Loops
end.
-file("src/svg_path/convex_hull.gleam", 3577).
-spec piece_to_segment(svg_path:segment(), hull_piece()) -> {ok,
svg_path:segment()} |
{error, hull_error()}.
piece_to_segment(Segment, Piece) ->
case Piece of
{hull_curve, From, To} ->
_pipe = svg_path:sub_segment(Segment, From, To),
map_path_error(_pipe);
{hull_line, From@1, To@1} ->
gleam@result:'try'(
begin
_pipe@1 = svg_path:segment_point(Segment, From@1),
map_path_error(_pipe@1)
end,
fun(Start) ->
gleam@result:'try'(
begin
_pipe@2 = svg_path:segment_point(Segment, To@1),
map_path_error(_pipe@2)
end,
fun(End) -> {ok, {line, Start, End}} end
)
end
)
end.
-file("src/svg_path/convex_hull.gleam", 3565).
-spec pieces_to_segments(svg_path:segment(), list(hull_piece())) -> {ok,
list(svg_path:segment())} |
{error, hull_error()}.
pieces_to_segments(Segment, Pieces) ->
_pipe = gleam@list:fold(
Pieces,
{ok, []},
fun(Segments, Piece) ->
gleam@result:'try'(
Segments,
fun(Segments@1) ->
gleam@result:'try'(
piece_to_segment(Segment, Piece),
fun(Segment@1) -> {ok, [Segment@1 | Segments@1]} end
)
end
)
end
),
gleam@result:map(_pipe, fun lists:reverse/1).
-file("src/svg_path/convex_hull.gleam", 2298).
-spec build_hull(svg_path:segment(), list(hull_piece())) -> {ok,
svg_path:subpath()} |
{error, hull_error()}.
build_hull(Segment, Pieces) ->
gleam@result:'try'(
pieces_to_segments(Segment, Pieces),
fun(Segments) -> build_closed_subpath(Segments) end
).
-file("src/svg_path/convex_hull.gleam", 3555).
-spec hull_pieces_are_consecutive_curves(hull_piece(), hull_piece()) -> boolean().
hull_pieces_are_consecutive_curves(First, Second) ->
case {First, Second} of
{{hull_curve, _, _}, {hull_curve, _, _}} ->
true;
{_, _} ->
false
end.
-file("src/svg_path/convex_hull.gleam", 3539).
-spec has_consecutive_curves_loop(
hull_piece(),
hull_piece(),
list(hull_piece())
) -> boolean().
has_consecutive_curves_loop(First, Previous, Rest) ->
case Rest of
[] ->
hull_pieces_are_consecutive_curves(Previous, First);
[Current | Rest@1] ->
case hull_pieces_are_consecutive_curves(Previous, Current) of
true ->
true;
false ->
has_consecutive_curves_loop(First, Current, Rest@1)
end
end.
-file("src/svg_path/convex_hull.gleam", 3531).
-spec has_consecutive_curves(list(hull_piece())) -> boolean().
has_consecutive_curves(Pieces) ->
case Pieces of
[] ->
false;
[First | Rest] ->
has_consecutive_curves_loop(First, First, Rest)
end.
-file("src/svg_path/convex_hull.gleam", 3522).
-spec reject_consecutive_curves(list(hull_piece())) -> {ok, list(hull_piece())} |
{error, hull_error()}.
reject_consecutive_curves(Pieces) ->
case has_consecutive_curves(Pieces) of
true ->
{error, consecutive_curves};
false ->
{ok, Pieces}
end.
-file("src/svg_path/convex_hull.gleam", 3240).
-spec sync_line_endpoints_loop(
list(hull_piece()),
integer(),
list(hull_piece())
) -> list(hull_piece()).
sync_line_endpoints_loop(Window, Remaining, Synced) ->
case Remaining =< 0 of
true ->
Synced;
false ->
{Previous@1, Current@1, Next@1, Rest@1} = case Window of
[Previous, Current, Next | Rest] -> {
Previous,
Current,
Next,
Rest};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"sync_line_endpoints_loop"/utf8>>,
line => 3248,
value => _assert_fail,
start => 85250,
'end' => 85303,
pattern_start => 85261,
pattern_end => 85294})
end,
Current@2 = case Current@1 of
{hull_line, From, To} ->
From@1 = case Previous@1 of
{hull_curve, _, Curve_to} ->
Curve_to;
_ ->
From
end,
To@1 = case Next@1 of
{hull_curve, Curve_from, _} ->
Curve_from;
_ ->
To
end,
{hull_line, From@1, To@1};
_ ->
Current@1
end,
sync_line_endpoints_loop(
[Current@2, Next@1 | Rest@1],
Remaining - 1,
[Current@2 | Synced]
)
end.
-file("src/svg_path/convex_hull.gleam", 3223).
-spec sync_line_endpoints(list(hull_piece())) -> list(hull_piece()).
sync_line_endpoints(Pieces) ->
case Pieces of
[] ->
[];
[_] ->
Pieces;
[First | _] ->
Last@1 = case gleam@list:last(Pieces) of
{ok, Last} -> Last;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"sync_line_endpoints"/utf8>>,
line => 3228,
value => _assert_fail,
start => 84796,
'end' => 84835,
pattern_start => 84807,
pattern_end => 84815})
end,
Window = lists:append([Last@1 | Pieces], [First]),
_pipe = sync_line_endpoints_loop(Window, erlang:length(Pieces), []),
lists:reverse(_pipe)
end.
-file("src/svg_path/convex_hull.gleam", 3351).
-spec finish_refinement_scan(refinement_scan()) -> float().
finish_refinement_scan(Scan) ->
case Scan of
{done, Root} ->
Root;
{continue, {_, _, Best, _}} ->
Best
end.
-file("src/svg_path/convex_hull.gleam", 3908).
-spec cubic_derivative(svg_path:segment(), float()) -> vec@vec2:vec2(float()).
cubic_derivative(Segment, T) ->
case Segment of
{cubic_bezier, Start, Control1, Control2, End} ->
Mt = 1.0 - T,
add_points(
add_points(
scale_point(subtract(Control1, Start), (3.0 * Mt) * Mt),
scale_point(subtract(Control2, Control1), (6.0 * Mt) * T)
),
scale_point(subtract(End, Control2), (3.0 * T) * T)
);
_ ->
svg_path:point(+0.0, +0.0)
end.
-file("src/svg_path/convex_hull.gleam", 3898).
-spec chord_tangent_value(svg_path:segment(), float(), float()) -> float().
chord_tangent_value(Segment, T, Other) ->
Point@1 = case svg_path:segment_point(Segment, T) of
{ok, Point} -> Point;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"chord_tangent_value"/utf8>>,
line => 3903,
value => _assert_fail,
start => 101833,
'end' => 101894,
pattern_start => 101844,
pattern_end => 101853})
end,
Other_point@1 = case svg_path:segment_point(Segment, Other) of
{ok, Other_point} -> Other_point;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"chord_tangent_value"/utf8>>,
line => 3904,
value => _assert_fail@1,
start => 101897,
'end' => 101968,
pattern_start => 101908,
pattern_end => 101923})
end,
cross(cubic_derivative(Segment, T), subtract(Other_point@1, Point@1)).
-file("src/svg_path/convex_hull.gleam", 3375).
-spec bisect_chord_tangent_loop(
svg_path:segment(),
float(),
float(),
float(),
float(),
integer()
) -> float().
bisect_chord_tangent_loop(Segment, Left, Left_value, Right, Other, Remaining) ->
Midpoint = Left + ((Right - Left) / 2.0),
Midpoint_value = chord_tangent_value(Segment, Midpoint, Other),
case ((Remaining =< 0) orelse (gleam@float:absolute_value(Midpoint_value) < 0.00000000000001))
orelse (gleam@float:absolute_value(Right - Left) < 0.000000000001) of
true ->
Midpoint;
false ->
case same_sign(Left_value, Midpoint_value) of
true ->
bisect_chord_tangent_loop(
Segment,
Midpoint,
Midpoint_value,
Right,
Other,
Remaining - 1
);
false ->
bisect_chord_tangent_loop(
Segment,
Left,
Left_value,
Midpoint,
Other,
Remaining - 1
)
end
end.
-file("src/svg_path/convex_hull.gleam", 3358).
-spec bisect_chord_tangent(svg_path:segment(), float(), float(), float()) -> float().
bisect_chord_tangent(Segment, Other, Left, Right) ->
Left_value = chord_tangent_value(Segment, Left, Other),
bisect_chord_tangent_loop(Segment, Left, Left_value, Right, Other, 80).
-file("src/svg_path/convex_hull.gleam", 3298).
-spec refine_chord_tangent_scan(
svg_path:segment(),
float(),
float(),
float(),
integer(),
float(),
float()
) -> float().
refine_chord_tangent_scan(Segment, Other, Left, Right, Steps, Best, Best_value) ->
Initial_value = chord_tangent_value(Segment, Left, Other),
_pipe = gleam@int:range(
1,
Steps,
{continue, {Left, Initial_value, Best, Best_value}},
fun(State, I) -> case State of
{done, Root} ->
{done, Root};
{continue, {Previous_t, Previous_value, Best@1, Best_value@1}} ->
T = Left + (case erlang:float(Steps) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> (Right - Left) * erlang:float(I) / Gleam@denominator
end),
Value = chord_tangent_value(Segment, T, Other),
{Best@2, Best_value@2} = case gleam@float:absolute_value(
Value
)
< Best_value@1 of
true ->
{T, gleam@float:absolute_value(Value)};
false ->
{Best@1, Best_value@1}
end,
case ((Value =:= +0.0) orelse (Previous_value =:= +0.0))
orelse (same_sign(Value, Previous_value) =:= false) of
true ->
{done,
bisect_chord_tangent(
Segment,
Other,
Previous_t,
T
)};
false ->
{continue, {T, Value, Best@2, Best_value@2}}
end
end end
),
finish_refinement_scan(_pipe).
-file("src/svg_path/convex_hull.gleam", 3272).
-spec refine_chord_tangent(svg_path:segment(), float(), float()) -> float().
refine_chord_tangent(Segment, Approximate, Other) ->
case (Approximate < 0.000001) orelse (Approximate > (1.0 - 0.000001)) of
true ->
Approximate;
false ->
Initial = chord_tangent_value(Segment, Approximate, Other),
case gleam@float:absolute_value(Initial) < 0.000000000001 of
true ->
Approximate;
false ->
refine_chord_tangent_scan(
Segment,
Other,
gleam@float:max(+0.0, Approximate - 0.08),
gleam@float:min(1.0, Approximate + 0.08),
64,
Approximate,
gleam@float:absolute_value(Initial)
)
end
end.
-file("src/svg_path/convex_hull.gleam", 3174).
-spec refine_pieces_loop(
svg_path:segment(),
list(hull_piece()),
integer(),
list(hull_piece())
) -> list(hull_piece()).
refine_pieces_loop(Segment, Window, Remaining, Refined) ->
case Remaining =< 0 of
true ->
Refined;
false ->
{Previous@1, Current@1, Next@1, Rest@1} = case Window of
[Previous, Current, Next | Rest] -> {
Previous,
Current,
Next,
Rest};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"refine_pieces_loop"/utf8>>,
line => 3183,
value => _assert_fail,
start => 83527,
'end' => 83580,
pattern_start => 83538,
pattern_end => 83571})
end,
Refined_current = case Current@1 of
{hull_curve, From, To} ->
From@1 = case Previous@1 of
{hull_line, Other, _} ->
refine_chord_tangent(Segment, From, Other);
_ ->
From
end,
To@1 = case Next@1 of
{hull_line, _, Other@1} ->
refine_chord_tangent(Segment, To, Other@1);
_ ->
To
end,
{hull_curve, From@1, To@1};
{hull_line, From@2, To@2} ->
From@3 = case Previous@1 of
{hull_curve, _, _} ->
refine_chord_tangent(Segment, From@2, To@2);
_ ->
From@2
end,
To@3 = case Next@1 of
{hull_curve, _, _} ->
refine_chord_tangent(Segment, To@2, From@3);
_ ->
To@2
end,
{hull_line, From@3, To@3}
end,
refine_pieces_loop(
Segment,
[Current@1, Next@1 | Rest@1],
Remaining - 1,
[Refined_current | Refined]
)
end.
-file("src/svg_path/convex_hull.gleam", 3152).
-spec refine_pieces(list(hull_piece()), svg_path:segment()) -> list(hull_piece()).
refine_pieces(Pieces, Segment) ->
case Pieces of
[] ->
[];
[_] ->
Pieces;
[First | _] ->
Last@1 = case gleam@list:last(Pieces) of
{ok, Last} -> Last;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"refine_pieces"/utf8>>,
line => 3160,
value => _assert_fail,
start => 83006,
'end' => 83045,
pattern_start => 83017,
pattern_end => 83025})
end,
Window = lists:append([Last@1 | Pieces], [First]),
_pipe = refine_pieces_loop(
Segment,
Window,
erlang:length(Pieces),
[]
),
_pipe@1 = lists:reverse(_pipe),
sync_line_endpoints(_pipe@1)
end.
-file("src/svg_path/convex_hull.gleam", 3138).
-spec start_t(run_endpoint()) -> float().
start_t(Endpoint) ->
case Endpoint of
{point_endpoint, T} ->
T;
{curve_endpoint, From, _} ->
From
end.
-file("src/svg_path/convex_hull.gleam", 3145).
-spec end_t(run_endpoint()) -> float().
end_t(Endpoint) ->
case Endpoint of
{point_endpoint, T} ->
T;
{curve_endpoint, _, To} ->
To
end.
-file("src/svg_path/convex_hull.gleam", 3130).
-spec add_line(list(hull_piece()), float(), float()) -> list(hull_piece()).
add_line(Pieces, From, To) ->
[{hull_line, From, To} | Pieces].
-file("src/svg_path/convex_hull.gleam", 3116).
-spec add_endpoint_curve(list(hull_piece()), run_endpoint()) -> list(hull_piece()).
add_endpoint_curve(Pieces, Endpoint) ->
case Endpoint of
{point_endpoint, _} ->
Pieces;
{curve_endpoint, From, To} ->
case gleam@float:absolute_value(From - To) =< 0.000001 of
true ->
Pieces;
false ->
[{hull_curve, From, To} | Pieces]
end
end.
-file("src/svg_path/convex_hull.gleam", 3076).
-spec pieces_from_endpoints_loop(
list(run_endpoint()),
run_endpoint(),
list(run_endpoint()),
list(hull_piece())
) -> list(hull_piece()).
pieces_from_endpoints_loop(Endpoints, First, Rest, Pieces) ->
case {Endpoints, Rest} of
{[], _} ->
Pieces;
{[Current | _], []} ->
Pieces@1 = add_endpoint_curve(Pieces, Current),
add_line(Pieces@1, end_t(Current), start_t(First));
{[Current@1 | Remaining], [Next | Next_rest]} ->
Pieces@2 = add_endpoint_curve(Pieces, Current@1),
Pieces@3 = add_line(Pieces@2, end_t(Current@1), start_t(Next)),
pieces_from_endpoints_loop(Remaining, First, Next_rest, Pieces@3)
end.
-file("src/svg_path/convex_hull.gleam", 3963).
-spec average(list(float())) -> float().
average(Values) ->
case erlang:float(erlang:length(Values)) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> gleam@list:fold(
Values,
+0.0,
fun(Total, Value) -> Total + Value end
)
/ Gleam@denominator
end.
-file("src/svg_path/convex_hull.gleam", 3102).
-spec run_endpoint(run()) -> run_endpoint().
run_endpoint(Run) ->
Min = gleam@list:fold(erlang:element(2, Run), +0.0, fun gleam@float:min/2),
Max = gleam@list:fold(erlang:element(2, Run), +0.0, fun gleam@float:max/2),
case (Max - Min) < 0.000001 of
true ->
{point_endpoint, average(erlang:element(2, Run))};
false ->
From@1 = case erlang:element(2, Run) of
[From | _] -> From;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"run_endpoint"/utf8>>,
line => 3109,
value => _assert_fail,
start => 82012,
'end' => 82042,
pattern_start => 82023,
pattern_end => 82033})
end,
To@1 = case gleam@list:last(erlang:element(2, Run)) of
{ok, To} -> To;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"run_endpoint"/utf8>>,
line => 3110,
value => _assert_fail@1,
start => 82049,
'end' => 82086,
pattern_start => 82060,
pattern_end => 82066})
end,
{curve_endpoint, From@1, To@1}
end.
-file("src/svg_path/convex_hull.gleam", 3065).
-spec pieces_from_runs(list(run())) -> list(hull_piece()).
pieces_from_runs(Runs) ->
Endpoints = gleam@list:map(Runs, fun run_endpoint/1),
case Endpoints of
[] ->
[];
[First | Rest] ->
_pipe = pieces_from_endpoints_loop(Endpoints, First, Rest, []),
lists:reverse(_pipe)
end.
-file("src/svg_path/convex_hull.gleam", 3047).
-spec merge_circular_run_boundary(list(run())) -> list(run()).
merge_circular_run_boundary(Runs) ->
case Runs of
[] ->
Runs;
[_] ->
Runs;
[First | Rest] ->
case {gleam@list:last(Rest), erlang:element(2, First)} of
{{ok, Last}, [First_t | _]} ->
Last_t@1 = case gleam@list:last(erlang:element(2, Last)) of
{ok, Last_t} -> Last_t;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"merge_circular_run_boundary"/utf8>>,
line => 3053,
value => _assert_fail,
start => 80536,
'end' => 80578,
pattern_start => 80547,
pattern_end => 80557})
end,
case gleam@float:absolute_value(First_t - Last_t@1) =< 0.08 of
true ->
[{run,
lists:append(
erlang:element(2, Last),
erlang:element(2, First)
)} |
drop_last(Rest)];
false ->
Runs
end;
{_, _} ->
Runs
end
end.
-file("src/svg_path/convex_hull.gleam", 3043).
-spec reverse_run(run()) -> run().
reverse_run(Run) ->
{run, lists:reverse(erlang:element(2, Run))}.
-file("src/svg_path/convex_hull.gleam", 3017).
-spec collapse_runs_loop(list(support_sample()), run(), list(run())) -> list(run()).
collapse_runs_loop(Samples, Current, Runs) ->
case Samples of
[] ->
[reverse_run(Current) | Runs];
[Sample | Rest] ->
Previous_t@1 = case erlang:element(2, Current) of
[Previous_t | _] -> Previous_t;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"svg_path/convex_hull"/utf8>>,
function => <<"collapse_runs_loop"/utf8>>,
line => 3025,
value => _assert_fail,
start => 79814,
'end' => 79854,
pattern_start => 79825,
pattern_end => 79841})
end,
case gleam@float:absolute_value(
erlang:element(3, Sample) - Previous_t@1
)
=< 0.08 of
true ->
collapse_runs_loop(
Rest,
{run,
[erlang:element(3, Sample) |
erlang:element(2, Current)]},
Runs
);
false ->
collapse_runs_loop(
Rest,
{run, [erlang:element(3, Sample)]},
[reverse_run(Current) | Runs]
)
end
end.
-file("src/svg_path/convex_hull.gleam", 3004).
-spec collapse_runs(list(support_sample())) -> list(run()).
collapse_runs(Samples) ->
case Samples of
[] ->
[];
[First | Rest] ->
Runs = begin
_pipe = collapse_runs_loop(
Rest,
{run, [erlang:element(3, First)]},
[]
),
lists:reverse(_pipe)
end,
merge_circular_run_boundary(Runs)
end.
-file("src/svg_path/convex_hull.gleam", 2990).
-spec raw_samples(svg_path:segment(), integer()) -> list(support_sample()).
raw_samples(Segment, Sample_count) ->
_pipe = gleam@int:range(
0,
Sample_count - 1,
[],
fun(Samples, I) ->
Angle = case erlang:float(Sample_count) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(I) * 360.0 / Gleam@denominator
end,
case segment_support(Segment, Angle) of
{ok, Sample} ->
[Sample | Samples];
{error, _} ->
Samples
end
end
),
lists:reverse(_pipe).
-file("src/svg_path/convex_hull.gleam", 2280).
-spec cubic_hull(svg_path:segment()) -> {ok, svg_path:subpath()} |
{error, hull_error()}.
cubic_hull(Segment) ->
case segment_is_point_like(Segment) of
true ->
build_hull(
Segment,
[{hull_line, +0.0, +0.0}, {hull_line, +0.0, +0.0}]
);
false ->
Pieces = begin
_pipe = raw_samples(Segment, 3600),
_pipe@1 = collapse_runs(_pipe),
_pipe@2 = pieces_from_runs(_pipe@1),
refine_pieces(_pipe@2, Segment)
end,
gleam@result:'try'(
reject_consecutive_curves(Pieces),
fun(Pieces@1) -> build_hull(Segment, Pieces@1) end
)
end.
-file("src/svg_path/convex_hull.gleam", 2271).
-spec simple_curve_hull(svg_path:segment()) -> {ok, svg_path:subpath()} |
{error, hull_error()}.
simple_curve_hull(Segment) ->
case segment_is_point_like(Segment) of
true ->
build_hull(
Segment,
[{hull_line, +0.0, +0.0}, {hull_line, +0.0, +0.0}]
);
false ->
build_hull(
Segment,
[{hull_curve, +0.0, 1.0}, {hull_line, 1.0, +0.0}]
)
end.
-file("src/svg_path/convex_hull.gleam", 2264).
-spec line_hull(svg_path:segment()) -> {ok, svg_path:subpath()} |
{error, hull_error()}.
line_hull(Segment) ->
case segment_is_point_like(Segment) of
true ->
build_hull(
Segment,
[{hull_line, +0.0, +0.0}, {hull_line, +0.0, +0.0}]
);
false ->
build_hull(
Segment,
[{hull_line, +0.0, 1.0}, {hull_line, 1.0, +0.0}]
)
end.
-file("src/svg_path/convex_hull.gleam", 222).
-spec segment_hull(svg_path:segment()) -> {ok, svg_path:subpath()} |
{error, hull_error()}.
segment_hull(Segment) ->
case Segment of
{line, _, _} ->
line_hull(Segment);
{quadratic_bezier, _, _, _} ->
simple_curve_hull(Segment);
{arc, _, _, _, _, _, _} ->
simple_curve_hull(Segment);
{cubic_bezier, _, _, _, _} ->
cubic_hull(Segment)
end.
-file("src/svg_path/convex_hull.gleam", 436).
-spec segment_hull_segments(svg_path:segment()) -> {ok,
list(svg_path:segment())} |
{error, hull_error()}.
segment_hull_segments(Segment) ->
gleam@result:'try'(
segment_hull(Segment),
fun(Subpath) -> {ok, svg_path:segments(Subpath)} end
).
-file("src/svg_path/convex_hull.gleam", 443).
-spec segment_convex_loop(svg_path:segment()) -> {ok, convex_loop()} |
{error, hull_error()}.
segment_convex_loop(Segment) ->
gleam@result:'try'(
segment_hull_segments(Segment),
fun(Segments) -> {ok, convex_loop(Segments)} end
).
-file("src/svg_path/convex_hull.gleam", 410).
-spec segment_convex_loops(list(svg_path:segment())) -> {ok,
list(convex_loop())} |
{error, hull_error()}.
segment_convex_loops(Segments) ->
_pipe = Segments,
_pipe@1 = gleam@list:fold(
_pipe,
{ok, []},
fun(Loops, Segment) ->
gleam@result:'try'(
Loops,
fun(Loops@1) ->
gleam@result:'try'(
segment_convex_loop(Segment),
fun(Loop) -> {ok, [Loop | Loops@1]} end
)
end
)
end
),
gleam@result:map(_pipe@1, fun lists:reverse/1).
-file("src/svg_path/convex_hull.gleam", 388).
-spec segments_hull(list(svg_path:segment()), binary()) -> {ok,
svg_path:subpath()} |
{error, hull_error()}.
segments_hull(Segments, Repair_mode) ->
gleam@result:'try'(
segment_convex_loops(Segments),
fun(Loops) ->
Loops@1 = maybe_prefilter_convex_loops(Loops),
Repair_point_groups = convex_loop_endpoint_groups(Loops@1),
gleam@result:'try'(
begin
_pipe = Loops@1,
union_convex_loop_list(_pipe, <<"none"/utf8>>)
end,
fun(Convex_loop) ->
{convex_loop, Loop, _} = Convex_loop,
gleam@result:'try'(
final_repair_loop(
Loop,
Loops@1,
Repair_point_groups,
Repair_mode
),
fun(Repaired) ->
{loop, Segments@1} = Repaired,
build_closed_subpath(Segments@1)
end
)
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 422).
-spec hull_input_segments(svg_path:subpath()) -> list(svg_path:segment()).
hull_input_segments(Subpath) ->
case svg_path:segments(Subpath) of
[] ->
Start@1 = case svg_path:start(Subpath) 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/convex_hull"/utf8>>,
function => <<"hull_input_segments"/utf8>>,
line => 425,
value => _assert_fail,
start => 10790,
'end' => 10836,
pattern_start => 10801,
pattern_end => 10810})
end,
[point_segment(Start@1)];
Segments ->
Segments
end.
-file("src/svg_path/convex_hull.gleam", 186).
?DOC(
" Compute the convex hull of a subpath.\n"
"\n"
" The result is a closed subpath. Move-only subpaths are treated as a single\n"
" point at their start. Otherwise each individual segment is first converted\n"
" to its own convex hull, then those convex loops are unioned one at a time.\n"
).
-spec subpath_hull(svg_path:subpath()) -> {ok, svg_path:subpath()} |
{error, hull_error()}.
subpath_hull(Subpath) ->
_pipe = Subpath,
_pipe@1 = hull_input_segments(_pipe),
segments_hull(_pipe@1, <<"ambitious"/utf8>>).
-file("src/svg_path/convex_hull.gleam", 199).
?DOC(
" Compute the convex hull of a path.\n"
"\n"
" Move-only subpaths are treated as single points at their starts. The result\n"
" is a single closed subpath containing the hull of every subpath in the input\n"
" path.\n"
).
-spec path_hull(svg_path:path()) -> {ok, svg_path:subpath()} |
{error, hull_error()}.
path_hull(Path) ->
case svg_path:subpaths(Path) of
[] ->
{error, {path_error, empty_path}};
Subpaths ->
_pipe = Subpaths,
_pipe@1 = gleam@list:flat_map(_pipe, fun hull_input_segments/1),
segments_hull(_pipe@1, <<"ambitious"/utf8>>)
end.
-file("src/svg_path/convex_hull.gleam", 213).
?DOC(
" Compute the convex hull of a list of points.\n"
"\n"
" The result is a single closed subpath containing every input point.\n"
).
-spec points_hull(list(vec@vec2:vec2(float()))) -> {ok, svg_path:subpath()} |
{error, hull_error()}.
points_hull(Points) ->
_pipe = Points,
_pipe@1 = gleam@list:map(
_pipe,
fun(Point) -> svg_path:empty_subpath(Point) end
),
_pipe@2 = {path, _pipe@1},
path_hull(_pipe@2).
-file("src/svg_path/convex_hull.gleam", 234).
?DOC(false).
-spec test_segment_support(svg_path:segment(), float()) -> {ok,
{float(), vec@vec2:vec2(float()), float()}} |
{error, svg_path:error()}.
test_segment_support(Segment, Angle) ->
gleam@result:'try'(
segment_support(Segment, Angle),
fun(Sample) ->
{ok,
{erlang:element(3, Sample),
erlang:element(4, Sample),
erlang:element(5, Sample)}}
end
).
-file("src/svg_path/convex_hull.gleam", 243).
?DOC(false).
-spec test_brute_segment_support(svg_path:segment(), float()) -> {ok,
{float(), vec@vec2:vec2(float()), float()}} |
{error, svg_path:error()}.
test_brute_segment_support(Segment, Angle) ->
gleam@result:'try'(
brute_segment_support(Segment, Angle),
fun(Sample) ->
{ok,
{erlang:element(3, Sample),
erlang:element(4, Sample),
erlang:element(5, Sample)}}
end
).
-file("src/svg_path/convex_hull.gleam", 252).
?DOC(false).
-spec test_point_chord_polygon_loop_separation(
list(svg_path:segment()),
vec@vec2:vec2(float())
) -> gleam@option:option({float(), vec@vec2:vec2(float())}).
test_point_chord_polygon_loop_separation(Segments, Point) ->
point_chord_polygon_loop_separation({loop, Segments}, Point).
-file("src/svg_path/convex_hull.gleam", 2093).
-spec midpoint(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> vec@vec2:vec2(float()).
midpoint(A, B) ->
scale_point(add_points(A, B), 0.5).
-file("src/svg_path/convex_hull.gleam", 2007).
-spec vertex_chain_is_outside(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
loop_orientation()
) -> boolean().
vertex_chain_is_outside(Vertices, Point, Orientation) ->
case Vertices of
[A, B] ->
Middle = midpoint(A, B),
point_loop_view(
Point,
Middle,
subtract(B, A),
subtract(B, A),
Orientation
)
=:= outside_point;
[A@1, B@1, C | _] ->
point_loop_view(
Point,
B@1,
subtract(B@1, A@1),
subtract(C, B@1),
Orientation
)
=:= outside_point;
_ ->
false
end.
-file("src/svg_path/convex_hull.gleam", 2043).
-spec vertices_to_lines(list(vec@vec2:vec2(float()))) -> list(svg_path:segment()).
vertices_to_lines(Vertices) ->
case Vertices of
[A, B | Rest] ->
[{line, A, B} | vertices_to_lines([B | Rest])];
_ ->
[]
end.
-file("src/svg_path/convex_hull.gleam", 2032).
-spec build_open_subpath_from_vertices(list(vec@vec2:vec2(float()))) -> {ok,
svg_path:subpath()} |
{error, hull_error()}.
build_open_subpath_from_vertices(Vertices) ->
case vertices_to_lines(Vertices) of
[] ->
{error, tangent_search_degenerate_loop};
Segments ->
_pipe = svg_path:subpath_with(Segments, wiggle_then_bridge),
map_path_error(_pipe)
end.
-file("src/svg_path/convex_hull.gleam", 2062).
-spec vertex_chain_loop(
list(vec@vec2:vec2(float())),
integer(),
integer(),
list(vec@vec2:vec2(float()))
) -> list(vec@vec2:vec2(float())).
vertex_chain_loop(Vertices, Current, Target, Points) ->
Points@1 = [vertex_at(Vertices, Current) | Points],
case Current =:= Target of
true ->
Points@1;
false ->
vertex_chain_loop(
Vertices,
next_index(Current, erlang:length(Vertices)),
Target,
Points@1
)
end.
-file("src/svg_path/convex_hull.gleam", 2053).
-spec vertex_chain(list(vec@vec2:vec2(float())), integer(), integer()) -> list(vec@vec2:vec2(float())).
vertex_chain(Vertices, From, To) ->
_pipe = vertex_chain_loop(Vertices, From, To, []),
lists:reverse(_pipe).
-file("src/svg_path/convex_hull.gleam", 1985).
-spec tangent_chains_to_subpaths(
list(vec@vec2:vec2(float())),
tangent_candidate(),
tangent_candidate(),
vec@vec2:vec2(float()),
loop_orientation()
) -> {ok, {svg_path:subpath(), svg_path:subpath()}} | {error, hull_error()}.
tangent_chains_to_subpaths(Vertices, First, Second, Point, Orientation) ->
{tangent_candidate, First_index, _} = First,
{tangent_candidate, Second_index, _} = Second,
First_chain = vertex_chain(Vertices, First_index, Second_index),
Second_chain = vertex_chain(Vertices, Second_index, First_index),
gleam@result:'try'(
build_open_subpath_from_vertices(First_chain),
fun(First_subpath) ->
gleam@result:'try'(
build_open_subpath_from_vertices(Second_chain),
fun(Second_subpath) ->
case vertex_chain_is_outside(
First_chain,
Point,
Orientation
) of
true ->
{ok, {First_subpath, Second_subpath}};
false ->
{ok, {Second_subpath, First_subpath}}
end
end
)
end
).
-file("src/svg_path/convex_hull.gleam", 1801).
-spec point_chord_polygon_vertex_view(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
integer(),
loop_orientation()
) -> point_loop_view().
point_chord_polygon_vertex_view(Vertices, Point, Index, Orientation) ->
Previous = vertex_at(
Vertices,
previous_index(Index, erlang:length(Vertices))
),
Q = vertex_at(Vertices, Index),
Next = vertex_at(Vertices, next_index(Index, erlang:length(Vertices))),
point_loop_view(
Point,
Q,
subtract(Q, Previous),
subtract(Next, Q),
Orientation
).
-file("src/svg_path/convex_hull.gleam", 1777).
-spec point_chord_polygon_tangent_vertices(
list(vec@vec2:vec2(float())),
vec@vec2:vec2(float()),
loop_orientation()
) -> list(tangent_candidate()).
point_chord_polygon_tangent_vertices(Vertices, Point, Orientation) ->
_pipe = gleam@int:range(
0,
erlang:length(Vertices) - 1,
[],
fun(Tangents, Index) ->
case point_chord_polygon_vertex_view(
Vertices,
Point,
Index,
Orientation
) of
tangent_point ->
Q = vertex_at(Vertices, Index),
[{tangent_candidate, Index, Q} | Tangents];
_ ->
Tangents
end
end
),
lists:reverse(_pipe).
-file("src/svg_path/convex_hull.gleam", 842).
-spec point_chord_polygon_tangent_subpaths(loop(), vec@vec2:vec2(float())) -> {ok,
{svg_path:subpath(), svg_path:subpath()}} |
{error, hull_error()}.
point_chord_polygon_tangent_subpaths(Loop, Point) ->
{loop, Segments} = Loop,
Vertices = loop_vertices(Segments),
Orientation = convex_polygon_orientation({convex_polygon, Vertices}),
case Orientation of
degenerate_orientation ->
{error, tangent_search_degenerate_loop};
_ ->
gleam@result:'try'(
validate_chord_polygon_convex(Vertices, Orientation),
fun(_) ->
Tangents = point_chord_polygon_tangent_vertices(
Vertices,
Point,
Orientation
),
case Tangents of
[First, Second] ->
tangent_chains_to_subpaths(
Vertices,
First,
Second,
Point,
Orientation
);
_ ->
{error,
{tangent_search_expected_two_tangencies,
erlang:length(Tangents)}}
end
end
)
end.
-file("src/svg_path/convex_hull.gleam", 260).
?DOC(false).
-spec test_point_chord_polygon_tangent_subpaths(
list(svg_path:segment()),
vec@vec2:vec2(float())
) -> {ok, {svg_path:subpath(), svg_path:subpath()}} | {error, hull_error()}.
test_point_chord_polygon_tangent_subpaths(Segments, Point) ->
point_chord_polygon_tangent_subpaths({loop, Segments}, Point).
-file("src/svg_path/convex_hull.gleam", 268).
?DOC(false).
-spec test_point_exact_loop_tangent_subpaths(
list(svg_path:segment()),
vec@vec2:vec2(float())
) -> {ok, {svg_path:subpath(), svg_path:subpath()}} | {error, hull_error()}.
test_point_exact_loop_tangent_subpaths(Segments, Point) ->
point_exact_loop_tangent_subpaths({loop, Segments}, Point).
-file("src/svg_path/convex_hull.gleam", 276).
?DOC(false).
-spec test_loop_plus_point_hull(
list(svg_path:segment()),
vec@vec2:vec2(float())
) -> {ok, list(svg_path:segment())} | {error, hull_error()}.
test_loop_plus_point_hull(Segments, Point) ->
gleam@result:'try'(
loop_plus_point_hull({loop, Segments}, Point),
fun(Loop) ->
{loop, Segments@1} = Loop,
{ok, Segments@1}
end
).
-file("src/svg_path/convex_hull.gleam", 939).
-spec dumb_repair_loop_with_points(loop(), list(vec@vec2:vec2(float()))) -> {ok,
loop()} |
{error, hull_error()}.
dumb_repair_loop_with_points(Loop, Points) ->
repair_loop_with_points(Loop, lists:append(Points, Points)).
-file("src/svg_path/convex_hull.gleam", 286).
?DOC(false).
-spec test_loop_plus_points_hull(
list(svg_path:segment()),
list(vec@vec2:vec2(float()))
) -> {ok, list(svg_path:segment())} | {error, hull_error()}.
test_loop_plus_points_hull(Segments, Points) ->
gleam@result:'try'(
dumb_repair_loop_with_points({loop, Segments}, Points),
fun(Loop) ->
{loop, Segments@1} = Loop,
{ok, Segments@1}
end
).
-file("src/svg_path/convex_hull.gleam", 296).
?DOC(false).
-spec test_path_hull_with_repair_mode(svg_path:path(), binary()) -> {ok,
svg_path:subpath()} |
{error, hull_error()}.
test_path_hull_with_repair_mode(Path, Repair_mode) ->
case svg_path:subpaths(Path) of
[] ->
{error, {path_error, empty_path}};
Subpaths ->
_pipe = Subpaths,
_pipe@1 = gleam@list:flat_map(_pipe, fun hull_input_segments/1),
segments_hull(_pipe@1, Repair_mode)
end.
-file("src/svg_path/convex_hull.gleam", 311).
?DOC(false).
-spec test_ambitious_repair_loop_with_loop(
list(svg_path:segment()),
list(svg_path:segment())
) -> {ok, list(svg_path:segment())} | {error, hull_error()}.
test_ambitious_repair_loop_with_loop(Current, Addition) ->
gleam@result:'try'(
ambitious_repair_loop_with_loop({loop, Current}, {loop, Addition}),
fun(Loop) ->
{loop, Segments} = Loop,
{ok, Segments}
end
).
-file("src/svg_path/convex_hull.gleam", 324).
?DOC(false).
-spec test_find_seeded_worst_direction(
list(svg_path:segment()),
list(svg_path:segment()),
float(),
float()
) -> {ok, {float(), float()}} | {error, hull_error()}.
test_find_seeded_worst_direction(Loop_a, Loop_b, Direction, Threshold) ->
find_seeded_worst_direction(
{loop, Loop_a},
{loop, Loop_b},
Direction,
Threshold
).
-file("src/svg_path/convex_hull.gleam", 339).
?DOC(false).
-spec test_loop_initial_sample_angles(integer(), list(float())) -> list(float()).
test_loop_initial_sample_angles(Sample_count, Seed_angles) ->
loop_initial_sample_angles(Sample_count, Seed_angles).
-file("src/svg_path/convex_hull.gleam", 347).
?DOC(false).
-spec test_loop_union_segments_with_seed_angles(
list(svg_path:segment()),
list(svg_path:segment()),
list(float())
) -> list(svg_path:segment()).
test_loop_union_segments_with_seed_angles(Loop_a, Loop_b, Seed_angles) ->
Loop_a@1 = {loop, Loop_a},
Loop_b@1 = {loop, Loop_b},
_pipe = loop_union(Loop_a@1, Loop_b@1, 360, Seed_angles),
union_piece_segments(_pipe, Loop_a@1, Loop_b@1).
-file("src/svg_path/convex_hull.gleam", 364).
?DOC(false).
-spec test_segment_tangent_monotone(svg_path:segment(), boolean()) -> {ok, nil} |
{error, float()}.
test_segment_tangent_monotone(Segment, Clockwise) ->
segment_tangent_turn_algebraic(Segment, case Clockwise of
true ->
clockwise;
false ->
counter_clockwise
end).
-file("src/svg_path/convex_hull.gleam", 375).
?DOC(false).
-spec test_point_loop_view(
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
vec@vec2:vec2(float()),
boolean()
) -> point_loop_view().
test_point_loop_view(Point, Q, Arriving, Leaving, Clockwise) ->
point_loop_view(Point, Q, Arriving, Leaving, case Clockwise of
true ->
clockwise;
false ->
counter_clockwise
end).