All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrasstools.lesto.modules.utilities.LasSlicer Maven / Gradle / Ivy

/*
 * This file is part of JGrasstools (http://www.jgrasstools.org)
 * (C) HydroloGIS - www.hydrologis.com 
 * 
 * JGrasstools 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 3 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, see .
 */
package org.jgrasstools.lesto.modules.utilities;

import static java.lang.Math.round;
import static org.jgrasstools.gears.i18n.GearsMessages.OMSHYDRO_AUTHORCONTACTS;
import static org.jgrasstools.gears.i18n.GearsMessages.OMSHYDRO_AUTHORNAMES;
import static org.jgrasstools.gears.i18n.GearsMessages.OMSHYDRO_DRAFT;
import static org.jgrasstools.gears.i18n.GearsMessages.OMSHYDRO_LICENSE;

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.media.jai.iterator.WritableRandomIter;

import oms3.annotations.Author;
import oms3.annotations.Description;
import oms3.annotations.Execute;
import oms3.annotations.In;
import oms3.annotations.Keywords;
import oms3.annotations.Label;
import oms3.annotations.License;
import oms3.annotations.Name;
import oms3.annotations.Status;
import oms3.annotations.UI;
import oms3.annotations.Unit;

import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.jts.ReferencedEnvelope3D;
import org.jgrasstools.gears.io.las.ALasDataManager;
import org.jgrasstools.gears.io.las.core.LasRecord;
import org.jgrasstools.gears.libs.exceptions.ModelsIOException;
import org.jgrasstools.gears.libs.modules.JGTConstants;
import org.jgrasstools.gears.libs.modules.JGTModel;
import org.jgrasstools.gears.utils.RegionMap;
import org.jgrasstools.gears.utils.chart.Scatter;
import org.jgrasstools.gears.utils.coverage.CoverageUtilities;
import org.jgrasstools.gears.utils.geometry.GeometryUtilities;
import org.jgrasstools.gears.utils.math.NumericsUtilities;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Polygon;

@Description("Creates vertical slices of a las file. The resulting raster will have the slice height value as valid pixel value.")
@Author(name = OMSHYDRO_AUTHORNAMES, contact = OMSHYDRO_AUTHORCONTACTS)
@Keywords("slices, lidar, las")
@Label(JGTConstants.LESTO + "/utilities")
@Name("lasslicer")
@Status(OMSHYDRO_DRAFT)
@License(OMSHYDRO_LICENSE)
public class LasSlicer extends JGTModel {
    @Description("Las file or folder path.")
    @UI(JGTConstants.FILEIN_UI_HINT)
    @In
    public String inLas = null;

    @Description("DTM path for normalization.")
    @UI(JGTConstants.FILEIN_UI_HINT)
    @In
    public String inDtm = null;

    @Description("The slicing interval.")
    @In
    @Unit("m")
    public double pInterval = 1.0;

    @Description("The slice thickness.")
    @In
    @Unit("m")
    public double pThickness = 0.8;

    @Description("Threshold from ground (-1 means no threshold).")
    @In
    @Unit("m")
    public double pGroundThreshold = 0.5;

    @Description("Type of output to use.")
    @UI("combo: chart, raster")
    @In
    public String pMode = "raster";

    @Description("Raster resolution in case of raster mode..")
    @In
    @Unit("m")
    public double pResolution = 0.5;

    @Execute
    public void process() throws Exception {
        checkNull(inLas);

        boolean doRaster = true;
        if (pMode.equals("chart")) {
            doRaster = false;
        }

        File lasFile = new File(inLas);
        File parentFile = lasFile.getParentFile();
        File outputFolder = new File(parentFile, "vertical_slices");
        if (!outputFolder.exists() && !outputFolder.mkdir()) {
            throw new ModelsIOException("Can't create folder: " + outputFolder, this);
        }

        GridCoverage2D dtm = getRaster(inDtm);

        try (ALasDataManager dataManager = ALasDataManager.getDataManager(lasFile, dtm, pGroundThreshold, null)) {
            dataManager.open();
            ReferencedEnvelope3D dataEnvelope = dataManager.getEnvelope3D();
            CoordinateReferenceSystem crs = dataEnvelope.getCoordinateReferenceSystem();

            double minX = dataEnvelope.getMinX();
            double minY = dataEnvelope.getMinY();
            double minZ = dataEnvelope.getMinZ();
            double maxX = dataEnvelope.getMaxX();
            double maxY = dataEnvelope.getMaxY();
            double maxZ = dataEnvelope.getMaxZ();

            double xDelta = maxX - minX;
            double yDelta = maxY - minY;
            int chartWidth = 1600;
            int chartHeigth = (int) (chartWidth * yDelta / xDelta);
            pm.message("Generating charts of " + chartWidth + "x" + chartHeigth);

            double[] xRange = NumericsUtilities.range2Bins(minX, maxX, 3.0, false);
            double[] yRange = NumericsUtilities.range2Bins(minY, maxY, 3.0, false);

            int tilesNum = xRange.length * yRange.length;
            int tilesCount = 0;
            LinkedHashMap> recordsMap = new LinkedHashMap<>();
            pm.beginTask("Producing slices...", (xRange.length - 1));
            for( int x = 0; x < xRange.length - 1; x++ ) {
                for( int y = 0; y < yRange.length - 1; y++ ) {
                    tilesCount++;
                    Envelope env = new Envelope(xRange[x], xRange[x + 1], yRange[y], yRange[y + 1]);
                    Polygon polygon = GeometryUtilities.createPolygonFromEnvelope(env);
                    List pointsInGeometry = dataManager.getPointsInGeometry(polygon, true);

                    pm.message("Points in tile " + x + "/" + y + "(" + tilesCount + " of " + tilesNum + "): "
                            + pointsInGeometry.size());
                    if (pointsInGeometry.size() == 0) {
                        continue;
                    }
                    for( double z = minZ + pInterval; z < maxZ; z = z + pInterval ) {
                        String key = String.valueOf(z);
                        List pointsInSlice = recordsMap.get(key);
                        if (pointsInSlice == null) {
                            pointsInSlice = new ArrayList();
                            recordsMap.put(key, pointsInSlice);
                        }
                        double height = z - minZ;
                        double low = height - pThickness / 2.0;
                        double high = height + pThickness / 2.0;
                        List pointsInHeightRange = ALasDataManager.getPointsInHeightRange(pointsInGeometry, low, high);
                        if (pointsInHeightRange.size() > 0) {
                            pointsInSlice.addAll(pointsInHeightRange);
                            // pm.message("Added points: " + pointsInHeightRange.size());
                            if (!doRaster)
                                chartPoints(outputFolder, height, pointsInSlice, chartWidth, chartHeigth, minX, maxX, minY, maxY);
                        }
                    }
                }
                pm.worked(1);
            }
            pm.done();

            if (doRaster) {
                Set>> entrySet = recordsMap.entrySet();
                int size = entrySet.size();
                pm.beginTask("Generating rasters...", size);
                for( Entry> entry : entrySet ) {
                    double z = Double.parseDouble(entry.getKey());
                    double height = z - minZ;
                    List points = entry.getValue();

                    dumpRaster(outputFolder, height, points, pResolution, minX, maxX, minY, maxY, crs);
                    pm.worked(1);
                }
                pm.done();
            }

        }
    }

    private void dumpRaster( File outputFolder, double height, List points, double resolution, double minX,
            double maxX, double minY, double maxY, CoordinateReferenceSystem crs ) throws Exception {

        File rasterFile = new File(outputFolder, "slice_" + height + ".asc");

        int rows = (int) round((maxY - minY) / resolution);
        int cols = (int) round((maxX - minX) / resolution);

        GridGeometry2D gridGeometry = CoverageUtilities.gridGeometryFromRegionValues(maxY, minY, maxX, minX, cols, rows, crs);
        RegionMap regionMap = CoverageUtilities.gridGeometry2RegionParamsMap(gridGeometry);

        WritableRaster outWR = CoverageUtilities.createDoubleWritableRaster(cols, rows, null, null, JGTConstants.doubleNovalue);
        WritableRandomIter outIter = CoverageUtilities.getWritableRandomIterator(outWR);

        Point point = new Point();
        for( LasRecord dot : points ) {
            CoverageUtilities.colRowFromCoordinate(new Coordinate(dot.x, dot.y), gridGeometry, point);
            outIter.setSample(point.x, point.y, 0, height);
        }
        outIter.done();

        GridCoverage2D outRaster = CoverageUtilities.buildCoverage(rasterFile.getName(), outWR, regionMap, crs);
        dumpRaster(outRaster, rasterFile.getAbsolutePath());
    }

    private void chartPoints( File chartFolder, double z, List pointsInSlice, int width, int height, double minX,
            double maxX, double minY, double maxY ) throws IOException {
        File chartFile = new File(chartFolder, "slice_" + z + ".png");

        int size = pointsInSlice.size();
        double[] xPlanim = new double[size];
        double[] yPlanim = new double[size];
        for( int i = 0; i < size; i++ ) {
            LasRecord dot = pointsInSlice.get(i);
            xPlanim[i] = dot.x;
            yPlanim[i] = dot.y;
        }

        Scatter scatterPlanim = new Scatter("Slice " + z);
        scatterPlanim.addSeries("planimetry", xPlanim, yPlanim);
        scatterPlanim.setShowLines(false);
        scatterPlanim.setXLabel("longitude");
        scatterPlanim.setYLabel("latitude");
        scatterPlanim.setXRange(minX, maxX);
        scatterPlanim.setYRange(minY, maxY);
        BufferedImage imagePlanim = scatterPlanim.getImage(width, height);
        ImageIO.write(imagePlanim, "png", chartFile);

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy