Convex hull: Difference between revisions
Content added Content deleted
Line 3,826: | Line 3,826: | ||
<pre>Convex Hull (7 points): [(-3, -9) (19, -8) (17, 5) (12, 17) (5, 19) (-3, 15) (-9, -3)] |
<pre>Convex Hull (7 points): [(-3, -9) (19, -8) (17, 5) (12, 17) (5, 19) (-3, 15) (-9, -3)] |
||
Convex Hull (7 points): [(-3, -9) (20, -9) (17, 5) (12, 17) (5, 19) (-3, 15) (-9, -3)]</pre> |
Convex Hull (7 points): [(-3, -9) (20, -9) (17, 5) (12, 17) (5, 19) (-3, 15) (-9, -3)]</pre> |
||
=={{header|RATFOR}}== |
|||
{{trans|Fortran}} |
|||
<lang ratfor># |
|||
# 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 |
|||
# |
|||
# As in the Fortran 2018 version upon which this code is based, I |
|||
# shall use the built-in "complex" type to represent "points" in the |
|||
# plane. This is merely for convenience, rather than to express a |
|||
# mathematical equivalence. |
|||
# |
|||
define(point, complex) |
|||
function x (u) |
|||
# Return the x-coordinate of "point" u. |
|||
implicit none |
|||
point u |
|||
real x |
|||
x = real (u) |
|||
end |
|||
function y (u) |
|||
# Return the y-coordinate of "point" u. |
|||
implicit none |
|||
point u |
|||
real y |
|||
y = aimag (u) |
|||
end |
|||
function cross (u, v) |
|||
# Return, as a signed scalar, the cross product of "points" u and v |
|||
# (regarded as "vectors" or multivectors). |
|||
implicit none |
|||
point u, v |
|||
real cross, x, y |
|||
cross = (x (u) * y (v)) - (y (u) * x (v)) |
|||
end |
|||
subroutine sortpt (numpt, pt) |
|||
# Sort "points" in ascending order, first by the x-coordinates and |
|||
# then by the y-coordinates. Any decent sort algorithm will suffice; |
|||
# for the sake of interest, here is the Shell sort of |
|||
# https://en.wikipedia.org/w/index.php?title=Shellsort&oldid=1084744510 |
|||
implicit none |
|||
integer numpt |
|||
point pt(0:*) |
|||
real x, y |
|||
integer i, j, k, gap, offset |
|||
point temp |
|||
logical done |
|||
integer gaps(1:8) |
|||
data gaps / 701, 301, 132, 57, 23, 10, 4, 1 / |
|||
for (k = 1; k <= 8; k = k + 1) |
|||
{ |
|||
gap = gaps(k) |
|||
for (offset = 0; offset <= gap - 1; offset = offset + 1) |
|||
for (i = offset; i <= numpt - 1; i = i + gap) |
|||
{ |
|||
temp = pt(i) |
|||
j = i |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
if (j < gap) |
|||
done = .true. |
|||
else if (x (pt(j - gap)) < x (temp)) |
|||
done = .true. |
|||
else if (x (pt(j - gap)) == x (temp) _ |
|||
&& (y (pt(j - gap)) <= y (temp))) |
|||
done = .true. |
|||
else |
|||
{ |
|||
pt(j) = pt(j - gap) |
|||
j = j - gap |
|||
} |
|||
} |
|||
pt(j) = temp |
|||
} |
|||
} |
|||
end |
|||
subroutine deltrd (n, pt) |
|||
# Delete trailing neighbor duplicates. |
|||
implicit none |
|||
integer n |
|||
point pt(0:*) |
|||
integer i |
|||
logical done |
|||
i = n - 1 |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
n = 1 |
|||
done = .true. |
|||
} |
|||
else if (pt(i - 1) != pt(i)) |
|||
{ |
|||
n = i + 1 |
|||
done = .true. |
|||
} |
|||
else |
|||
i = i - 1 |
|||
} |
|||
end |
|||
subroutine delntd (n, pt) |
|||
# Delete non-trailing neighbor duplicates. |
|||
implicit none |
|||
integer n |
|||
point pt(0:*) |
|||
integer i, j, numdel |
|||
logical done |
|||
i = 0 |
|||
while (i < n - 1) |
|||
{ |
|||
j = i + 1 |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
if (j == n) |
|||
done = .true. |
|||
else if (pt(j) != pt(i)) |
|||
done = .true. |
|||
else |
|||
j = j + 1 |
|||
} |
|||
if (j != i + 1) |
|||
{ |
|||
numdel = j - i - 1 |
|||
while (j != n) |
|||
{ |
|||
pt(j - numdel) = pt(j) |
|||
j = j + 1 |
|||
} |
|||
n = n - numdel |
|||
} |
|||
i = i + 1 |
|||
} |
|||
end |
|||
subroutine deldup (n, pt) |
|||
# Delete neighbor duplicates. |
|||
implicit none |
|||
integer n |
|||
point pt(0:*) |
|||
call deltrd (n, pt) |
|||
call delntd (n, pt) |
|||
end |
|||
subroutine cxlhul (n, pt, hullsz, hull) |
|||
# Construct the lower hull. |
|||
implicit none |
|||
integer n # Number of points. |
|||
point pt(0:*) |
|||
integer hullsz # Output. |
|||
point hull(0:*) # Output. |
|||
real cross |
|||
integer i, j |
|||
logical done |
|||
j = 1 |
|||
hull(0) = pt(0) |
|||
hull(1) = pt(1) |
|||
for (i = 2; i <= n - 1; i = i + 1) |
|||
{ |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
if (j == 0) |
|||
{ |
|||
j = j + 1 |
|||
hull(j) = pt(i) |
|||
done = .true. |
|||
} |
|||
else if (0.0 < cross (hull(j) - hull(j - 1), _ |
|||
pt(i) - hull(j - 1))) |
|||
{ |
|||
j = j + 1 |
|||
hull(j) = pt(i) |
|||
done = .true. |
|||
} |
|||
else |
|||
j = j - 1 |
|||
} |
|||
} |
|||
hullsz = j + 1 |
|||
end |
|||
subroutine cxuhul (n, pt, hullsz, hull) |
|||
# Construct the upper hull. |
|||
implicit none |
|||
integer n # Number of points. |
|||
point pt(0:*) |
|||
integer hullsz # Output. |
|||
point hull(0:*) # Output. |
|||
real cross |
|||
integer i, j |
|||
logical done |
|||
j = 1 |
|||
hull(0) = pt(n - 1) |
|||
hull(1) = pt(n - 2) |
|||
for (i = n - 3; 0 <= i; i = i - 1) |
|||
{ |
|||
done = .false. |
|||
while (!done) |
|||
{ |
|||
if (j == 0) |
|||
{ |
|||
j = j + 1 |
|||
hull(j) = pt(i) |
|||
done = .true. |
|||
} |
|||
else if (0.0 < cross (hull(j) - hull(j - 1), _ |
|||
pt(i) - hull(j - 1))) |
|||
{ |
|||
j = j + 1 |
|||
hull(j) = pt(i) |
|||
done = .true. |
|||
} |
|||
else |
|||
j = j - 1 |
|||
} |
|||
} |
|||
hullsz = j + 1 |
|||
end |
|||
subroutine cxhull (n, pt, hullsz, lhull, uhull) |
|||
# Construct the hull. |
|||
implicit none |
|||
integer n # Number of points. |
|||
point pt(0:*) # Overwritten with hull. |
|||
integer hullsz # Output. |
|||
point lhull(0:*) # Workspace. |
|||
point uhull(0:*) # Workspace |
|||
integer lhulsz, uhulsz, i |
|||
# A side note: the calls to construct_lower_hull and |
|||
# construct_upper_hull could be done in parallel. |
|||
call cxlhul (n, pt, lhulsz, lhull) |
|||
call cxuhul (n, pt, uhulsz, uhull) |
|||
hullsz = lhulsz + uhulsz - 2 |
|||
for (i = 0; i <= lhulsz - 2; i = i + 1) |
|||
pt(i) = lhull(i) |
|||
for (i = 0; i <= uhulsz - 2; i = i + 1) |
|||
pt(lhulsz - 1 + i) = uhull(i) |
|||
end |
|||
subroutine cvxhul (n, pt, hullsz, lhull, uhull) |
|||
# Find a convex hull. |
|||
implicit none |
|||
integer n # Number of points. |
|||
point pt(0:*) # The contents of pt is replaced with the hull. |
|||
integer hullsz # Output. |
|||
point lhull(0:*) # Workspace. |
|||
point uhull(0:*) # Workspace |
|||
integer numpt |
|||
numpt = n |
|||
call sortpt (numpt, pt) |
|||
call deldup (numpt, pt) |
|||
if (numpt == 0) |
|||
hullsz = 0 |
|||
else if (numpt <= 2) |
|||
hullsz = numpt |
|||
else |
|||
call cxhull (numpt, pt, hullsz, lhull, uhull) |
|||
end |
|||
program cvxtsk |
|||
# The Rosetta Code convex hull task. |
|||
implicit none |
|||
integer n, i |
|||
point points(0:100) |
|||
point lhull(0:100) |
|||
point uhull(0:100) |
|||
character*100 fmt |
|||
point exampl(0:19) |
|||
data exampl / (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) / |
|||
n = 20 |
|||
for (i = 0; i <= n - 1; i = i + 1) |
|||
points(i) = exampl(i) |
|||
call cvxhul (n, points, n, lhull, uhull) |
|||
write (fmt, '("(", I20, ''("(", F3.0, 1X, F3.0, ") ")'', ")")') n |
|||
write (*, fmt) (points(i), i = 0, n - 1) |
|||
end</lang> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |