/*
 * $Id: GridCartesianRenderer.java,v 1.30 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.awt.Graphics;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Font;
import java.awt.Point;
import java.awt.FontMetrics;
import java.util.Enumeration;
import java.beans.PropertyChangeEvent;

import org.freehep.graphics2d.VectorGraphics;

import sgtplot.contour.Contour;
import sgtplot.contour.ContourLine;
import sgtplot.dm.SGTData;
import sgtplot.dm.SGTGrid;
import sgtplot.util.Debug;
import sgtplot.util.GeoDate;
import sgtplot.util.Point2D;
import sgtplot.util.Range2D;

/**
 * Produces a cartesian plot from a SGTGrid object.
 *
 * @author Donald Denbo
 * @version $Revision: 1.30 $, $Date: 2003/08/22 23:02:32 $
 * @since 1.0
 */
public class GridCartesianRenderer extends CartesianRenderer {
  /**@shapeType AggregationLink
   * @label grid
   * @undirected
   * @supplierCardinality 1*/
  private SGTGrid grid_;
  /**@shapeType AggregationLink
   * @label attr
   * @undirected
   * @supplierCardinality 1*/
  private GridAttribute attr_ = null;

  /**
   * @link aggregationByValue
   * @supplierCardinality 1
   * @label con
   */
  private Contour con_ = null;
  //
  private void drawRaster(VectorGraphics g) {
    int nT, nX, nY, nZ;
    int[] xp, yp;
    int i, j;
    Color color;
    int xSize, ySize, count;
    double[] xValues, yValues, gValues;
    double val;
    GeoDate[] tValues;
    //
    if(grid_.isXTime()) {
      if(grid_.getTimeArray().length <= 2) return;
      if(grid_.hasXEdges()) {
        tValues = grid_.getTimeEdges();
        xSize = tValues.length;
        xp = new int[xSize];
        for(count=0; count < xSize; count++) {
          xp[count] = cg_.getXUtoD(tValues[count]);
        }
      } else {
        tValues = grid_.getTimeArray();
        xSize = tValues.length;
        xp = new int[xSize+1];
        xp[0] = cg_.getXUtoD(tValues[0].subtract(
                            (tValues[1].subtract(tValues[0])).divide(2.0)));
        for(count=1; count < xSize; count++) {
          xp[count] = cg_.getXUtoD(
                    (tValues[count-1].add(tValues[count])).divide(2.0));
        }
        xp[xSize] = cg_.getXUtoD(tValues[xSize-1].add(
                    (tValues[xSize-1].subtract(tValues[xSize-2])).divide(2.0)));
      }
    } else {
      if(grid_.getXArray().length <= 2) return;
      if(grid_.hasXEdges()) {
        xValues = grid_.getXEdges();
        xSize = xValues.length;
        xp = new int[xSize];
        for(count=0; count < xSize; count++) {
          xp[count] = cg_.getXUtoD(xValues[count]);
        }
      } else {
        xValues = grid_.getXArray();
        xSize = xValues.length;
        xp = new int[xSize+1];
        xp[0] = cg_.getXUtoD(xValues[0]-(xValues[1]-xValues[0])*0.5);
        for(count=1; count < xSize; count++) {
          xp[count] = cg_.getXUtoD((xValues[count-1]+xValues[count])*0.5);
        }
        xp[xSize] = cg_.getXUtoD(xValues[xSize-1]+
                                 (xValues[xSize-1]-xValues[xSize-2])*0.5);
      }
    }
    if(grid_.isYTime()) {
      if(grid_.getTimeArray().length <= 2) return;
      if(grid_.hasYEdges()) {
        tValues = grid_.getTimeEdges();
        ySize = tValues.length;
        yp = new int[ySize];
        for(count=0; count < ySize; count++) {
          yp[count] = cg_.getYUtoD(tValues[count]);
        }
      } else {
        tValues = grid_.getTimeArray();
        ySize = tValues.length;
        yp = new int[ySize+1];
        yp[0] = cg_.getYUtoD(tValues[0].subtract(
                          (tValues[1].subtract(tValues[0])).divide(2.0)));
        for(count=1; count < ySize; count++) {
          yp[count] = cg_.getYUtoD((tValues[count-1].add(
                               tValues[count])).divide(2.0));
        }
        yp[ySize] = cg_.getYUtoD(tValues[ySize-1].add(
                     (tValues[ySize-1].subtract(tValues[ySize-2])).divide(2.0)));
      }
    } else {
      if(grid_.getYArray().length <= 2) return;
      if(grid_.hasYEdges()) {
        yValues = grid_.getYEdges();
        ySize = yValues.length;
        yp = new int[ySize];
        for(count=0; count < ySize; count++) {
          yp[count] = cg_.getYUtoD(yValues[count]);
        }
      } else {
        yValues = grid_.getYArray();
        ySize = yValues.length;
        yp = new int[ySize+1];
        yp[0] = cg_.getYUtoD(yValues[0]-(yValues[1]-yValues[0])*0.5);
        for(count=1; count < ySize; count++) {
          yp[count] = cg_.getYUtoD((yValues[count-1]+yValues[count])*0.5);
        }
        yp[ySize] = cg_.getYUtoD(yValues[ySize-1]+
                                 (yValues[ySize-1]-yValues[ySize-2])*0.5);
      }
    }
    //
    // draw raster
    //
    gValues = grid_.getZArray();
    count=0;
    for(i=0; i < xSize; i++) {
      for(j=0; j < ySize; j++) {
        val = gValues[count];
        if(!Double.isNaN(val)) {
          color = attr_.getColorMap().getColor(val);
          g.setColor(color);
          drawRect(g, xp[i], yp[j], xp[i+1], yp[j+1]);
        }
        count++;
      }
    }
  }
  /**
   * Get the Attribute associated with
   * the SGTGrid data.
   *
   * @return Attribute
   */
  public Attribute getAttribute() {
    return attr_;
  }
  /**
   * Set the GridAttribute for the renderer.
   * @since 2.0
   */
  public void setAttribute(GridAttribute attr) {
    if(attr_ != null) attr_.removePropertyChangeListener(this);
    attr_ = attr;
    attr_.addPropertyChangeListener(this);
  }
  private void drawRect(VectorGraphics g,int x1,int y1,int x2,int y2) {
    int x, y, width, height;
    if(x1 < x2) {
      x = x1;
      width = x2 - x1;
    } else {
      x=x2;
      width = x1 - x2;
    }
    if(y1 < y2) {
      y = y1;
      height = y2 - y1;
    } else {
      y = y2;
      height = y1 - y2;
    }
    g.fillRect(x, y, width, height);
  }
  /**
   * Default constructor. The GridCartesianRenderer should
   * be created using the CartesianRenderer.getRenderer
   * method.
   *
   * @see CartesianRenderer#getRenderer
   * @see Graph
   **/
  public GridCartesianRenderer(CartesianGraph cg) {
    this(cg, null, null);
  }
  /**
   * Construct a GridCartesianRenderer.
   * The GridCartesianRenderer should
   * be created using the CartesianRenderer.getRenderer
   * method.
   *
   * @see CartesianRenderer#getRenderer
   * @see Graph
   **/
  public GridCartesianRenderer(CartesianGraph cg, SGTGrid data) {
    this(cg, data, null);
  }
  /**
   * Construct a GridCartesianRenderer.
   * The GridCartesianRenderer should
   * be created using the CartesianRenderer.getRenderer
   * method.
   *
   * @see CartesianRenderer#getRenderer
   * @see Graph
   **/
  public GridCartesianRenderer(CartesianGraph cg, SGTGrid grid, GridAttribute attr) {
    cg_ = cg;
    grid_ = grid;
    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) {
    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_.isRaster()) {
      drawRaster(g);
    }
    if(attr_.isAreaFill()) {
      //
      // This is a temporary method based on the
      // PPLUS area fill algorthim
      //
      // To be replaced by a area fill method that
      // uses the ContourLines
      //
      double[] x = xArrayP();
      double[] y = yArrayP();
      double[] z = grid_.getZArray();
      int i,j;
      int nx = x.length;
      int ny = y.length;
      double[] xt = new double[5];
      double[] yt = new double[5];
      double[] zt = new double[5];
      for(i=0; i < nx-1; i++) {
        for(j=0; j < ny-1; j++) {
          xt[0] = x[i];
          yt[0] = y[j];
          zt[0] = z[j + i*ny];
          //
          xt[1] = x[i+1];
          yt[1] = y[j];
          zt[1] = z[j + (i+1)*ny];
          //
          xt[2] = x[i+1];
          yt[2] = y[j+1];
          zt[2] = z[j+1 + (i+1)*ny];
          //
          xt[3] = xt[0];
          yt[3] = yt[2];
          zt[3] = z[j+1 + i*ny];
          //
          // repeat first point
          //
          xt[4] = xt[0];
          yt[4] = yt[0];
          zt[4] = zt[0];
          //
          fillSquare(g, xt, yt, zt);
        }
      }
    }
    if(attr_.isContour()) {
      double val;
      String label;
      Range2D range = computeRange(10);
      Format format;
      //	con_ = new Contour(cg_, grid_, range);
      con_ = new Contour(cg_, grid_, attr_.getContourLevels());
      ContourLevels clevels = con_.getContourLevels();
      DefaultContourLineAttribute attr;
      //
      // set labels
      //
      for(int i=0; i < clevels.size(); i++) {
        try {
          val = clevels.getLevel(i);
          attr = clevels.getDefaultContourLineAttribute(i);
          if(attr.isAutoLabel()) {
            if(attr.getLabelFormat().length() <= 0) {
              format  = new Format(Format.computeFormat(range.start,
                                                        range.end,
                                                        attr.getSignificantDigits()));
            } else {
              format = new Format(attr.getLabelFormat());
            }
            label = format.form(val);
            attr.setLabelText(label);
          }
        } catch (ContourLevelNotFoundException e) {
          System.out.println(e);
        }
      }
      con_.generateContourLines();
      con_.generateContourLabels(g);
      Enumeration elem = con_.elements();
      ContourLine cl;
      while(elem.hasMoreElements()) {
        cl = (ContourLine)elem.nextElement();
        if(Debug.CONTOUR) {
          System.out.println(" level = " + cl.getLevel() +
                             ", length = " + cl.getKmax() +
                             ", closed = " + cl.isClosed());
        }
        cl.draw(g);
      }
    }
    //
    // reset clip
    //
    Rectangle rect = cg_.getLayer().getPane().getBounds();
    g.setClip(rect);
  }

  private void fillSquare(VectorGraphics g, double[] x,
                          double[] y, double[] z) {
    ContourLevels clevels = attr_.getContourLevels();
    IndexedColor cmap = (IndexedColor)attr_.getColorMap();
    int i,j,cindex, npoly, maxindex;
    double zlev, zlevp1, f;
    Color col;
    double[] xpoly = new double[20];
    double[] ypoly = new double[20];
    double zmin = Math.min(z[0], z[1]);
    double zmax = Math.max(z[0], z[1]);
    for(i=2; i <= 3; i++) {
      zmin = Math.min(zmin, z[i]);
      zmax = Math.max(zmax, z[i]);
    }
    if(Double.isNaN(zmax)) return;
    maxindex = clevels.getMaximumIndex();
    for(cindex=-1; cindex <= maxindex; cindex++) {
      try {
        if(cindex == -1) {
          zlev = -Double.MAX_VALUE;
        } else {
          zlev = clevels.getLevel(cindex);
        }
        if(cindex == maxindex) {
          zlevp1 = Double.MAX_VALUE;
        } else {
          zlevp1 = clevels.getLevel(cindex+1);
        }
      } catch (ContourLevelNotFoundException e) {
        System.out.println(e);
        break;
      }
      col = cmap.getColorByIndex(cindex+1);
      if(zmin > zlevp1 || zmax < zlev) continue;
      if(zmin >= zlev && zmax <= zlevp1) {
        fillPolygon(g, col, x, y, 4);
        return;
      }
      npoly = -1;
      for(j=0; j < 4; j++) {  /* sides */
        if(z[j] < zlev) {
          //
          // z[j] is below
          //
          if(z[j+1] > zlevp1) {
            //
            // z[j+1] is above
            //
            npoly=npoly+1;
            f = (z[j]-zlev)/(z[j]-z[j+1]);
            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
            //
            npoly=npoly+1;
            f = (z[j]-zlevp1)/(z[j]-z[j+1]);
            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
          } else if(z[j+1] >= zlev &&
                    z[j+1] <= zlevp1) {
            //
            // z[j+1] is inside
            //
            npoly=npoly+1;
            f = (z[j]-zlev)/(z[j]-z[j+1]);
            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
            //
            npoly=npoly+1;
            xpoly[npoly] = x[j+1];
            ypoly[npoly] = y[j+1];
          }
        } else if(z[j] > zlevp1) {
          //
          // z[j] is above
          //
          if(z[j+1] < zlev) {
            //
            // z[j+1] is below
            //
            npoly=npoly+1;
            f = (z[j]-zlevp1)/(z[j]-z[j+1]);
            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
            //
            npoly=npoly+1;
            f = (z[j]-zlev)/(z[j]-z[j+1]);
            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
          } else if(z[j+1] >= zlev && z[j+1] <= zlevp1) {
            //
            // z[j+1] is inside
            //
            npoly=npoly+1;
            f = (z[j]-zlevp1)/(z[j]-z[j+1]);
            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
            //
            npoly=npoly+1;
            xpoly[npoly] = x[j+1];
            ypoly[npoly] = y[j+1];
          }
        } else {
          //
          // x[j] is inside
          //
          if(z[j+1] > zlevp1) {
            //
            // z[j+1] is above
            //
            npoly=npoly+1;
            f = (z[j]-zlevp1)/(z[j]-z[j+1]);
            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
          } else if(z[j+1] < zlev) {
            //
            // z[j+1] is below
            //
            npoly=npoly+1;
            f = (z[j]-zlev)/(z[j]-z[j+1]);
            xpoly[npoly] = x[j] - f*(x[j]-x[j+1]);
            ypoly[npoly] = y[j] - f*(y[j]-y[j+1]);
          } else {
            //
            // z[j+1] is inside
            //
            npoly=npoly+1;
            xpoly[npoly] = x[j+1];
            ypoly[npoly] = y[j+1];
          }
        }
      }
      fillPolygon(g, col, xpoly, ypoly, npoly+1);
    }
  }

  private void fillPolygon(VectorGraphics g, Color c,
                           double[] x, double[] y,
                           int npoints) {
    Layer layer = cg_.getLayer();
    int[] xt = new int[20];
    int[] yt = new int[20];
    g.setColor(c);
    for(int i=0; i < npoints; i++) {
      xt[i] = layer.getXPtoD(x[i]);
      yt[i] = layer.getYPtoD(y[i]);
    }
    g.fillPolygon(xt, yt, npoints);
  }

  private double[] xArrayP() {
    int i;
    double[] p;
    if(grid_.isXTime()) {
      GeoDate[] t = grid_.getTimeArray();
      p = new double[t.length];
      for(i=0; i < t.length; i++) {
        p[i] = cg_.getXUtoP(t[i]);
      }
    } else {
      double[] x = grid_.getXArray();
      p = new double[x.length];
      for(i=0; i < x.length; i++) {
        p[i] = cg_.getXUtoP(x[i]);
      }
    }
    return p;
  }

  private double[] yArrayP() {
    int i;
    double[] p;
    if(grid_.isYTime()) {
      GeoDate[] t = grid_.getTimeArray();
      p = new double[t.length];
      for(i=0; i < t.length; i++) {
        p[i] = cg_.getYUtoP(t[i]);
      }
    } else {
      double[] y = grid_.getYArray();
      p = new double[y.length];
      for(i=0; i < y.length; i++) {
        p[i] = cg_.getYUtoP(y[i]);
      }
    }
    return p;
  }

  private Range2D computeRange(int levels) {
    Range2D range;
    double zmin = Double.POSITIVE_INFINITY;
    double zmax = Double.NEGATIVE_INFINITY;
    double[] array = grid_.getZArray();
    for(int i=0; i < array.length; i++) {
      if(!Double.isNaN(array[i])) {
        zmin = Math.min(zmin, array[i]);
        zmax = Math.max(zmax, array[i]);
      }
    }
    range = Graph.computeRange(zmin, zmax, levels);
    return range;
  }
  /**
   * Get the SGTGrid.
   *
   * @return SGTGrid
   */
  public SGTGrid getGrid() {
    return grid_;
  }
  /**
   * Get the associated CartesianGraph object.
   * @since 2.0
   * @return CartesianGraph
   */
  public CartesianGraph getCartesianGraph() {
    return cg_;
  }

  public void propertyChange(PropertyChangeEvent evt) {
//      if(Debug.EVENT) {
//        System.out.println("GridCartesianRenderer: " + evt);
//        System.out.println("                       " + evt.getPropertyName());
//      }
    modified("GridCartesianRenderer: propertyChange(" +
             evt.getSource().toString() + "[" +
             evt.getPropertyName() + "]" + ")");
  }
  /**
   * @since 3.0
   */
  public SGTData getDataAt(Point pt) {
    return null;
  }
}

 

Ads help maintain this website.