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