1 //--------------------------------------------------------------------------
2 // Drawing "spirograph" curves - epitrochoids, cycolids, roulettes
3 //--------------------------------------------------------------------------
4 //
5 //--------------------------------------------------------------------------
6 // Copyright (C) 2007  Arjen Markus
7 // Copyright (C) 2008  Andrew Ross
8 //
9 // This file is part of PLplot.
10 //
11 // PLplot is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; version 2 of the License.
14 //
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.
19 //
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
23 
24 //--------------------------------------------------------------------------
25 // Implementation of PLplot example 27 in Java.
26 //--------------------------------------------------------------------------
27 
28 package plplot.examples;
29 
30 import plplot.core.*;
31 import static plplot.core.plplotjavacConstants.*;
32 
33 import java.lang.Math;
34 
35 class x27 {
36     PLStream pls = new PLStream();
37 
main( String[] args )38     public static void main( String[] args )
39     {
40         new x27( args );
41     }
42 
43     //--------------------------------------------------------------------
44     // Generates two kinds of plots:
45     //   - construction of a cycloid (animated)
46     //   - series of epitrochoids and hypotrochoids
47     //--------------------------------------------------------------------
48 
x27( String[] args )49     public x27( String[] args )
50     {
51         // R, r, p, N
52         // R and r should be integers to give correct termination of the
53         // angle loop using gcd.
54         // N.B. N is just a place holder since it is no longer used
55         // (because we now have proper termination of the angle loop).
56         double  params[][] = {
57             { 21.0,   7.0,  7.0,  3.0 }, // Deltoid
58             { 21.0,   7.0, 10.0,  3.0 },
59             { 21.0,  -7.0, 10.0,  3.0 },
60             { 20.0,   3.0,  7.0, 20.0 },
61             { 20.0,   3.0, 10.0, 20.0 },
62             { 20.0,  -3.0, 10.0, 20.0 },
63             { 20.0,  13.0,  7.0, 20.0 },
64             { 20.0,  13.0, 20.0, 20.0 },
65             { 20.0, -13.0, 20.0, 20.0 } };
66 
67         int     i;
68         boolean fill;
69 
70         // plplot initialization
71 
72         // Parse and process command line arguments
73         pls.parseopts( args, PL_PARSE_FULL | PL_PARSE_NOPROGRAM );
74 
75         // Initialize plplot
76         pls.init();
77 
78         // Illustrate the construction of a cycloid
79         cycloid();
80 
81         // Loop over the various curves
82         // First an overview, then all curves one by one
83         pls.ssub( 3, 3 ); // Three by three window
84 
85         fill = false;
86         for ( i = 0; i < 9; i++ )
87         {
88             pls.adv( 0 );
89             pls.vpor( 0.0, 1.0, 0.0, 1.0 );
90             spiro( params[i], fill );
91         }
92 
93         pls.adv( 0 );
94         pls.ssub( 1, 1 ); // One window per curve
95 
96         for ( i = 0; i < 9; i++ )
97         {
98             pls.adv( 0 );
99             pls.vpor( 0.0, 1.0, 0.0, 1.0 );
100             spiro( params[i], fill );
101         }
102 
103         // Fill the curves
104         fill = true;
105 
106         pls.adv( 0 );
107         pls.ssub( 1, 1 ); // One window per curve
108 
109         for ( i = 0; i < 9; i++ )
110         {
111             pls.adv( 0 );
112             pls.vpor( 0.0, 1.0, 0.0, 1.0 );
113             spiro( params[i], fill );
114         }
115 
116         // Finally, an example to test out plarc capabilities
117         arcs();
118 
119         pls.end();
120     }
121 
122 //--------------------------------------------------------------------------
123 // Calculate greatest common divisor following pseudo-code for the
124 // Euclidian algorithm at http://en.wikipedia.org/wiki/Euclidean_algorithm
125 
gcd( int a, int b )126     int gcd( int a, int b )
127     {
128         int t;
129         a = Math.abs( a );
130         b = Math.abs( b );
131         while ( b != 0 )
132         {
133             t = b;
134             b = a % b;
135             a = t;
136         }
137         return a;
138     }
139 
140     // ===============================================================
141 
cycloid()142     void cycloid()
143     {
144         // TODO
145     }
146 
147     // ===============================================================
148 
spiro( double params[], boolean fill )149     void spiro( double params[], boolean fill )
150     {
151         int    NPNT = 2000;
152         double xcoord[];
153         double ycoord[];
154 
155         int    windings;
156         int    steps;
157         int    i;
158         double phi;
159         double phiw;
160         double dphi;
161         // Initialize to quiet java compiler errors about the possibility
162         // these variables are not initialized in the code below.
163         double xmin = 0.;
164         double xmax = 0.;
165         double ymin = 0.;
166         double ymax = 0.;
167         double xrange_adjust;
168         double yrange_adjust;
169 
170         // Fill the coordinates
171 
172         // Proper termination of the angle loop very near the beginning
173         // point, see
174         // http://mathforum.org/mathimages/index.php/Hypotrochoid.
175         windings = (int) Math.abs( params[1] ) / gcd( (int) params[0], (int) params[1] );
176         steps    = NPNT / windings;
177         dphi     = 2.0 * Math.PI / steps;
178 
179         xcoord = new double[windings * steps + 1];
180         ycoord = new double[windings * steps + 1];
181 
182         for ( i = 0; i <= windings * steps; i++ )
183         {
184             phi       = i * dphi;
185             phiw      = ( params[0] - params[1] ) / params[1] * phi;
186             xcoord[i] = ( params[0] - params[1] ) * Math.cos( phi ) + params[2] * Math.cos( phiw );
187             ycoord[i] = ( params[0] - params[1] ) * Math.sin( phi ) - params[2] * Math.sin( phiw );
188 
189             if ( i == 0 )
190             {
191                 xmin = xcoord[i];
192                 xmax = xcoord[i];
193                 ymin = ycoord[i];
194                 ymax = ycoord[i];
195             }
196             if ( xmin > xcoord[i] ) xmin = xcoord[i];
197             if ( xmax < xcoord[i] ) xmax = xcoord[i];
198             if ( ymin > ycoord[i] ) ymin = ycoord[i];
199             if ( ymax < ycoord[i] ) ymax = ycoord[i];
200         }
201 
202         xrange_adjust = 0.15 * ( xmax - xmin );
203         xmin         -= xrange_adjust;
204         xmax         += xrange_adjust;
205         yrange_adjust = 0.15 * ( ymax - ymin );
206         ymin         -= yrange_adjust;
207         ymax         += yrange_adjust;
208 
209         pls.wind( xmin, xmax, ymin, ymax );
210 
211         pls.col0( 1 );
212 
213         if ( fill )
214             pls.fill( xcoord, ycoord );
215         else
216             pls.line( xcoord, ycoord );
217     }
218 
arcs()219     void arcs()
220     {
221         int    NSEG = 8;
222         int    i;
223         double theta, dtheta;
224         double a, b;
225 
226         theta  = 0.0;
227         dtheta = 360.0 / NSEG;
228         pls.env( -10.0, 10.0, -10.0, 10.0, 1, 0 );
229 
230         // Plot segments of circle in different colors
231         for ( i = 0; i < NSEG; i++ )
232         {
233             pls.col0( i % 2 + 1 );
234             pls.arc( 0.0, 0.0, 8.0, 8.0, theta, theta + dtheta, 0.0, false );
235             theta = theta + dtheta;
236         }
237 
238         // Draw several filled ellipses inside the circle at different
239         // angles.
240         a     = 3.0;
241         b     = a * Math.tan( ( dtheta / 180.0 * Math.PI ) / 2.0 );
242         theta = dtheta / 2.0;
243         for ( i = 0; i < NSEG; i++ )
244         {
245             pls.col0( 2 - i % 2 );
246             pls.arc( a * Math.cos( theta / 180.0 * Math.PI ), a * Math.sin( theta / 180.0 * Math.PI ), a, b, 0.0, 360.0, theta, true );
247             theta = theta + dtheta;
248         }
249     }
250 }
251 
252 //--------------------------------------------------------------------------
253 //                              End of x27.java
254 //--------------------------------------------------------------------------
255