KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > info > monitorenter > gui > util > ColorIterator


1 /*
2  * ColorIterator.java, something that walks over the Hue-Saturation-Brightness
3  * color space.
4  * Copyright (C) Achim Westermann, created on 19.05.2005, 22:01:51
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  * If you modify or optimize the code in a useful way please let me know.
21  * Achim.Westermann@gmx.de
22  *
23  */

24 package info.monitorenter.gui.util;
25
26 import java.util.Iterator JavaDoc;
27 import java.util.NoSuchElementException JavaDoc;
28
29 /**
30  * Iterator of ther color space.
31  * <p>
32  *
33  * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
34  *
35  * @version $Revision: 1.1 $
36  */

37 public class ColorIterator implements Iterator JavaDoc {
38
39   /**
40    * To allow clean reset of ColorIterator, also the start HSBColor has to be
41    * reset. This is done by a deep copy at construction time.
42    */

43   private HSBColor m_start;
44
45   /** Reference to the currently iterated color. */
46   private HSBColor m_iterate;
47
48   /** The stepping model that defines the path throught the color space. */
49   private ColorIterator.ISteppingModel m_stepModel;
50
51   /**
52    * To allow clean reset of ColorIterator, also the SteppingModel has to be
53    * reset. This is done by a deep copy at construction time.
54    */

55   private ColorIterator.ISteppingModel m_resetModel;
56
57   /**
58    * Creates an instance that starts with a red and walks the hue line with a
59    * {@link ColorIterator.HueStepper}.
60    * <p>
61    */

62   public ColorIterator() {
63     // brightest red ever
64
this.m_start = new HSBColor(0.0f, 1.0f, 1.0f);
65     this.m_iterate = (HSBColor) this.m_start.clone();
66     this.m_stepModel = new HueStepper(0.001f);
67     this.m_resetModel = (ColorIterator.ISteppingModel) this.m_stepModel.clone();
68   }
69
70   /** Flag to show if more colors are iterateable. */
71   private boolean m_hasnext = true;
72
73   /**
74    * Returns true if more colors are available.
75    * <p>
76    *
77    * @return true if more colors are available.
78    *
79    * @see java.util.Iterator#hasNext()
80    */

81   public boolean hasNext() {
82     return this.m_hasnext;
83   }
84
85   /**
86    * Returns instances of java.awt.Color or throws a NoSuchElementException, if
87    * iterator has finished.
88    * <p>
89    *
90    * @return the next available Color.
91    *
92    * @throws NoSuchElementException
93    * if {@link #hasNext()} returns false.
94    */

95   public Object JavaDoc next() throws NoSuchElementException JavaDoc {
96     if (!this.m_hasnext) {
97       throw new java.util.NoSuchElementException JavaDoc("No more colors to give (call reset for new run!)");
98     }
99     this.m_stepModel.doStep(this);
100     if (this.m_iterate.equals(this.m_start)) {
101       this.m_hasnext = false;
102     }
103     return this.m_iterate.getRGBColor();
104   }
105
106   /**
107    * Resets the ColorIterator. It will be able to start a new iteration over the
108    * colorspace.
109    * <p>
110    */

111   public void reset() {
112     this.m_iterate = (HSBColor) this.m_start.clone();
113     // also reset the SteppingModel!!!!
114
this.m_stepModel = (ColorIterator.ISteppingModel) this.m_resetModel.clone();
115     this.m_hasnext = true;
116   }
117
118   /**
119    * Nothing is done here. Do you really want to remove a color from the
120    * colorcircle model?
121    * <p>
122    */

123   public void remove() {
124     // nop
125
}
126
127   /**
128    * Defines the strategy of walking through the HSB color space.
129    * <p>
130    *
131    * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
132    *
133    *
134    * @version $Revision: 1.1 $
135    */

136   public static interface ISteppingModel extends Cloneable JavaDoc {
137     /**
138      * Performs a step on the given color iterator.
139      * <p>
140      *
141      * @param tostep
142      * the color iterator to perform a step on.
143      */

144     public void doStep(final ColorIterator tostep);
145
146     /**
147      * Creates a clone of this stepper.
148      * <p>
149      *
150      * @return a clone of this stepper.
151      */

152     public Object JavaDoc clone();
153   }
154
155   /**
156    * Just for protected internal float stepping.
157    * <p>
158    *
159    *
160    */

161   public abstract static class DefaultStepping implements ColorIterator.ISteppingModel {
162     /** The amount of stepping. */
163     protected float m_stepping;
164
165     /**
166      * Creates a stepper with 100 steps in the color space.
167      * <p>
168      */

169     public DefaultStepping() {
170       this(1.0f / 100.0f);
171     }
172
173     /**
174      * Creates a stepper with the given step length.
175      * <p>
176      *
177      * @param stepping
178      * a step length in-between 0.0 and 1.0.
179      *
180      * @throws IllegalArgumentException
181      * if the stepping is <= 0.0 or >=1.0.
182      */

183     public DefaultStepping(final float stepping) throws IllegalArgumentException JavaDoc {
184       if (stepping > 1.0f || stepping <= 0.0f) {
185         throw new IllegalArgumentException JavaDoc("Illegal stepping param: choose within 0.0 and 1.0.");
186       }
187       this.m_stepping = stepping;
188     }
189
190     /**
191      * Too lazy to implement for each subclass. An overhead for newInstance()
192      * (return dynamic subtype) is paid here.
193      * <p>
194      *
195      * @return a clone of the stepper.
196      */

197     public Object JavaDoc clone() {
198       try {
199         DefaultStepping ret = (DefaultStepping) (this.getClass().newInstance());
200         ret.m_stepping = this.m_stepping;
201         return ret;
202       } catch (Throwable JavaDoc f) {
203         // this will never happen
204
f.printStackTrace();
205         return null;
206       }
207     }
208   }
209
210   /**
211    * A stepper that walks along the hue line of the color space.
212    * <p>
213    *
214    * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
215    *
216    * @version $Revision: 1.1 $
217    */

218   public static class HueStepper extends ColorIterator.DefaultStepping {
219     /**
220      * Creates an instance with 100 steps left.
221      * <p>
222      */

223     public HueStepper() {
224       super();
225     }
226
227     /**
228      * Creates a stepper with the given step length.
229      * <p>
230      *
231      * @param stepping
232      * a step length in-between 0.0 and 1.0.
233      *
234      * @throws IllegalArgumentException
235      * if the stepping is <= 0.0 or >=1.0.
236      */

237     public HueStepper(final float stepping) throws IllegalArgumentException JavaDoc {
238       super(stepping);
239     }
240
241     /**
242      * Performs a hue step on the given ColorIterator's HSBColor.
243      * <p>
244      *
245      * The bounds are watched: if a hue step would cross 1.0f it will be
246      * continued beginning from 0. if a hue step would cross the hue value of
247      * the ColorIterator's start hue value, the step will only go as far as this
248      * value. Else there would be problems with finding the end of the
249      * iteration.
250      * <p>
251      *
252      * @param tostep
253      * the iterator to perform the step on.
254      */

255     public void doStep(final ColorIterator tostep) {
256       float increment = tostep.m_iterate.m_hue;
257       float bound = tostep.m_start.m_hue;
258       if (increment == bound) {
259         increment += this.m_stepping;
260       } else if (increment < bound) {
261         // before crossing 1.0, i will cross the iteration bound (no care for
262
// 1.0
263
// needed)
264
increment += this.m_stepping;
265         if (increment > bound) {
266           increment = bound;
267         }
268       } else {
269         // more complicated: watch for crossing 1.0, then watch for crossing
270
// iteration bound.
271
increment += this.m_stepping;
272         if (increment > 1.0f) {
273           increment -= 1.0;
274           // only for the case that we jumped look for overtaking the bound
275
if (increment > bound) {
276             increment = bound;
277           }
278         }
279       }
280       tostep.m_iterate.m_hue = increment;
281     }
282   }
283
284   /**
285    * A stepping model that steps on the luminance line of the HSB color space.
286    * <p>
287    *
288    * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
289    *
290    * @version $Revision: 1.1 $
291    */

292   public static class LuminanceStepper extends ColorIterator.DefaultStepping {
293     /**
294      * Defcon.
295      * <p>
296      */

297     public LuminanceStepper() {
298       // nop
299
}
300
301     /**
302      * Creates an instance with the given stepping to go on the luminance line
303      * of the color space.
304      * <p>
305      *
306      * @param stepping
307      * the stepping for each step in between 0.0 and 1.0.
308      *
309      * @throws IllegalArgumentException
310      * if stepping is <= 0.0 or >= 1.0.
311      */

312     public LuminanceStepper(final float stepping) throws IllegalArgumentException JavaDoc {
313       super(stepping);
314     }
315
316     /**
317      * Performs a luminance step on the given ColorIterator's HSBColor.
318      * <p>
319      *
320      * The bounds are watched: if a step would cross 1.0f, it will be continued
321      * beginning from 0. if a step would cross the luminance value of the
322      * ColorIterator's start luminance, the step will only go as far as this
323      * value. Else there would be problems with finding the end of the
324      * iteration.
325      * <p>
326      *
327      * @param tostep
328      * the color iterator to perform the step on.
329      */

330     public void doStep(final ColorIterator tostep) {
331       float increment = tostep.m_iterate.m_lum;
332       float bound = tostep.m_start.m_lum;
333       if (increment == bound) {
334         increment += this.m_stepping;
335       } else if (increment < bound) {
336         // before crossing 1.0, i will cross the iteration bound (no care for
337
// 1.0
338
// needed)
339
increment += this.m_stepping;
340         if (increment > bound) {
341           increment = bound;
342         }
343       } else {
344         // more complicated: watch for crossing 1.0, then watch for crossing
345
// iteration bound.
346
increment += this.m_stepping;
347         if (increment > 1.0f) {
348           increment -= 1.0;
349           if (increment > bound) {
350             increment = bound;
351           }
352         }
353       }
354       tostep.m_iterate.m_lum = increment;
355     }
356   }
357
358   /**
359    * A stepping model that steps on the saturation line of the HSB color space.
360    * <p>
361    *
362    * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
363    *
364    * @version $Revision: 1.1 $
365    */

366   public static class SaturationStepper extends ColorIterator.DefaultStepping {
367     /**
368      * Defcon.
369      * <p>
370      */

371     public SaturationStepper() {
372       // nop
373
}
374
375     /**
376      * Creates an instance with the given stepping to go on the saturation line
377      * of the color space.
378      * <p>
379      *
380      * @param stepping
381      * the stepping for each step in between 0.0 and 1.0.
382      *
383      * @throws IllegalArgumentException
384      * if stepping is <= 0.0 or >= 1.0.
385      */

386     public SaturationStepper(final float stepping) throws IllegalArgumentException JavaDoc {
387       super(stepping);
388     }
389
390     /**
391      * Performs a saturation step on the given ColorIterator's HSBColor.
392      * <p>
393      * he bounds are watched: if a step would cross 1.0f, it will be continued
394      * beginning from 0. if a step would cross the luminance value of the
395      * ColorIterator's start luminance, the step will only go as far as this
396      * value. Else there would be problems with finding the end of the
397      * iteration.
398      * <p>
399      *
400      * @param tostep
401      * the color iterator to perform the step on.
402      */

403     public void doStep(final ColorIterator tostep) {
404       float increment = tostep.m_iterate.m_sat;
405       float bound = tostep.m_start.m_sat;
406       if (increment == bound) {
407         increment += this.m_stepping;
408       } else if (increment < bound) {
409         // before crossing 1.0, i will cross the iteration bound (no care for
410
// 1.0
411
// needed)
412
increment += this.m_stepping;
413         if (increment > bound) {
414           increment = bound;
415         }
416       } else {
417         // more complicated: watch for crossing 1.0, then watch for crossing
418
// iteration bound.
419
increment += this.m_stepping;
420         if (increment > 1.0f) {
421           increment -= 1.0;
422           if (increment > bound) {
423             increment = bound;
424           }
425         }
426       }
427       tostep.m_iterate.m_sat = increment;
428     }
429   }
430
431   /**
432    * Base class for stepping models that may step in each direction of the Hue
433    * Saturation Luminance color space.
434    * <p>
435    *
436    * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
437    *
438    *
439    * @version $Revision: 1.1 $
440    */

441   public abstract static class PiggyBackStepper extends ColorIterator.DefaultStepping {
442     /** The hue stepper to use. */
443     protected HueStepper m_huestep;
444
445     /** The saturation stepper to use. */
446     protected SaturationStepper m_satstep;
447
448     /** The luminance stepper to use. */
449     protected LuminanceStepper m_lumstep;
450
451     /**
452      * Defcon.
453      * <p>
454      */

455     public PiggyBackStepper() {
456       this(0.002f, 0.2f, 0.2f);
457     }
458
459     /**
460      * Creates an instance that uses the given step lengths for hue, luminance
461      * and saturation.
462      * <p>
463      *
464      * @param hueStepping
465      * the step length on the hue line of the HSB color space.
466      *
467      * @param satStepping
468      * the step length on the saturation line of the HSB color space.
469      *
470      * @param lumStepping
471      * the step length on the luminance line of the HSB color space.
472      *
473      * @throws IllegalArgumentException
474      * if any of the arguments is <= 0.0 or >= 1.0.
475      */

476     public PiggyBackStepper(final float hueStepping, final float satStepping,
477         final float lumStepping) throws IllegalArgumentException JavaDoc {
478       this.m_huestep = new HueStepper(hueStepping);
479       this.m_satstep = new SaturationStepper(satStepping);
480       this.m_lumstep = new LuminanceStepper(lumStepping);
481     }
482
483     /**
484      * @see java.lang.Object#clone()
485      */

486     public Object JavaDoc clone() {
487       PiggyBackStepper ret = (PiggyBackStepper) super.clone();
488       ret.m_huestep = (HueStepper) this.m_huestep.clone();
489       ret.m_satstep = (SaturationStepper) this.m_satstep.clone();
490       ret.m_lumstep = (LuminanceStepper) this.m_lumstep.clone();
491       return ret;
492     }
493   }
494
495   /**
496    * Performs hue steps until it has walked the whole hue line, then performs a
497    * saturation step to start with hue steps again. If the saturation steps have
498    * walked the whole saturation line, a luminance step is done before starting
499    * with hue steps again.
500    * <p>
501    *
502    * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
503    *
504    * @version $Revision: 1.1 $
505    */

506   public static class HSBStepper extends ColorIterator.PiggyBackStepper {
507     /**
508      * Defcon.
509      * <p>
510      */

511     public HSBStepper() {
512       super();
513     }
514
515     /**
516      * @see info.monitorenter.gui.util.ColorIterator.ISteppingModel#doStep(info.monitorenter.gui.util.ColorIterator)
517      */

518     public void doStep(final ColorIterator tostep) {
519       // technique: without testing the step is done
520
// this allows to restart with huestep even if start.hue==iterate.hue
521
// after having performed a step of different kind
522
this.m_huestep.doStep(tostep);
523       if (tostep.m_iterate.m_hue == tostep.m_start.m_hue) {
524         this.m_satstep.doStep(tostep);
525         if (tostep.m_iterate.m_sat == tostep.m_start.m_sat) {
526           this.m_lumstep.doStep(tostep);
527         }
528       }
529     }
530   }
531
532   /**
533    * Performs hue steps until it has walked the whole hue line, then performs a
534    * saturation step to start with hue steps again.
535    * <p>
536    *
537    * @author <a HREF="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
538    *
539    * @version $Revision: 1.1 $
540    */

541   public static class HSStepper extends ColorIterator.PiggyBackStepper {
542     /**
543      * Defcon.
544      * <p>
545      */

546     public HSStepper() {
547       // nop
548
}
549
550     /**
551      * @see info.monitorenter.gui.util.ColorIterator.ISteppingModel#doStep(info.monitorenter.gui.util.ColorIterator)
552      */

553     public void doStep(final ColorIterator tostep) {
554       // technique: without testing the step is done
555
// this allows to restart with huestep even if start.hue==iterate.hue
556
// after having performed a step of different kind
557
this.m_huestep.doStep(tostep);
558       if (tostep.m_iterate.m_hue == tostep.m_start.m_hue) {
559         this.m_satstep.doStep(tostep);
560       }
561     }
562   }
563
564   /**
565    * Main entry for a test application.
566    * <p>
567    *
568    * @param args
569    * ignored.
570    */

571   public static void main(final String JavaDoc[] args) {
572     final javax.swing.JFrame JavaDoc frame = new javax.swing.JFrame JavaDoc("ColorCircleIterator-test");
573
574     javax.swing.JPanel JavaDoc panel = new javax.swing.JPanel JavaDoc() {
575       /**
576        * Generated <code>serialVersionUID</code>.
577        */

578       private static final long serialVersionUID = 3258408422146715703L;
579
580       private ColorIterator m_color = new ColorIterator();
581       {
582         // System.out.println("start: " + color.start.toString());
583
// System.out.println("iterate: " + color.iterate.toString());
584
int wdt = 0;
585         while (this.m_color.hasNext()) {
586           wdt++;
587           this.m_color.next();
588         }
589         System.out.println("found " + wdt + " different colors.");
590         System.out.println("size: " + wdt);
591         this.setSize(wdt, 100);
592         this.setPreferredSize(new java.awt.Dimension JavaDoc(wdt, 100));
593         this.setMinimumSize(new java.awt.Dimension JavaDoc(wdt, 100));
594       }
595
596       /**
597        * @see java.awt.Component#paint(java.awt.Graphics)
598        */

599       public void paint(final java.awt.Graphics JavaDoc g) {
600         super.paint(g);
601         // refresh iterator
602
this.m_color.reset();
603         int width = this.getWidth();
604         int height = this.getHeight();
605         int pxdrawn = 0;
606         while (this.m_color.hasNext()) {
607           if (pxdrawn == width) {
608             break;
609           }
610           g.setColor((java.awt.Color JavaDoc) this.m_color.next());
611           g.drawLine(pxdrawn, 0, pxdrawn, height);
612           pxdrawn++;
613         }
614       }
615     };
616
617     javax.swing.JScrollPane JavaDoc scroll = new javax.swing.JScrollPane JavaDoc(panel);
618     java.awt.Container JavaDoc contentPane = frame.getContentPane();
619     contentPane.setLayout(new java.awt.BorderLayout JavaDoc());
620     contentPane.add(scroll, java.awt.BorderLayout.CENTER);
621
622     frame.setLocation(200, 200);
623     frame.setSize(new java.awt.Dimension JavaDoc(400, 100));
624     frame.addWindowListener(new java.awt.event.WindowAdapter JavaDoc() {
625       public void windowClosing(final java.awt.event.WindowEvent JavaDoc e) {
626         System.exit(0);
627       }
628     });
629     frame.setResizable(true);
630     frame.setVisible(true);
631   }
632 }
633
Popular Tags