Skip to content

Commit 494aff9

Browse files
authored
Add Convex Hull in Tcl (#5045)
1 parent 67c89aa commit 494aff9

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

archive/t/tcl/convex-hull.tcl

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
proc usage {} {
2+
puts stderr {Usage: please provide at least 3 x and y coordinates as separate lists (e.g. "100, 440, 210")}
3+
exit 1
4+
}
5+
6+
proc parseList {s} {
7+
set s [string trim $s]
8+
if {$s eq ""} {
9+
usage
10+
}
11+
12+
set tokens [split $s ","]
13+
set result {}
14+
15+
foreach token $tokens {
16+
set t [string trim $token]
17+
if {![string is integer -strict $token]} { usage }
18+
lappend result [expr {$token}]
19+
}
20+
21+
if {[llength $result] < 3} { usage }
22+
return $result
23+
}
24+
25+
if {$argc != 2} { usage }
26+
27+
set xs [parseList [lindex $argv 0]]
28+
set ys [parseList [lindex $argv 1]]
29+
30+
if {[llength $xs] != [llength $ys]} { usage }
31+
32+
set points {}
33+
for {set i 0} {$i < [llength $xs]} {incr i} {
34+
lappend points [list [lindex $xs $i] [lindex $ys $i]]
35+
}
36+
37+
proc cross {a b c} {
38+
set x1 [expr {[lindex $b 0] - [lindex $a 0]}]
39+
set y1 [expr {[lindex $b 1] - [lindex $a 1]}]
40+
set x2 [expr {[lindex $c 0] - [lindex $a 0]}]
41+
set y2 [expr {[lindex $c 1] - [lindex $a 1]}]
42+
return [expr {$x1 * $y2 - $y1 * $x2}]
43+
}
44+
45+
proc pointCompare {a b} {
46+
if {[lindex $a 0] < [lindex $b 0]} { return -1 }
47+
if {[lindex $a 0] > [lindex $b 0]} { return 1 }
48+
if {[lindex $a 1] < [lindex $b 1]} { return -1 }
49+
if {[lindex $a 1] > [lindex $b 1]} { return 1 }
50+
return 0
51+
}
52+
53+
proc convexHull {points} {
54+
set n [llength $points]
55+
if {$n < 3} { return $points }
56+
57+
set sorted [lsort -command pointCompare $points]
58+
59+
set lower {}
60+
foreach p $sorted {
61+
while {[llength $lower] >= 2} {
62+
set q [lindex $lower end-1]
63+
set r [lindex $lower end]
64+
if {[cross $q $r $p] > 0} { break }
65+
set lower [lrange $lower 0 end-1]
66+
}
67+
lappend lower $p
68+
}
69+
70+
set upper {}
71+
foreach p [lreverse $sorted] {
72+
while {[llength $upper] >= 2} {
73+
set q [lindex $upper end-1]
74+
set r [lindex $upper end]
75+
if {[cross $q $r $p] > 0} { break }
76+
set upper [lrange $upper 0 end-1]
77+
}
78+
lappend upper $p
79+
}
80+
81+
set hull [concat [lrange $lower 0 end-1] [lrange $upper 0 end-1]]
82+
return $hull
83+
}
84+
85+
set hull [convexHull $points]
86+
87+
foreach pt $hull {
88+
set x [string trim [lindex $pt 0]]
89+
set y [string trim [lindex $pt 1]]
90+
puts "($x, $y)"
91+
}
92+

0 commit comments

Comments
 (0)