/*
* 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.hortonmachine.modules.hydrogeomorphology.adige.core;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor;
import org.jgrasstools.hortonmachine.modules.network.PfafstetterNumber;
import org.jgrasstools.hortonmachine.modules.network.networkattributes.NetworkChannel;
import org.opengis.feature.simple.SimpleFeature;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
/**
* The hillslope area, related to a particular network link.
*
* @author Andrea Antonello - www.hydrologis.com
*/
public class HillSlope implements IHillSlope {
private int hillslopeId = -1;
private SimpleFeature hillslopeFeature = null;
private SimpleFeature linkFeature = null;
private PfafstetterNumber pfafstetterNumber = null;
private final List<IHillSlope> upstreamElements = new ArrayList<IHillSlope>();
private IHillSlope downstreamElement = null;
private IHillSlope firstOfMaiorBasin = null;
private Geometry totalGeometryUpstream;
private Random rn;
private double hillslopeArea = -1;
private double hillslopeUpstreamArea = -1;
private double linkLength = -1;
private double linkSlope = -1;
private double baricenterElevation = -1;
public HillSlope( SimpleFeature netFeature, SimpleFeature basinFeature, PfafstetterNumber pfafNumber, int hillslopeId ) {
this.hillslopeId = hillslopeId;
this.hillslopeFeature = basinFeature;
this.linkFeature = netFeature;
this.pfafstetterNumber = pfafNumber;
rn = new Random();
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getHillslopeId()
*/
public int getHillslopeId() {
return hillslopeId;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getLinkFeature()
*/
public SimpleFeature getLinkFeature() {
return linkFeature;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getLinkLength()
*/
public double getLinkLength() {
if (linkLength == -1) {
linkLength = ((Geometry) linkFeature.getDefaultGeometry()).getLength(); // [m]
}
return linkLength;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getLinkSlope()
*/
public double getLinkSlope() {
if ((int) linkSlope == -1) {
// hillslopeFeature.getAttribute(baricenterElevationAttribute);
double startElev = (Double) linkFeature.getAttribute(NetworkChannel.STARTELEVNAME);
double endElev = (Double) linkFeature.getAttribute(NetworkChannel.ENDELEVNAME);
linkSlope = (startElev - endElev) / getLinkLength();
if (linkSlope <= 0) {
/*
* if < 0 then probably it is very flat and the dem si not precise. The slope is
* set.
*/
linkSlope = 0.001;
}
}
return linkSlope;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getLinkWidth(double, double, double)
*/
public double getLinkWidth( double coefficient, double exponent, double sdResiduals ) {
// Returns a random value that follows a gaussian distribution
double sampleGaussian = rn.nextGaussian() * sdResiduals;
double upstreamArea = getUpstreamArea(null) / 1000000.0;
double width = coefficient * Math.pow(upstreamArea, exponent) * Math.exp(sampleGaussian);
return width;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getLinkChezi(double, double)
*/
public double getLinkChezi( double coefficient, double exponent ) {
double chezi = coefficient * Math.pow(getLinkSlope(), exponent);
return chezi;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getHillslopeFeature()
*/
public SimpleFeature getHillslopeFeature() {
return hillslopeFeature;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getHillslopeArea()
*/
public double getHillslopeArea() {
if (hillslopeArea == -1) {
hillslopeArea = ((Geometry) hillslopeFeature.getDefaultGeometry()).getArea(); // m^2
}
return hillslopeArea;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getBaricenterElevation()
*/
public double getBaricenterElevation() {
if (baricenterElevation == -1) {
baricenterElevation = (Double) hillslopeFeature.getAttribute(NetworkChannel.BARICENTERELEVNAME);
}
return baricenterElevation;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getHillslopeClosure()
*/
public Coordinate getHillslopeClosure() {
Coordinate[] coords = ((Geometry) linkFeature.getDefaultGeometry()).getCoordinates();
return coords[coords.length - 1];
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getGeometry(java.util.List, org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor, boolean)
*/
public Geometry getGeometry( List<PfafstetterNumber> limit, IJGTProgressMonitor pm, boolean doMonitor ) {
if (limit == null && totalGeometryUpstream != null) {
return totalGeometryUpstream;
}
List<Geometry> geometries = new ArrayList<Geometry>();
geometries.add((Geometry) hillslopeFeature.getDefaultGeometry());
getAllUpstreamElementsGeometries(geometries, limit, this);
GeometryFactory gFactory = new GeometryFactory();
/*
* join the geoms to a single one
*/
Geometry runningGeometry = geometries.get(0);
if (doMonitor)
pm.beginTask("Estrazione geometrie dei bacini elementari a monte", geometries.size() - 1);
for( int i = 1; i < geometries.size(); i++ ) {
if (doMonitor) {
pm.worked(1);
} else {
pm.subTask("Unione geometrie " + i + "/" + (geometries.size() - 1));
}
List<Geometry> tmp = new ArrayList<Geometry>(2);
tmp.add(runningGeometry);
tmp.add(geometries.get(i));
Geometry gCollection = gFactory.buildGeometry(tmp);
runningGeometry = gCollection.buffer(0.0);
}
pm.subTask("");
if (doMonitor)
pm.done();
// keep the total geometry, in case it is asked again
if (limit == null) {
totalGeometryUpstream = runningGeometry;
}
return runningGeometry;
// return gCollection.buffer(0.0);
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getUpstreamArea(java.util.List)
*/
public double getUpstreamArea( List<PfafstetterNumber> limit ) {
if (hillslopeUpstreamArea == -1) {
List<IHillSlope> basins = new ArrayList<IHillSlope>();
getAllUpstreamElements(basins, limit);
hillslopeUpstreamArea = 0;
for( IHillSlope elementarBasin : basins ) {
hillslopeUpstreamArea = hillslopeUpstreamArea + elementarBasin.getHillslopeArea();
}
}
return hillslopeUpstreamArea;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getPfafstetterNumber()
*/
public PfafstetterNumber getPfafstetterNumber() {
return pfafstetterNumber;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getFirstOfMaiorBasinElement()
*/
public IHillSlope getFirstOfMaiorBasinElement() {
return firstOfMaiorBasin;
}
// public UpstreamElement[] getHeadElements() {
//
// return null;
// }
//
// public UpstreamElement getStartElement() {
// UpstreamElement ue = getConnectedDownstreamElement().getStartElement();
// if (ue == null) {
// return this;
// }
// return ue;
// }
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#addConnectedUpstreamElementWithCheck(org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.HillSlope)
*/
public boolean addConnectedUpstreamElementWithCheck( IHillSlope element ) {
if (PfafstetterNumber.areConnectedUpstream(this.getPfafstetterNumber(), element.getPfafstetterNumber())) {
if (!upstreamElements.contains(element)) {
upstreamElements.add(element);
element.addConnectedDownstreamElementWithCheck(this);
}
return true;
}
return false;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#addConnectedDownstreamElementWithChech(org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.HillSlope)
*/
public boolean addConnectedDownstreamElementWithCheck( IHillSlope element ) {
if (PfafstetterNumber.areConnectedDownstream(this.getPfafstetterNumber(), element.getPfafstetterNumber())) {
downstreamElement = element;
element.addConnectedUpstreamElementWithCheck(this);
return true;
}
return false;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getUpstreamElementAtPfafstetter(org.jgrasstools.hortonmachine.modules.network.PfafstetterNumber)
*/
public IHillSlope getUpstreamElementAtPfafstetter( PfafstetterNumber pNum ) {
// am I the one
if (pfafstetterNumber.compareTo(pNum) == 0) {
return this;
}
// // perhaps my upstream elements
// for( UpstreamElement upstreamElement : upstreamElements ) {
// if (upstreamElement.getPfafstetterNumber().compare(
// upstreamElement.getPfafstetterNumber(), pNum) == 0) {
// return upstreamElement;
// }
// }
// digg further
IHillSlope theChosen = null;
for( IHillSlope upstreamElement : upstreamElements ) {
theChosen = upstreamElement.getUpstreamElementAtPfafstetter(pNum);
if (theChosen != null) {
break;
}
}
return theChosen;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getConnectedDownstreamElement()
*/
public IHillSlope getConnectedDownstreamElement() {
if (downstreamElement == null) {
return null;
}
return downstreamElement;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getConnectedUpstreamElements()
*/
public List<IHillSlope> getConnectedUpstreamElements() {
if (upstreamElements.size() > 0) {
return upstreamElements;
}
return null;
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getAllUpstreamElements(java.util.List, java.util.List)
*/
public void getAllUpstreamElements( List<IHillSlope> elems, List<PfafstetterNumber> limit ) {
// if the limit is the number of the actual element, return
if (limit != null && limit.size() > 0) {
for( PfafstetterNumber pfafs : limit ) {
if (pfafs.compareTo(pfafstetterNumber) == 0) {
return;
}
}
}
elems.add(this);
for( IHillSlope upstreamElement : upstreamElements ) {
upstreamElement.getAllUpstreamElements(elems, limit);
}
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#getAllUpstreamElementsGeometries(java.util.List, java.util.List, org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope)
*/
public void getAllUpstreamElementsGeometries( List<Geometry> elems, List<PfafstetterNumber> limit,
IHillSlope firstOfMaiorBasin ) {
// if the limit is the number of the actual element, return
if (limit != null && limit.size() > 0) {
for( PfafstetterNumber pfafs : limit ) {
if (pfafs.compareTo(pfafstetterNumber) == 0) {
return;
}
}
}
this.firstOfMaiorBasin = firstOfMaiorBasin;
elems.add((Geometry) hillslopeFeature.getDefaultGeometry());
for( IHillSlope upstreamElement : upstreamElements ) {
upstreamElement.getAllUpstreamElementsGeometries(elems, limit, firstOfMaiorBasin);
}
}
/**
* Connect the various elements in a chain of tributary basins and nets
*
* @param elements
*/
public static void connectElements( List<IHillSlope> elements ) {
Collections.sort(elements, elements.get(0));
for( int i = 0; i < elements.size(); i++ ) {
IHillSlope elem = elements.get(i);
for( int j = i + 1; j < elements.size(); j++ ) {
IHillSlope tmp = elements.get(j);
elem.addConnectedDownstreamElementWithCheck(tmp);
}
}
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#toString()
*/
@SuppressWarnings("nls")
public String toString() {
StringBuilder b = new StringBuilder();
b.append("=====================\n= PF: " + pfafstetterNumber).append("\n= ").append("DownElem: \n= ");
if (downstreamElement != null) {
b.append(downstreamElement.getPfafstetterNumber()).append("\n= ");
}
b.append("UpElem:\n= ");
for( int i = 0; i < upstreamElements.size(); i++ ) {
if (upstreamElements.get(i) != null)
b.append("\t" + upstreamElements.get(i).getPfafstetterNumber()).append("\n= ");
}
b.append("\n=====================\n");
return b.toString();
}
/* (non-Javadoc)
* @see org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.IHillSlope#compare(org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.HillSlope, org.jgrasstools.hortonmachine.modules.hydrogeomorphology.adige.core.HillSlope)
*/
public int compare( IHillSlope ue1, IHillSlope ue2 ) {
PfafstetterNumber p1 = ue1.getPfafstetterNumber();
PfafstetterNumber p2 = ue2.getPfafstetterNumber();
return p1.compareTo(p2);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + hillslopeId;
result = prime * result + ((pfafstetterNumber == null) ? 0 : pfafstetterNumber.hashCode());
return result;
}
@Override
public boolean equals( Object obj ) {
if (obj instanceof IHillSlope) {
IHillSlope other = (IHillSlope) obj;
PfafstetterNumber p1 = getPfafstetterNumber();
PfafstetterNumber p2 = other.getPfafstetterNumber();
return p1.compareTo(p2) == 0;
}
return false;
}
}