Convex hull: Difference between revisions

Content added Content deleted
Line 3,280: Line 3,280:
(x: -3.0, y: 15.0)
(x: -3.0, y: 15.0)
</pre>
</pre>

=={{header|ObjectIcon}}==
{{trans|Fortran}}
{{trans|Standard ML}}


<lang objecticon># -*- ObjectIcon -*-
#
# Convex hulls by Andrew's monotone chain algorithm.
#
# For a description of the algorithm, see
# https://en.wikibooks.org/w/index.php?title=Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain&stableid=40169
#

import io
import ipl.sort

class PlanePoint () # Enough plane geometry for our purpose.

private readable x, y

public new (x, y)
self.x := x
self.y := y
return
end

public equals (other)
if self.x = other.x & self.y = other.y then
return
else
fail
end

# Impose a total order on points, making it one that will work for
# Andrew's monotone chain algorithm. *)
public comes_before (other)
if (self.x < other.x) | (self.x = other.x & self.y < other.y) then
return
else
fail
end

# Subtraction is really a vector or multivector operation.
public minus (other)
return PlanePoint (self.x - other.x, self.y - other.y)
end

# Cross product is really a multivector operation.
public cross (other)
return (self.x * other.y) - (self.y * other.x)
end

public to_string ()
return "(" || string (self.x) || " " || string (self.y) || ")"
end

end

# Comparison like C's strcmp(3).
procedure compare_points (p, q)
local cmp

if p.comes_before (q) then
cmp := -1
else if q.comes_before (p) then
cmp := 1
else
cmp := 0
return cmp
end

procedure sort_points (points)
# Non-destructive sort.
return mergesort (points, compare_points)
end

procedure delete_neighbor_dups (arr, equals)
local arr1, i

if *arr = 0 then {
arr1 := []
} else {
arr1 := [arr[1]]
i := 2
while i <= *arr do {
unless equals (arr[i], arr1[-1]) then
put (arr1, arr[i])
i +:= 1
}
}
return arr1
end

procedure construct_lower_hull (pt)
local hull, i, j

hull := list (*pt)
hull[1] := pt[1]
hull[2] := pt[2]
j := 2
every i := 3 to *pt do {
while (j ~= 1 &
(hull[j].minus (hull[j - 1])).cross (pt[i].minus (hull[j - 1])) <= 0) do
j -:= 1
j +:= 1
hull[j] := pt[i]
}
return hull[1 : j + 1]
end

procedure construct_upper_hull (pt)
local hull, i, j

hull := list (*pt)
hull[1] := pt[-1]
hull[2] := pt[-2]
j := 2
every i := 3 to *pt do {
while (j ~= 1 &
(hull[j].minus (hull[j - 1])).cross (pt[-i].minus (hull[j - 1])) <= 0) do
j -:= 1
j +:= 1
hull[j] := pt[-i]
}
return hull[1 : j + 1]
end

procedure construct_hull (pt)
local lower_hull, upper_hull

lower_hull := construct_lower_hull (pt)
upper_hull := construct_upper_hull (pt)
return lower_hull[1 : -1] ||| upper_hull [1 : -1]
end

procedure points_equal (p, q)
if p.equals (q) then
return
else
fail
end

procedure find_convex_hull (points)
local pt, hull

if *points = 0 then {
hull := []
} else {
pt := delete_neighbor_dups (sort_points (points), points_equal)
if *pt <= 2 then
hull := pt
else
hull := construct_hull (pt)
}
return hull
end

procedure main ()
local example_points, hull

example_points :=
[PlanePoint (16.0, 3.0),
PlanePoint (12.0, 17.0),
PlanePoint (0.0, 6.0),
PlanePoint (-4.0, -6.0),
PlanePoint (16.0, 6.0),
PlanePoint (16.0, -7.0),
PlanePoint (16.0, -3.0),
PlanePoint (17.0, -4.0),
PlanePoint (5.0, 19.0),
PlanePoint (19.0, -8.0),
PlanePoint (3.0, 16.0),
PlanePoint (12.0, 13.0),
PlanePoint (3.0, -4.0),
PlanePoint (17.0, 5.0),
PlanePoint (-3.0, 15.0),
PlanePoint (-3.0, -9.0),
PlanePoint (0.0, 11.0),
PlanePoint (-9.0, -3.0),
PlanePoint (-4.0, -2.0),
PlanePoint (12.0, 10.0)]

hull := find_convex_hull (example_points)

every write ((!hull).to_string ())
end</lang>

{{out}}
<pre>$ oiscript convex_hull_task-OI.icn
(-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|OCaml}}==
=={{header|OCaml}}==