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