Skip to main content

src/svg_path@convex_hull.erl

-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).