/* 
 * 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.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.Formatter;
import kcl.waterloo.marker.GJMarker;
import kcl.waterloo.math.ArrayMath;

/**
 *
 * GJQuiver or vector plot.
 *
 * 

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

* * @author Malcolm Lidierth, King's College London [Contact] */ public final class GJQuiver extends GJAbstractPlot { /** * An affine transform used to scale the arrow heads */ private final AffineTransform af = new AffineTransform(); public GJQuiver() { super(); } public GJQuiver(GJAbstractPlot p) { super(p); } // private GJQuiver() { // } public static GJPlotInterface createInstance() { GJPlotInterface p = GJAbstractPlot.createInstance(new GJQuiver()); p.getDataModel().setExtraObject(new QuiverExtra(1)); return p; } /** * Paints the plot. * * @param g2 */ @Override public final void paintPlot(Graphics2D g2) { Path2D path; super.paintPlot(g2); getScreenDataArray().clear(); final double[] X = getXData().getRawDataValues(); final double[] Y = getYData().getRawDataValues(); final double[] dX; final double[] dY; if (X != null && Y != null) { // Deal with user-specified scaling // N.B. If UserScaleFactor == 0, scale will be set to 1d final double scale = getFinalScaleFactor(getDataModel().getExtraData0(), getDataModel().getExtraData1()); if (scale != 1d) { dX = ArrayMath.mul(getDataModel().getExtraData0(), scale); dY = ArrayMath.mul(getDataModel().getExtraData1(), scale); } else { dX = getDataModel().getExtraData0(); dY = getDataModel().getExtraData1(); } double Yopix; double Xopix; double dXpix, dYpix; double xsz, ysz; Shape arrowhead; double x0, x1; for (int i = 0; i < dX.length; i++) { path = new Path2D.Double(); Xopix = getParentGraph().xPositionToPixel(getParentGraph().getXTransform().getData(X[i])); Yopix = getParentGraph().yPositionToPixel(getParentGraph().getYTransform().getData(Y[i])); dXpix = getParentGraph().xPositionToPixel(getParentGraph().getXTransform().getData(X[i] + dX[i])); dYpix = getParentGraph().yPositionToPixel(getParentGraph().getYTransform().getData(Y[i] + dY[i])); if (!Double.isNaN(Xopix) && !Double.isNaN(Yopix) && !Double.isInfinite(Xopix) && !Double.isInfinite(Yopix)) { path.moveTo(Xopix, Yopix); if (isUseQuad()) { x0 = getParentGraph().xPositionToPixel(getParentGraph().getXTransform().getData(X[i] + dX[i] / 2d)); x1 = getParentGraph().yPositionToPixel(getParentGraph().getYTransform().getData(Y[i] + dY[i] * 2d / 3d)); if (Double.isNaN(x0) || Double.isNaN(x1)) { continue; } path.quadTo(x0, x1, dXpix, dYpix); } else { path.lineTo(dXpix, dYpix); } if (getVisualModel().getDynamicMarkerSize().size() == 0) { xsz = 1.5; ysz = 1.5; } else { xsz = getVisualModel().getDynamicMarkerSize().get(i).getWidth(); ysz = getVisualModel().getDynamicMarkerSize().get(i).getHeight(); } arrowhead = GJMarker.makeArrow(dXpix, dYpix, xsz, ysz, getVisualModel().getFill() != null); af.setToRotation(Math.atan2(dYpix - Yopix, dXpix - Xopix), dXpix, dYpix); arrowhead = af.createTransformedShape(arrowhead); g2.setStroke(getVisualModel().getLineStroke().get(i)); g2.setPaint(getVisualModel().getLineColor().get(i)); g2.draw(path); if (getVisualModel().getFill() != null) { g2.setPaint(getVisualModel().getFill().get(i)); g2.fill(arrowhead); } g2.setPaint(getVisualModel().getLineColor().get(i)); g2.draw(arrowhead); path.append(arrowhead, false); getScreenDataArray().add(path); } } } } private double getFinalScaleFactor(final double[] dX, final double[] dY) { if (dX == null || dY == null || dX.length != dY.length || dX.length == 0) { return 1d; } QuiverExtra q = (QuiverExtra) getDataModel().getExtraObject(); //Find the maximum spacing between vector origins in X and Y palce double spacingX = ArrayMath.max(ArrayMath.absi(ArrayMath.diffi(getXData().getRawDataValues()))); double spacingY = ArrayMath.max(ArrayMath.absi(ArrayMath.diffi(getYData().getRawDataValues()))); // Maximum distance for vectors along X and Y axes double dU = ArrayMath.max(dX); double dV = ArrayMath.max(dY); // Scale factor required for vectors to just fill the available x,y // spacing double scx = spacingX / dU; double scy = spacingY / dV; double scale2 = Math.min(scx, scy); // Calculate the final scaling based on user-setting double scale; if (q.getUserScaleFactor() == 0) { // If zero, do not scale - just use the values supplied in dX and dY scale = 1d; } else { // Stretch or shrink the factors according to the user-specified scale scale = q.getUserScaleFactor() * scale2; } return scale; } /** * @return the useQuad */ public boolean isUseQuad() { QuiverExtra q = (QuiverExtra) getDataModel().getExtraObject(); return q.isUseQuad(); } /** * @param useQuad the useQuad to set */ public void setUseQuad(boolean useQuad) { QuiverExtra q = (QuiverExtra) getDataModel().getExtraObject(); boolean old = q.isUseQuad(); q.setUseQuad(useQuad); getPCS().firePropertyChange("useQuad", old, useQuad); } public void setScale(double scale) { QuiverExtra q = (QuiverExtra) getDataModel().getExtraObject(); double old = q.getUserScaleFactor(); q.setUserScaleFactor(scale); getPCS().firePropertyChange("Scale", old, scale); } public double getScale() { QuiverExtra q = (QuiverExtra) getDataModel().getExtraObject(); return q.getUserScaleFactor(); } @Override protected String stringSupplement() { String str = ""; StringBuilder s = new StringBuilder(); Formatter f = new Formatter(s); if (getDataModel().getExtraData0() != null && getDataModel().getExtraData0().length > 0) { f.format("dx:\t"); printData(f, getDataModel().getExtraData0()); } if (getDataModel().getExtraData1() != null && getDataModel().getExtraData1().length > 0) { f.format("dy:\t"); printData(f, getDataModel().getExtraData1()); } str = str.concat(f.toString()); return str; } }

Ads help maintain this website.