1# draw_geometry.tcl -- 2# Draw and manipulate (plane) geometrical objects. Well, it is 3# merely an illustration of what I mean by "geometrical drawing app" 4# 5# Note: 6# Not quite an example of the use of the Diagrams pacakge, but 7# it is related 8# 9 10# PixelPoint -- 11# Compute pixel coordinates 12# Arguments: 13# x X-coordinate/point 14# y Y-coordinate/point 15# type Type of object 16# Result: 17# List of pixel coordinates 18# 19proc PixelPoint {x {y {}} {type {}}} { 20 if { $y == {} } { 21 set px [lindex $x 1] 22 set py [lindex $x 2] 23 return [list [expr {$px*100+200}] [expr {-$py*100+200}]] 24 } 25 if { $type == "oval" } { 26 return [list [expr {$x*100+200-2}] [expr {-$y*100+200-2}] \ 27 [expr {$x*100+200+2}] [expr {-$y*100+200+2}]] 28 } 29} 30 31# point -- 32# Create (and draw) a point at given coordinates 33# Arguments: 34# x X-coordinate 35# y Y-coordinate 36# Result: 37# A point at the given coordinates 38# 39proc point {x y} { 40 .c create oval [PixelPoint $x $y oval] -fill black 41 return [list POINT $x $y] 42} 43 44# line -- 45# Create (and draw) a line through two points 46# Arguments: 47# point1 First point 48# point2 Second point 49# Result: 50# A line through the two points 51# 52proc line {point1 point2} { 53 .c create line [concat [PixelPoint $point1] [PixelPoint $point2]] -fill black 54 return [list LINE $point1 $point2] 55} 56 57# circle -- 58# Create (and draw) a circle at given coordinates 59# Arguments: 60# point Centre of the circle 61# rad Radius 62# Result: 63# A circle at the given centre and given radius 64# 65proc circle {point rad} { 66 set x [lindex $point 1] 67 set y [lindex $point 2] 68 set p1 [list POINT [expr {$x+$rad}] [expr {$y+$rad}]] 69 set p2 [list POINT [expr {$x-$rad}] [expr {$y-$rad}]] 70 .c create oval [concat [PixelPoint $p1] [PixelPoint $p2]] -outline black 71 return [list CIRCLE $point $rad] 72} 73 74# distance -- 75# Compute the distance between two objects 76# Arguments: 77# obj1 Point, line, ... 78# obj2 Point, line, ... 79# Result: 80# Distance between the given objects (now: only points) 81# 82proc distance {obj1 obj2} { 83 if { [lindex $obj1 0] == "POINT" } { 84 set px1 [lindex $obj1 1] 85 set py1 [lindex $obj1 2] 86 if { [lindex $obj2 0] == "POINT" } { 87 set px2 [lindex $obj2 1] 88 set py2 [lindex $obj2 2] 89 return [expr {hypot($px2-$px1,$py2-$py1)}] 90 } else { 91 error "Types unsupported" 92 } 93 } else { 94 error "Types unsupported" 95 } 96} 97 98# inprod -- 99# Compute the inproduct of two vectors 100# Arguments: 101# vect1 First vector 102# vect2 Second vector 103# Result: 104# Inproduct 105# 106proc inprod {vect1 vect2} { 107 set vx1 [lindex $vect1 1] 108 set vy1 [lindex $vect1 2] 109 set vx2 [lindex $vect2 1] 110 set vy2 [lindex $vect2 2] 111 112 return [expr {$vx1*$vx2+$vy1*$vy2}] 113} 114 115# pointonline -- 116# Compute the coordinates of a point on a line 117# Arguments: 118# line Line in question 119# lambda Parameter value 120# Result: 121# Point on the line 122# 123proc pointonline {line lambda} { 124 set v [vectorfromline $line] 125 126 set vx [lindex $v 1] 127 set vy [lindex $v 2] 128 set px [lindex $line 1 1] 129 set py [lindex $line 1 2] 130 set x [expr {$px+$lambda*$vx}] 131 set y [expr {$py+$lambda*$vy}] 132 133 return [point $x $y] ;# Make it visible 134} 135 136# vectorfromline -- 137# Compute the directional vector of a line 138# Arguments: 139# line Line in question 140# Result: 141# Vector in the direction of the line 142# 143proc vectorfromline {line} { 144 set px1 [lindex $line 1 1] 145 set py1 [lindex $line 1 2] 146 set px2 [lindex $line 2 1] 147 set py2 [lindex $line 2 2] 148 set vx [expr {$px2-$px1}] 149 set vy [expr {$py2-$py1}] 150 151 return [list VECTOR $vx $vy] 152} 153 154# diffvector -- 155# Compute the vector from one point to the next 156# Arguments: 157# point1 First point 158# point2 Second point 159# Result: 160# Vector 161# 162proc diffvector {point1 point2} { 163 set px1 [lindex $point1 1] 164 set py1 [lindex $point1 2] 165 set px2 [lindex $point2 1] 166 set py2 [lindex $point2 2] 167 set vx [expr {$px2-$px1}] 168 set vy [expr {$py2-$py1}] 169 170 return [list VECTOR $vx $vy] 171} 172 173# normal -- 174# Compute the normal vector to another vector or a line 175# Arguments: 176# obj Directed object 177# Result: 178# Vector normal to the direction of the object 179# 180proc normal {obj} { 181 if { [lindex $obj 0] == "LINE" } { 182 set obj [vectorfromline $obj] 183 } 184 185 set vy [expr {-[lindex $obj 1]}] 186 set vx [lindex $obj 2] 187 set len [expr {hypot($vx,$vy)}] 188 189 return [list VECTOR [expr {$vx/$len}] [expr {$vy/$len}]] 190} 191 192# intersect -- 193# Compute the intersection between two objects 194# Arguments: 195# obj1 line, circle, ... 196# obj2 line, circle, ... 197# Result: 198# One point or a collection of points (now: only lines) 199# 200proc intersect {obj1 obj2} { 201 if { [lindex $obj1 0] == "LINE" } { 202 # 203 # Construct the equation for the line obj1 204 # 205 set n1 [normal $obj1] 206 set p1 [lindex $obj1 1] 207 208 if { [lindex $obj2 0] == "LINE" } { 209 # 210 # Get the parametrisation of the line obj2 211 # 212 set v2 [vectorfromline $obj2] 213 set p2 [lindex $obj2 1] 214 set lambda [expr {[inprod [diffvector $p2 $p1] $n1]/ \ 215 [inprod $v2 $n1]}] 216 return [pointonline $obj2 $lambda] 217 } else { 218 error "Types unsupported" 219 } 220 } else { 221 error "Types unsupported" 222 } 223} 224 225# 226# Create the standard canvas 227# 228pack [canvas .c -width 400 -height 300 -bg white] 229 230# 231# Simple illustration: 232# Define two lines, get their intersection and draw a circle with that 233# point as the centre. 234# 235 236circle [point 0 0] 1 237line [point -3 0] [point 3 0] 238set p [point [expr {cos(1)}] [expr {sin(1)}]] 239line [point 1 0] $p 240line [point -1 0] $p 241 242.c move all 0 -50 243update 244.c postscript -file circle.eps 245