/* * Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata * * Portions of this software were developed by the Unidata Program at the * University Corporation for Atmospheric Research. * * Access and use of this software shall impose the following obligations * and understandings on the user. The user is granted the right, without * any fee or cost, to use, copy, modify, alter, enhance and distribute * this software, and any derivative works thereof, and its supporting * documentation for any purpose whatsoever, provided that this entire * notice appears in all copies of the software, derivative works and * supporting documentation. Further, UCAR requests that the user credit * UCAR/Unidata in any publications that result from the use of this * software or in any product that includes this software. The names UCAR * and/or Unidata, however, may not be used in any advertising or publicity * to endorse or promote any products or commercial entity unless specific * written permission is obtained from UCAR/Unidata. The user also * understands that UCAR/Unidata is not obligated to provide the user with * any support, consulting, training or assistance of any kind with regard * to the use, operation and performance of this software nor to provide * the user with any updates, revisions, new versions or "bug fixes." * * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE. */ package ucar.nc2.ui.grid; import ucar.ma2.*; import ucar.nc2.NCdumpW; import ucar.nc2.constants.CDM; import ucar.nc2.dataset.CoordinateAxis; import ucar.nc2.dataset.CoordinateAxis1D; import ucar.nc2.dataset.CoordinateAxis2D; import ucar.nc2.dt.GridCoordSystem; import ucar.nc2.dt.GridDatatype; import ucar.unidata.geoloc.*; import ucar.unidata.geoloc.projection.LatLonProjection; import ucar.unidata.util.Format; import ucar.util.prefs.ui.Debug; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.ArrayList; /** * Render grids using Java2D API. * * @author caron */ public class GridRenderer { // draw state private boolean drawGrid = true; private boolean drawGridLines = true; private boolean drawContours = false; private boolean drawContourLabels = false; private boolean isNewField = true; private ColorScale cs = null; private ColorScale.MinMaxType dataMinMaxType = ColorScale.MinMaxType.horiz; private ProjectionImpl drawProjection = null; // current drawing Projection private ProjectionImpl dataProjection = null; // current GridDatatype Projection private GridDatatype orgGrid = null; private GridDatatype stridedGrid = null; // data stuff private Array dataH, dataV; private int wantLevel = -1, wantSlice = -1, wantTime = -1, horizStride = 1; // for next draw() private int wantRunTime = -1, wantEnsemble = -1; private int lastLevel = -1, lastTime = -1, lastSlice = -1, lastStride = -1; // last data read private int lastRunTime = -1, lastEnsemble = -1; // last data read private GridDatatype lastGrid = null; // drawing optimization private boolean useModeForProjections = false; // use colorMode optimization for different projections private boolean sameProjection = false; private LatLonProjection projectll; // special handling for LatLonProjection // working objects to minimize excessive gc private ProjectionPointImpl ptP1 = new ProjectionPointImpl(); private static final boolean debugHorizDraw = false, debugSeam = false, debugLatLon = false, debugMiss = false; private static boolean debugPathShape = false, debugArrayShape = false, debugPts = false; ///// bean properties /** * get the current ColorScale */ public ColorScale getColorScale() { return cs; } /** * set the ColorScale to use */ public void setColorScale(ColorScale cs) { this.cs = cs; } /** * set the ColorScale data min/max type * @param type MinMaxType */ public void setDataMinMaxType(ColorScale.MinMaxType type) { if (type != dataMinMaxType) { dataMinMaxType = type; } } /** * get the current GridDatatype */ public GridDatatype getGeoGrid() { return orgGrid; } public void clear() { this.orgGrid = null; this.lastGrid = null; this.stridedGrid = null; } /** * set the Grid */ public void setGeoGrid(GridDatatype grid) { this.orgGrid = grid; this.lastGrid = null; dataProjection = grid.getProjection(); makeStridedGrid(); isNewField = true; } public Array getCurrentHorizDataSlice() { return dataH; } /** * get the current GridDatatype data projection */ public ProjectionImpl getDataProjection() { return dataProjection; } /** * get the current display projection */ public ProjectionImpl getProjection() { return drawProjection; } /** * set the Projection to use for drawing */ public void setProjection(ProjectionImpl project) { drawProjection = project; } /* get whether grid should be drawn */ public boolean getDrawGrid() { return drawGrid; } /* set whether grid should be drawn */ public void setDrawGridLines(boolean drawGrid) { this.drawGridLines = drawGrid; } /* get whether countours should be drawn */ public boolean getDrawContours() { return drawContours; } /* set whether countours should be drawn */ public void setDrawContours(boolean drawContours) { this.drawContours = drawContours; } /* set whether contour labels should be drawn */ public boolean getDrawContourLabels() { return drawContourLabels; } /* set whether contour labels should be drawn */ public void setDrawContourLabels(boolean drawContourLabels) { this.drawContourLabels = drawContourLabels; } /* get what vertical level to draw */ public int getLevel() { return wantLevel; } /* set what vertical level to draw */ public void setLevel(int level) { wantLevel = level; } /* get what time slice to draw */ public int getTime() { return wantTime; } /* set what time slice to draw */ public void setTime(int time) { wantTime = time; } /* get what runtime slice to draw */ public int getRunTime() { return wantRunTime; } /* set what runtime slice to draw */ public void setRunTime(int runtime) { wantRunTime = runtime; } /* get what ensemble slice to draw */ public int getEnsemble() { return wantEnsemble; } /* set what ensemble slice to draw */ public void setEnsemble(int ensemble) { wantEnsemble = ensemble; } /* get what y-z slice to draw */ public int getSlice() { return wantSlice; } /* set what y-z slice to draw */ public void setSlice(int slice) { wantSlice = slice; } public int getHorizStride() { return horizStride; } public void setHorizStride(int horizStride) { this.horizStride = horizStride; } void makeStridedGrid() { if (horizStride > 1) { try { stridedGrid = orgGrid.makeSubset(null, null, null, 1, horizStride, horizStride); } catch (InvalidRangeException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } else { stridedGrid = orgGrid; } } /// info at a point /** * find the level (z) index that is represented by this point * * @param pos coord in data z coordinate space. */ public int findLevelCoordElement(double pos) { if (null == orgGrid) return -1; // find the grid index GridCoordSystem geocs = orgGrid.getCoordinateSystem(); CoordinateAxis1D zaxis = geocs.getVerticalAxis(); return (zaxis == null) ? -1 : zaxis.findCoordElement(pos); } /** * @param pp * @return x index for this point */ public int findSliceFromPoint(ProjectionPoint pp) { if ((null == drawProjection) || (null == stridedGrid)) return -1; // convert to dataProjection, where x and y are orthogonal if (!sameProjection) { LatLonPoint llpt = drawProjection.projToLatLon(pp); pp = dataProjection.latLonToProj(llpt); } // find the grid index GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); CoordinateAxis xaxis = geocs.getXHorizAxis(); if (xaxis == null || !(xaxis instanceof CoordinateAxis1D)) return -1; int[] index = geocs.findXYindexFromCoord(pp.getX(), pp.getY(), null); return index[0]; } /** * Get the data value at this projection (x,y) point. * * @param loc : point in display projection coordinates (plan view) * @return String representation of value */ public String getXYvalueStr(ProjectionPoint loc) { if ((stridedGrid == null) || (dataH == null)) return ""; // convert to dataProjection, where x and y are orthogonal if (!sameProjection) { LatLonPoint llpt = drawProjection.projToLatLon(loc); loc = dataProjection.latLonToProj(llpt); } // find the grid indexes GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); valueIndex = geocs.findXYindexFromCoord(loc.getX(), loc.getY(), valueIndex); int wantx = valueIndex[0]; int wanty = valueIndex[1]; // get value, construct the string if ((wantx == -1) || (wanty == -1)) return "outside grid area"; else { try { Index imaH = dataH.getIndex(); double value = dataH.getDouble(imaH.set(wanty, wantx)); int wantz = (geocs.getVerticalAxis() == null) ? -1 : lastLevel; return makeXYZvalueStr(value, wantx, wanty, wantz); } catch (Exception e) { return "error " + wantx + " " + wanty; } } } private int[] valueIndex = new int[2]; /** * Get the (y,z) position from the vertical view coordinates. * * @param loc : point in display projection coordinates (vertical view) * @return String representation of position */ public String getYZpositionStr(Point2D loc) { if ((stridedGrid == null) || (dataV == null)) return ""; GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); /* CoordinateAxis1D xaxis = (CoordinateAxis1D) geocs.getXHorizAxis(); double x = (xaxis == null) ? 0.0 : xaxis.getCoordValue(lastSlice); double y = loc.getX(); LatLonPointImpl lpt = dataProjection.projToLatLon(x, y); sbuff.setLength(0); sbuff.append(LatLonPointImpl.latToString(lpt.getLatitude(), 3)); */ StringBuilder sbuff = new StringBuilder(); sbuff.setLength(0); sbuff.append(Format.d(loc.getX(), 3)); CoordinateAxis yaxis = geocs.getYHorizAxis(); sbuff.append(" " + yaxis.getUnitsString()); sbuff.append(" "); sbuff.append(Format.d(loc.getY(), 3)); CoordinateAxis1D zaxis = geocs.getVerticalAxis(); sbuff.append(" " + zaxis.getUnitsString()); return sbuff.toString(); } /** * find the data value at this point * * @param loc : point in display projection coordinates (vertical view) * @return String representation of value */ public String getYZvalueStr(Point2D loc) { if ((stridedGrid == null) || (dataV == null)) return ""; // find the grid indexes GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); CoordinateAxis1D zaxis = geocs.getVerticalAxis(); if (zaxis == null) return ""; valueIndex = geocs.findXYindexFromCoord(loc.getX(), lastSlice, valueIndex); int wanty = valueIndex[1]; int wantz = zaxis.findCoordElement(loc.getY()); // get value, construct the string if ((wanty == -1) || (wantz == -1)) return "outside grid area"; else { Index imaV = dataV.getIndex(); double value = dataV.getDouble(imaV.set(wantz, wanty)); int wantx = (geocs.getXHorizAxis() == null) ? -1 : lastSlice; return makeXYZvalueStr(value, wantx, wanty, wantz); } } private String makeXYZvalueStr(double value, int wantx, int wanty, int wantz) { if (stridedGrid.isMissingData(value)) { //if (debugMiss) System.out.println("debug miss = "+value+" "+cs.getIndexFromValue(value)); if (Debug.isSet("pick/showGridIndexes")) return ("missing data @ (" + wantx + "," + wanty + ")"); else return "missing data"; } StringBuilder sbuff = new StringBuilder(); sbuff.append(Format.d(value, 6)); sbuff.append(" " + stridedGrid.getUnitsString()); GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); if (!(geocs.getXHorizAxis() instanceof CoordinateAxis1D) || !(geocs.getXHorizAxis() instanceof CoordinateAxis1D)) { if (Debug.isSet("pick/showGridIndexes")) sbuff.append("@ (" + wantx + "," + wanty + ")"); return sbuff.toString(); } CoordinateAxis1D xaxis = (CoordinateAxis1D) geocs.getXHorizAxis(); CoordinateAxis1D yaxis = (CoordinateAxis1D) geocs.getYHorizAxis(); CoordinateAxis1D zaxis = geocs.getVerticalAxis(); sbuff.append(" @ "); if ((wantx >= 0) && (wanty >= 0)) { LatLonPoint lpt; if (dataProjection.isLatLon()) lpt = new LatLonPointImpl(yaxis.getCoordValue(wanty), xaxis.getCoordValue(wantx)); else lpt = dataProjection.projToLatLon(xaxis.getCoordValue(wantx), yaxis.getCoordValue(wanty)); sbuff.append(lpt.toString()); if (Debug.isSet("pick/showDataProjectionCoords")) { sbuff.append("(" + Format.d(xaxis.getCoordValue(wantx), 3)); sbuff.append(" " + Format.d(yaxis.getCoordValue(wanty), 3)); sbuff.append(" " + xaxis.getUnitsString() + ")"); } if (Debug.isSet("pick/showDisplayProjectionCoords")) { ProjectionPoint pt = drawProjection.latLonToProj(lpt); sbuff.append("(" + Format.d(pt.getX(), 3)); sbuff.append(" " + Format.d(pt.getY(), 3) + ")"); } if (Debug.isSet("pick/showGridIndexes")) { sbuff.append("(" + wantx + "," + wanty + ")"); } } else if (wantx >= 0) { if (dataProjection.isLatLon()) sbuff.append(LatLonPointImpl.latToString(xaxis.getCoordValue(wantx), 3)); else { sbuff.append(" " + Format.d(xaxis.getCoordValue(wantx), 3)); sbuff.append(" " + xaxis.getUnitsString()); } } else if (wanty >= 0) { if (dataProjection.isLatLon()) sbuff.append(LatLonPointImpl.latToString(yaxis.getCoordValue(wanty), 3)); else { sbuff.append(" " + Format.d(yaxis.getCoordValue(wanty), 3)); sbuff.append(" " + yaxis.getUnitsString()); } } if (wantz >= 0) { sbuff.append(" " + Format.d(zaxis.getCoordValue(wantz), 3)); sbuff.append(" " + zaxis.getUnitsString()); } return sbuff.toString(); } //////// data routines /* get an x,y,z data volume for the given time private void makeDataVolume( GridDatatype g, int time) { try { dataVolume = g.readVolumeData( time); } catch (java.io.IOException e) { System.out.println("Error reading netcdf file "+e); dataVolume = null; } lastGrid = g; lastTime = time; lastLevel = -1; // invalidate lastSlice = -1; // invalidate dataVolumeChanged = true; } */ private Array makeHSlice(GridDatatype useG, int level, int time, int ensemble, int runtime) throws IOException { // make sure x, y exists GridCoordSystem gcs = useG.getCoordinateSystem(); CoordinateAxis xaxis = gcs.getXHorizAxis(); CoordinateAxis yaxis = gcs.getYHorizAxis(); if ((xaxis == null) || (yaxis == null)) // doesnt exist return null; if ((xaxis.getSize() <= 1) || (yaxis.getSize() <= 1)) // LOOK ?? return null; // make sure we need new one if (useG.equals(lastGrid) && (time == lastTime) && (level == lastLevel) && (horizStride == lastStride) && (ensemble == lastEnsemble) && (runtime == lastRunTime)) return dataH; // nothing changed // get the data slice dataH = useG.readDataSlice(runtime, ensemble, time, level, -1, -1); lastGrid = useG; lastTime = time; lastLevel = level; lastEnsemble = ensemble; lastRunTime = runtime; lastStride = horizStride; /* CoordinateAxis1D zaxis = gcs.getVerticalAxis(); if ((zaxis == null) || (zaxis.getSize() < 1)) { dataH = dataVolume; // volume is xy plane } else { dataH = dataVolume.slice(0, level); // if z exists, always first (logical) dimension } */ if (debugArrayShape) { System.out.println("Horiz shape = "); for (int i = 0; i < dataH.getRank(); i++) System.out.println(" shape = " + dataH.getShape()[i]); } return dataH; } private Array makeVSlice(GridDatatype g, int vSlice, int time, int ensemble, int runtime) { // make sure we have x, z GridCoordSystem gcs = g.getCoordinateSystem(); CoordinateAxis xaxis = gcs.getXHorizAxis(); CoordinateAxis zaxis = gcs.getVerticalAxis(); if ((xaxis == null) || (zaxis == null)) // doesnt exist return null; if ((xaxis.getSize() <= 1) || (zaxis.getSize() <= 1)) // LOOK ?? return null; // make sure we need it if (g.equals(lastGrid) && (time == lastTime) && (vSlice == lastSlice) && (ensemble == lastEnsemble) && (runtime == lastRunTime)) return dataV; // nothing changed // get the slice try { dataV = g.readDataSlice(runtime, ensemble, time, -1, -1, vSlice); } catch (java.io.IOException e) { System.out.println("GridRender.makeHSlice Error reading netcdf file= " + e); return null; } lastGrid = g; lastTime = time; lastSlice = vSlice; lastEnsemble = ensemble; lastRunTime = runtime; if (debugArrayShape) { System.out.println("Vert shape = "); for (int i = 0; i < dataV.getRank(); i++) System.out.println(" shape = " + dataV.getShape()[i]); } return dataV; } //////////// Renderer stuff /** * returns null * public ucar.unidata.geoloc.LatLonRect getPreferredArea() { * /* if (dataProjection != null) * return dataProjection.getPreferredArea(); * else * return null; * } * <p/> * /* private java.awt.Color color, backColor; * public void setBackgroundColor(java.awt.Color backColor) { this.backColor = backColor;} * public void setColor(java.awt.Color color) { this.color = color;} * public java.awt.Color getColor() { return color; } */ // set colorscale limits, missing data private void setColorScaleParams() throws IOException { if (dataMinMaxType == ColorScale.MinMaxType.hold && !isNewField) return; isNewField = false; Array dataArr = makeHSlice(stridedGrid, wantLevel, wantTime, wantEnsemble, wantRunTime); //else // dataArr = makeVSlice(stridedGrid, wantSlice, wantTime, wantEnsemble, wantRunTime); if (dataArr != null) { MAMath.MinMax minmax = stridedGrid.hasMissingData() ? stridedGrid.getMinMaxSkipMissingData(dataArr) : MAMath.getMinMax(dataArr); cs.setMinMax(minmax.min, minmax.max); cs.setGeoGrid(stridedGrid); } } /** * Do the rendering to the given Graphics2D object. * * @param g Graphics2D object: has clipRect and AffineTransform set. * @param dFromN transforms "Normalized Device" to Device coordinates */ public void renderVertView(java.awt.Graphics2D g, AffineTransform dFromN) { if ((stridedGrid == null) || (cs == null) || (drawProjection == null)) return; if (!drawGrid && !drawContours) return; dataV = makeVSlice(stridedGrid, wantSlice, wantTime, wantEnsemble, wantRunTime); if (dataV == null) return; if (Debug.isSet("GridRenderer/vert")) System.out.println("GridRenderer/vert: redraw grid"); GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); CoordinateAxis1D zaxis = geocs.getVerticalAxis(); CoordinateAxis1D yaxis = (CoordinateAxis1D) geocs.getYHorizAxis(); if ((yaxis == null) || (zaxis == null)) return; int nz = (int) zaxis.getSize(); int ny = (int) yaxis.getSize(); if (drawGrid) { int count = 0; Index imaV = dataV.getIndex(); for (int z = 0; z < nz; z++) { double zbeg = zaxis.getCoordEdge(z); double zend = zaxis.getCoordEdge(z + 1); for (int y = 0; y < ny; y++) { double ybeg = yaxis.getCoordEdge(y); double yend = yaxis.getCoordEdge(y + 1); double val = dataV.getDouble(imaV.set(z, y)); int thisColor = cs.getIndexFromValue(val); count += drawRect(g, thisColor, ybeg, zbeg, yend, zend, false); } } } if (drawContours) { double[] zedges = zaxis.getCoordValues(); double[] yedges = yaxis.getCoordValues(); int nlevels = cs.getNumColors(); ArrayList levels = new ArrayList(nlevels); for (int i = 1; i < nlevels - 1; i++) levels.add(new Double(cs.getEdge(i))); long startTime = System.currentTimeMillis(); ContourFeatureRenderer contourRendererV; try { ContourGrid conGrid = new ContourGrid(dataV.transpose(0, 1), levels, yedges, zedges, stridedGrid); contourRendererV = new ContourFeatureRenderer(conGrid, null); //contourRendererV.setProjection(drawProjection); contourRendererV.setColor(Color.black); contourRendererV.setShowLabels(drawContourLabels); contourRendererV.draw(g, dFromN); } catch (Exception e) { System.out.println("draw Contours Vert exception = " + e); e.printStackTrace(System.err); } if (Debug.isSet("timing/contourDraw")) { long tookTime = System.currentTimeMillis() - startTime; System.out.println("timing/contourDraw: Vert:" + tookTime * .001 + " seconds"); } } if ((lastLevel >= 0) && (lastLevel < nz)) drawXORline(g, yaxis.getCoordEdge(0), zaxis.getCoordValue(lastLevel), yaxis.getCoordEdge(ny), zaxis.getCoordValue(lastLevel)); } /** * Do the rendering to the given Graphics2D object. * * @param g Graphics2D object: has clipRect and AffineTransform set. * @param dFromN transforms "Normalized Device" to Device coordinates */ public void renderPlanView(java.awt.Graphics2D g, AffineTransform dFromN) throws IOException { if ((stridedGrid == null) || (cs == null) || (drawProjection == null)) return; if (!drawGrid && !drawContours) return; // no anitaliasing g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); dataH = makeHSlice(stridedGrid, wantLevel, wantTime, wantEnsemble, wantRunTime); if (dataH == null) return; setColorScaleParams(); if (drawGrid) drawGridHoriz(g, dataH); if (drawContours) drawContours(g, dataH.transpose(0, 1), dFromN); if (drawGridLines) drawGridLines(g); } private void drawGridHoriz(java.awt.Graphics2D g, Array data) { int count = 0; GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); CoordinateAxis xaxis = geocs.getXHorizAxis(); CoordinateAxis yaxis = geocs.getYHorizAxis(); if ((xaxis instanceof CoordinateAxis1D) && (yaxis instanceof CoordinateAxis1D)) { drawGridHoriz1D(g, data, (CoordinateAxis1D) xaxis, (CoordinateAxis1D) yaxis); return; } data = data.reduce(); if (data.getRank() != 2) throw new IllegalArgumentException("must be 2D"); if (!(xaxis instanceof CoordinateAxis2D) || !(yaxis instanceof CoordinateAxis2D)) throw new IllegalArgumentException("must be CoordinateAxis2D"); // 2D case CoordinateAxis2D xaxis2D = (CoordinateAxis2D) xaxis; CoordinateAxis2D yaxis2D = (CoordinateAxis2D) yaxis; String stag = geocs.getHorizStaggerType(); if (stag != null && stag.equals(CDM.ARAKAWA_E)) { drawGridHorizRotated(g, data, xaxis2D, yaxis2D); return; } ArrayDouble.D2 edgex = xaxis2D.getXEdges(); ArrayDouble.D2 edgey = yaxis2D.getYEdges(); Index ima = data.getIndex(); GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 5); int[] shape = xaxis2D.getShape(); // should both be the same int ny = shape[0]; int nx = shape[1]; for (int y = 0; y < ny; y++) { for (int x = 0; x < nx; x++) { gp.reset(); gp.moveTo((float) edgex.get(y, x), (float) edgey.get(y, x)); gp.lineTo((float) edgex.get(y, x + 1), (float) edgey.get(y, x + 1)); gp.lineTo((float) edgex.get(y + 1, x + 1), (float) edgey.get(y + 1, x + 1)); gp.lineTo((float) edgex.get(y + 1, x), (float) edgey.get(y + 1, x)); // debug F:\data2\formats\hdf4\AMSR_E_L2A_BrightnessTemperatures_V08_200801012345_A.hdf if (false) { double d1 = Math.abs(edgex.get(y, x) - edgex.get(y, x+1)); double d2 = Math.abs(edgex.get(y, x+1) - edgex.get(y+1, x+1)); double d3 = Math.abs(edgex.get(y+1, x+1) - edgex.get(y+1, x) ); double d4 = Math.abs(edgex.get(y+1, x) - edgex.get(y, x)); if (Math.abs(d1) > 10 || Math.abs(d2) > 10 || Math.abs(d3) > 10 || Math.abs(d4) > 10) { System.out.printf("x=%d y=%d %n", x, y); System.out.printf("%f %f %f %f %n", edgex.get(y, x), edgex.get(y, x + 1), edgex.get(y + 1, x), edgex.get(y + 1, x + 1)); System.out.printf("%n%s", NCdumpW.toString(edgex.slice(0,y+1), "row "+y, null)); System.out.printf("%n%s", NCdumpW.toString(edgex.slice(0,y+1), "row "+(y+1), null)); } } double val = data.getDouble(ima.set(y, x)); // ordering LOOK int colorIndex = cs.getIndexFromValue(val); g.setColor(cs.getColor(colorIndex)); g.fill(gp); } } } private void drawGridLines(java.awt.Graphics2D g) { int count = 0; GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); CoordinateAxis xaxis = geocs.getXHorizAxis(); CoordinateAxis yaxis = geocs.getYHorizAxis(); if (!(xaxis instanceof CoordinateAxis2D) || !(yaxis instanceof CoordinateAxis2D)) return; // 2D case CoordinateAxis2D xaxis2D = (CoordinateAxis2D) xaxis; CoordinateAxis2D yaxis2D = (CoordinateAxis2D) yaxis; ArrayDouble.D2 edgex = xaxis2D.getXEdges(); ArrayDouble.D2 edgey = yaxis2D.getYEdges(); GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 5); g.setColor(Color.BLACK); int[] shape = xaxis2D.getShape(); // should both be the same int ny = shape[0]; int nx = shape[1]; for (int y = 0; y < ny+1; y += 10) { gp.reset(); for (int x = 0; x < nx+1; x++) { if (x == 0) gp.moveTo((float) edgex.get(y, x), (float) edgey.get(y, x)); else gp.lineTo((float) edgex.get(y, x), (float) edgey.get(y, x)); } g.draw(gp); } for (int x = 0; x < nx+1; x += 10) { gp.reset(); for (int y = 0; y < ny+1; y++) { if (y == 0) gp.moveTo((float) edgex.get(y, x), (float) edgey.get(y, x)); else gp.lineTo((float) edgex.get(y, x), (float) edgey.get(y, x)); } g.draw(gp); } } private void drawGridHorizRotated(java.awt.Graphics2D g, Array data, CoordinateAxis2D xaxis2D, CoordinateAxis2D yaxis2D) { ArrayDouble.D2 edgex = CoordinateAxis2D.makeXEdgesRotated(xaxis2D.getMidpoints()); ArrayDouble.D2 edgey = CoordinateAxis2D.makeYEdgesRotated(yaxis2D.getMidpoints()); Index ima = data.getIndex(); GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 5); int[] shape = xaxis2D.getShape(); // should both be the same int ny = shape[0]; int nx = shape[1]; // even y for (int y = 0; y < ny - 1; y += 2) { for (int x = 0; x < nx - 1; x++) { gp.reset(); gp.moveTo((float) edgex.get(y, x), (float) edgey.get(y, x)); gp.lineTo((float) edgex.get(y + 1, x), (float) edgey.get(y + 1, x)); gp.lineTo((float) edgex.get(y + 2, x), (float) edgey.get(y + 2, x)); gp.lineTo((float) edgex.get(y + 1, x + 1), (float) edgey.get(y + 1, x + 1)); double val = data.getDouble(ima.set(y, x)); // ordering LOOK int colorIndex = cs.getIndexFromValue(val); g.setColor(cs.getColor(colorIndex)); g.fill(gp); } } // odd y for (int y = 1; y < ny - 1; y += 2) { for (int x = 0; x < nx - 1; x++) { gp.reset(); gp.moveTo((float) edgex.get(y, x + 1), (float) edgey.get(y, x + 1)); gp.lineTo((float) edgex.get(y + 1, x), (float) edgey.get(y + 1, x)); gp.lineTo((float) edgex.get(y + 2, x + 1), (float) edgey.get(y + 2, x + 1)); gp.lineTo((float) edgex.get(y + 1, x + 1), (float) edgey.get(y + 1, x + 1)); double val = data.getDouble(ima.set(y, x)); // ordering LOOK int colorIndex = cs.getIndexFromValue(val); g.setColor(cs.getColor(colorIndex)); g.fill(gp); } } } /* draw using GeneralPath shape private GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 5); private Shape makeShape(double lon1, double lat1, double lon2, double lat2) { gp.reset(); ProjectionPoint pt = drawProjection.latLonToProj( lat1, lon1); gp.moveTo( (float) pt.getX(), (float) pt.getY()); ptP1.setLocation(pt); pt = drawProjection.latLonToProj( lat1, lon2); gp.lineTo( (float) pt.getX(), (float) pt.getY()); if (drawProjection.crossSeam(ptP1, pt)) return null; ptP1.setLocation(pt); pt = drawProjection.latLonToProj( lat2, lon2); gp.lineTo( (float) pt.getX(), (float) pt.getY()); if (drawProjection.crossSeam(ptP1, pt)) return null; ptP1.setLocation(pt); pt = drawProjection.latLonToProj( lat2, lon1); gp.lineTo( (float) pt.getX(), (float) pt.getY()); if (drawProjection.crossSeam(ptP1, pt)) return null; return gp; } */ private void drawGridHoriz1D(java.awt.Graphics2D g, Array data, CoordinateAxis1D xaxis1D, CoordinateAxis1D yaxis1D) { int count = 0; int nx = (int) xaxis1D.getSize(); int ny = (int) yaxis1D.getSize(); /* how big is one pixel ? if (debug) System.out.println("affine transform = "+g.getTransform()); if (debug) System.out.println(" scaleY= "+g.getTransform().getScaleY()); onePixel = Math.abs(1.5/g.getTransform().getScaleY()); // a little nudge more than 1 pixel onePixel = 0; */ //// drawing optimizations sameProjection = drawProjection.equals(dataProjection); if (drawProjection.isLatLon()) { projectll = (LatLonProjection) drawProjection; double centerLon = projectll.getCenterLon(); if (Debug.isSet("projection/LatLonShift")) System.out.println("projection/LatLonShift: gridDraw = " + centerLon); } // find the most common color and fill the entire area with it int modeColor = cs.getHistMax(); cs.resetHist(); IndexIterator iiter = data.getIndexIterator(); while (iiter.hasNext()) { double val = iiter.getDoubleNext(); cs.getIndexFromValue(val); // accum in histogram } modeColor = cs.getHistMax(); if (debugMiss) System.out.println("mode = " + modeColor + " sameProj= " + sameProjection); if (sameProjection) { count += drawRect(g, modeColor, xaxis1D.getCoordEdge(0), yaxis1D.getCoordEdge(0), xaxis1D.getCoordEdge(nx), yaxis1D.getCoordEdge(ny), drawProjection.isLatLon()); } else if (useModeForProjections) drawPathShape(g, modeColor, xaxis1D, yaxis1D); debugPts = Debug.isSet("GridRenderer/showPts"); // draw individual rects with run length Index imaH = dataH.getIndex(); for (int y = 0; y < ny; y++) { double ybeg = yaxis1D.getCoordEdge(y); double yend = yaxis1D.getCoordEdge(y + 1); int thisColor = 0, lastColor = 0; int run = 0; int xbeg = 0; debugPts = debugPts && (y == 0); for (int x = 0; x < nx; x++) { try { double val = data.getDouble(imaH.set(y, x)); thisColor = cs.getIndexFromValue(val); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("bad"); throw e; } if ((run == 0) || (lastColor == thisColor)) // same color - keep running run++; else { if (sameProjection) { if (lastColor != modeColor) // dont have to draw these count += drawRect(g, lastColor, xaxis1D.getCoordEdge(xbeg), ybeg, xaxis1D.getCoordEdge(x), yend, drawProjection.isLatLon()); } else { //if (!useModeForProjections || (lastColor != modeColor)) // dont have to draw mode count += drawPathRun(g, lastColor, ybeg, yend, xaxis1D, xbeg, x); } xbeg = x; } lastColor = thisColor; } // get the ones at the end if (sameProjection) { if (lastColor != modeColor) count += drawRect(g, lastColor, xaxis1D.getCoordEdge(xbeg), ybeg, xaxis1D.getCoordEdge(nx), yend, drawProjection.isLatLon()); } else { //if (!useModeForProjections || (lastColor != modeColor)) count += drawPathRun(g, lastColor, ybeg, yend, xaxis1D, xbeg, nx - 1); } // if (debugPts) break; } if (debugHorizDraw) System.out.println("debugHorizDraw = " + count); } //// draw using Rectangle when possible private Rectangle2D rect = new Rectangle2D.Double(); private int drawRectLatLon(Graphics2D g, int color, double lon1, double lat1, double lon2, double lat2) { g.setColor(cs.getColor(color)); int count = 0; ProjectionRect[] rect = projectll.latLonToProjRect(lat1, lon1, lat2, lon2); for (int i = 0; i < 2; i++) if (null != rect[i]) { ProjectionRect r2 = rect[i]; Rectangle2D.Double r = new Rectangle2D.Double(r2.getX(), r2.getY(), r2.getWidth(), r2.getHeight()); g.fill(r); } return count; } private int drawRect(Graphics2D g, int color, double w1, double h1, double w2, double h2, boolean useLatlon) { if (useLatlon) return drawRectLatLon(g, color, w1, h1, w2, h2); g.setColor(cs.getColor(color)); double wmin = Math.min(w1, w2); double hmin = Math.min(h1, h2); double width = Math.abs(w1 - w2); double height = Math.abs(h1 - h2); rect.setRect(wmin, hmin, width, height); g.fill(rect); return 1; } private GeneralPath gpRun = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 25); private int drawPathRun(Graphics2D g, int color, double y1, double y2, CoordinateAxis1D xaxis, int x1, int x2) { int nx = (int) xaxis.getSize(); if ((x1 < 0) || (x1 > nx) || (x2 < 0) || (x2 > nx) || (x1 > x2)) // from the recursion return 0; gpRun.reset(); LatLonPoint llp = dataProjection.projToLatLon(xaxis.getCoordEdge(x1), y1); ProjectionPoint pt = drawProjection.latLonToProj(llp); if (debugPts) System.out.println("** moveTo = " + pt.getX() + " " + pt.getY()); gpRun.moveTo((float) pt.getX(), (float) pt.getY()); ptP1.setLocation(pt); for (int e = x1 + 1; e <= x2 + 1; e++) { llp = dataProjection.projToLatLon(xaxis.getCoordEdge(e), y1); pt = drawProjection.latLonToProj(llp); if (drawProjection.crossSeam(ptP1, pt)) { // break it in two & recurse int x = e - 1; // which col has to be dropped ? if (debugPathShape) System.out.println("split1 at x = " + x + " " + x1 + " " + x2); int count = 0; count += drawPathRun(g, color, y1, y2, xaxis, x1, x - 1); count += drawPathRun(g, color, y1, y2, xaxis, x + 1, x2); return count; } if (debugPts) System.out.println(" lineTo = " + pt.getX() + " " + pt.getY()); gpRun.lineTo((float) pt.getX(), (float) pt.getY()); ptP1.setLocation(pt); } for (int e = x2 + 1; e >= x1; e--) { llp = dataProjection.projToLatLon(xaxis.getCoordEdge(e), y2); pt = drawProjection.latLonToProj(llp); if (drawProjection.crossSeam(ptP1, pt)) { // break it in two & recurse int x = (e == x2 + 1) ? x2 : e; // which col has to be dropped ? if (debugPathShape) System.out.println("split2 at x = " + x + " " + x1 + " " + x2); int count = 0; count += drawPathRun(g, color, y1, y2, xaxis, x1, x - 1); count += drawPathRun(g, color, y1, y2, xaxis, x + 1, x2); return count; } if (debugPts) System.out.println(" lineTo = " + pt.getX() + " " + pt.getY()); gpRun.lineTo((float) pt.getX(), (float) pt.getY()); ptP1.setLocation(pt); } g.setColor(cs.getColor(color)); try { g.fill(gpRun); } catch (Throwable e) { System.out.println("Exception in drawPathRun = " + e); return 0; } return 1; } private int drawPathShape(Graphics2D g, int color, CoordinateAxis1D xaxis, CoordinateAxis1D yaxis) { int count = 0; for (int y = 0; y < yaxis.getSize() - 1; y++) { double y1 = yaxis.getCoordEdge(y); double y2 = yaxis.getCoordEdge(y + 1); count += drawPathRun(g, color, y1, y2, xaxis, 0, (int) xaxis.getSize() - 1); } return count; } private void drawXORline(Graphics2D g, double x1, double y1, double x2, double y2) { gpRun.reset(); gpRun.moveTo((float) x1, (float) y1); gpRun.lineTo((float) x2, (float) y2); //g.setXORMode(Color.black); g.setColor(Color.black); if (Double.isInfinite(x1) || Double.isInfinite(x2) || Double.isInfinite(y1) || Double.isInfinite(y2)) return; g.draw(gpRun); //g.setPaintMode(); } /* private int drawPathShape(Graphics2D g, int color, CoordinateAxis xaxis, CoordinateAxis yaxis) { Point2D pt; gpRun.reset(); int nx = xaxis.getNumElements(); int ny = yaxis.getNumElements(); boolean debugPathShape = true; int x, y; pt = drawProjection.latLonToProj( yaxis.getCoordValue(0), xaxis.getCoordValue(0)); gpRun.moveTo( (float) pt.getX(), (float) pt.getY()); ptP1.set(pt); y = 0; for (x=1; x<nx; x++) { pt = drawProjection.latLonToProj( yaxis.getCoordValue(y), xaxis.getCoordValue(x)); gpRun.lineTo( (float) pt.getX(), (float) pt.getY()); ptP1.set(pt); if (debugPathShape) System.out.println(x+" "+y+" "+pt+" "+drawProjection.crossSeam(ptP1, pt)); } x = nx-1; for (y=0; y<ny; y++) { pt = drawProjection.latLonToProj( yaxis.getCoordValue(y), xaxis.getCoordValue(x)); gpRun.lineTo( (float) pt.getX(), (float) pt.getY()); ptP1.set(pt); if (debugPathShape) System.out.println(x+" "+y+" "+pt+" "+drawProjection.crossSeam(ptP1, pt)); } y = ny-1; for (x=nx-1; x>=0; x--) { pt = drawProjection.latLonToProj( yaxis.getCoordValue(y), xaxis.getCoordValue(x)); gpRun.lineTo( (float) pt.getX(), (float) pt.getY()); ptP1.set(pt); if (debugPathShape) System.out.println(x+" "+y+" "+pt+" "+drawProjection.crossSeam(ptP1, pt)); } x = 0; for (y=ny-1; y>=0; y--) { pt = drawProjection.latLonToProj( yaxis.getCoordValue(y), xaxis.getCoordValue(x)); gpRun.lineTo( (float) pt.getX(), (float) pt.getY()); ptP1.set(pt); if (debugPathShape) System.out.println(x+" "+y+" "+pt+" "+drawProjection.crossSeam(ptP1, pt)); } g.setColor( cs.getColor(color)); //g.fill(gpRun); return 1; } */ /* private void drawLine(Graphics2D g, double lat1, double lon1, double lat2, double lon2) { ptP1.set(drawProjection.latLonToProj( lat1, lon1)); Point2D pt2 = drawProjection.latLonToProj( lat2, lon2); if (drawProjection.crossSeam(ptP1, pt2)) if (debugSeam) System.out.println( "crossSeam: "+ ptP1+ " to "+ pt2); else { line2D.setLine( ptP1, pt2); g.draw( line2D); } } */ //////// contouring private void drawContours(java.awt.Graphics2D g, Array hslice, AffineTransform dFromN) { // make ContourGrid object GridCoordSystem geocs = stridedGrid.getCoordinateSystem(); CoordinateAxis1D xaxis = (CoordinateAxis1D) geocs.getXHorizAxis(); CoordinateAxis1D yaxis = (CoordinateAxis1D) geocs.getYHorizAxis(); double[] xedges = xaxis.getCoordValues(); double[] yedges = yaxis.getCoordValues(); int nlevels = cs.getNumColors(); ArrayList levels = new ArrayList(nlevels); for (int i = 1; i < nlevels - 1; i++) levels.add(new Double(cs.getEdge(i))); ContourFeatureRenderer contourRenderer; long startTime = System.currentTimeMillis(); try { ContourGrid conGrid = new ContourGrid((Array) hslice, levels, xedges, yedges, stridedGrid); contourRenderer = new ContourFeatureRenderer(conGrid, dataProjection); } catch (Exception e) { System.out.println("make Contours exception = " + e); e.printStackTrace(System.out); return; } if (Debug.isSet("timing/contourMake")) { long tookTime = System.currentTimeMillis() - startTime; System.out.println("timing/contourMake: " + tookTime * .001 + " seconds"); } startTime = System.currentTimeMillis(); try { contourRenderer.setProjection(drawProjection); contourRenderer.setColor(Color.black); contourRenderer.setShowLabels(drawContourLabels); contourRenderer.draw(g, dFromN); } catch (Exception e) { System.out.println("draw Contours exception = " + e); e.printStackTrace(System.err); } if (Debug.isSet("timing/contourDraw")) { long tookTime = System.currentTimeMillis() - startTime; System.out.println("timing/contourDraw: " + tookTime*.001 + " seconds"); } } }