1
# $Id: x27.tcl 11859 2011-08-05 08:38:34Z andrewross $
3
# Drawing "spirograph" curves - epitrochoids, cycolids, roulettes
5
# Copyright (C) 2007 Arjen Markus
6
# Copyright (C) 2008 Andrew Ross
8
# This file is part of PLplot.
10
# PLplot is free software; you can redistribute it and/or modify
11
# it under the terms of the GNU Library General Public License as published
12
# by the Free Software Foundation; either version 2 of the License, or
13
# (at your option) any later version.
15
# PLplot is distributed in the hope that it will be useful,
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
# GNU Library General Public License for more details.
20
# You should have received a copy of the GNU Library General Public License
21
# along with PLplot; if not, write to the Free Software
22
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
# --------------------------------------------------------------------------
29
# Generates two kinds of plots:
30
# - construction of a cycloid (animated)
31
# - series of epitrochoids and hypotrochoids
32
# --------------------------------------------------------------------------
34
proc x27 {{w loopback}} {
40
{ 21.0 -7.0 10.0 3.0 }
42
{ 20.0 3.0 10.0 20.0 }
43
{ 20.0 -3.0 10.0 20.0 }
44
{ 20.0 13.0 7.0 20.0 }
45
{ 20.0 13.0 20.0 20.0 }
46
{ 20.0 -13.0 20.0 20.0 }}
48
# Illustrate the construction of a cycloid
52
# Loop over the various curves
53
# First an overview, then all curves one by one
59
for { set i 0 } { $i < 9 } { incr i } {
61
$w cmd plvpor 0.0 1.0 0.0 1.0
62
spiro $w [lindex $params $i] $fill
67
for { set i 0 } { $i < 9 } { incr i } {
69
$w cmd plvpor 0.0 1.0 0.0 1.0
70
spiro $w [lindex $params $i] $fill
77
$w cmd plssub 1 1 ;# One window per curve
79
for { set i 0 } { $i < 9 } { incr i } {
81
$w cmd plvpor 0.0 1.0 0.0 1.0
82
spiro $w [lindex $params $i] $fill
88
#--------------------------------------------------------------------------
89
# Calculate greatest common divisor following pseudo-code for the
90
# Euclidian algorithm at http://en.wikipedia.org/wiki/Euclidean_algorithm
94
set a [expr {int(abs($a))}]
95
set b [expr {int(abs($b))}]
98
set b [expr {$a % $b}]
104
# ===============================================================
112
# ===============================================================
114
proc spiro {w params fill} {
116
foreach {param1 param2 param3 param4} $params {break}
120
matrix xcoord f [expr {$NPNT+1}]
121
matrix ycoord f [expr {$NPNT+1}]
123
# Fill the coordinates
125
# Proper termination of the angle loop very near the beginning
127
# http://mathforum.org/mathimages/index.php/Hypotrochoid.
128
set windings [expr {int(abs($param2)/[gcd $param1 $param2])}]
129
set steps [expr {int($NPNT/$windings)}]
130
set dphi [expr {2.0*$::PLPLOT::PL_PI/double($steps)}]
131
# puts [ format "windings, steps, dphi = %d, %d, %f" $windings $steps $dphi ]
133
set n [expr {int($windings*$steps)+1}]
135
for { set i 0 } { $i < $n } { incr i } {
136
set phi [expr {double($i) * $dphi}]
137
set phiw [expr {($param1-$param2)/$param2*$phi}]
138
xcoord $i = [expr {($param1-$param2)*cos($phi)+$param3*cos($phiw)}]
139
ycoord $i = [expr {($param1-$param2)*sin($phi)-$param3*sin($phiw)}]
147
if { $xmin > [xcoord $i] } { set xmin [xcoord $i] }
148
if { $xmax < [xcoord $i] } { set xmax [xcoord $i] }
149
if { $ymin > [ycoord $i] } { set ymin [ycoord $i] }
150
if { $ymax < [ycoord $i] } { set ymax [ycoord $i] }
153
set xrange_adjust [expr {0.15 * ($xmax - $xmin) }]
154
set xmin [expr {$xmin - $xrange_adjust }]
155
set xmax [expr {$xmax + $xrange_adjust }]
156
set yrange_adjust [expr {0.15 * ($ymax - $ymin) }]
157
set ymin [expr {$ymin - $yrange_adjust }]
158
set ymax [expr {$ymax + $yrange_adjust }]
160
$w cmd plwind $xmin $xmax $ymin $ymax
165
$w cmd plfill $n xcoord ycoord
167
$w cmd plline $n xcoord ycoord
173
set pi $::PLPLOT::PL_PI
176
set dtheta [expr {360.0 / $NSEG}]
177
$w cmd plenv -10.0 10.0 -10.0 10.0 1 0
179
# Plot segments of circle in different colors
180
for { set i 0 } { $i < $NSEG } {incr i} {
181
$w cmd plcol0 [expr {$i%2 + 1}]
182
$w cmd plarc 0.0 0.0 8.0 8.0 $theta [expr {$theta + $dtheta}] 0.0 0
183
set theta [expr {$theta + $dtheta}]
186
# Draw several filled ellipses inside the circle at different
189
set b [expr {$a * tan( ($dtheta/180.0*$pi)/2.0 )}]
190
set theta [expr {$dtheta/2.0}]
191
for {set i 0} { $i < $NSEG } { incr i } {
192
$w cmd plcol0 [expr {2 - $i%2}]
193
$w cmd plarc [expr {$a*cos($theta/180.0*$pi)}] [expr {$a*sin($theta/180.0*$pi)}] $a $b 0.0 360.0 $theta 1
194
set theta [expr {$theta + $dtheta}]