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

org.jgrasstools.lesto.modules.flightlines.FlightLinesIntensityNormalizer Maven / Gradle / Ivy

The newest version!
/*
 * 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.flightlines;
import static java.lang.Math.floor;
import static java.lang.Math.pow;

import java.io.File;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import org.geotools.data.simple.SimpleFeatureCollection;
import org.jgrasstools.gears.io.las.core.ALasReader;
import org.jgrasstools.gears.io.las.core.ALasWriter;
import org.jgrasstools.gears.io.las.core.ILasHeader;
import org.jgrasstools.gears.io.las.core.LasRecord;
import org.jgrasstools.gears.io.las.utils.GpsTimeConverter;
import org.jgrasstools.gears.io.las.utils.LasUtils;
import org.jgrasstools.gears.io.vectorreader.OmsVectorReader;
import org.jgrasstools.gears.libs.exceptions.ModelsIllegalargumentException;
import org.jgrasstools.gears.libs.modules.JGTConstants;
import org.jgrasstools.gears.libs.modules.JGTModel;
import org.jgrasstools.gears.utils.features.FeatureUtilities;
import org.jgrasstools.gears.utils.geometry.GeometryUtilities;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineSegment;
import com.vividsolutions.jts.index.strtree.STRtree;

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;

@Description("A module that normalizes flightlines based on the aircraft position.")
@Author(name = "Andrea Antonello, Silvia Franceschi", contact = "www.hydrologis.com")
@Keywords("las, normalize, flightlines")
@Label(JGTConstants.LESTO + "/flightlines")
@Name("lasflightlinesnormalization")
@Status(Status.EXPERIMENTAL)
@License(JGTConstants.GPL3_LICENSE)
public class FlightLinesIntensityNormalizer extends JGTModel {
    @Description("A las file.")
    @UI(JGTConstants.FILEIN_UI_HINT)
    @In
    public String inLas;

    @Description("Shapefile containing the string fields of date, time, elev.")
    @UI(JGTConstants.FILEIN_UI_HINT)
    @In
    public String inFlightpoints;

    @Description("The square of standard range.")
    @In
    public double pStdRange = 600.0;

    @Description("The date and time pattern (date and time field content will be concatenated through a space).")
    @In
    public String pDateTimePattern = "yyyy-MM-dd HH:mm:ss";

    @Description("The gps time type used in the las file.")
    @UI("combo:" + FlightLinesExtractor.ADJUSTED_STANDARD_GPS_TIME + "," + FlightLinesExtractor.WEEK_SECONDS_TIME)
    @In
    public String pGpsTimeType = FlightLinesExtractor.ADJUSTED_STANDARD_GPS_TIME;

    @Description("Normalized output las file.")
    @UI(JGTConstants.FILEOUT_UI_HINT)
    @In
    public String outLas;

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

        int timeType = -1;
        if (pGpsTimeType.equals(FlightLinesExtractor.ADJUSTED_STANDARD_GPS_TIME)) {
            timeType = 1;
        }
        if (pGpsTimeType.equals(FlightLinesExtractor.WEEK_SECONDS_TIME)) {
            timeType = 0;
        }

        SimpleFeatureCollection flightPointsFC = OmsVectorReader.readVector(inFlightpoints);
        List flightPointsList = FeatureUtilities.featureCollectionToList(flightPointsFC);
        SimpleFeatureType schema = flightPointsFC.getSchema();

        String dateName = FeatureUtilities.findAttributeName(schema, "date");
        String timeName = FeatureUtilities.findAttributeName(schema, "time");
        String elevName = FeatureUtilities.findAttributeName(schema, "elev");
        if (dateName == null || timeName == null || elevName == null) {
            throw new ModelsIllegalargumentException("The shapefile has to contain the fields date time and elev.", this);
        }

        pm.beginTask("Defining flight intervals and positions...", flightPointsList.size());
        DateTimeFormatter formatter = DateTimeFormat.forPattern(pDateTimePattern).withZone(DateTimeZone.UTC);
        TreeMap date2pointsMap = new TreeMap();
        TreeMap points2dateMap = new TreeMap();
        for( int i = 0; i < flightPointsList.size(); i++ ) {
            SimpleFeature flightPoint = flightPointsList.get(i);
            Geometry g1 = (Geometry) flightPoint.getDefaultGeometry();
            Coordinate c1 = g1.getCoordinate();
            double elev1 = ((Number) flightPoint.getAttribute(elevName)).doubleValue();
            c1.z = elev1;
            String date1 = flightPoint.getAttribute(dateName).toString();
            String time1 = flightPoint.getAttribute(timeName).toString();
            String dateTime1 = date1 + " " + time1;
            DateTime d1 = formatter.parseDateTime(dateTime1);
            date2pointsMap.put(d1, c1);
            points2dateMap.put(c1, d1);
            pm.worked(1);
        }
        pm.done();

        pm.beginTask("Create time index...", flightPointsList.size() - 1);
        DateTime minDate = null;
        DateTime maxDate = null;
        long minLong = Long.MAX_VALUE;
        long maxLong = -Long.MAX_VALUE;
        STRtree tree = new STRtree(flightPointsList.size());
        Set> pointsSet = date2pointsMap.entrySet();
        Entry[] array = pointsSet.toArray(new Entry[0]);
        for( int i = 0; i < array.length - 1; i++ ) {
            DateTime d1 = (DateTime) array[i].getKey();
            Coordinate c1 = (Coordinate) array[i].getValue();
            DateTime d2 = (DateTime) array[i + 1].getKey();
            Coordinate c2 = (Coordinate) array[i + 1].getValue();
            long millis1 = d1.getMillis();
            long millis2 = d2.getMillis();
            Envelope timeEnv = new Envelope(millis1, millis2, millis1, millis2);
            tree.insert(timeEnv, new Coordinate[]{c1, c2});
            if (millis1 < minLong) {
                minLong = millis1;
                minDate = d1;
            }
            if (millis2 > maxLong) {
                maxLong = millis2;
                maxDate = d2;
            }
            pm.worked(1);
        }
        pm.done();

        StringBuilder sb = new StringBuilder();
        sb.append("Flight data interval: ");
        sb.append(minDate.toString(JGTConstants.dateTimeFormatterYYYYMMDDHHMMSS));
        sb.append(" to ");
        sb.append(maxDate.toString(JGTConstants.dateTimeFormatterYYYYMMDDHHMMSS));
        pm.message(sb.toString());

        CoordinateReferenceSystem crs = null;
        File lasFile = new File(inLas);
        File outLasFile = new File(outLas);
        try (ALasReader reader = ALasReader.getReader(lasFile, crs); //
                ALasWriter writer = ALasWriter.getWriter(outLasFile, crs);) {
            reader.setOverrideGpsTimeType(timeType);
            ILasHeader header = reader.getHeader();
            int gpsTimeType = header.getGpsTimeType();
            writer.setBounds(header);
            writer.open();

            pm.beginTask("Interpolating flight points and normalizing...", (int) header.getRecordsCount());
            while( reader.hasNextPoint() ) {
                LasRecord r = reader.getNextPoint();

                DateTime gpsTimeToDateTime;
                if (timeType == 0) {
                    gpsTimeToDateTime = GpsTimeConverter.gpsWeekTime2DateTime(r.gpsTime);
                } else {
                    gpsTimeToDateTime = LasUtils.adjustedStandardGpsTime2DateTime(r.gpsTime);
                }
                long gpsMillis = gpsTimeToDateTime.getMillis();
                Coordinate lasCoordinate = new Coordinate(r.x, r.y, r.z);
                Envelope pEnv = new Envelope(new Coordinate(gpsMillis, gpsMillis));
                List points = tree.query(pEnv);
                Coordinate[] flightCoords = (Coordinate[]) points.get(0);
                long d1 = points2dateMap.get(flightCoords[0]).getMillis();
                long d2 = points2dateMap.get(flightCoords[1]).getMillis();

                LineSegment line = new LineSegment(flightCoords[0], flightCoords[1]);
                double fraction = (gpsMillis - d1) / (d2 - d1);
                Coordinate interpolatedFlightPoint = line.pointAlong(fraction);
                // calculate interpolated elevation

                double distX = interpolatedFlightPoint.distance(flightCoords[0]);
                double dist12 = flightCoords[1].distance(flightCoords[0]);
                double interpolatedElev = distX / dist12 * (flightCoords[1].z - flightCoords[0].z) + flightCoords[0].z;
                interpolatedFlightPoint.z = interpolatedElev;

                double distanceFlightTerrain = GeometryUtilities.distance3d(lasCoordinate, interpolatedFlightPoint, null);

                short norm = (short) floor(r.intensity * pow(distanceFlightTerrain, 2.0) / pStdRange + 0.5);
                r.intensity = norm;
                writer.addPoint(r);

                pm.worked(1);
            }
            pm.done();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy