Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: exptree/utilities/imageGenerator.java


1   /* Evolvo - Image Generator
2    * Copyright (C) 2000 Andrew Molloy
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU General Public License
6    * as published by the Free Software Foundation; either version 2
7    * of the License, or (at your option) any later version.
8   
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13  
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   */
18  
19  /*
20   * @(#)imageGenerator.java   0.1   08/19/2000
21   */
22  package exptree.utilities;
23  
24  import myComponents.*;
25  import java.awt.*;
26  import java.awt.event.*;
27  import java.awt.image.*;
28  import javax.swing.*;
29  import settings.*;
30  import exptree.*;
31  import java.util.EventListener;
32  import javax.swing.event.*;
33  import java.awt.color.*;
34  /**
35   * Generates an image based on expressionTrees.  Currently, this supports images in the
36   * RGB and HSB colorspaces, and therefore takes 3 expressionTrees.  The image generation
37   * takes place in a thread, and does not begin until the startIt() method is called.
38   *
39   * @version 1.1 08/19/2000
40   * @author Andy Molloy
41   */
42  public class imageGenerator extends JComponent implements Runnable, Cloneable
43  {
44     /** Stores the generated image. */
45     BufferedImage image;
46     /** Local copy of the settings package. */
47     globalSettings settings;
48     /** The set of variables retrieved from the variablePackage. */
49     variable variables[];
50     variablePackage vp;
51     /** The actual expressionTrees that describe the image. */
52     expressionTree expressions[];
53     /** The image's imageWidth and imageHeight. */
54     int imageWidth, imageHeight;
55  
56     Thread theThread;
57     boolean threadKeepRunning = true;
58     ColorModel colorModel;
59     WritableRaster raster;
60     boolean finished = false;
61  
62     double magnification;
63     double x_translation;
64     double y_translation;
65  
66     transient myProgressMonitor pm;
67  
68     protected transient ChangeEvent changeEvent = null;
69     protected EventListenerList listenerList = new EventListenerList();
70  
71     protected transient ChangeEvent finishedEvent = null;
72     protected EventListenerList finishedListenerList = new EventListenerList();
73  
74     static private final double map_height  = Math.pow(0.5, 2);
75     static private final double PI_OVER_TWO = Math.PI / 2.0;
76  
77     /** Class constuctor. */
78     public imageGenerator(globalSettings s, 
79         imageGeneratorParams params, 
80         myProgressMonitor myPM, 
81         Dimension D)
82     {
83        super();
84        settings  = s;
85        vp = params.getVariablePackage();
86        variables = vp.getVariables();
87        expressions = params.getExpressions();
88        pm = myPM;
89  
90        magnification = settings.getDoubleProperty("magnification");
91        x_translation = settings.getDoubleProperty("x_trans");
92        y_translation = settings.getDoubleProperty("y_trans");
93  
94        int colorModel;
95        setSize(D);
96        setPreferredSize(D);
97        setImageSize(D.width, D.height);
98  
99        image = initImage(D.width, D.height);
100 
101       theThread = new Thread(this);
102    }
103 
104    public void setProgressMonitor(myProgressMonitor p)
105    {
106       pm = p;
107    }
108 
109    /** Sets the component's size, as well as the size of the image to generate. */
110    public void setSize(int w, int h)
111    {
112       super.setSize(w, h);
113    }
114 
115    /** Sets the component's size, as well as the size of the image to generate. */
116    public void setSize(Dimension d)
117    {
118       super.setSize(d);
119    }
120 
121    /** Sets the component's preferred size, as well as the size of the image to generate. */
122    public void setPreferredSize(Dimension d)
123    {
124       super.setPreferredSize(d);
125    }
126 
127    public void setImageSize(int w, int h)
128    {
129       imageWidth = w;
130       imageHeight= h;
131    }
132 
133    public void startIt()
134    {
135       synchronized ( image )
136       {
137          image = initImage(imageWidth, imageHeight);
138       }
139 
140        theThread.setPriority( Thread.NORM_PRIORITY - 1);
141       theThread.start();
142    }
143 
144    /** Thread which actually generates the image. */
145    public void run()
146    {
147       int x, y;
148       double tx, ty;
149       int index = 0;
150       double c1, c2, c3;
151       int ic1, ic2, ic3;
152       int offset;
153       boolean HSBFlag = settings.getStringProperty("render.colormodel").equals("HSB");
154 
155       for (int i = 0; i < expressions.length; i++)
156       {
157          expressions[i].buildCache();
158       }
159 
160       int data[] = new int[imageHeight * imageWidth]; 
161 
162       for (y = 0; y < imageHeight; y++)
163       {
164          offset = y * imageWidth;
165          index = 0; // reset index for each scanline
166          ty = ((double)y / (double)imageHeight) * 2.0 - 1.0; // translate y to the range of -1.0 to 1.0
167 
168          ty = (ty + y_translation) * magnification;
169          for (x = 0; x < imageWidth; x++ )
170          {
171             if (!threadKeepRunning)
172             {
173                return;
174             }
175             tx = ((double)x / (double)imageWidth) * 2.0 - 1.0; // translate x to the range of -1.0 to 1.0
176 
177             tx = (tx + x_translation) * magnification;
178 
179             variables[0].setVariable(tx); // Set the "x" variable to the translated x
180             variables[1].setVariable(ty); // Set the "y" variable to the translated y
181             variables[2].setVariable( Math.sqrt( (tx * tx) + (ty * ty) ) ); 
182             variables[3].setVariable( Math.atan2(tx, ty)  );            
183             // Each expressionTree is evaluated, and the results translated from [-1.0,1.0] to [0.0,1.0]
184             c1 = map(expressions[0].evaluate());
185             c2 = map(expressions[1].evaluate());
186             c3 = map(expressions[2].evaluate());
187 
188             // Decide how the colors are being represented.  Right now only RGB and HSB are 
189             // supported.  I may add others in the  near future, such as Lab and Luv.
190             if ( HSBFlag )
191             {
192                data[offset + index++] = java.awt.Color.HSBtoRGB((float)c1, (float)c2, (float)c3);  
193                // Java has a nice built in routine to 
194                // convert from HSB to Java, so we use it.
195             } else {
196                ic1 = (int)(c1 * 255);
197                ic2 = (int)(c2 * 255);
198                ic3 = (int)(c3 * 255);
199                data[offset + index++] = (ic1 << 16) | (ic2 << 8) | ic3;
200             }
201          }
202 
203          if (pm != null)
204    {
205        pm.incrementProgress(1);
206        if (pm.isCanceled())
207        {
208      synchronized ( image )
209      {
210          image.setRGB(0, 0, imageWidth, imageHeight, data, 0, imageWidth);
211      }
212      
213      repaint(); 
214      fireStateChanged();
215      
216      finished = true;
217      threadKeepRunning = false;
218      fireFinished();
219        }
220    }
221    
222    theThread.yield(); // and allow other threads to do their thing...
223       }
224       
225       synchronized ( image )
226       {
227           image.setRGB(0, 0, imageWidth, imageHeight, data, 0, imageWidth);
228       }
229 
230       repaint(); 
231       fireStateChanged();
232 
233       finished = true;
234       fireFinished();
235    }
236 
237    public void stop()
238    {
239       threadKeepRunning = false;
240    }
241 
242    public void paint(Graphics g)
243    {
244       super.paint(g);
245    
246       if (image != null)
247       {
248          g.drawImage(image, 0, 0, this);  // put the image on the graphics context
249       }
250    }
251 
252    public void update(Graphics g)
253    {
254       paint(g);
255    }
256 
257    public BufferedImage getImage()
258    {
259       synchronized ( image )
260       {
261          return image;
262       }
263    }
264 
265    /**
266      * Adds a ChangeListener to the image.
267      */
268    public void addChangeListener(ChangeListener l)
269    {
270       listenerList.add(ChangeListener.class, l);
271    }  
272 
273     /**
274      * Removes a ChangeListener from the button.
275      */
276    public void removeChangeListener(ChangeListener l)
277    {
278       listenerList.remove(ChangeListener.class, l);
279    }
280 
281    /** Notify all listeners that have registered interest for
282      * notification on this event type.  The event instance 
283      * is lazily created using the parameters passed into 
284      * the fire method.
285      */
286    protected void fireStateChanged() {
287       this.repaint();
288       // Guaranteed to return a non-null array
289       Object[] listeners = listenerList.getListenerList();
290       // Process the listeners last to first, notifying
291       // those that are interested in this event
292       for (int i = listeners.length-2; i>=0; i-=2)
293       {
294          if (listeners[i]==ChangeListener.class)
295          {
296             // Lazily create the event:
297             if (changeEvent == null)
298             {
299                changeEvent = new ChangeEvent(this);
300             }
301             ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
302          }          
303       }
304    }
305 
306    /**
307      * Adds a ChangeListener to the image.
308      */
309    public void addFinishedListener(ChangeListener l)
310    {
311       finishedListenerList.add(ChangeListener.class, l);
312    }  
313 
314     /**
315      * Removes a ChangeListener from the button.
316      */
317    public void removeFinishedListener(ChangeListener l)
318    {
319       finishedListenerList.remove(ChangeListener.class, l);
320    }
321 
322    /** Notify all listeners that have registered interest for
323      * notification on this event type.  The event instance 
324      * is lazily created using the parameters passed into 
325      * the fire method.
326      */
327    protected void fireFinished() {
328       this.repaint();
329       
330       // Guaranteed to return a non-null array
331       Object[] listeners = finishedListenerList.getListenerList();
332       // Process the listeners last to first, notifying
333       // those that are interested in this event
334       for (int i = listeners.length-2; i>=0; i-=2)
335       {
336          if (listeners[i]==ChangeListener.class)
337          {
338             // Lazily create the event:
339             if (finishedEvent == null)
340             {
341                finishedEvent = new ChangeEvent(this);
342             }
343             ((ChangeListener)listeners[i+1]).stateChanged(finishedEvent);
344          }          
345       }
346    }
347 
348    protected Object clone()
349    {
350       imageGenerator newImgG = new imageGenerator(
351          settings, 
352    new imageGeneratorParams(vp, expressions), 
353    pm,
354    new Dimension(imageWidth, imageHeight));
355 
356       return (Object)newImgG;
357    }
358 
359    public imageGenerator getClone()
360    {
361       return (imageGenerator)clone();
362    }
363 
364    private BufferedImage initImage(int width, int height)
365    {
366       return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
367    }
368 
369    public boolean isFinished()
370    {
371       return finished;
372    }
373 
374    public imageGeneratorParams getImageGeneratorParams()
375    {
376       return new imageGeneratorParams(vp, expressions);
377    }
378 
379    public String toString()
380    {
381       StringBuffer sb = new StringBuffer("ImageGenerator: ");
382       
383       for (int i = 0; i < expressions.length; i++)
384       {
385          sb.append("Expression " + i + ": [");
386          if (expressions[i] == null)
387          {
388             sb.append("null");
389          }
390          else
391          {
392             sb.append(expressions.toString());
393          }
394          sb.append("] ");
395       }
396 
397       return sb.toString();
398    }
399 
400    static double map(double a)
401    {
402       double a_squared  = Math.pow(a, 2);
403       double distance   = Math.sqrt( map_height + a_squared );
404       double angle      = Math.asin(a / distance);
405       double translated = (PI_OVER_TWO - Math.abs(angle)) / PI_OVER_TWO;
406 
407       return translated;
408    }
409    
410    public Dimension getSize(Dimension rv)
411    {
412       if (rv == null)
413       {
414          rv = new Dimension();
415       }
416       
417       rv.setSize(imageWidth, imageHeight);
418       return rv;
419     }
420 }