001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * -----------------
028 * WaferMapPlot.java
029 * -----------------
030 *
031 * (C) Copyright 2003, 2004, by Robert Redburn and Contributors.
032 *
033 * Original Author: Robert Redburn;
034 * Contributor(s): David Gilbert (for Object Refinery Limited);
035 *
036 * Changes
037 * -------
038 * 25-Nov-2003 : Version 1 contributed by Robert Redburn (DG);
039 * 05-May-2005 : Updated draw() method parameters (DG);
040 * 10-Jun-2005 : Changed private --> protected for drawChipGrid(),
041 * drawWaferEdge() and getWafterEdge() (DG);
042 * 16-Jun-2005 : Added default constructor and setDataset() method (DG);
043 *
044 */
045
046 package org.jfree.chart.plot;
047
048 import java.awt.BasicStroke;
049 import java.awt.Color;
050 import java.awt.Graphics2D;
051 import java.awt.Paint;
052 import java.awt.Shape;
053 import java.awt.Stroke;
054 import java.awt.geom.Arc2D;
055 import java.awt.geom.Ellipse2D;
056 import java.awt.geom.Point2D;
057 import java.awt.geom.Rectangle2D;
058 import java.io.Serializable;
059 import java.util.ResourceBundle;
060
061 import org.jfree.chart.LegendItemCollection;
062 import org.jfree.chart.event.PlotChangeEvent;
063 import org.jfree.chart.event.RendererChangeEvent;
064 import org.jfree.chart.event.RendererChangeListener;
065 import org.jfree.chart.renderer.WaferMapRenderer;
066 import org.jfree.data.general.DatasetChangeEvent;
067 import org.jfree.data.general.WaferMapDataset;
068 import org.jfree.ui.RectangleInsets;
069
070 /**
071 * A wafer map plot.
072 */
073 public class WaferMapPlot extends Plot implements RendererChangeListener,
074 Cloneable,
075 Serializable {
076
077 /** For serialization. */
078 private static final long serialVersionUID = 4668320403707308155L;
079
080 /** The default grid line stroke. */
081 public static final Stroke DEFAULT_GRIDLINE_STROKE = new BasicStroke(0.5f,
082 BasicStroke.CAP_BUTT,
083 BasicStroke.JOIN_BEVEL,
084 0.0f,
085 new float[] {2.0f, 2.0f},
086 0.0f);
087
088 /** The default grid line paint. */
089 public static final Paint DEFAULT_GRIDLINE_PAINT = Color.lightGray;
090
091 /** The default crosshair visibility. */
092 public static final boolean DEFAULT_CROSSHAIR_VISIBLE = false;
093
094 /** The default crosshair stroke. */
095 public static final Stroke DEFAULT_CROSSHAIR_STROKE
096 = DEFAULT_GRIDLINE_STROKE;
097
098 /** The default crosshair paint. */
099 public static final Paint DEFAULT_CROSSHAIR_PAINT = Color.blue;
100
101 /** The resourceBundle for the localization. */
102 protected static ResourceBundle localizationResources =
103 ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
104
105 /** The plot orientation.
106 * vertical = notch down
107 * horizontal = notch right
108 */
109 private PlotOrientation orientation;
110
111 /** The dataset. */
112 private WaferMapDataset dataset;
113
114 /**
115 * Object responsible for drawing the visual representation of each point
116 * on the plot.
117 */
118 private WaferMapRenderer renderer;
119
120 /**
121 * Creates a new plot with no dataset.
122 */
123 public WaferMapPlot() {
124 this(null);
125 }
126
127 /**
128 * Creates a new plot.
129 *
130 * @param dataset the dataset (<code>null</code> permitted).
131 */
132 public WaferMapPlot(WaferMapDataset dataset) {
133 this(dataset, null);
134 }
135
136 /**
137 * Creates a new plot.
138 *
139 * @param dataset the dataset (<code>null</code> permitted).
140 * @param renderer the renderer (<code>null</code> permitted).
141 */
142 public WaferMapPlot(WaferMapDataset dataset, WaferMapRenderer renderer) {
143
144 super();
145
146 this.orientation = PlotOrientation.VERTICAL;
147
148 this.dataset = dataset;
149 if (dataset != null) {
150 dataset.addChangeListener(this);
151 }
152
153 this.renderer = renderer;
154 if (renderer != null) {
155 renderer.setPlot(this);
156 renderer.addChangeListener(this);
157 }
158
159 }
160
161 /**
162 * Returns the plot type as a string.
163 *
164 * @return A short string describing the type of plot.
165 */
166 public String getPlotType() {
167 return ("WMAP_Plot");
168 }
169
170 /**
171 * Returns the dataset
172 *
173 * @return The dataset (possibly <code>null</code>).
174 */
175 public WaferMapDataset getDataset() {
176 return this.dataset;
177 }
178
179 /**
180 * Sets the dataset used by the plot and sends a {@link PlotChangeEvent}
181 * to all registered listeners.
182 *
183 * @param dataset the dataset (<code>null</code> permitted).
184 */
185 public void setDataset(WaferMapDataset dataset) {
186 // if there is an existing dataset, remove the plot from the list of
187 // change listeners...
188 if (this.dataset != null) {
189 this.dataset.removeChangeListener(this);
190 }
191
192 // set the new dataset, and register the chart as a change listener...
193 this.dataset = dataset;
194 if (dataset != null) {
195 setDatasetGroup(dataset.getGroup());
196 dataset.addChangeListener(this);
197 }
198
199 // send a dataset change event to self to trigger plot change event
200 datasetChanged(new DatasetChangeEvent(this, dataset));
201 }
202
203 /**
204 * Sets the item renderer, and notifies all listeners of a change to the
205 * plot. If the renderer is set to <code>null</code>, no chart will be
206 * drawn.
207 *
208 * @param renderer the new renderer (<code>null</code> permitted).
209 */
210 public void setRenderer(WaferMapRenderer renderer) {
211
212 if (this.renderer != null) {
213 this.renderer.removeChangeListener(this);
214 }
215
216 this.renderer = renderer;
217 if (renderer != null) {
218 renderer.setPlot(this);
219 }
220
221 notifyListeners(new PlotChangeEvent(this));
222
223 }
224
225 /**
226 * Draws the wafermap view.
227 *
228 * @param g2 the graphics device.
229 * @param area the plot area.
230 * @param anchor the anchor point (<code>null</code> permitted).
231 * @param state the plot state.
232 * @param info the plot rendering info.
233 */
234 public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
235 PlotState state,
236 PlotRenderingInfo info) {
237
238 // if the plot area is too small, just return...
239 boolean b1 = (area.getWidth() <= MINIMUM_WIDTH_TO_DRAW);
240 boolean b2 = (area.getHeight() <= MINIMUM_HEIGHT_TO_DRAW);
241 if (b1 || b2) {
242 return;
243 }
244
245 // record the plot area...
246 if (info != null) {
247 info.setPlotArea(area);
248 }
249
250 // adjust the drawing area for the plot insets (if any)...
251 RectangleInsets insets = getInsets();
252 insets.trim(area);
253
254 drawChipGrid(g2, area);
255 drawWaferEdge(g2, area);
256
257 }
258
259 /**
260 * Calculates and draws the chip locations on the wafer.
261 *
262 * @param g2 the graphics device.
263 * @param plotArea the plot area.
264 */
265 protected void drawChipGrid(Graphics2D g2, Rectangle2D plotArea) {
266
267 Shape savedClip = g2.getClip();
268 g2.setClip(getWaferEdge(plotArea));
269 Rectangle2D chip = new Rectangle2D.Double();
270 int xchips = 35;
271 int ychips = 20;
272 double space = 1d;
273 if (this.dataset != null) {
274 xchips = this.dataset.getMaxChipX() + 2;
275 ychips = this.dataset.getMaxChipY() + 2;
276 space = this.dataset.getChipSpace();
277 }
278 double startX = plotArea.getX();
279 double startY = plotArea.getY();
280 double chipWidth = 1d;
281 double chipHeight = 1d;
282 if (plotArea.getWidth() != plotArea.getHeight()) {
283 double major = 0d;
284 double minor = 0d;
285 if (plotArea.getWidth() > plotArea.getHeight()) {
286 major = plotArea.getWidth();
287 minor = plotArea.getHeight();
288 }
289 else {
290 major = plotArea.getHeight();
291 minor = plotArea.getWidth();
292 }
293 //set upperLeft point
294 if (plotArea.getWidth() == minor) { // x is minor
295 startY += (major - minor) / 2;
296 chipWidth = (plotArea.getWidth() - (space * xchips - 1))
297 / xchips;
298 chipHeight = (plotArea.getWidth() - (space * ychips - 1))
299 / ychips;
300 }
301 else { // y is minor
302 startX += (major - minor) / 2;
303 chipWidth = (plotArea.getHeight() - (space * xchips - 1))
304 / xchips;
305 chipHeight = (plotArea.getHeight() - (space * ychips - 1))
306 / ychips;
307 }
308 }
309
310 for (int x = 1; x <= xchips; x++) {
311 double upperLeftX = (startX - chipWidth) + (chipWidth * x)
312 + (space * (x - 1));
313 for (int y = 1; y <= ychips; y++) {
314 double upperLeftY = (startY - chipHeight) + (chipHeight * y)
315 + (space * (y - 1));
316 chip.setFrame(upperLeftX, upperLeftY, chipWidth, chipHeight);
317 g2.setColor(Color.white);
318 if (this.dataset.getChipValue(x - 1, ychips - y - 1) != null) {
319 g2.setPaint(
320 this.renderer.getChipColor(
321 this.dataset.getChipValue(x - 1, ychips - y - 1)
322 )
323 );
324 }
325 g2.fill(chip);
326 g2.setColor(Color.lightGray);
327 g2.draw(chip);
328 }
329 }
330 g2.setClip(savedClip);
331 }
332
333 /**
334 * Calculates the location of the waferedge.
335 *
336 * @param plotArea the plot area.
337 *
338 * @return The wafer edge.
339 */
340 protected Ellipse2D getWaferEdge(Rectangle2D plotArea) {
341 Ellipse2D edge = new Ellipse2D.Double();
342 double diameter = plotArea.getWidth();
343 double upperLeftX = plotArea.getX();
344 double upperLeftY = plotArea.getY();
345 //get major dimension
346 if (plotArea.getWidth() != plotArea.getHeight()) {
347 double major = 0d;
348 double minor = 0d;
349 if (plotArea.getWidth() > plotArea.getHeight()) {
350 major = plotArea.getWidth();
351 minor = plotArea.getHeight();
352 }
353 else {
354 major = plotArea.getHeight();
355 minor = plotArea.getWidth();
356 }
357 //ellipse diameter is the minor dimension
358 diameter = minor;
359 //set upperLeft point
360 if (plotArea.getWidth() == minor) { // x is minor
361 upperLeftY = plotArea.getY() + (major - minor) / 2;
362 }
363 else { // y is minor
364 upperLeftX = plotArea.getX() + (major - minor) / 2;
365 }
366 }
367 edge.setFrame(upperLeftX, upperLeftY, diameter, diameter);
368 return edge;
369 }
370
371 /**
372 * Draws the waferedge, including the notch.
373 *
374 * @param g2 the graphics device.
375 * @param plotArea the plot area.
376 */
377 protected void drawWaferEdge(Graphics2D g2, Rectangle2D plotArea) {
378 // draw the wafer
379 Ellipse2D waferEdge = getWaferEdge(plotArea);
380 g2.setColor(Color.black);
381 g2.draw(waferEdge);
382 // calculate and draw the notch
383 // horizontal orientation is considered notch right
384 // vertical orientation is considered notch down
385 Arc2D notch = null;
386 Rectangle2D waferFrame = waferEdge.getFrame();
387 double notchDiameter = waferFrame.getWidth() * 0.04;
388 if (this.orientation == PlotOrientation.HORIZONTAL) {
389 Rectangle2D notchFrame =
390 new Rectangle2D.Double(
391 waferFrame.getX() + waferFrame.getWidth()
392 - (notchDiameter / 2), waferFrame.getY()
393 + (waferFrame.getHeight() / 2) - (notchDiameter / 2),
394 notchDiameter, notchDiameter
395 );
396 notch = new Arc2D.Double(notchFrame, 90d, 180d, Arc2D.OPEN);
397 }
398 else {
399 Rectangle2D notchFrame =
400 new Rectangle2D.Double(
401 waferFrame.getX() + (waferFrame.getWidth() / 2)
402 - (notchDiameter / 2), waferFrame.getY()
403 + waferFrame.getHeight() - (notchDiameter / 2),
404 notchDiameter, notchDiameter
405 );
406 notch = new Arc2D.Double(notchFrame, 0d, 180d, Arc2D.OPEN);
407 }
408 g2.setColor(Color.white);
409 g2.fill(notch);
410 g2.setColor(Color.black);
411 g2.draw(notch);
412
413 }
414
415 /**
416 * Return the legend items from the renderer.
417 *
418 * @return The legend items.
419 */
420 public LegendItemCollection getLegendItems() {
421 return this.renderer.getLegendCollection();
422 }
423
424 /**
425 * Notifies all registered listeners of a renderer change.
426 *
427 * @param event the event.
428 */
429 public void rendererChanged(RendererChangeEvent event) {
430 notifyListeners(new PlotChangeEvent(this));
431 }
432
433 }