/*
 * $Id: VectorKey.java,v 1.14 2003/08/22 23:02:32 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.util.Vector;
import java.util.Enumeration;
import java.awt.Graphics;
import java.awt.Stroke;
import java.awt.BasicStroke;
import java.awt.geom.GeneralPath;
import java.awt.Rectangle;
import java.awt.Point;
import java.text.DecimalFormat;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeSupport;

import org.freehep.graphics2d.VectorGraphics;

import sgtplot.util.Debug;
import sgtplot.util.Point2D;
import sgtplot.util.Rectangle2D;

/**
 * VectorKey is used to create a key for the
 * VectorCartesianRenderer. Multiple
 * lines can be included in the key.
 *
 * @author Donald Denbo
 * @version $Revision: 1.14 $, $Date: 2003/08/22 23:02:32 $
 * @since 2.1
**/
public class VectorKey implements Cloneable,
    DataKey, Moveable, PropertyChangeListener {
  private String ident_;
  /** @directed */
  private Layer layer_;
  /** @link aggregation
   * @supplierCardinality *
   * @label vectors*/
  /*#VectorCartesianRenderer lnkVectorCartesianRenderer; */
  private Vector vectors_;
  /**
     *@link aggregation
     *     @associates <{SGLabel}>
     * @label label
     * @supplierCardinality *
     * @undirected
     */
  /* private Vector lnkSGLabel; */
  private Vector label_;
  private Vector scaleLabel_;
  private int columns_;
  private int style_;
  private int valign_;
  private int halign_;
  private Point2D.Double porigin_;
  private double vectorLengthP_;
  private int maxLabelLength_;
  private int maxLabelHeight_;
  private int maxScaleLength_;
  private String floatScaleFormat_ = "###.##";
  private String expScaleFormat_ = "0.####E0";
  private DecimalFormat floatFormat_;
  private DecimalFormat expFormat_;
  private float xoff_;
  private float yoff_;
  private float slope_;
  private boolean selected_;
  private boolean selectable_;
  private boolean visible_;
  private boolean moveable_;
  private PropertyChangeSupport changes_ = new PropertyChangeSupport(this);
  private static final int VERTICAL_BORDER_ = 3;
  private static final int HORIZONTAL_BORDER_ = 15;
  private static final int COLUMN_SPACE_ = 10;
  private static final int ROW_SPACE_ = 3;
  private static final int LABEL_SPACE_ = 10;
  private static final int SCALE_SPACE_ = 7;
  /**
   * Use plain line border.
   */
  public static final int PLAIN_LINE = 0;
  /**
   * Use raised border.
   */
  public static final int RAISED = 1;
  /**
   * Do not draw a border.
   */
  public static final int NO_BORDER = 2;
  /**
   * Align to top of key.
   */
  public static final int TOP = 0;
  /**
   * Align to middle of key.
   */
  public static final int MIDDLE = 1;
  /**
   * Align to bottom of key.
   */
  public static final int BOTTOM = 2;
  /**
   * Align to left of key.
   */
  public static final int LEFT = 0;
  /**
   * Align to center of key.
   */
  public static final int CENTER = 1;
  /**
   * Align to right of key.
   */
  public static final int RIGHT = 2;


  /**
   * Default constructor.
   */
  public VectorKey() {
    this(new Point2D.Double(0.0, 0.0), BOTTOM, LEFT);
  }
  /**
   * Create VectorKey.
   */
  public VectorKey(Point2D.Double loc,int valign,int halign) {
    porigin_ = loc;
    valign_ = valign;
    halign_ = halign;
    vectors_ = new Vector(2,2);
    label_ = new Vector(2,2);
    scaleLabel_ = new Vector(2,2);
    //
    // set defaults
    //
    style_ = PLAIN_LINE;
    columns_ = 1;
    ident_ = "";
    vectorLengthP_ = 0.3f;
    selected_ = false;
    selectable_ = true;
    visible_ = true;
    moveable_ = true;

    floatFormat_ = new DecimalFormat(floatScaleFormat_);
    expFormat_ = new DecimalFormat(expScaleFormat_);
  }
  /**
   * Create of copy of VectorKey.
   */
  public LayerChild copy() {
    VectorKey newKey;
    try {
      newKey = (VectorKey)clone();
    } catch (CloneNotSupportedException e) {
      newKey = new VectorKey();
    }
    newKey.vectors_ = new Vector(2,2);
    newKey.label_ = new Vector(2,2);
    return newKey;
  }
  public void setSelected(boolean sel) {
    selected_ = sel;
  }
  public boolean isSelected() {
    return selected_;
  }
  public void setSelectable(boolean select) {
    selectable_ = select;
  }
  public boolean isSelectable() {
    return selectable_;
  }
  public boolean isMoveable() {
    return moveable_;
  }
  public void setMoveable(boolean moveable) {
    moveable_ = moveable;
  }
  /**
   * Set parent layer.
   *
   * @param l parent layer
   */
  public void setLayer(Layer l) {
    layer_ = l;
  }
  /**
   * Get layer.
   *
   * @return layer
   */
  public Layer getLayer() {
    return layer_;
  }

  public AbstractPane getPane() {
    return layer_.getPane();
  }

  public void modified(String mess) {
    if(layer_ != null)
      layer_.modified(mess);
  }
  /**
   * Set VectorKey identifier.
   *
   * @param id key identifier
   */
  public void setId(String id) {
    ident_ = id;
  }
  /**
   * Get VectorKey identifier
   *
   * @return identifier
   */
  public String getId() {
    return ident_;
  }
  /**
   * Set line length.
   *
   * @param len line length
   */
  public void setVectorLengthP(double len) {
    if(vectorLengthP_ != len) {
      vectorLengthP_ = len;
      modified("VectorKey: setVectorLengthP()");
    }
  }
  /**
   * @since 3.0
   */
  public void setLineLengthP(double len) {
    setVectorLengthP(len);
  }
  /**
   * Get line length
   *
   * @return line length
   */
  public double getVectorLengthP() {
    return vectorLengthP_;
  }
  /**
   * Set the number of columns.
   *
   * @param col number of columns
   */
  public void setColumns(int col) {
    if(columns_ != col) {
      columns_ = col;
      modified("VectorKey: setColumms()");
    }
  }
  /**
   * Get the number of columns.
   *
   * @return number of columns
   */
  public int getColumns() {
    return columns_;
  }
  /**
   * Set border style.
   *
   * @param style border style
   * @see #PLAIN_LINE
   * @see #RAISED
   * @see #NO_BORDER
   */
  public void setBorderStyle(int style) {
    if(style_ != style) {
      style_ = style;
      modified("VectorKey: setBorderStyle()");
    }
  }
  /**
   * Get border style.
   *
   * @return border style
   */
  public int getBorderStyle() {
    return style_;
  }
  /**
   * Set alignment.
   *
   * @param vert vertical alignment
   * @param horz horizontal alignment
   */
  public void setAlign(int vert,int horz) {
    if(valign_ != vert || halign_ != horz) {
      valign_ = vert;
      halign_ = horz;
      modified("VectorKey: setAlign()");
    }
  }
  /**
   * Set vertical alignment
   *
   * @param vert vertical alignment
   */
  public void setVAlign(int vert) {
    if(valign_ != vert) {
      valign_ = vert;
      modified("VectorKey: setVAlign()");
    }
  }
  /**
   * Set horizontal alignment
   *
   * @param horz horizontal alignment
   */
  public void setHAlign(int horz) {
    if(halign_ != horz) {
      halign_ = horz;
      modified("VectorKey: setHAlign()");
    }
  }
  /**
   * Get vertical alignment
   *
   * @return vertical alignment
   */
  public int getVAlign() {
    return valign_;
  }
  /**
   * Get horizontal alignment
   *
   * @return horizontal alignment
   */
  public int getHAlign() {
    return halign_;
  }
  /**
   * Set location of key
   * 
Property Change: location. * * @param loc key location */ public void setLocationP(Point2D.Double loc) { if(porigin_ == null || !porigin_.equals(loc)) { Point2D.Double temp = porigin_; porigin_ = loc; changes_.firePropertyChange("location", temp, porigin_); modified("VectorKey: setLocationP()"); } } /** * Set the bounds, in physical units, of the VectorKey */ public void setBoundsP(Rectangle2D.Double r) { setLocationP(new Point2D.Double(r.x, r.y)); } public Rectangle2D.Double getBoundsP() { throw new MethodNotImplementedError(); } /** * Get location of key. * * @return Key location */ public Point2D.Double getLocationP() { return porigin_; } /** * Add a VectorCartesianRenderer and label to the VectorKey. * * @param line VectorCartesianRenderer object * @param label descriptive label */ public void addVectorGraph(VectorCartesianRenderer vector, SGLabel label) { vectors_.addElement(vector); label.setLayer(layer_); label.setMoveable(false); label.setSelectable(false); label_.addElement(label); SGLabel scale = new SGLabel("scale label", " ", label.getHeightP(), label.getLocationP(), label.getVAlign(), label.getHAlign()); scale.setFont(label.getFont()); scale.setLayer(label.getLayer()); scale.setMoveable(false); scale.setSelectable(false); scaleLabel_.addElement(scale); ((VectorAttribute)vector.getAttribute()).addPropertyChangeListener(this); modified("VectorKey: addVectorGraph()"); } /** * Add a VectorCartesianRenderer and label to the VectorKey. * * @param rend CartesianRenderer object * @param label descriptive label * @since 3.0 */ public void addGraph(CartesianRenderer rend, SGLabel label) throws IllegalArgumentException { if(!(rend instanceof VectorCartesianRenderer)) throw new IllegalArgumentException("Renderer is not a VectorCartesianRenderer"); addVectorGraph((VectorCartesianRenderer)rend, label); } /** * Remove a line from the VectorKey. * */ public void removeVectorGraph(SGLabel label) { } /** * Remove a line from the VectorKey. * */ public void removeVectorRenderer(VectorCartesianRenderer line) { } /** * Remove a line from the VectorKey. * */ public void removeVectorGraph(String ident) { } /** * Remove all lines from the VectorKey. */ public void clearAll() { VectorAttribute attr; for(Enumeration e = vectors_.elements(); e.hasMoreElements(); ) { attr = (VectorAttribute)((VectorCartesianRenderer)e.nextElement()).getAttribute(); attr.removePropertyChangeListener(this); } vectors_.removeAllElements(); label_.removeAllElements(); modified("VectorKey: clearAll()"); } /** * Remove data from key by id. */ public void clear(String data_id) { VectorCartesianRenderer vcr; int indx = -1; for(Enumeration it = vectors_.elements(); it.hasMoreElements();) { indx++; vcr = (VectorCartesianRenderer)it.nextElement(); // if(pcr.getLine().getId().equals(data_id)) { // pcr.getAttribute().removePropertyChangeListener(this); // points_.removeElement(lcr); // label_.removeElementAt(indx); // modified("VectorKey: clear()"); // break; // } } } /** * Return height of key row in pixels. */ public int getRowHeight() { Rectangle bounds; bounds = getBounds(); return ROW_SPACE_ + maxLabelHeight_; } /** * Draw the Key. */ public void draw(VectorGraphics g) { double maxLabelLength, maxLabelHeight; int numLines, numRows, i; float vectorLength; float vectorLengthU; int col, row, ytemp; double xloc, labelSpace, scaleSpace, scaleLength; double[] xp, yp; int[] xd, yd; int[] xout, yout; float hx1, hx2; float hy1, hy2; float headX, headY; float orgX, orgY; float xphead, yphead; float tScale, fixedScale; float scale; float headScale; float minSize; float maxSize; Rectangle bounds; VectorCartesianRenderer render = null; SGLabel label; SGLabel scaleLabel; String scaleStr; VectorAttribute attr = null; VectorGraphics g2 = VectorGraphics.create(g); GeneralPath gp; Stroke savedStroke = g2.getStroke(); BasicStroke stroke; slope_ = (float)layer_.getXSlope(); xoff_ = (float)layer_.getXOffset(); yoff_ = (float)layer_.getYOffset(); // numLines = vectors_.size(); if((numLines <= 0) || !visible_) return; numRows = numLines/columns_; if(numLines%columns_ != 0) numRows++; xp = new double[columns_]; xd = new int[columns_]; yp = new double[numRows]; yd = new int[numRows]; xout = new int[2]; yout = new int[2]; g.setColor(layer_.getPane().getComponent().getForeground()); bounds = getBounds(); // // compute location of rows and columns in device and physical coordinates // vectorLength = xPtoD((float)vectorLengthP_) - xPtoD(0.0f); labelSpace = layer_.getXDtoP(LABEL_SPACE_) - layer_.getXDtoP(0); scaleLength = layer_.getXDtoP(maxScaleLength_) - layer_.getXDtoP(0); scaleSpace = layer_.getXDtoP(SCALE_SPACE_) - layer_.getXDtoP(0); // yd[0] = bounds.y + VERTICAL_BORDER_ + maxLabelHeight_; yp[0] = layer_.getYDtoP(yd[0]); for(i=1; i < numRows; i++) { yd[i] = yd[i-1] + ROW_SPACE_ + maxLabelHeight_; yp[i] = layer_.getYDtoP(yd[i]); } xd[0] = bounds.x + HORIZONTAL_BORDER_; xp[0] = layer_.getXDtoP(xd[0]); for(i=1; i < columns_; i++) { xd[i] = xd[i-1] + COLUMN_SPACE_ + (int)vectorLength + SCALE_SPACE_ + maxScaleLength_ + LABEL_SPACE_ + maxLabelLength_; xp[i] = layer_.getXDtoP(xd[i]); } // row = 0; col = 0; Object obj; Enumeration labelIt = label_.elements(); Enumeration scaleIt = scaleLabel_.elements(); for(Enumeration lineIt = vectors_.elements(); lineIt.hasMoreElements();) { obj = lineIt.nextElement(); render = (VectorCartesianRenderer)obj; attr = (VectorAttribute)render.getAttribute(); label = (SGLabel)labelIt.nextElement(); scaleLabel = (SGLabel)scaleIt.nextElement(); // // draw line // g2.setColor(attr.getVectorColor()); stroke = new BasicStroke(attr.getWidth(), attr.getCapStyle(), attr.getMiterStyle(), attr.getMiterLimit()); scale = (float)attr.getVectorScale(); headScale = (float)attr.getHeadScale()*0.94386f; fixedScale = (float)(headScale*attr.getHeadFixedSize()); minSize = (float)attr.getHeadMinSize(); maxSize = (float)attr.getHeadMaxSize(); vectorLengthU = (float)(vectorLengthP_/scale); g2.setStroke(stroke); gp = new GeneralPath(); orgX = (float)xd[col]; orgY = (float)(yd[row] - maxLabelHeight_/2); headX = orgX + vectorLength; headY = orgY; xphead = xDtoP(headX); yphead = yDtoP(headY); gp.moveTo(orgX, orgY); gp.lineTo(headX, headY); // // add head // if(vectorLength == 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; hx1 = xPtoD(xphead - tScale); hy1 = yPtoD(yphead + 0.35f*tScale); hx2 = xPtoD(xphead - tScale); hy2 = yPtoD(yphead - 0.35f*tScale); gp.moveTo(hx1, hy1); gp.lineTo(headX, headY); gp.lineTo(hx2, hy2); } else { // scaled head if(vectorLengthP_ >= maxSize) { tScale = maxSize*headScale; } else if(vectorLengthP_ <= minSize) { tScale = minSize*headScale; } else { tScale = (float)(vectorLengthP_*headScale); } hx1 = xPtoD(xphead - tScale); hy1 = yPtoD(yphead + 0.35f*tScale); hx2 = xPtoD(xphead - tScale); hy2 = yPtoD(yphead - 0.35f*tScale); gp.moveTo(hx1, hy1); gp.lineTo(headX, headY); gp.lineTo(hx2, hy2); } } } g2.draw(gp); g2.setStroke(savedStroke); // // draw mark // xout[0] = (int)orgX; yout[0] = (int)orgY; if(attr.getOriginStyle() == VectorAttribute.MARK) { g.setColor(attr.getMarkColor()); render.drawMark(g, xout, yout, 1, attr); } // // scale label // xloc = xp[col] + vectorLengthP_ + scaleSpace; if(vectorLengthU > 1000.0 || vectorLengthU < 0.01) { scaleStr = expFormat_.format(vectorLengthU); } else { scaleStr = floatFormat_.format(vectorLengthU); } scaleLabel.setText(scaleStr); scaleLabel.setLocationP(new Point2D.Double(xloc, yp[row])); // // user label // xloc = xloc + scaleLength + labelSpace; label.setLocationP(new Point2D.Double(xloc, yp[row])); try { scaleLabel.draw(g); label.draw(g); } catch (SGException e) { System.out.println(e);} // col++; if(col >= columns_) { col = 0; row++; } } switch(style_) { case PLAIN_LINE: g.drawRect(bounds.x, bounds.y, bounds.width-1, bounds.height-1); break; case RAISED: break; default: case NO_BORDER: } } private float xPtoD(float xp) { return slope_*xp + xoff_; } private float yPtoD(float yp) { return yoff_ - slope_*yp; } private float xDtoP(float xd) { return (xd - xoff_)/slope_; } private float yDtoP(float yd) { return (yoff_ - yd)/slope_; } /** * Get the bounding rectangle. * * @return bounding rectangle */ public Rectangle getBounds() { int vectorLength; int numLines, rows; int x, y, height, width; numLines = vectors_.size(); if(numLines <= 0) return new Rectangle(0, 0, 0, 0); // // find longest label and scale // maxLabelLength_ = 0; maxLabelHeight_ = 0; maxScaleLength_ = 0; Object obj; VectorCartesianRenderer render; VectorAttribute attr; double vectorLengthU; Enumeration lineIt = vectors_.elements(); Enumeration scaleIt = scaleLabel_.elements(); SGLabel label; String scaleStr; SGLabel scaleLabel; for(Enumeration it = label_.elements(); it.hasMoreElements();) { label = (SGLabel)it.nextElement(); Rectangle sz = label.getBounds(); maxLabelLength_ = Math.max(maxLabelLength_, sz.width); maxLabelHeight_ = Math.max(maxLabelHeight_, sz.height); // obj = lineIt.nextElement(); render = (VectorCartesianRenderer)obj; attr = (VectorAttribute)render.getAttribute(); vectorLengthU = vectorLengthP_/attr.getVectorScale(); if(vectorLengthU > 1000.0 || vectorLengthU < 0.01) { scaleStr = expFormat_.format(vectorLengthU); } else { scaleStr = floatFormat_.format(vectorLengthU); } scaleLabel = (SGLabel)scaleIt.nextElement(); scaleLabel.setText(scaleStr); sz = scaleLabel.getBounds(); maxScaleLength_ = Math.max(maxScaleLength_, sz.width); } // rows = numLines/columns_; if(numLines%columns_ != 0) rows++; vectorLength = layer_.getXPtoD(vectorLengthP_) - layer_.getXPtoD(0.0f); width = 2*HORIZONTAL_BORDER_ + columns_*(vectorLength + SCALE_SPACE_ + maxScaleLength_ + LABEL_SPACE_ + maxLabelLength_) + (columns_ - 1)*COLUMN_SPACE_; height = 2*VERTICAL_BORDER_ + rows*maxLabelHeight_ + (rows-1)*ROW_SPACE_; // temp fudge height = height + 5; // x = layer_.getXPtoD(porigin_.x); y = layer_.getYPtoD(porigin_.y); switch(halign_) { case RIGHT: x = x - width; break; case CENTER: x = x - width/2; } switch(valign_) { case BOTTOM: y = y - height; break; case MIDDLE: y = y - height/2; } return new Rectangle(x, y, width, height); } public Point getLocation() { Rectangle bnds = getBounds(); return new Point(bnds.x, bnds.y); } public void setLocation(Point loc) { Rectangle bnds = getBounds(); setBounds(loc.x, loc.y, bnds.width, bnds.height); } /** * Set the bounds, in pixels, of the VectorKey */ public void setBounds(Rectangle r) { setBounds(r.x, r.y, r.width, r.height); } /** * Set the bounds, in pixels, of the VectorKey *
Property Change: location. */ public void setBounds(int x, int y, int width, int height) { switch(halign_) { case RIGHT: x = x + width; break; case CENTER: x = x + width/2; } switch(valign_) { case BOTTOM: y = y + height; break; case MIDDLE: y = y + height/2; } double xp = layer_.getXDtoP(x); double yp = layer_.getYDtoP(y); if(porigin_.x != xp || porigin_.y != yp) { Point2D.Double temp = porigin_; porigin_.x = xp; porigin_.y = yp; changes_.firePropertyChange("location", temp, new Point2D.Double(xp, yp)); modified("VectorKey: setBounds()"); } } Object getObjectAt(Point pt) { Rectangle lbnds; Rectangle bounds; VectorCartesianRenderer vector; int[] xout, yout; int[] xd, yd; int numLines, numRows; int vectorLength; double labelSpace, scaleSpace; int i; numLines = vectors_.size(); if(numLines <= 0) return null; numRows = numLines/columns_; if(numLines%columns_ != 0) numRows++; xd = new int[columns_]; yd = new int[numRows]; xout = new int[2]; yout = new int[2]; bounds = getBounds(); // // compute location of rows and columns in device and physical coordinates // vectorLength = layer_.getXPtoD(vectorLengthP_) - layer_.getXPtoD(0.0); labelSpace = layer_.getXDtoP(LABEL_SPACE_) - layer_.getXDtoP(0); scaleSpace = layer_.getXDtoP(SCALE_SPACE_) - layer_.getXDtoP(0); // yd[0] = bounds.y + VERTICAL_BORDER_ + maxLabelHeight_; for(i=1; i < numRows; i++) { yd[i] = yd[i-1] + ROW_SPACE_ + maxLabelHeight_; } xd[0] = bounds.x + HORIZONTAL_BORDER_; for(i=1; i < columns_; i++) { xd[i] = xd[i-1] + COLUMN_SPACE_ + vectorLength + SCALE_SPACE_ + maxScaleLength_ + LABEL_SPACE_ + maxLabelLength_; } // loop over all the lines int row = 0; int col = 0; for(Enumeration lineIt = vectors_.elements(); lineIt.hasMoreElements();) { vector = (VectorCartesianRenderer)lineIt.nextElement(); xout[0] = xd[col]; // xout[1] = xout[0] + vectorLength + 2*LABEL_SPACE_ + // maxScaleLenght_ + maxLabelLength_; xout[1] = xout[0] + vectorLength + SCALE_SPACE_; yout[0] = yd[row] - maxLabelHeight_; yout[1] = yd[row]; lbnds = new Rectangle(xout[0], yout[0], xout[1] - xout[0], yout[1] - yout[0]); if(lbnds.contains(pt)) { return vector; } // col++; if(col >= columns_) { col = 0; row++; } } if(bounds.contains(pt)) { return this; } return null; } public String toString() { String name = getClass().getName(); return name.substring(name.lastIndexOf(".")+1) + ": " + ident_; } public boolean isVisible() { return visible_; } public void setVisible(boolean visible) { if(visible_ != visible) { visible_ = visible; modified("VectorKey: setVisible()"); } } public void propertyChange(PropertyChangeEvent evt) { // if(Debug.EVENT) { // System.out.println("VectorKey: " + evt); // System.out.println(" " + evt.getPropertyName()); // } modified("VectorKey: propertyChange(" + evt.getSource().toString() + "[" + evt.getPropertyName() + "]" + ")"); } public void addPropertyChangeListener(PropertyChangeListener l) { changes_.addPropertyChangeListener(l); } public void removePropertyChangeListener(PropertyChangeListener l) { changes_.removePropertyChangeListener(l); } }

Ads help maintain this website.