/*
* $Id: VectorCartesianRenderer.java,v 1.12 2002/06/26 23:18:23 dwd Exp $
*
* This software is provided by NOAA for full, free and open release. It is
* understood by the recipient/user that NOAA assumes no liability for any
* errors contained in the code. Although this software is released without
* conditions or restrictions in its use, it is expected that appropriate
* credit be given to its author and to the National Oceanic and Atmospheric
* Administration should the software be included by the recipient as an
* element in other product development.
*/
package sgtplot;
import java.awt.BasicStroke;
import java.awt.Stroke;
import java.awt.geom.GeneralPath;
//import java.awt.geom.AffineTransform;
import java.util.Vector;
import java.util.Enumeration;
import java.awt.Graphics;
import java.awt.Event;
import java.awt.Point;
import java.awt.Color;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import org.freehep.graphics2d.VectorGraphics;
import sgtplot.dm.Collection;
import sgtplot.dm.SGTData;
import sgtplot.dm.SGTVector;
import sgtplot.util.Debug;
import sgtplot.util.GeoDate;
import java.lang.Math;
/**
* Produces a vector plot. If
* a second data set is specified it must have the same shape as the first.
*
* @author Donald Denbo
* @version $Revision: 1.12 $, $Date: 2002/06/26 23:18:23 $
* @since 2.1
*/
public class VectorCartesianRenderer extends CartesianRenderer {
/**
* @link aggregation
* @label attr
*/
private VectorAttribute attr_ = null;
/**
* @link aggregation
* @label vector
*/
private SGTVector vector_ = null;
private Collection collection_ = null;
private float slope_;
private float xoff_;
private float yoff_;
/**
* Get the Attribute associated with the data.
*/
public Attribute getAttribute() {
return attr_;
}
private void drawVector(VectorGraphics g, SGTVector vector,
VectorAttribute attr) {
Layer ly = cg_.getLayer();
VectorGraphics g2 = VectorGraphics.create(g);
slope_ = (float)ly.getXSlope();
xoff_ = (float)ly.getXOffset();
yoff_ = (float)ly.getYOffset();
GeneralPath gp = null;
Stroke savedStroke = g2.getStroke();
BasicStroke stroke = new BasicStroke(attr_.getWidth(),
attr_.getCapStyle(),
attr_.getMiterStyle(),
attr_.getMiterLimit());
g2.setStroke(stroke);
//
// a 1 unit lenght vector with a headScale of 1.0 will
// create a head barb that is 1.05948 long. A factor of
// 0.94386 is required to remove this effect
//
float scale = (float)attr_.getVectorScale();
float headScale = (float)attr_.getHeadScale()*0.94386f;
float fixedScale = (float)(headScale*attr_.getHeadFixedSize());
float minSize = (float)attr_.getHeadMinSize();
float maxSize = (float)attr_.getHeadMaxSize();
double angle = attr_.getOffsetAngle()*0.017453293;
float tScale;
float[] xp, yp;
int[] xtail, ytail;
int xdhead, ydhead;
int xdtemp, ydtemp;
float xphead, yphead;
int count, size, nout, idx;
double[] xValues, yValues;
GeoDate[] xTValues, yTValues;
double[] uValues, vValues;
float vx, vy, vclen;
double vdx, vdy;
float hx1, hx2;
float hy1, hy2;
float headX, headY;
float orgX, orgY;
//
// get axes
//
if(vector.isXTime()) {
xTValues = vector.getU().getTimeArray();
size = xTValues.length;
xp = new float[size];
for(count=0; count < size; count++) {
xp[count] = (float)cg_.getXUtoP(xTValues[count]);
}
} else {
xValues = vector.getU().getXArray();
size = xValues.length;
xp = new float[size];
for(count=0; count < size; count++) {
xp[count] = (float)cg_.getXUtoP(xValues[count]);
}
}
//
if(vector.isYTime()) {
yTValues = vector.getU().getTimeArray();
size = yTValues.length;
yp = new float[size];
for(count=0; count < size; count++) {
yp[count] = (float)cg_.getYUtoP(yTValues[count]);
}
} else {
yValues = vector.getU().getYArray();
size = yValues.length;
yp = new float[size];
for(count=0; count < size; count++) {
yp[count] = (float)cg_.getYUtoP(yValues[count]);
}
}
//
// get u & v
//
uValues = vector.getU().getZArray();
vValues = vector.getV().getZArray();
//
xtail = new int[uValues.length];
ytail = new int[uValues.length];
count = 0;
// int nx = xp.length;
int ny = yp.length;
int idx_ny;
for(int i=0; i < xp.length; i++) {
idx_ny = i*ny;
for(int j=0; j < yp.length; j++) {
idx = j + idx_ny;
if(Double.isNaN(uValues[idx]) || Double.isNaN(vValues[idx])) continue;
orgX = xPtoD(xp[i]);
orgY = yPtoD(yp[j]);
xtail[count] = (int)orgX;
ytail[count] = (int)orgY;
vdx = uValues[idx]*scale;
vdy = vValues[idx]*scale;
if(angle != 0.0) {
vx = (float)(vdx*Math.cos(angle)-vdy*Math.sin(angle));
vy = (float)(vdy*Math.cos(angle)+vdx*Math.sin(angle));
} else {
vx = (float)vdx;
vy = (float)vdy;
}
xphead = xp[i] + vx;
yphead = yp[j] + vy;
//
// draw line
//
gp = new GeneralPath();
gp.moveTo(orgX, orgY);
headX = xPtoD(xphead);
headY = yPtoD(yphead);
gp.lineTo(headX, headY);
//
// draw head
//
// if(true) continue;
vclen = (float)Math.sqrt((double)(vx*vx+vy*vy));
if(vclen == 0.0) {
g.drawLine((int)headX, (int)headY, (int)headX, (int)headY);
} else {
if(attr_.getVectorStyle() != VectorAttribute.NO_HEAD) {
if(attr_.getVectorStyle() == VectorAttribute.HEAD) {
// unscaled head
tScale = fixedScale/vclen;
hx1 = xPtoD(xphead + (-vx-0.35f*vy)*tScale);
hy1 = yPtoD(yphead + (-vy+0.35f*vx)*tScale);
hx2 = xPtoD(xphead + (-vx+0.35f*vy)*tScale);
hy2 = yPtoD(yphead + (-vy-0.35f*vx)*tScale);
gp.moveTo(hx1, hy1);
gp.lineTo(headX, headY);
gp.lineTo(hx2, hy2);
} else {
// scaled head
if(vclen >= maxSize) {
tScale = maxSize*headScale/vclen;
} else if(vclen <= minSize) {
tScale = minSize*headScale/vclen;
} else {
tScale = headScale;
}
hx1 = xPtoD(xphead + (-vx-0.35f*vy)*tScale);
hy1 = yPtoD(yphead + (-vy+0.35f*vx)*tScale);
hx2 = xPtoD(xphead + (-vx+0.35f*vy)*tScale);
hy2 = yPtoD(yphead + (-vy-0.35f*vx)*tScale);
gp.moveTo(hx1, hy1);
gp.lineTo(headX, headY);
gp.lineTo(hx2, hy2);
}
}
}
count++;
g2.draw(gp);
}
}
g2.setStroke(savedStroke);
//
// draw mark
//
if(attr_.getOriginStyle() == VectorAttribute.MARK) {
g.setColor(attr_.getMarkColor());
drawMark(g, xtail, ytail, xtail.length, attr_);
}
}
private float xPtoD(float xp) {
return slope_*xp + xoff_;
}
private float yPtoD(float yp) {
return yoff_ - slope_*yp;
}
/**
* Draw a mark at the requested location. This routine is used by
* VectorCartesianGraph and VectorKey.
*
* @param g Graphics object
* @param xp horizontal coordinate
* @param yp vertical coordinate
* @param attr vector attribute
* @see VectorKey
*/
protected void drawMark(VectorGraphics g, int[] xp, int[] yp,
int npoints, VectorAttribute attr) {
Layer ly = cg_.getLayer();
PlotMark pm = new PlotMark(attr.getMark());
pm.setMarkHeightP(attr.getMarkHeightP());
for(int i=0; i < npoints; i++) {
pm.paintMark(g, ly, xp[i], yp[i]);
}
}
/**
* Default constructor.
*
* @see CartesianGraph
* @see Graph
**/
public VectorCartesianRenderer(CartesianGraph cg) {
this(cg, (SGTVector)null, null);
}
/**
* Construct a VectorCartesianRenderer. The default
* VectorAttribute will be used.
*
* @param cg the parent CartesianGraph
* @param data an SGTVector object
*
* @see CartesianGraph
* @see Graph
**/
public VectorCartesianRenderer(CartesianGraph cg, SGTVector vector) {
this(cg, vector, null);
cg_ = cg;
vector_ = vector;
}
/**
* Construct a VectorCartesianRenderer.
*
* @param cg the parent CartesianGraph
* @param vector a SGTVector
* @param attr the VectorAttribute
* @see CartesianGraph
* @see Graph
**/
public VectorCartesianRenderer(CartesianGraph cg,
SGTVector vector,
VectorAttribute attr) {
cg_ = cg;
vector_ = vector;
attr_ = attr;
if(attr_ != null) attr_.addPropertyChangeListener(this);
}
/**
* Construct a VectorCartesianRenderer.
*
* @param cg the parent CartesianGraph
* @param col a Collection of SGTVector objects
* @param attr the VectorAttribute
* @see CartesianGraph
* @see Graph
**/
public VectorCartesianRenderer(CartesianGraph cg, Collection col,
VectorAttribute attr) {
cg_ = cg;
collection_ = col;
attr_ = attr;
if(attr_ != null) attr_.addPropertyChangeListener(this);
}
/**
* Render the SGTData. This method should not
* be directly called.
*
* @param g graphics context
*
* @see Pane#draw
*/
public void draw(VectorGraphics g) {
VectorAttribute attr;
Object vector;
if(cg_.clipping_) {
int xmin, xmax, ymin, ymax;
int x, y, width, height;
if(cg_.xTransform_.isSpace()) {
xmin = cg_.getXUtoD(cg_.xClipRange_.start);
xmax = cg_.getXUtoD(cg_.xClipRange_.end);
} else {
xmin = cg_.getXUtoD(cg_.tClipRange_.start);
xmax = cg_.getXUtoD(cg_.tClipRange_.end);
}
if(cg_.yTransform_.isSpace()) {
ymin = cg_.getYUtoD(cg_.yClipRange_.start);
ymax = cg_.getYUtoD(cg_.yClipRange_.end);
} else {
ymin = cg_.getYUtoD(cg_.tClipRange_.start);
ymax = cg_.getYUtoD(cg_.tClipRange_.end);
}
if(xmin < xmax) {
x = xmin;
width = xmax - xmin;
} else {
x=xmax;
width = xmin - xmax;
}
if(ymin < ymax) {
y = ymin;
height = ymax - ymin;
} else {
y = ymax;
height = ymin - ymax;
}
g.setClip(x, y, width, height);
}
if(attr_ == null) {
attr = new VectorAttribute(1.0,
cg_.getPane().getComponent().getForeground());
} else {
attr = attr_;
}
g.setColor(attr.getVectorColor());
if(collection_ == null) {
drawVector(g, vector_, attr);
} else {
for(Enumeration li = collection_.elements(); li.hasMoreElements();) {
vector = li.nextElement();
if(vector instanceof SGTVector) {
drawVector(g, (SGTVector)vector, attr);
}
}
}
//
// reset clip
//
Rectangle rect = cg_.getLayer().getPane().getBounds();
g.setClip(rect);
}
/**
* Set the VectorAttribute. The line appearance is controlled by
* this object.
*
* @param l VectorAttribute
**/
public void setVectorAttribute(VectorAttribute l) {
if(attr_ != null) attr_.removePropertyChangeListener(this);
attr_ = l;
if(attr_ != null) attr_.addPropertyChangeListener(this);
}
/**
* Get the VectorAttribute.
*
* @return VectorAttribute
**/
public VectorAttribute getVectorAttribute() {
return attr_;
}
/**
* Test if a Collection of SGTVector
* was using to construct this renderer.
*
* @return true if Collection was used
*/
public boolean hasCollection() {
return (collection_ != null);
}
/**
* Get the Collection of SGTVector objects.
*
* @return Collection
*/
public Collection getCollection() {
return collection_;
}
/**
* Get the SGTVector object.
*
* @return SGTVector
*/
public SGTVector getVector(){
return vector_;
}
/**
* Get the associated CartesianGraph object.
*
* @return CartesianGraph
*/
public CartesianGraph getCartesianGraph() {
return cg_;
}
public void propertyChange(PropertyChangeEvent evt) {
// if(Debug.EVENT) {
// System.out.println("VectorCartesianRenderer: " + evt);
// System.out.println(" " + evt.getPropertyName());
// }
modified("VectorCartesianRenderer: propertyChange(" +
evt.getSource().toString() + "[" +
evt.getPropertyName() + "]" + ")");
}
public SGTData getDataAt(Point pt) {
return null;
}
}
Ads help maintain this website.