/* =========================================================== * JFreeChart : a free chart library for the Java(tm) platform * =========================================================== * * (C) Copyright 2000-2014, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jfreechart/index.html * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners.] * * ----------------- * WaferMapPlot.java * ----------------- * * (C) Copyright 2003-2014, by Robert Redburn and Contributors. * * Original Author: Robert Redburn; * Contributor(s): David Gilbert (for Object Refinery Limited); * * Changes * ------- * 25-Nov-2003 : Version 1 contributed by Robert Redburn (DG); * 05-May-2005 : Updated draw() method parameters (DG); * 10-Jun-2005 : Changed private --> protected for drawChipGrid(), * drawWaferEdge() and getWafterEdge() (DG); * 16-Jun-2005 : Added default constructor and setDataset() method (DG); * 18-Dec-2008 : Use ResourceBundleWrapper - see patch 1607918 by * Jess Thrysoee (DG); * 17-Jun-2012 : Removed JCommon dependencies (DG); * 10-Mar-2014 : Removed LegendItemCollection (DG); * */ package org.jfree.chart.plot; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.Arc2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.Serializable; import java.util.List; import java.util.ResourceBundle; import org.jfree.chart.LegendItem; import org.jfree.chart.ui.RectangleInsets; import org.jfree.chart.event.PlotChangeEvent; import org.jfree.chart.event.RendererChangeEvent; import org.jfree.chart.event.RendererChangeListener; import org.jfree.chart.renderer.WaferMapRenderer; import org.jfree.chart.util.ResourceBundleWrapper; import org.jfree.data.general.DatasetChangeEvent; import org.jfree.data.general.WaferMapDataset; /** * A wafer map plot. */ public class WaferMapPlot extends Plot implements RendererChangeListener, Cloneable, Serializable { /** For serialization. */ private static final long serialVersionUID = 4668320403707308155L; /** The default grid line stroke. */ public static final Stroke DEFAULT_GRIDLINE_STROKE = new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0.0f, new float[] {2.0f, 2.0f}, 0.0f); /** The default grid line paint. */ public static final Paint DEFAULT_GRIDLINE_PAINT = Color.LIGHT_GRAY; /** The default crosshair visibility. */ public static final boolean DEFAULT_CROSSHAIR_VISIBLE = false; /** The default crosshair stroke. */ public static final Stroke DEFAULT_CROSSHAIR_STROKE = DEFAULT_GRIDLINE_STROKE; /** The default crosshair paint. */ public static final Paint DEFAULT_CROSSHAIR_PAINT = Color.BLUE; /** The resourceBundle for the localization. */ protected static ResourceBundle localizationResources = ResourceBundleWrapper.getBundle( "org.jfree.chart.plot.LocalizationBundle"); /** The plot orientation. * vertical = notch down * horizontal = notch right */ private PlotOrientation orientation; /** The dataset. */ private WaferMapDataset dataset; /** * Object responsible for drawing the visual representation of each point * on the plot. */ private WaferMapRenderer renderer; /** * Creates a new plot with no dataset. */ public WaferMapPlot() { this(null); } /** * Creates a new plot. * * @param dataset the dataset (<code>null</code> permitted). */ public WaferMapPlot(WaferMapDataset dataset) { this(dataset, null); } /** * Creates a new plot. * * @param dataset the dataset (<code>null</code> permitted). * @param renderer the renderer (<code>null</code> permitted). */ public WaferMapPlot(WaferMapDataset dataset, WaferMapRenderer renderer) { super(); this.orientation = PlotOrientation.VERTICAL; this.dataset = dataset; if (dataset != null) { dataset.addChangeListener(this); } this.renderer = renderer; if (renderer != null) { renderer.setPlot(this); renderer.addChangeListener(this); } } /** * Returns the plot type as a string. * * @return A short string describing the type of plot. */ @Override public String getPlotType() { return ("WMAP_Plot"); } /** * Returns the dataset * * @return The dataset (possibly <code>null</code>). */ public WaferMapDataset getDataset() { return this.dataset; } /** * Sets the dataset used by the plot and sends a {@link PlotChangeEvent} * to all registered listeners. * * @param dataset the dataset (<code>null</code> permitted). */ public void setDataset(WaferMapDataset dataset) { // if there is an existing dataset, remove the plot from the list of // change listeners... if (this.dataset != null) { this.dataset.removeChangeListener(this); } // set the new dataset, and register the chart as a change listener... this.dataset = dataset; if (dataset != null) { dataset.addChangeListener(this); } // send a dataset change event to self to trigger plot change event datasetChanged(new DatasetChangeEvent(this, dataset)); } /** * Sets the item renderer, and notifies all listeners of a change to the * plot. If the renderer is set to <code>null</code>, no chart will be * drawn. * * @param renderer the new renderer (<code>null</code> permitted). */ public void setRenderer(WaferMapRenderer renderer) { if (this.renderer != null) { this.renderer.removeChangeListener(this); } this.renderer = renderer; if (renderer != null) { renderer.setPlot(this); } fireChangeEvent(); } /** * Draws the wafermap view. * * @param g2 the graphics device. * @param area the plot area. * @param anchor the anchor point (<code>null</code> permitted). * @param state the plot state. * @param info the plot rendering info. */ @Override public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState state, PlotRenderingInfo info) { // if the plot area is too small, just return... boolean b1 = (area.getWidth() <= MINIMUM_WIDTH_TO_DRAW); boolean b2 = (area.getHeight() <= MINIMUM_HEIGHT_TO_DRAW); if (b1 || b2) { return; } // record the plot area... if (info != null) { info.setPlotArea(area); } // adjust the drawing area for the plot insets (if any)... RectangleInsets insets = getInsets(); insets.trim(area); drawChipGrid(g2, area); drawWaferEdge(g2, area); } /** * Calculates and draws the chip locations on the wafer. * * @param g2 the graphics device. * @param plotArea the plot area. */ protected void drawChipGrid(Graphics2D g2, Rectangle2D plotArea) { Shape savedClip = g2.getClip(); g2.setClip(getWaferEdge(plotArea)); Rectangle2D chip = new Rectangle2D.Double(); int xchips = 35; int ychips = 20; double space = 1d; if (this.dataset != null) { xchips = this.dataset.getMaxChipX() + 2; ychips = this.dataset.getMaxChipY() + 2; space = this.dataset.getChipSpace(); } double startX = plotArea.getX(); double startY = plotArea.getY(); double chipWidth = 1d; double chipHeight = 1d; if (plotArea.getWidth() != plotArea.getHeight()) { double major, minor; if (plotArea.getWidth() > plotArea.getHeight()) { major = plotArea.getWidth(); minor = plotArea.getHeight(); } else { major = plotArea.getHeight(); minor = plotArea.getWidth(); } //set upperLeft point if (plotArea.getWidth() == minor) { // x is minor startY += (major - minor) / 2; chipWidth = (plotArea.getWidth() - (space * xchips - 1)) / xchips; chipHeight = (plotArea.getWidth() - (space * ychips - 1)) / ychips; } else { // y is minor startX += (major - minor) / 2; chipWidth = (plotArea.getHeight() - (space * xchips - 1)) / xchips; chipHeight = (plotArea.getHeight() - (space * ychips - 1)) / ychips; } } for (int x = 1; x <= xchips; x++) { double upperLeftX = (startX - chipWidth) + (chipWidth * x) + (space * (x - 1)); for (int y = 1; y <= ychips; y++) { double upperLeftY = (startY - chipHeight) + (chipHeight * y) + (space * (y - 1)); chip.setFrame(upperLeftX, upperLeftY, chipWidth, chipHeight); g2.setColor(Color.WHITE); if (this.dataset.getChipValue(x - 1, ychips - y - 1) != null) { g2.setPaint( this.renderer.getChipColor( this.dataset.getChipValue(x - 1, ychips - y - 1) ) ); } g2.fill(chip); g2.setColor(Color.LIGHT_GRAY); g2.draw(chip); } } g2.setClip(savedClip); } /** * Calculates the location of the waferedge. * * @param plotArea the plot area. * * @return The wafer edge. */ protected Ellipse2D getWaferEdge(Rectangle2D plotArea) { Ellipse2D edge = new Ellipse2D.Double(); double diameter = plotArea.getWidth(); double upperLeftX = plotArea.getX(); double upperLeftY = plotArea.getY(); //get major dimension if (plotArea.getWidth() != plotArea.getHeight()) { double major, minor; if (plotArea.getWidth() > plotArea.getHeight()) { major = plotArea.getWidth(); minor = plotArea.getHeight(); } else { major = plotArea.getHeight(); minor = plotArea.getWidth(); } //ellipse diameter is the minor dimension diameter = minor; //set upperLeft point if (plotArea.getWidth() == minor) { // x is minor upperLeftY = plotArea.getY() + (major - minor) / 2; } else { // y is minor upperLeftX = plotArea.getX() + (major - minor) / 2; } } edge.setFrame(upperLeftX, upperLeftY, diameter, diameter); return edge; } /** * Draws the waferedge, including the notch. * * @param g2 the graphics device. * @param plotArea the plot area. */ protected void drawWaferEdge(Graphics2D g2, Rectangle2D plotArea) { // draw the wafer Ellipse2D waferEdge = getWaferEdge(plotArea); g2.setColor(Color.BLACK); g2.draw(waferEdge); // calculate and draw the notch // horizontal orientation is considered notch right // vertical orientation is considered notch down Arc2D notch; Rectangle2D waferFrame = waferEdge.getFrame(); double notchDiameter = waferFrame.getWidth() * 0.04; if (this.orientation == PlotOrientation.HORIZONTAL) { Rectangle2D notchFrame = new Rectangle2D.Double( waferFrame.getX() + waferFrame.getWidth() - (notchDiameter / 2), waferFrame.getY() + (waferFrame.getHeight() / 2) - (notchDiameter / 2), notchDiameter, notchDiameter ); notch = new Arc2D.Double(notchFrame, 90d, 180d, Arc2D.OPEN); } else { Rectangle2D notchFrame = new Rectangle2D.Double( waferFrame.getX() + (waferFrame.getWidth() / 2) - (notchDiameter / 2), waferFrame.getY() + waferFrame.getHeight() - (notchDiameter / 2), notchDiameter, notchDiameter ); notch = new Arc2D.Double(notchFrame, 0d, 180d, Arc2D.OPEN); } g2.setColor(Color.WHITE); g2.fill(notch); g2.setColor(Color.BLACK); g2.draw(notch); } /** * Return the legend items from the renderer. * * @return The legend items. */ @Override public List<LegendItem> getLegendItems() { return this.renderer.getLegendCollection(); } /** * Notifies all registered listeners of a renderer change. * * @param event the event. */ @Override public void rendererChanged(RendererChangeEvent event) { fireChangeEvent(); } }