Convex hull: Difference between revisions
Content added Content deleted
Line 3,151: | Line 3,151: | ||
hullPoints[{{16, 3}, {12, 17}, {0, 6}, {-4, -6}, {16, 6}, {16, -7}, {16, -3}, {17, -4}, {5, 19}, {19, -8}, {3, 16}, {12, 13}, {3, -4}, {17, 5}, {-3, 15}, {-3, -9}, {0, 11}, {-9, -3}, {-4, -2}, {12, 10}}]</lang> |
hullPoints[{{16, 3}, {12, 17}, {0, 6}, {-4, -6}, {16, 6}, {16, -7}, {16, -3}, {17, -4}, {5, 19}, {19, -8}, {3, 16}, {12, 13}, {3, -4}, {17, 5}, {-3, 15}, {-3, -9}, {0, 11}, {-9, -3}, {-4, -2}, {12, 10}}]</lang> |
||
{{out}}{{12., 17.}, {5., 19.}, {19., -8.}, {17., 5.}, {-3., 15.}, {-3., -9.}, {-9., -3.}} |
{{out}}{{12., 17.}, {5., 19.}, {19., -8.}, {17., 5.}, {-3., 15.}, {-3., -9.}, {-9., -3.}} |
||
=={{header|Mercury}}== |
|||
{{trans|Standard ML}} |
|||
{{works with|Mercury|20.06.1}} |
|||
<lang mercury>:- module convex_hull_task. |
|||
:- interface. |
|||
:- import_module io. |
|||
:- pred main(io, io). |
|||
:- mode main(di, uo) is det. |
|||
:- implementation. |
|||
:- import_module exception. |
|||
:- import_module float. |
|||
:- import_module int. |
|||
:- import_module list. |
|||
:- import_module pair. |
|||
:- import_module string. |
|||
:- import_module version_array. |
|||
%%-------------------------------------------------------------------- |
|||
%% fetch_items/3 for version_array, similar to the library function |
|||
%% for regular array. |
|||
:- func fetch_items(version_array(T), int, int) = list(T). |
|||
fetch_items(Arr, I, J) = fetch_items_(Arr, I, J, []). |
|||
:- func fetch_items_(version_array(T), int, int, list(T)) = list(T). |
|||
fetch_items_(Arr, I, J, Lst0) = Lst :- |
|||
if (J < I) then (Lst = Lst0) |
|||
else (J1 = J - 1, |
|||
Lst = fetch_items_(Arr, I, J1, [Arr^elem(J) | Lst0])). |
|||
%%-------------------------------------------------------------------- |
|||
:- type point == pair(float). |
|||
:- type point_list == list(point). |
|||
:- type point_array == version_array(point). |
|||
:- pred point_eq(point, point). |
|||
:- mode point_eq(in, in) is semidet. |
|||
point_eq(P, Q) :- |
|||
(fst(P) - fst(Q) = 0.0), |
|||
(snd(P) - snd(Q) = 0.0). |
|||
:- pred point_comes_before(point, point). |
|||
:- mode point_comes_before(in, in) is semidet. |
|||
point_comes_before(P, Q) :- |
|||
(fst(P) < fst(Q); fst(P) - fst(Q) = (0.0), |
|||
snd(P) < snd(Q)). |
|||
:- pred point_compare(point, point, comparison_result). |
|||
:- mode point_compare(in, in, out) is det. |
|||
point_compare(P, Q, Cmp) :- |
|||
if (point_comes_before(P, Q)) then (Cmp = (<)) |
|||
else if (point_comes_before(Q, P)) then (Cmp = (>)) |
|||
else (Cmp = (=)). |
|||
:- func point_subtract(point, point) = point. |
|||
point_subtract(P, Q) = pair(fst(P) - fst(Q), |
|||
snd(P) - snd(Q)). |
|||
:- func point_cross_product(point, point) = float. |
|||
point_cross_product(P, Q) = (fst(P) * snd(Q)) - (snd(P) * fst(Q)). |
|||
:- func point_to_string(point) = string. |
|||
point_to_string(P) = ("(" ++ from_float(fst(P)) ++ |
|||
" " ++ from_float(snd(P)) ++ ")"). |
|||
%%-------------------------------------------------------------------- |
|||
:- func convex_hull(point_list) = point_list. |
|||
convex_hull(Pt) = Hull :- |
|||
Pt1 = unique_points_sorted(Pt), |
|||
(if (Pt1 = []; Pt1 = [_]; Pt1 = [_, _]) then (Hull = Pt1) |
|||
else (Hull = construct_hull(Pt1))). |
|||
:- func unique_points_sorted(point_list) = point_list. |
|||
unique_points_sorted(Pt0) = Pt :- |
|||
sort_and_remove_dups(point_compare, Pt0, Pt). |
|||
:- func construct_hull(point_list) = point_list. |
|||
construct_hull(Pt) = (construct_lower_hull(Pt) ++ |
|||
construct_upper_hull(Pt)). |
|||
:- func construct_lower_hull(point_list) = point_list. |
|||
construct_lower_hull(Pt) = Hull :- |
|||
if (Pt = [P0, P1 | Rest]) |
|||
then (N = length(Pt), |
|||
Arr0 = (version_array.init(N, P0)), |
|||
Arr1 = (Arr0^elem(1) := P1), |
|||
hull_construction(Rest, Arr1, Arr2, 1, N_Hull), |
|||
%% In the fetch_items/3 call, we leave out the last item. It |
|||
%% is redundant with the first item of the upper hull. |
|||
N_Hull2 = N_Hull - 2, |
|||
Hull = fetch_items(Arr2, 0, N_Hull2)) |
|||
else throw("construct_lower_hull expects list of length >= 3"). |
|||
:- func construct_upper_hull(point_list) = point_list. |
|||
%% An upper hull is merely a lower hull for points going the other |
|||
%% way. |
|||
construct_upper_hull(Pt) = construct_lower_hull(reverse(Pt)). |
|||
:- pred hull_construction(point_list, point_array, point_array, |
|||
int, int). |
|||
:- mode hull_construction(in, in, out, in, out) is det. |
|||
hull_construction([], Arr0, Arr, J, N_Hull) :- |
|||
Arr = Arr0, |
|||
N_Hull = J + 1. |
|||
hull_construction([P | Rest], Arr0, Arr, J, N_Hull) :- |
|||
if cross_test(P, Arr0, J) |
|||
then (J1 = J + 1, |
|||
Arr1 = (Arr0^elem(J1) := P), |
|||
hull_construction(Rest, Arr1, Arr, J1, N_Hull)) |
|||
else (J1 = J - 1, |
|||
hull_construction([P | Rest], Arr0, Arr, J1, N_Hull)). |
|||
:- pred cross_test(point, point_array, int). |
|||
:- mode cross_test(in, in, in) is semidet. |
|||
cross_test(P, Arr, J) :- |
|||
if (J = 0) then true |
|||
else (Elem_J = Arr^elem(J), |
|||
J1 = J - 1, |
|||
Elem_J1 = Arr^elem(J1), |
|||
0.0 < point_cross_product(point_subtract(Elem_J, Elem_J1), |
|||
point_subtract(P, Elem_J1))). |
|||
%%-------------------------------------------------------------------- |
|||
main(!IO) :- |
|||
Example_points = [pair(16.0, 3.0), |
|||
pair(12.0, 17.0), |
|||
pair(0.0, 6.0), |
|||
pair(-4.0, -6.0), |
|||
pair(16.0, 6.0), |
|||
pair(16.0, -7.0), |
|||
pair(16.0, -3.0), |
|||
pair(17.0, -4.0), |
|||
pair(5.0, 19.0), |
|||
pair(19.0, -8.0), |
|||
pair(3.0, 16.0), |
|||
pair(12.0, 13.0), |
|||
pair(3.0, -4.0), |
|||
pair(17.0, 5.0), |
|||
pair(-3.0, 15.0), |
|||
pair(-3.0, -9.0), |
|||
pair(0.0, 11.0), |
|||
pair(-9.0, -3.0), |
|||
pair(-4.0, -2.0), |
|||
pair(12.0, 10.0)], |
|||
Hull = convex_hull(Example_points), |
|||
HullStr = join_list(" ", map(point_to_string, Hull)), |
|||
write_string(HullStr, !IO), |
|||
nl(!IO). |
|||
%%%------------------------------------------------------------------- |
|||
%%% local variables: |
|||
%%% mode: mercury |
|||
%%% prolog-indent-width: 2 |
|||
%%% end:</lang> |
|||
{{out}} |
|||
<pre>$ mmc convex_hull_task.m && ./convex_hull_task |
|||
(-9.0 -3.0) (-3.0 -9.0) (19.0 -8.0) (17.0 5.0) (12.0 17.0) (5.0 19.0) (-3.0 15.0)</pre> |
|||
=={{header|Modula-2}}== |
=={{header|Modula-2}}== |