Revision: 6090 http://sourceforge.net/p/jump-pilot/code/6090 Author: ma15569 Date: 2019-01-17 16:02:31 +0000 (Thu, 17 Jan 2019) Log Message: ----------- Added a set to transform a grid (GridWrapperNotInterpolated.class wrapped from a RasterImageLayer.class) into vector objetcs: currently polygons, contour lines and points are supported
Added Paths: ----------- core/trunk/src/org/openjump/core/rasterimage/algorithms/ core/trunk/src/org/openjump/core/rasterimage/algorithms/VectorizeAlgorithm.java Added: core/trunk/src/org/openjump/core/rasterimage/algorithms/VectorizeAlgorithm.java =================================================================== --- core/trunk/src/org/openjump/core/rasterimage/algorithms/VectorizeAlgorithm.java (rev 0) +++ core/trunk/src/org/openjump/core/rasterimage/algorithms/VectorizeAlgorithm.java 2019-01-17 16:02:31 UTC (rev 6090) @@ -0,0 +1,621 @@ +package org.openjump.core.rasterimage.algorithms; + +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.Collections; + +import org.openjump.core.rasterimage.sextante.rasterWrappers.GridWrapperNotInterpolated; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory; +import com.vividsolutions.jts.operation.union.CascadedPolygonUnion; +import com.vividsolutions.jts.simplify.DouglasPeuckerSimplifier; +import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier; +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; + +/** + * This class provides a complete set to transform a grid (GridWrapperNotInterpolated.class) derived + * from a RasterImageLayer.class into vector objetcs. + * All methods derived from AdbToolbox project, from Sextante and from OpenJUMP inner methods. + * To build a grid from RasterImageLayer: + * OpenJUMPSextanteRasterLayer rstLayer = new OpenJUMPSextanteRasterLayer(); + * rstLayer.create(rLayer, false); + * GridWrapperNotInterpolated gwrapper = new GridWrapperNotInterpolated(rstLayer, rstLayer.getLayerGridExtent()); + * @author Giuseppe Aruta + * + */ +public class VectorizeAlgorithm { + + private static int arrPos(int valIn, int[] arrayIn) { + + int valOut = -9999; + for (int i = 0; i < arrayIn.length; i++) { + if (arrayIn[i] == valIn) { + valOut = i; + break; + } + } + return valOut; + } + + /** + * Create a FeatureCollection of polygons defining GridWrapperNotInterpolated and number of band + * + * @param gwrapper. GridWrapperNotInterpolated + * @param explodeMultipolygons. Explode MultiPolygons in Polygons + * @param band. Number of band (0,1,2,etc) + * @return + */ + public static FeatureCollection toPolygons( + GridWrapperNotInterpolated gwrapper, boolean explodeMultipolygons, + String attributeName, int band) { + + final double cellSize = gwrapper.getGridExtent().getCellSize().x; + final double xllCorner = gwrapper.getGridExtent().getXMin() + cellSize; + final double yllCorner = gwrapper.getGridExtent().getYMin() - cellSize; + final double noData = gwrapper.getNoDataValue(); + + // Find unique values + final int[] uniqueVals = findUniqueVals(gwrapper, noData, band); + final int uniqueValsCount = uniqueVals.length; + + // Scan lines + @SuppressWarnings("unchecked") + final ArrayList<Polygon>[] arrAll = new ArrayList[uniqueValsCount]; + for (int i = 0; i < arrAll.length; i++) { + arrAll[i] = new ArrayList<Polygon>(); + } + final Coordinate[] coords = new Coordinate[5]; + final PackedCoordinateSequenceFactory pcsf = new PackedCoordinateSequenceFactory(); + final GeometryFactory geomFactory = new GeometryFactory(); + LinearRing lr; + Polygon polygon; + final int nCols = gwrapper.getGridExtent().getNX(); + final int nRows = gwrapper.getGridExtent().getNY(); + final double yurCorner = yllCorner + (nRows * cellSize); + for (int r = 0; r <= nRows + 1; r++) { + double oldVal = noData; + int cStart = 0; + int cEnd; + for (int c = 0; c <= nCols + 1; c++) { + final double val = gwrapper.getCellValueAsDouble(c, r, band); + if (val != oldVal) { + cEnd = c - 1; + // Get polygon vertices + if (oldVal != noData) { + + coords[0] = new Coordinate(xllCorner + + (cStart * cellSize) - cellSize, yurCorner + - (r * cellSize)); + coords[1] = new Coordinate(coords[0].x, coords[0].y + + cellSize); + coords[2] = new Coordinate(xllCorner + + (cEnd * cellSize), coords[1].y); + coords[3] = new Coordinate(coords[2].x, coords[0].y); + coords[4] = coords[0]; + final CoordinateSequence cs = pcsf.create(coords); + lr = new LinearRing(cs, geomFactory); + polygon = new Polygon(lr, null, geomFactory); + arrAll[arrPos((int) oldVal, uniqueVals)].add(polygon); + } + oldVal = val; + cStart = c; + } + } + } + + // Collapse polygons + final FeatureSchema featSchema = new FeatureSchema(); + featSchema.addAttribute("GEOMETRY", AttributeType.GEOMETRY); + featSchema.addAttribute(attributeName, AttributeType.INTEGER); + Feature feature; + + // Create feature collection + final FeatureCollection featColl = new FeatureDataset(featSchema); + + for (int i = 0; i < uniqueValsCount; i++) { + + Geometry geom = CascadedPolygonUnion.union(arrAll[i]); + geom = DouglasPeuckerSimplifier.simplify(geom, 0); + geom = TopologyPreservingSimplifier.simplify(geom, 00); + + if (explodeMultipolygons) { + + // From multipolygons to single polygons + for (int g = 0; g < geom.getNumGeometries(); g++) { + feature = new BasicFeature(featSchema); + feature.setGeometry(geom.getGeometryN(g)); + feature.setAttribute(1, uniqueVals[i]); + featColl.add(feature); + } + } else { + feature = new BasicFeature(featSchema); + feature.setGeometry(geom); + feature.setAttribute(1, uniqueVals[i]); + featColl.add(feature); + } + } + System.gc(); + return featColl; + + } + + private static int[] findUniqueVals(GridWrapperNotInterpolated gwrapper, + double nodata, int band) { + + // Pass values to 1D array + final ArrayList<Integer> vals = new ArrayList<Integer>(); + + final int nx = gwrapper.getNX();//rstLayer.getLayerGridExtent().getNX(); + final int ny = gwrapper.getNY();// rstLayer.getLayerGridExtent().getNY(); + for (int x = 0; x < nx; x++) {//cols + for (int y = 0; y < ny; y++) {//rows + final double value = gwrapper.getCellValueAsDouble(x, y, band); + if (value != nodata) { + vals.add((int) gwrapper.getCellValueAsDouble(x, y, band)); + } + } + } + + // Find unique values + Collections.sort(vals); + + final ArrayList<Integer> uniqueValsArr = new ArrayList<Integer>(); + uniqueValsArr.add(vals.get(0)); + + for (int i = 1; i < vals.size(); i++) { + if (!vals.get(i).equals(vals.get(i - 1))) { + uniqueValsArr.add(vals.get(i)); + } + } + + final int[] uniqueVals = new int[uniqueValsArr.size()]; + for (int i = 0; i < uniqueValsArr.size(); i++) { + uniqueVals[i] = uniqueValsArr.get(i); + } + + return uniqueVals; + + } + + private static final String ATTRIBUTE_NAME = I18N + .get("org.openjump.core.ui.plugin.raster.RasterQueryPlugIn.value"); + private static char[][] m_Row; + private static char[][] m_Col; + private final static GeometryFactory m_GF = new GeometryFactory(); + private static boolean removeZeroCells = false; + + public static FeatureCollection toContours( + GridWrapperNotInterpolated gwrapper, final double dMin, + final double dMax, double dDistance, String attributeName, int band) { + final FeatureCollection featColl = new FeatureDataset( + schema(attributeName)); + int x, y; + int i; + int ID; + int iNX, iNY; + double dZ; + double dValue = 0; + + iNX = gwrapper.getGridExtent().getNX(); + iNY = gwrapper.getGridExtent().getNY(); + + m_Row = new char[iNY][iNX]; + m_Col = new char[iNY][iNX]; + + if (dDistance <= 0) { + dDistance = 1; + } + + for (dZ = dMin, ID = 0; (dZ <= dMax); dZ += dDistance) { + for (y = 0; y < iNY - 1; y++) { + for (x = 0; x < iNX - 1; x++) { + dValue = gwrapper.getCellValueAsDouble(x, y, band); + if (dValue >= dZ) { + m_Row[y][x] = (char) (gwrapper.getCellValueAsDouble( + x + 1, y, band) < dZ ? 1 : 0); + m_Col[y][x] = (char) (gwrapper.getCellValueAsDouble(x, + y + 1, band) < dZ ? 1 : 0); + } else { + m_Row[y][x] = (char) (gwrapper.getCellValueAsDouble( + x + 1, y, band) >= dZ ? 1 : 0); + m_Col[y][x] = (char) (gwrapper.getCellValueAsDouble(x, + y + 1, band) >= dZ ? 1 : 0); + } + } + } + + for (y = 0; y < iNY - 1; y++) { + for (x = 0; x < iNX - 1; x++) { + if (m_Row[y][x] != 0) { + for (i = 0; i < 2; i++) { + final Feature feat = findContour(gwrapper, x, y, + dZ, true, ID++, attributeName, band); + if (feat.getGeometry().getGeometryType() + .equals("LineString") + || feat.getGeometry().getGeometryType() + .equals("LineString")) { + featColl.add(feat); + } + } + m_Row[y][x] = 0; + } + + if (m_Col[y][x] != 0) { + for (i = 0; i < 2; i++) { + final Feature feat = findContour(gwrapper, x, y, + dZ, false, ID++, attributeName, band); + if (feat.getGeometry().getGeometryType() + .equals("LineString") + || feat.getGeometry().getGeometryType() + .equals("LineString")) { + featColl.add(feat); + } + } + m_Col[y][x] = 0; + } + } + } + + } + + System.gc(); + return featColl; + + } + + private static Feature findContour(GridWrapperNotInterpolated gwrapper, + final int x, final int y, final double z, final boolean doRow, + final int ID, String attribueName, int band) { + final Feature feature = new BasicFeature(schema(attribueName)); + boolean doContinue = true; + int zx = doRow ? x + 1 : x; + int zy = doRow ? y : y + 1; + double d; + double xPos, yPos; + final double xMin = gwrapper.getGridExtent().getXMin(); + final double yMax = gwrapper.getGridExtent().getYMax(); + Geometry line; + final Object values[] = new Object[1]; + final NextContourInfo info = new NextContourInfo(); + final ArrayList<Coordinate> coords = new ArrayList<Coordinate>(); + info.x = x; + info.y = y; + info.iDir = 0; + info.doRow = doRow; + do { + d = gwrapper.getCellValueAsDouble(info.x, info.y, band); + d = (d - z) / (d - gwrapper.getCellValueAsDouble(zx, zy, band)); + + xPos = xMin + gwrapper.getGridExtent().getCellSize().x + * (info.x + d * (zx - info.x) + 0.5); + yPos = yMax - gwrapper.getGridExtent().getCellSize().y + * (info.y + d * (zy - info.y) + 0.5); + coords.add(new Coordinate(xPos, yPos)); + if (!findNextContour(info)) { + doContinue = findNextContour(info); + } + info.iDir = (info.iDir + 5) % 8; + if (info.doRow) { + m_Row[info.y][info.x] = 0; + zx = info.x + 1; + zy = info.y; + } else { + m_Col[info.y][info.x] = 0; + zx = info.x; + zy = info.y + 1; + } + } while (doContinue); + // values[0] = new Integer(ID); + values[0] = new Double(z); + final Coordinate[] coordinates = new Coordinate[coords.size()]; + for (int i = 0; i < coordinates.length; i++) { + coordinates[i] = coords.get(i); + } + if (coordinates.length > 1) { + line = m_GF.createLineString(coordinates); + feature.setGeometry(line); + feature.setAttribute(1, values[0]); + // feature.setAttribute(2, values[1]); + } else if (coordinates.length == 1) { + final Geometry point = m_GF.createPoint(coordinates[0]); + feature.setGeometry(point); + feature.setAttribute(1, values[0]); + } else if (coordinates.length == 0) { + + final Geometry gc = m_GF.createGeometryCollection(new Geometry[0]); + feature.setGeometry(gc); + feature.setAttribute(1, values[0]); + + } + return feature; + } + + private static FeatureSchema schema(String attributeName) { + final FeatureSchema featSchema = new FeatureSchema(); + featSchema.addAttribute("GEOMETRY", AttributeType.GEOMETRY); + // featSchema.addAttribute("ID", AttributeType.INTEGER); + featSchema.addAttribute(attributeName, AttributeType.DOUBLE); + return featSchema; + } + + private static boolean findNextContour(final NextContourInfo info) { + boolean doContinue; + if (info.doRow) { + switch (info.iDir) { + case 0: + if (m_Row[info.y + 1][info.x] != 0) { + info.y++; + info.iDir = 0; + doContinue = true; + break; + } + case 1: + if (m_Col[info.y][info.x + 1] != 0) { + info.x++; + info.iDir = 1; + info.doRow = false; + doContinue = true; + break; + } + case 2: + case 3: + if (info.y - 1 >= 0) { + if (m_Col[info.y - 1][info.x + 1] != 0) { + info.x++; + info.y--; + info.doRow = false; + info.iDir = 3; + doContinue = true; + break; + } + } + case 4: + if (info.y - 1 >= 0) { + if (m_Row[info.y - 1][info.x] != 0) { + info.y--; + info.iDir = 4; + doContinue = true; + break; + } + } + case 5: + if (info.y - 1 >= 0) { + if (m_Col[info.y - 1][info.x] != 0) { + info.y--; + info.doRow = false; + info.iDir = 5; + doContinue = true; + break; + } + } + case 6: + case 7: + if (m_Col[info.y][info.x] != 0) { + info.doRow = false; + info.iDir = 7; + doContinue = true; + break; + } + default: + info.iDir = 0; + doContinue = false; + } + } else { + switch (info.iDir) { + case 0: + case 1: + if (m_Row[info.y + 1][info.x] != 0) { + info.y++; + info.doRow = true; + info.iDir = 1; + doContinue = true; + break; + } + case 2: + if (m_Col[info.y][info.x + 1] != 0) { + info.x++; + info.iDir = 2; + doContinue = true; + break; + } + case 3: + if (m_Row[info.y][info.x] != 0) { + info.doRow = true; + info.iDir = 3; + doContinue = true; + break; + } + case 4: + case 5: + if (info.x - 1 >= 0) { + if (m_Row[info.y][info.x - 1] != 0) { + info.x--; + info.doRow = true; + info.iDir = 5; + doContinue = true; + break; + } + } + case 6: + if (info.x - 1 >= 0) { + if (m_Col[info.y][info.x - 1] != 0) { + info.x--; + info.iDir = 6; + doContinue = true; + break; + } + } + case 7: + if (info.x - 1 >= 0) { + if (m_Row[info.y + 1][info.x - 1] != 0) { + info.x--; + info.y++; + info.doRow = true; + info.iDir = 7; + doContinue = true; + break; + } + } + default: + info.iDir = 0; + doContinue = false; + } + } + return (doContinue); + } + + private static class NextContourInfo { + public int iDir; + public int x; + public int y; + public boolean doRow; + } + + public static FeatureCollection toGridPoint( + GridWrapperNotInterpolated gwrapper, int numBands) { + final FeatureSchema fs = new FeatureSchema(); + fs.addAttribute("geometry", AttributeType.GEOMETRY); + fs.addAttribute("cellid_x", AttributeType.INTEGER); + fs.addAttribute("cellid_y", AttributeType.INTEGER); + + for (int i = 0; i < numBands; i++) { + fs.addAttribute("band" + "_" + i, AttributeType.DOUBLE); + } + //-- create a new empty dataset + final FeatureCollection fd = new FeatureDataset(fs); + + final int nx = gwrapper.getGridExtent().getNX(); + final int ny = gwrapper.getGridExtent().getNY(); + //int numPoints = nx * ny; + for (int x = 0; x < nx; x++) {//cols + for (int y = 0; y < ny; y++) {//rows + final Feature ftemp = new BasicFeature(fs); + final Point2D pt = gwrapper.getGridExtent() + .getWorldCoordsFromGridCoords(x, y); + final Geometry centerPoint = m_GF.createPoint(new Coordinate(pt + .getX(), pt.getY())); + ftemp.setGeometry(centerPoint); + for (int i = 0; i < numBands; i++) { + final double value = gwrapper.getCellValueAsDouble(x, y, i); + ftemp.setAttribute("band" + "_" + i, value); + } + ftemp.setAttribute("cellid_x", x); + ftemp.setAttribute("cellid_y", y); + //-- add the feature + fd.add(ftemp); + + } + } + return fd; + + } + + public static FeatureCollection toPoint( + GridWrapperNotInterpolated gwrapper, int band) { + final FeatureSchema fs = new FeatureSchema(); + fs.addAttribute("geometry", AttributeType.GEOMETRY); + + fs.addAttribute("value", AttributeType.DOUBLE); + + //-- create a new empty dataset + final FeatureCollection fd = new FeatureDataset(fs); + + final int nx = gwrapper.getGridExtent().getNX(); + final int ny = gwrapper.getGridExtent().getNY(); + final double noData = gwrapper.getNoDataValue(); + + for (int x = 0; x < nx; x++) {//cols + for (int y = 0; y < ny; y++) {//rows + + final double value = gwrapper.getCellValueAsDouble(x, y, band); + if (value != noData) { + final Feature ftemp = new BasicFeature(fs); + final Point2D pt = gwrapper.getGridExtent() + .getWorldCoordsFromGridCoords(x, y); + final Geometry centerPoint = m_GF + .createPoint(new Coordinate(pt.getX(), pt.getY())); + ftemp.setGeometry(centerPoint); + + //-- add the feature + fd.add(ftemp); + } + } + } + return fd; + + } + + public static FeatureCollection toGridPolygon( + GridWrapperNotInterpolated gwrapper, int maxCells, int numBands) { + final FeatureSchema fs = new FeatureSchema(); + fs.addAttribute("geometry", AttributeType.GEOMETRY); + + for (int i = 0; i < numBands; i++) { + fs.addAttribute("band" + "_" + i, AttributeType.DOUBLE); + } + //-- create a new empty dataset + final FeatureCollection fd = new FeatureDataset(fs); + //-- create points + + final int nx = gwrapper.getGridExtent().getNX(); + final int ny = gwrapper.getGridExtent().getNY(); + final double halfCellDimX = 0.5 * gwrapper.getGridExtent() + .getCellSize().x; + final double halfCellDimY = 0.5 * gwrapper.getGridExtent() + .getCellSize().y; + final int numPoints = nx * ny; + + for (int x = 0; x < nx; x++) {//cols + for (int y = 0; y < ny; y++) {//rows + final Feature ftemp = new BasicFeature(fs); + final Point2D pt = gwrapper.getGridExtent() + .getWorldCoordsFromGridCoords(x, y); + final Coordinate[] coords = new Coordinate[5]; + coords[0] = new Coordinate(pt.getX() - halfCellDimX, pt.getY() + + halfCellDimY); //topleft + coords[1] = new Coordinate(pt.getX() + halfCellDimX, pt.getY() + + halfCellDimY); //topright + coords[2] = new Coordinate(pt.getX() + halfCellDimX, pt.getY() + - halfCellDimY); //lowerright + coords[3] = new Coordinate(pt.getX() - halfCellDimX, pt.getY() + - halfCellDimY); //lowerleft + //-- to close poly + coords[4] = (Coordinate) coords[0].clone(); //topleft + //-- create the cell poly + final LinearRing lr = m_GF.createLinearRing(coords); + final Geometry poly = m_GF.createPolygon(lr, null); + ftemp.setGeometry(poly); + //-- set attributes + double sumvalue = 0; + for (int i = 0; i < numBands; i++) { + final double value = gwrapper.getCellValueAsDouble(x, y, i); + ftemp.setAttribute("band" + "_" + i, value); + sumvalue = sumvalue + value; + } + //-- add the feature + if (removeZeroCells == true) { + if (sumvalue > 0) { + fd.add(ftemp); + } + } else { + fd.add(ftemp); + } + } + } + return fd; + + } + +} Property changes on: core/trunk/src/org/openjump/core/rasterimage/algorithms/VectorizeAlgorithm.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property _______________________________________________ Jump-pilot-devel mailing list Jump-pilot-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel