/* 
 * This code is part of Project Waterloo from King's College London
 * 
 *
 * Copyright King's College London 2012-
 * 
 * @author Malcolm Lidierth, King's College London  [Contact]
 * 
 * Project Waterloo 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 3 of the License, or
 * (at your option) any later version.
 *
 * Project Waterloo 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 program.  If not, see .
 *
 */
package kcl.waterloo.graphics.plots2D;

import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.util.Formatter;
import kcl.waterloo.graphics.plots2D.contour.Contour;
import kcl.waterloo.graphics.plots2D.contour.ContourExtra;
import kcl.waterloo.graphics.plots2D.contour.ContourExtra.SortedContour;

/**
 *
 * GJContour class for plotting contours.
 *
 * Note that the MarkerArray is not used for this class - Paths are instead
 * represented by the ContourExtra object that provides methods to generate the
 * contour lines from data.
 *
 * 

* This code is part of the Waterloo Scientific Graphics package from King's * College London

* * @author Malcolm Lidierth, King's College London [Contact] */ public class GJContour extends GJAbstractPlot implements GJTransformUpdateInterface { /** * Set true to label the contours with their levels */ private boolean labelled = false; private Font labelFont = null; private boolean fillClipping = true; private boolean filled = true; public GJContour() { super(); } public GJContour(GJAbstractPlot p) { super(p); } public static GJPlotInterface createInstance() { GJPlotInterface p = GJAbstractPlot.createInstance(new GJContour()); p.setXData(new double[]{0d}); p.setYData(new double[]{0d}); return p; } @Override public void paintPlot(Graphics2D g) { super.paintPlot(g); getScreenDataArray().clear(); ContourExtra extra = (ContourExtra) this.getDataModel().getExtraObject(); if (extra == null || extra.size() == 0 || extra.getCompounds().size() == 0) { return; } Graphics2D g2 = (Graphics2D) g.create(); double scx = getParentGraph().xPositionToPixel(1) - getParentGraph().xPositionToPixel(0); double scy = getParentGraph().yPositionToPixel(0) - getParentGraph().yPositionToPixel(1); if (Double.isInfinite(scx) || Double.isNaN(scx)) { scx = 1d; } if (Double.isInfinite(scy) || Double.isNaN(scy)) { scy = 1d; } AffineTransform af1 = AffineTransform.getScaleInstance(scx, -scy); AffineTransform af2 = new AffineTransform(); double xt = getParentGraph().xPositionToPixel(0); double yt = getParentGraph().yPositionToPixel(0); af2.setToTranslation(xt, yt); // If filled, draw the fills first.... if (isFilled()) { doFill(g2, extra, af1, af2); } //... then draw the lines //setTranslation(af2, x[0], y[0]); for (Double thisLevel : extra.keySet()) { Path2D p = extra.getCompound(thisLevel); // Treat as zero if within 1 ulp of 1f if (extra.getZeroStroke() != null && Math.abs(thisLevel) <= Math.ulp(1f)) { g2.setStroke(extra.getZeroStroke()); } else { g2.setStroke(getEdgeStroke().get(extra.getColorIndex(thisLevel))); } if (extra.getPositiveLineColor() != null && thisLevel >= 0) { g2.setPaint(extra.getPositiveLineColor()); } else if (extra.getNegativeLineColor() != null && thisLevel < 0) { g2.setPaint(extra.getNegativeLineColor()); } else { g2.setPaint(getEdgeColor().get(extra.getColorIndex(thisLevel))); } p.transform(af1); p.transform(af2); g2.draw(p); getScreenDataArray().add(p); } //... then the labels if required if (isLabelled()) { g2.setFont(labelFont); for (SortedContour c : extra.sort()) { Path2D p = new Path2D.Double(); Contour contour = c.getContour(); String str = String.format("%4.2f", contour.getLevel()); GlyphVector glyph = g2.getFont().createGlyphVector(g2.getFontRenderContext(), str); float glyphX = (float) (scx * contour.getLabel().getX() - g2.getFontMetrics().stringWidth(str) / 2d); float glyphY = (float) (-scy * contour.getLabel().getY()); if (!Double.isNaN(glyphX) && !Double.isNaN(glyphY)) { Shape s = glyph.getOutline(glyphX, glyphY); double theta = contour.getTheta(); if (Math.abs(theta) > Math.PI / 2) { theta += Math.PI; } p.append(s, false); p.transform(AffineTransform.getRotateInstance(theta, s.getBounds2D().getCenterX(), s.getBounds2D().getCenterY())); p.transform(af2); if (contour.getLabel().getBackground() != null) { g2.setPaint(contour.getLabel().getBackground()); Path2D p2 = new Path2D.Double(); Rectangle2D r = s.getBounds2D(); p2.append(new Rectangle.Double(r.getX() - 1, r.getY() - 1, r.getWidth() + 2, r.getHeight() + 2), false); p2.transform(AffineTransform.getRotateInstance(theta, s.getBounds2D().getCenterX(), s.getBounds2D().getCenterY())); p2.transform(af2); g2.fill(p2); } g2.setPaint(contour.getLabel().getForeground()); g2.fill(p); } } } } private void doFill(Graphics2D g2, ContourExtra extra, AffineTransform af1, AffineTransform af2) { Area commonPath; Shape clip = g2.getClip(); if (fillClipping && clip != null) { commonPath = extra.getCommonPath(); if (!commonPath.isEmpty()) { commonPath.transform(af1); commonPath.transform(af2); commonPath.intersect(new Area(clip)); g2.setClip(commonPath); } } for (SortedContour sortedContour : extra.sort()) { Area p = sortedContour.getFillArea(); p.transform(af1); p.transform(af2); g2.setPaint(getFill().get(sortedContour.getColorIndex())); g2.fill(p); } g2.setClip(clip); } @Override public boolean isMultiplexible() { return false; } @Override public String stringSupplement() { Formatter f = new Formatter(); ContourExtra extra = (ContourExtra) getDataModel().getExtraObject(); f.format("%n%15s%10s%20s%20s%18s%18s%20s%n", "Level", "Count", "Data Points", "Closed", "Edge Color", "Fill Color", "Color Index"); int i = 0; for (Double thisLevel : extra.getLevelData().keySet()) { f.format("%4d:%10.3f", i, thisLevel.doubleValue()); f.format("%10s", extra.getLevelData().get(thisLevel).size()); String str = "["; for (int k = 0; k < extra.getLevelData().get(thisLevel).size(); k++) { str = str.concat(String.format("%d", extra.getLevelData().get(thisLevel).get(k).size())); if (k == 4 && extra.getLevelData().get(thisLevel).size() >= 5) { str = str.concat("..."); break; } else if (k < extra.getLevelData().get(thisLevel).size() - 1) { str = str.concat("+"); } } str = str.concat("]"); f.format("\t%-18s", str); str = "["; int n = 0; for (Contour c : extra.getLevel(thisLevel)) { str = str.concat(String.format("%s", c.isClosed() ? "T" : "F")); if (n == 4 && extra.getLevel(thisLevel).size() >= 5) { str = str.concat("..."); break; } else if (n < extra.getLevel(thisLevel).size() - 1) { str = str.concat("+"); } n++; } str = str.concat("]"); f.format("\t%-10s", str); f.format("%18s", getEdgeColor().get(i).toString().replaceAll("java.awt.Color", "")); f.format(" _|-> %12s", getFill().get(i).toString().replaceAll("java.awt.Color", "")); f.format("\t%-10d", extra.getColorIndex(thisLevel)); f.format("%n"); i++; } return f.toString(); } /** * @return the labelled */ public boolean isLabelled() { return labelled; } /** * @param labelled the labelled to set */ public void setLabelled(boolean labelled) { this.labelled = labelled; } /** * @return the fillClipping */ public boolean isFillClipping() { return fillClipping; } /** * @param fillClipping the fillClipping to set */ public void setFillClipping(boolean fillClipping) { this.fillClipping = fillClipping; } @Override public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName().equals("extraObject") || e.getPropertyName().equals("parentGraph") || e.getPropertyName().equals("dataBuffer")) { transformUpdate(); } } @Override public final boolean transformUpdate() { if (getParentGraph() != null) { ((ContourExtra) getDataModel().getExtraObject()).generateContours(this); ((Component) getParentGraph()).repaint(); //getParentGraph().autoScale(); if (labelFont == null) { labelFont = ((Component) getParentGraph()).getFont().deriveFont(10f); } } return true; } /** * @return the filled */ public boolean isFilled() { return filled; } /** * @param filled the filled to set */ public void setFilled(boolean filled) { this.filled = filled; } /** * @return the labelFontSize */ public Font getLabelFont() { return labelFont; } /** * @param labelFont */ public void setLabelFont(Font labelFont) { this.labelFont = labelFont; } }

Ads help maintain this website.