File: example_circle.tcl

package info (click to toggle)
r-cran-tcltk2 1.2-10-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 5,356 kB
  • ctags: 1,386
  • sloc: tcl: 37,888; ansic: 792; python: 324; sh: 68; sed: 16; makefile: 1
file content (244 lines) | stat: -rwxr-xr-x 6,027 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# draw_geometry.tcl --
#    Draw and manipulate (plane) geometrical objects. Well, it is
#    merely an illustration of what I mean by "geometrical drawing app"
#
#    Note:
#    Not quite an example of the use of the Diagrams package, but
#    it is related
#

# PixelPoint --
#    Compute pixel coordinates
# Arguments:
#    x         X-coordinate/point
#    y         Y-coordinate/point
#    type      Type of object
# Result:
#    List of pixel coordinates
#
proc PixelPoint {x {y {}} {type {}}} {
    if { $y == {} } {
        set px [lindex $x 1]
        set py [lindex $x 2]
        return [list [expr {$px*100+200}] [expr {-$py*100+200}]]
    }
    if { $type == "oval" } {
        return [list [expr {$x*100+200-2}] [expr {-$y*100+200-2}] \
                     [expr {$x*100+200+2}] [expr {-$y*100+200+2}]]
    }
}

# point --
#    Create (and draw) a point at given coordinates
# Arguments:
#    x         X-coordinate
#    y         Y-coordinate
# Result:
#    A point at the given coordinates
#
proc point {x y} {
    .c create oval [PixelPoint $x $y oval] -fill black
    return [list POINT $x $y]
}

# line --
#    Create (and draw) a line through two points
# Arguments:
#    point1    First point
#    point2    Second point
# Result:
#    A line through the two points
#
proc line {point1 point2} {
    .c create line [concat [PixelPoint $point1] [PixelPoint $point2]] -fill black
    return [list LINE $point1 $point2]
}

# circle --
#    Create (and draw) a circle at given coordinates
# Arguments:
#    point     Centre of the circle
#    rad       Radius
# Result:
#    A circle at the given centre and given radius
#
proc circle {point rad} {
    set x  [lindex $point 1]
    set y  [lindex $point 2]
    set p1 [list POINT [expr {$x+$rad}] [expr {$y+$rad}]]
    set p2 [list POINT [expr {$x-$rad}] [expr {$y-$rad}]]
    .c create oval [concat [PixelPoint $p1] [PixelPoint $p2]] -outline black
    return [list CIRCLE $point $rad]
}

# distance --
#    Compute the distance between two objects
# Arguments:
#    obj1      Point, line, ...
#    obj2      Point, line, ...
# Result:
#    Distance between the given objects (now: only points)
#
proc distance {obj1 obj2} {
    if { [lindex $obj1 0] == "POINT" } {
        set px1 [lindex $obj1 1]
        set py1 [lindex $obj1 2]
        if { [lindex $obj2 0] == "POINT" } {
            set px2 [lindex $obj2 1]
            set py2 [lindex $obj2 2]
            return [expr {hypot($px2-$px1,$py2-$py1)}]
        } else {
            error "Types unsupported"
        }
    } else {
        error "Types unsupported"
    }
}

# inprod --
#    Compute the inproduct of two vectors
# Arguments:
#    vect1     First vector
#    vect2     Second vector
# Result:
#    Inproduct
#
proc inprod {vect1 vect2} {
    set vx1 [lindex $vect1 1]
    set vy1 [lindex $vect1 2]
    set vx2 [lindex $vect2 1]
    set vy2 [lindex $vect2 2]

    return [expr {$vx1*$vx2+$vy1*$vy2}]
}

# pointonline --
#    Compute the coordinates of a point on a line
# Arguments:
#    line      Line in question
#    lambda    Parameter value
# Result:
#    Point on the line
#
proc pointonline {line lambda} {
    set v   [vectorfromline $line]

    set vx  [lindex $v 1]
    set vy  [lindex $v 2]
    set px  [lindex $line 1 1]
    set py  [lindex $line 1 2]
    set x   [expr {$px+$lambda*$vx}]
    set y   [expr {$py+$lambda*$vy}]

    return [point $x $y] ;# Make it visible
}

# vectorfromline --
#    Compute the directional vector of a line
# Arguments:
#    line      Line in question
# Result:
#    Vector in the direction of the line
#
proc vectorfromline {line} {
    set px1 [lindex $line 1 1]
    set py1 [lindex $line 1 2]
    set px2 [lindex $line 2 1]
    set py2 [lindex $line 2 2]
    set vx  [expr {$px2-$px1}]
    set vy  [expr {$py2-$py1}]

    return [list VECTOR $vx $vy]
}

# diffvector --
#    Compute the vector from one point to the next
# Arguments:
#    point1    First point
#    point2    Second point
# Result:
#    Vector
#
proc diffvector {point1 point2} {
    set px1 [lindex $point1 1]
    set py1 [lindex $point1 2]
    set px2 [lindex $point2 1]
    set py2 [lindex $point2 2]
    set vx  [expr {$px2-$px1}]
    set vy  [expr {$py2-$py1}]

    return [list VECTOR $vx $vy]
}

# normal --
#    Compute the normal vector to another vector or a line
# Arguments:
#    obj       Directed object
# Result:
#    Vector normal to the direction of the object
#
proc normal {obj} {
    if { [lindex $obj 0] == "LINE" } {
        set obj [vectorfromline $obj]
    }

    set vy  [expr {-[lindex $obj 1]}]
    set vx  [lindex $obj 2]
    set len [expr {hypot($vx,$vy)}]

    return [list VECTOR [expr {$vx/$len}] [expr {$vy/$len}]]
}

# intersect --
#    Compute the intersection between two objects
# Arguments:
#    obj1      line, circle, ...
#    obj2      line, circle, ...
# Result:
#    One point or a collection of points (now: only lines)
#
proc intersect {obj1 obj2} {
    if { [lindex $obj1 0] == "LINE" } {
        #
        # Construct the equation for the line obj1
        #
        set n1 [normal $obj1]
        set p1 [lindex $obj1 1]

        if { [lindex $obj2 0] == "LINE" } {
            #
            # Get the parametrisation of the line obj2
            #
            set v2     [vectorfromline $obj2]
            set p2     [lindex $obj2 1]
            set lambda [expr {[inprod [diffvector $p2 $p1] $n1]/ \
                              [inprod $v2 $n1]}]
            return [pointonline $obj2 $lambda]
        } else {
            error "Types unsupported"
        }
    } else {
        error "Types unsupported"
    }
}

#
# Create the standard canvas
#
pack [canvas .c -width 400 -height 300 -bg white]

#
# Simple illustration:
# Define two lines, get their intersection and draw a circle with that
# point as the centre.
#

circle [point  0 0] 1
line   [point -3 0] [point 3 0]
set p  [point [expr {cos(1)}] [expr {sin(1)}]]
line   [point  1 0] $p
line   [point -1 0] $p

.c move all 0 -50
update
#.c postscript -file circle.eps