/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.jgrasstools.gears.io.las;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.geometry.jts.ReferencedEnvelope3D;
import org.jgrasstools.gears.io.las.core.ALasReader;
import org.jgrasstools.gears.io.las.core.ILasHeader;
import org.jgrasstools.gears.io.las.core.LasRecord;
import org.jgrasstools.gears.io.las.index.LasIndexer;
import org.jgrasstools.gears.io.las.index.OmsLasIndexReader;
import org.jgrasstools.gears.libs.modules.JGTConstants;
import org.jgrasstools.gears.utils.CrsUtilities;
import org.jgrasstools.gears.utils.coverage.CoverageUtilities;
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.Polygon;
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
import com.vividsolutions.jts.index.strtree.STRtree;
/**
* A class that manages las folder data.
*
* @author Andrea Antonello (www.hydrologis.com)
*/
class LasFileDataManager extends ALasDataManager {
private File lasFile;
private GridCoverage2D inDem;
private double elevThreshold;
private SimpleFeatureCollection overviewFeatures;
private ReferencedEnvelope referencedEnvelope2D;
private List<ReferencedEnvelope> referencedEnvelope2DList = new ArrayList<ReferencedEnvelope>();
private List<String> fileNamesList = new ArrayList<String>();
private ReferencedEnvelope3D referencedEnvelope3D;
private ALasReader lasReader;
private ILasHeader lasHeader;
private boolean isOpen;
private STRtree pointsTree;
/**
* Constructor.
*
* @param lasFile the las folder index file.
* @param inDem a dem to normalize the elevation. If <code>null</code>, the original las elevation is used.
* @param elevThreshold a threshold to use for the elevation normalization.
* @param inCrs the data {@link org.opengis.referencing.crs.CoordinateReferenceSystem}. if null, the one of the dem is read, if available.
*/
LasFileDataManager( File lasFile, GridCoverage2D inDem, double elevThreshold, CoordinateReferenceSystem inCrs ) {
this.lasFile = lasFile;
this.inDem = inDem;
this.elevThreshold = elevThreshold;
fileNamesList.add(lasFile.getName());
try {
// prj file rules if available
inCrs = CrsUtilities.readProjectionFile(lasFile.getAbsolutePath(), "las");
} catch (Exception e) {
// ignore and try to read
}
if (inCrs != null) {
crs = inCrs;
} else if (inDem != null) {
crs = inDem.getCoordinateReferenceSystem();
} else {
throw new IllegalArgumentException("The Crs can't be null.");
}
}
@Override
public File getFile() {
return lasFile;
}
/**
* Open the main folder file and read the main index.
*
* @throws Exception
*/
@Override
public void open() throws Exception {
lasReader = ALasReader.getReader(lasFile, crs);
lasReader.open();
lasHeader = lasReader.getHeader();
isOpen = true;
}
@SuppressWarnings("unchecked")
@Override
public synchronized List<LasRecord> getPointsInGeometry( Geometry checkGeom, boolean doOnlyEnvelope ) throws Exception {
checkOpen();
ArrayList<LasRecord> pointsListForTile = new ArrayList<LasRecord>();
Envelope checkEnvelope = checkGeom.getEnvelopeInternal();
if (pointsTree != null) {
List<LasRecord> pointsList = pointsTree.query(checkEnvelope);
PreparedGeometry preparedGeometry = null;
if (!doOnlyEnvelope) {
preparedGeometry = PreparedGeometryFactory.prepare(checkGeom);
}
for( LasRecord lasDot : pointsList ) {
Coordinate c = new Coordinate(lasDot.x, lasDot.y);
if (!checkEnvelope.contains(c)) {
continue;
}
if (!doOnlyEnvelope && !preparedGeometry.contains(gf.createPoint(c))) {
continue;
}
pointsListForTile.add(lasDot);
}
} else {
pointsTree = new STRtree();
ReferencedEnvelope overallEnvelope = getOverallEnvelope();
if (doOnlyEnvelope && checkEnvelope.covers(overallEnvelope)) {
// read it straight
while( lasReader.hasNextPoint() ) {
LasRecord lasDot = lasReader.getNextPoint();
if (!doAccept(lasDot)) {
continue;
}
pointsTree.insert(new Envelope(new Coordinate(lasDot.x, lasDot.y)), lasDot);
pointsListForTile.add(lasDot);
}
} else {
Envelope env = checkGeom.getEnvelopeInternal();
PreparedGeometry preparedGeometry = null;
if (!doOnlyEnvelope) {
preparedGeometry = PreparedGeometryFactory.prepare(checkGeom);
}
while( lasReader.hasNextPoint() ) {
LasRecord lasDot = lasReader.getNextPoint();
if (!doAccept(lasDot)) {
continue;
}
Coordinate c = new Coordinate(lasDot.x, lasDot.y);
pointsTree.insert(new Envelope(c), lasDot);
if (!env.contains(c)) {
continue;
}
if (inDem != null) {
// check geom instead of only envelope?
if (!doOnlyEnvelope && !preparedGeometry.contains(gf.createPoint(c))) {
continue;
}
double value = CoverageUtilities.getValue(inDem, lasDot.x, lasDot.y);
if (JGTConstants.isNovalue(value)) {
continue;
}
double height = lasDot.z - value;
if (height > elevThreshold) {
lasDot.groundElevation = height;
pointsListForTile.add(lasDot);
}
} else {
if (!doOnlyEnvelope && !preparedGeometry.contains(gf.createPoint(c))) {
continue;
}
pointsListForTile.add(lasDot);
}
}
}
close();
}
return pointsListForTile;
}
@Override
public synchronized List<Geometry> getEnvelopesInGeometry( Geometry checkGeom, boolean doOnlyEnvelope, double[] minMaxZ )
throws Exception {
checkOpen();
ReferencedEnvelope3D dataEnvelope = lasHeader.getDataEnvelope();
Polygon envelopePolygon = LasIndexer.envelopeToPolygon(dataEnvelope);
ArrayList<Geometry> envelopeList = new ArrayList<Geometry>();
envelopeList.add(envelopePolygon);
return envelopeList;
}
@Override
public synchronized ReferencedEnvelope getOverallEnvelope() throws Exception {
if (referencedEnvelope2D == null) {
checkOpen();
ReferencedEnvelope3D dataEnvelope = lasHeader.getDataEnvelope();
referencedEnvelope2D = new ReferencedEnvelope(dataEnvelope, crs);
referencedEnvelope2DList.add(referencedEnvelope2D);
}
return referencedEnvelope2D;
}
@Override
public List<ReferencedEnvelope> getEnvelopeList() throws Exception {
getOverallEnvelope();
return referencedEnvelope2DList;
}
@Override
public synchronized ReferencedEnvelope3D getEnvelope3D() throws Exception {
if (referencedEnvelope3D == null) {
checkOpen();
ReferencedEnvelope3D dataEnvelope = lasHeader.getDataEnvelope();
referencedEnvelope3D = new ReferencedEnvelope3D(dataEnvelope, crs);
}
return referencedEnvelope3D;
}
@Override
public synchronized SimpleFeatureCollection getOverviewFeatures() throws Exception {
if (overviewFeatures == null) {
List<ReferencedEnvelope> envelopeList = getEnvelopeList();
SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
b.setName("overview");
b.setCRS(crs);
b.add("the_geom", Polygon.class);
b.add("name", String.class);
SimpleFeatureType type = b.buildFeatureType();
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
overviewFeatures = new DefaultFeatureCollection();
for( int i = 0; i < envelopeList.size(); i++ ) {
String name = fileNamesList.get(i);
ReferencedEnvelope envelope = envelopeList.get(i);
Polygon polygon = OmsLasIndexReader.envelopeToPolygon(envelope);
Object[] objs = new Object[]{polygon, name};
builder.addAll(objs);
SimpleFeature feature = builder.buildFeature(null);
((DefaultFeatureCollection) overviewFeatures).add(feature);
}
}
return overviewFeatures;
}
private void checkOpen() throws Exception {
if (!isOpen) {
open();
}
}
@Override
public void close() throws Exception {
isOpen = false;
if (lasReader != null)
lasReader.close();
}
}