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