/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * JUMP is Copyright (C) 2003 Vivid Solutions * * This program implements extensions to JUMP and is * Copyright (C) 2004 Integrated Systems Analysts, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Integrated Systems Analysts, Inc. * 630C Anchors St., Suite 101 * Fort Walton Beach, Florida * USA * * (850)862-7321 */ package org.openjump.core.ui.plugin.raster; import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.event.MouseEvent; import java.awt.geom.NoninvertibleTransformException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JInternalFrame; import org.openjump.core.apitools.LayerTools; import org.openjump.core.rasterimage.RasterImageLayer; import org.openjump.core.rasterimage.sextante.OpenJUMPSextanteRasterLayer; import org.openjump.core.rasterimage.sextante.rasterWrappers.GridExtent; import org.openjump.core.ui.plot.Plot2DPanelOJ; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jump.I18N; import com.vividsolutions.jump.feature.AttributeType; import com.vividsolutions.jump.feature.BasicFeature; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.feature.FeatureCollection; import com.vividsolutions.jump.feature.FeatureDataset; import com.vividsolutions.jump.feature.FeatureSchema; import com.vividsolutions.jump.workbench.WorkbenchContext; import com.vividsolutions.jump.workbench.model.StandardCategoryNames; import com.vividsolutions.jump.workbench.plugin.PlugInContext; import com.vividsolutions.jump.workbench.ui.LayerViewPanel; import com.vividsolutions.jump.workbench.ui.cursortool.MultiClickTool; public class ProfileGraphTool extends MultiClickTool { private final static String sDistance = I18N.get("org.openjump.core.ui.plugin.tools.MeasureM_FTool.Distance"); private final static String sMeters = I18N.get("org.openjump.core.ui.plugin.tools.MeasureM_FTool.meters"); private final static String sFeet = I18N.get("org.openjump.core.ui.plugin.tools.MeasureM_FTool.feet"); private List<Coordinate> savedCoordinates = new ArrayList<Coordinate>(); private Coordinate currCoord; private OpenJUMPSextanteRasterLayer rstLayer = null; private GeometryFactory gf = new GeometryFactory(); private FeatureCollection resultFC = null; private FeatureSchema resultFSchema = null; private double dDist = 0,dHorzDist = 0; private double m_dLastX, m_dLastY, m_dLastZ; private int nPoints = 0; //private FeatureDatasetFactory fdf = new FeatureDatasetFactory(); //private GridWrapperNotInterpolated gwrapper = null; public ProfileGraphTool() { this.allowSnapping(); //-- do on init this.resultFSchema = new FeatureSchema(); this.resultFSchema.addAttribute("geometry", AttributeType.GEOMETRY); this.resultFSchema.addAttribute("X", AttributeType.DOUBLE); this.resultFSchema.addAttribute("Y", AttributeType.DOUBLE); this.resultFSchema.addAttribute("Z", AttributeType.DOUBLE); this.resultFSchema.addAttribute("PlaneDist", AttributeType.DOUBLE); this.resultFSchema.addAttribute("TerrainDist", AttributeType.DOUBLE); this.resultFC = new FeatureDataset(this.resultFSchema); } public Icon getIcon() { return new ImageIcon(getClass().getResource("RulerM_F.gif")); } public Cursor getCursor() { for (int i = 0; i < savedCoordinates.size(); i++) { add((Coordinate)savedCoordinates.get(i)); } return createCursor(new ImageIcon(getClass().getResource("RulerCursorM_F.gif")).getImage()); } public void mouseLocationChanged(MouseEvent e) { try { if (isShapeOnScreen()) { ArrayList<Coordinate> currentCoordinates = new ArrayList<Coordinate>(getCoordinates()); currentCoordinates.add(getPanel().getViewport().toModelCoordinate(e.getPoint())); display(currentCoordinates, getPanel()); } currCoord = snap(e.getPoint()); super.mouseLocationChanged(e); } catch (Throwable t) { getPanel().getContext().handleThrowable(t); } } public void mousePressed(MouseEvent e) { super.mousePressed(e); savedCoordinates = new ArrayList<Coordinate>(getCoordinates()); } protected void gestureFinished() throws NoninvertibleTransformException{ reportNothingToUndoYet(); savedCoordinates.clear(); //Status bar is cleared before #gestureFinished is called. So redisplay //the length. [Jon Aquino] display(getCoordinates(), getPanel()); //-- [sstein] now all the raster profile stuff RasterImageLayer rLayer = (RasterImageLayer) LayerTools.getSelectedLayerable(this.getWorkbench().getContext(), RasterImageLayer.class); if (rLayer==null){ getPanel().getContext().warnUser(I18N.get("pirol.plugIns.EditAttributeByFormulaPlugIn.no-layer-selected")); return; } this.rstLayer = new OpenJUMPSextanteRasterLayer(); this.rstLayer.create(rLayer); this.rstLayer.setFullExtent(); // not sure why this needs to be done but it seems to // be necessary (otherwise I get an NPE when // doing this.rstLayer.getWindowCellSize()) GridExtent extent = this.rstLayer.getWindowGridExtent(); // not sure if this needs to be done - but it was in the Sextante class //-- clear the resultFC this.resultFC.clear(); this.nPoints = 0; //-- create a gridwrapper to access the cells //this.gwrapper = new GridWrapperNotInterpolated(rstLayer, rstLayer.getLayerGridExtent()); this.calculateProfile(getCoordinates(), getWorkbench().getContext()); /* //-- this was used for testing double rvalue = 0.0; Coordinate startCoord = (Coordinate)getCoordinates().get(0); GridCell cell = rstLayer.getLayerGridExtent().getGridCoordsFromWorldCoords(startCoord.x, startCoord.y); // rvalue = cell.getValue(); //can't use this, since the value will be zero, so I assume the cell //object is just a place holder for the coordinates rvalue = gwrapper.getCellValueAsDouble(cell.getX(), cell.getY(), 0); //get value for first band //--output getPanel().getContext().setStatusMessage("starting point value: " + rvalue); */ } private void display(List<Coordinate> coordinates, LayerViewPanel panel) throws NoninvertibleTransformException { display(distance(coordinates), panel); } private void display(double distance, LayerViewPanel panel) { DecimalFormat df3 = new DecimalFormat("###,###,##0.0##"); String distString = df3.format(distance / 0.3048); panel.getContext().setStatusMessage(sDistance+ ": " + panel.format(distance) + " " + sMeters + " " + " = " + distString + " feet"); } private double distance(List<Coordinate> coordinates) { double distance = 0; for (int i = 1; i < coordinates.size(); i++) { distance += ((Coordinate) coordinates.get(i - 1)).distance((Coordinate) coordinates.get(i)); } if ((currCoord != null) && (coordinates.size() > 1)) { distance -= ((Coordinate) coordinates.get(coordinates.size() - 2)).distance((Coordinate) coordinates.get(coordinates.size() - 1)); distance += ((Coordinate) coordinates.get(coordinates.size() - 2)).distance(currCoord); } return distance; } private void calculateProfile(List<Coordinate> coordinates, WorkbenchContext context){ //-- create a linestring Coordinate[] coords = new Coordinate[coordinates.size()]; int i = 0; for (Iterator iterator = coordinates.iterator(); iterator.hasNext();) { Coordinate c = (Coordinate) iterator.next(); coords[i] = c; i++; } LineString line = gf.createLineString(coords); this.processLine(line); PlugInContext pc = context.createPlugInContext(); if((this.resultFC != null) && (this.resultFC.size()>0)){ pc.addLayer(StandardCategoryNames.RESULT, I18N.get("org.openjump.core.ui.plugin.raster.ProfileGraphTool.profile-pts"), this.resultFC); } //-- graph stuff ShowProfile myScorePlot = new ShowProfile(this.resultFC); Plot2DPanelOJ plot = myScorePlot.getPlot(); // FrameView fv = new FrameView(plot); // -- replace the upper line by: JInternalFrame frame = new JInternalFrame(I18N.get("org.openjump.core.ui.plugin.raster.ProfileGraphTool.Profile-Plot")); frame.setLayout(new BorderLayout()); frame.add(plot, BorderLayout.CENTER); frame.setClosable(true); frame.setResizable(true); frame.setMaximizable(true); frame.setSize(450, 450); frame.setVisible(true); context.getWorkbench().getFrame().addInternalFrame(frame); } private void processLine(Geometry line){ double x,y,x2,y2; Coordinate[] coords = line.getCoordinates(); for (int i = 0; i < coords.length - 1; i++){ x = coords[i].x; y = coords[i].y; x2 = coords[i + 1].x; y2 = coords[i + 1].y; processSegment(x,y,x2,y2); } } private void processSegment(double x, double y, double x2, double y2){ double dx, dy, d, n; dx = Math.abs(x2 - x); dy = Math.abs(y2 - y); if( dx > 0.0 || dy > 0.0 ){ if( dx > dy ){ dx /= this.rstLayer.getWindowCellSize(); n = dx; dy /= dx; dx = this.rstLayer.getWindowCellSize(); } else{ dy /= this.rstLayer.getWindowCellSize(); n = dy; dx /= dy; dy = this.rstLayer.getWindowCellSize(); } if(x2 < x ){ dx = -dx; } if( y2 < y ){ dy = -dy; } for(d=0.0; d<=n; d++, x+=dx, y+=dy){ addPoint(x,y); } } } private void addPoint(double x, double y){ double z; double dDX, dDY, dDZ; z = this.rstLayer.getValueAt(x, y); if( this.nPoints == 0 ){ dDist = 0.0; dHorzDist = 0.0; } else{ dDX = x - m_dLastX; dDY = y - m_dLastY; if (this.rstLayer.isNoDataValue(z) ||this.rstLayer.isNoDataValue(m_dLastZ)){ dDZ = 0.0; } else{ dDZ = z - m_dLastZ; } dDist += Math.sqrt(dDX * dDX + dDY * dDY); dHorzDist += Math.sqrt(dDX * dDX + dDY * dDY + dDZ * dDZ); } m_dLastX = x; m_dLastY= y; m_dLastZ = z; this.nPoints++; Point geometry = new GeometryFactory().createPoint(new Coordinate(x,y)); Feature fpoint = new BasicFeature(this.resultFSchema); fpoint.setGeometry(geometry); fpoint.setAttribute("X", new Double(x)); fpoint.setAttribute("Y", new Double(y)); fpoint.setAttribute("Z", new Double(z)); fpoint.setAttribute("PlaneDist", new Double(dDist)); fpoint.setAttribute("TerrainDist", new Double(dHorzDist)); /*//--graph stuff if (!this.rstLayer.isNoDataValue(z)){ serie.add(dDist, z); } */ this.resultFC.add(fpoint); } } final class ShowProfile extends JFrame{ Plot2DPanelOJ plot = null; public ShowProfile(FeatureCollection fc){ // Build a 2D data set double[][] datas1 = new double [fc.size()][2]; for (int j = 0; j < fc.size(); j++) { Feature f = (Feature)fc.getFeatures().get(j); datas1[j][0] = (Double)f.getAttribute("PlaneDist"); datas1[j][1] = (Double)f.getAttribute("Z"); } // Build the 2D scatterplot of the datas in a Panel // LINE, SCATTER, BAR, QUANTILE, STAIRCASE, (HISTOGRAMM?) Plot2DPanelOJ plot2dA = new Plot2DPanelOJ(); plot2dA.addLinePlot("graph",datas1); //plot2dA.addScatterPlot("pts",datas1); //==================== plot2dA.setAxisLabel(0,I18N.get("org.openjump.core.ui.plugin.raster.ProfileGraphTool.2d-distance")); plot2dA.setAxisLabel(1,I18N.get("org.openjump.core.ui.plugin.raster.ProfileGraphTool.values")); // Display a Frame containing the plot panel //new FrameView(plot2dA); this.plot = plot2dA; } public Plot2DPanelOJ getPlot(){ return this.plot; } }