org.jgrasstools.gears.libs.modules.ModelsEngine Maven / Gradle / Ivy
/*
* JGrass - Free Open Source Java GIS http://www.jgrass.org
* (C) HydroloGIS - www.hydrologis.com
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Library General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* This library 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 Library General Public License for more
* details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; if not, write to the Free Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.jgrasstools.gears.libs.modules;
import static java.lang.Math.PI;
import static java.lang.Math.abs;
import static java.lang.Math.exp;
import static java.lang.Math.log;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
import static org.jgrasstools.gears.libs.modules.JGTConstants.doubleNovalue;
import static org.jgrasstools.gears.libs.modules.JGTConstants.isNovalue;
import static org.jgrasstools.gears.utils.math.NumericsUtilities.dEq;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.media.jai.iterator.RandomIter;
import javax.media.jai.iterator.RandomIterFactory;
import javax.media.jai.iterator.WritableRandomIter;
import javax.vecmath.Point4d;
import org.geotools.coverage.grid.GridCoordinates2D;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.InvalidGridGeometryException;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.feature.FeatureCollections;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.DirectPosition2D;
import org.jgrasstools.gears.i18n.GearsMessageHandler;
import org.jgrasstools.gears.libs.exceptions.ModelsIllegalargumentException;
import org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor;
import org.jgrasstools.gears.utils.RegionMap;
import org.jgrasstools.gears.utils.coverage.CoverageUtilities;
import org.jgrasstools.gears.utils.math.NumericsUtilities;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateList;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
/**
* A class containing several methods used by the modules.
*
* The methods are not static for usage in multithreading environment.
*
* @author Andrea Antonello (www.hydrologis.com)
* @author Silvia Franceschi (www.hydrologis.com)
* @author Erica Ghesla
* @author Daniele Andreis
*/
@SuppressWarnings("unchecked")
public class ModelsEngine {
private static int[][] DIR = ModelsSupporter.DIR;
private static int[][] dirIn = ModelsSupporter.DIR_WITHFLOW_ENTERING;
private static GearsMessageHandler msg = GearsMessageHandler.getInstance();
public static PixelInCell DEFAULTPIXELANCHOR = PixelInCell.CELL_CENTER;
/**
* Moves one pixel downstream.
*
* @param colRow
* the array containing the column and row of the current pixel.
* It will be modified here to represent the next downstream
* pixel.
* @param flowdirection
* the current flowdirection number.
* @return true if everything went well.
*/
public static boolean go_downstream( int[] colRow, double flowdirection ) {
int n = (int) flowdirection;
if (n == 10) {
return true;
} else if (n < 1 || n > 9) {
return false;
} else {
colRow[1] += DIR[n][0];
colRow[0] += DIR[n][1];
return true;
}
}
/**
* Moves one pixel upstream.
*
* @param p
* @param flowRandomIter
* @param tcaRandomIter
* @param lRandomIter
* @param param
*/
public static void go_upstream_a( int[] p, RandomIter flowRandomIter, RandomIter tcaRandomIter, RandomIter lRandomIter,
int[] param ) {
double area = 0, lenght = 0;
int[] point = new int[2];
int kk = 0, count = 0;
point[0] = p[0];
point[1] = p[1];
// check how many pixels are draining in the considered pixel and select
// the pixel with maximun tca
for( int k = 1; k <= 8; k++ ) {
if (flowRandomIter.getSampleDouble(p[0] + dirIn[k][1], p[1] + dirIn[k][0], 0) == dirIn[k][2]) {
// counts how many pixels are draining in the considere
count++;
if (tcaRandomIter.getSampleDouble(p[0] + dirIn[k][1], p[1] + dirIn[k][0], 0) >= area) {
// if two pixels has the same tca select the pixel with the
// maximum vale of hacklength
if (tcaRandomIter.getSampleDouble(p[0] + dirIn[k][1], p[1] + dirIn[k][0], 0) == area) {
if (lRandomIter.getSampleDouble(p[0] + dirIn[k][1], p[1] + dirIn[k][0], 0) > lenght) {
kk = k;
area = tcaRandomIter.getSampleDouble(p[0] + dirIn[k][1], p[1] + dirIn[k][0], 0);
lenght = lRandomIter.getSampleDouble(p[0] + dirIn[k][1], p[1] + dirIn[k][0], 0);
point[0] = p[0] + dirIn[k][1];
point[1] = p[1] + dirIn[k][0];
}
} else {
kk = k;
area = tcaRandomIter.getSampleDouble(p[0] + dirIn[k][1], p[1] + dirIn[k][0], 0);
lenght = lRandomIter.getSampleDouble(p[0] + dirIn[k][1], p[1] + dirIn[k][0], 0);
point[0] = p[0] + dirIn[k][1];
point[1] = p[1] + dirIn[k][0];
}
}
}
}
p[0] = point[0];
p[1] = point[1];
param[0] = kk;
param[1] = count;
}
/**
* Moves one pixel upstream following the supplied network. TODO Daniele doc
*
* @param colRow
* @param flowIterator
* @param netnumIterator
* @param param
*/
public static void goUpStreamOnNetFixed( int[] colRow, RandomIter flowIterator, RandomIter netnumIterator, int[] param ) {
int kk = 0, count = 0;
int[] point = new int[2];
for( int k = 1; k <= 8; k++ ) {
if (flowIterator.getSampleDouble(colRow[0] + dirIn[k][1], colRow[1] + dirIn[k][0], 0) == dirIn[k][2]) {
count++;
if (netnumIterator.getSampleDouble(colRow[0] + dirIn[k][1], colRow[1] + dirIn[k][0], 0) == netnumIterator
.getSampleDouble(colRow[0], colRow[1], 0)) {
kk = k;
point[0] = colRow[0] + dirIn[k][1];
point[1] = colRow[1] + dirIn[k][0];
}
}
}
if (kk == 0) {
for( int k = 1; k <= 8; k++ ) {
if (flowIterator.getSampleDouble(colRow[0] + dirIn[k][1], colRow[1] + dirIn[k][0], 0) == dirIn[k][2]) {
kk = k;
point[0] = colRow[0] + dirIn[k][1];
point[1] = colRow[1] + dirIn[k][0];
}
}
}
colRow[0] = point[0];
colRow[1] = point[1];
param[0] = kk;
param[1] = count;
}
/**
* It create the shape-file of channel network
*
* @param flowImage the map of flow direction.
* @param netNumImage the map of netnumbering.
* @param gridGeometry the {@link GridGeometry2D} of the flow coverage.
* @param nstream
* @param pm the progress monitor.
* @return the extracted features.
* @throws IOException
* @throws TransformException
*/
public static SimpleFeatureCollection net2ShapeOnly( RenderedImage flowImage, WritableRaster netNumImage,
GridGeometry2D gridGeometry, List nstream, IJGTProgressMonitor pm ) throws IOException, TransformException {
int activecols = flowImage.getWidth();
int activerows = flowImage.getHeight();
int[] flow = new int[2];
int[] flow_p = new int[2];
CoordinateList coordlist = new CoordinateList();
RandomIter m1RandomIter = RandomIterFactory.create(flowImage, null);
RandomIter netNumRandomIter = RandomIterFactory.create(netNumImage, null);
// GEOMETRY
// creates new LineSting array
LineString[] newGeometry = new LineString[nstream.size()];
// creates a vector of geometry
List newGeometryVectorLine = new ArrayList();
GeometryFactory newfactory = new GeometryFactory();
pm.beginTask(msg.message("utils.extracting_network_geometries"), nstream.size());
for( int num = 1; num <= nstream.size(); num++ ) {
for( int y = 0; y < activerows; y++ ) {
for( int x = 0; x < activecols; x++ ) {
if (!isNovalue(m1RandomIter.getSampleDouble(x, y, 0))) {
flow[0] = x;
flow[1] = y;
// looks for the source
if (netNumRandomIter.getSampleDouble(x, y, 0) == num) {
// if the point is a source it starts to extract the
// channel...
if (sourcesNet(m1RandomIter, flow, num, netNumRandomIter)) {
flow_p[0] = flow[0];
flow_p[1] = flow[1];
double[] worldPosition = gridGeometry.gridToWorld(new GridCoordinates2D(flow[0], flow[1]))
.getCoordinate();
Coordinate coordSource = new Coordinate(worldPosition[0], worldPosition[1]);
// creates new Object Coordinate... SOURCE
// POINT...
// adds the points to the CoordinateList
coordlist.add(coordSource);
if (!go_downstream(flow, m1RandomIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
// it extracts the other points of the
// channel... it
// continues until the next node...
while( !isNovalue(m1RandomIter.getSampleDouble(flow[0], flow[1], 0))
&& m1RandomIter.getSampleDouble(flow[0], flow[1], 0) != 10.0
&& netNumRandomIter.getSampleDouble(flow[0], flow[1], 0) == num
&& !isNovalue(netNumRandomIter.getSampleDouble(flow[0], flow[1], 0)) ) {
worldPosition = gridGeometry.gridToWorld(new GridCoordinates2D(flow[0], flow[1]))
.getCoordinate();
Coordinate coordPoint = new Coordinate(worldPosition[0], worldPosition[1]);
// creates new Object Coordinate... CHANNEL
// POINT...
// adds new points to CoordinateList
coordlist.add(coordPoint);
flow_p[0] = flow[0];
flow_p[1] = flow[1];
if (!go_downstream(flow, m1RandomIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
}
worldPosition = gridGeometry.gridToWorld(new GridCoordinates2D(flow[0], flow[1])).getCoordinate();
Coordinate coordNode = new Coordinate(worldPosition[0], worldPosition[1]);
// creates new Object Coordinate... NODE
// POINT...
// adds new points to CoordinateList
coordlist.add(coordNode);
}
}
}
}
}
// when the channel is complete creates one new geometry (new
// channel of the network)
newGeometry[num - 1] = newfactory.createLineString(coordlist.toCoordinateArray());
// adds the new geometry to the vector of geometry
newGeometryVectorLine.add(newGeometry[num - 1]);
// it removes every element of coordlist
coordlist.clear();
pm.worked(1);
}
pm.done();
// create the feature type
SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
b.setName("network"); //$NON-NLS-1$
b.setCRS(gridGeometry.getCoordinateReferenceSystem());
b.add("the_geom", LineString.class); //$NON-NLS-1$
SimpleFeatureType type = b.buildFeatureType();
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
SimpleFeatureCollection featureCollection = FeatureCollections.newCollection();
int index = 0;
for( LineString lineString : newGeometryVectorLine ) {
Object[] values = new Object[]{lineString};
// add the values
builder.addAll(values);
// build the feature with provided ID
SimpleFeature feature = builder.buildFeature(type.getTypeName() + "." + index); //$NON-NLS-1$
index++;
featureCollection.add(feature);
}
return featureCollection;
}
/**
* Create the {@link MultiLineString line} geometries of channel network
*
* @param flowIter the flow map.
* @param netNumIter the netnumbering map.
* @param nstream
* @param pm the progress monitor.
* @param gridGeometry the gridgeometry.
* @return the geometries of the network.
* @throws IOException
* @throws TransformException
*/
public static List net2ShapeGeometries( WritableRandomIter flowIter, RandomIter netNumIter, int[] nstream,
GridGeometry2D gridGeometry, IJGTProgressMonitor pm ) throws IOException, TransformException {
GridEnvelope2D gridRange = gridGeometry.getGridRange2D();
int rows = gridRange.height;
int cols = gridRange.width;
// screen2world
MathTransform2D gridToCRS2D = gridGeometry.getGridToCRS2D();
// get rows and cols from the active region
int[] flow = new int[2];
int[] flow_p = new int[2];
CoordinateList coordlist = new CoordinateList();
// creates a vector of geometry
List newGeometryVectorLine = new ArrayList();
GeometryFactory newfactory = new GeometryFactory();
/* name of new geometry (polyline) */
pm.beginTask("Extracting the network geometries...", nstream[0]);
for( int num = 1; num <= nstream[0]; num++ ) {
for( int y = 0; y < rows; y++ ) {
for( int x = 0; x < cols; x++ ) {
flow[0] = x;
flow[1] = y;
// looks for the source
if (netNumIter.getSampleDouble(x, y, 0) == num) {
// if the point is a source it starts to extract the
// channel...
if (sourcesNet(flowIter, flow, num, netNumIter)) {
flow_p[0] = flow[0];
flow_p[1] = flow[1];
Point2D worldPosition = new Point2D.Double(flow[0], flow[1]);
gridToCRS2D.transform(worldPosition, worldPosition);
Coordinate coordSource = new Coordinate(worldPosition.getX(), worldPosition.getY());
// creates new Object Coordinate... SOURCE POINT...
// adds the points to the CoordinateList
coordlist.add(coordSource);
if (!go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
// it extracts the other points of the channel... it
// continues until the next node...
while( !isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))
&& flowIter.getSampleDouble(flow[0], flow[1], 0) != 10.0
&& netNumIter.getSampleDouble(flow[0], flow[1], 0) == num
&& !isNovalue(netNumIter.getSampleDouble(flow[0], flow[1], 0)) ) {
worldPosition = new Point2D.Double(flow[0], flow[1]);
gridToCRS2D.transform(worldPosition, worldPosition);
Coordinate coordPoint = new Coordinate(worldPosition.getX(), worldPosition.getY());
// creates new Object Coordinate... CHANNEL
// POINT...
// adds new points to CoordinateList
coordlist.add(coordPoint);
flow_p[0] = flow[0];
flow_p[1] = flow[1];
if (!go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
}
worldPosition = new Point2D.Double(flow[0], flow[1]);
gridToCRS2D.transform(worldPosition, worldPosition);
Coordinate coordNode = new Coordinate(worldPosition.getX(), worldPosition.getY());
// creates new Object Coordinate... NODE POINT...
// adds new points to CoordinateList
coordlist.add(coordNode);
}
}
}
}
// when the channel is complete creates one new geometry (new
// channel of the network)
// adds the new geometry to the vector of geometry
// if (!coordlist.isEmpty()) {
newGeometryVectorLine.add(newfactory.createMultiLineString(new LineString[]{newfactory.createLineString(coordlist
.toCoordinateArray())}));
// } else {
// if (out != null)
// out.println("Found an empty geometry at " + num);
// }
// it removes every element of coordlist
coordlist.clear();
pm.worked(1);
}
pm.done();
return newGeometryVectorLine;
}
/**
* Controls if the considered point is a source in the network map.
*
* @param flowIterator
* {@link RandomIter iterator} of flowdirections map
* @param colRow the col and row of the point to check.
* @param num
* channel number
* @param netNum
* {@link RandomIter iterator} of the netnumbering map.
* @return
*/
public static boolean sourcesNet( RandomIter flowIterator, int[] colRow, int num, RandomIter netNum ) {
int[][] dir = {{0, 0, 0}, {1, 0, 5}, {1, -1, 6}, {0, -1, 7}, {-1, -1, 8}, {-1, 0, 1}, {-1, 1, 2}, {0, 1, 3}, {1, 1, 4}};
if (flowIterator.getSampleDouble(colRow[0], colRow[1], 0) <= 10.0
&& flowIterator.getSampleDouble(colRow[0], colRow[1], 0) > 0.0) {
for( int k = 1; k <= 8; k++ ) {
if (flowIterator.getSampleDouble(colRow[0] + dir[k][0], colRow[1] + dir[k][1], 0) == dir[k][2]
&& netNum.getSampleDouble(colRow[0] + dir[k][0], colRow[1] + dir[k][1], 0) == num) {
return false;
}
}
return true;
} else {
return false;
}
}
/**
* Takes a input raster and vectorializes it.
*
* @param input
* @return
*/
public static double[] vectorizeDoubleMatrix( RenderedImage input ) {
double[] U = new double[input.getWidth() * input.getHeight()];
RandomIter inputRandomIter = RandomIterFactory.create(input, null);
int j = 0;
for( int i = 0; i < input.getHeight() * input.getWidth(); i = i + input.getWidth() ) {
double tmp[] = new double[input.getWidth()];
for( int k = 0; k < input.getWidth(); k++ ) {
tmp[k] = inputRandomIter.getSampleDouble(k, j, 0);
}
System.arraycopy(tmp, 0, U, i, input.getWidth());
j++;
}
return U;
}
/**
* TODO Daniele doc
*
* @param U
* @param T
* @param theSplit
* @param binNum
* @param num_max
* @param out
* @return
*/
public static double split2realvectors( double[] U, double[] T, SplitVectors theSplit, int binNum, int num_max,
IJGTProgressMonitor pm ) {
double binStep = 0, minValue = 0, maxValue;
int i, count = 0, previousCount, minPosition = 0, maxPosition = 0, emptyBins;
int[] bins;
int head = 0;
bins = new int[U.length];
if (binNum <= 1) {
previousCount = 1;
count = 1;
int index = 0;
while( count < U.length ) {
// was while( count <= U.length && U[count] == U[count - 1] ) {
while( count < U.length && U[count] == U[count - 1] ) {
count++;
}
index++;
bins[index] = count - previousCount;
head++;
previousCount = count;
count++;
if (head > num_max)
throw new ModelsIllegalargumentException("The number of bin eccedes the maximum number allowed.", "MODEL");
}
} else if (binNum > 1) {
minPosition = 0;
maxValue = U[U.length - 1];
while( minPosition < U.length && isNovalue(U[minPosition]) ) {
minPosition++;
}
if (minPosition == U.length) {
// force the situation of non calculation
binStep = 0;
} else {
minValue = U[minPosition];
maxPosition = U.length - 1;
binStep = (maxValue - minValue) / (binNum - 1);
}
if (binStep != 0) {
int binIndex = 0;
previousCount = minPosition; // the novalues are already left aside
count = minPosition;
emptyBins = 0;
double runningCenter = minValue + binStep / 2.0;
for( int n = 0; n < binNum - 1; n++ ) {
double upperLimitOfBin;
if (n == binNum - 2) {
upperLimitOfBin = maxValue;
} else {
upperLimitOfBin = runningCenter + binStep / 2.0;
}
if (U[count] <= upperLimitOfBin) {
double value = U[count];
while( value <= upperLimitOfBin ) {
count++;
if (count > maxPosition) {
break;
}
value = U[count];
}
bins[binIndex] = count - previousCount;
// contained in the bin
binIndex++;
head++;
previousCount = count;
// count++;
} else {
emptyBins++;
}
runningCenter += binStep;
}
if (emptyBins != 0) {
pm.message(emptyBins + " empty bins where found");
}
} else {
for( double tmpValue : U ) {
if (!isNovalue(tmpValue)) {
count++;
}
}
bins[0] = count;
head = count;
}
}
if (head < 1) {
throw new ModelsIllegalargumentException("Something wrong happened in binning", "MODEL");
} else {
theSplit.initIndex(head);
int maxnumberinbin = 0;
for( i = 0; i < head; i++ ) {
theSplit.splitIndex[i] = bins[i];
if (bins[i] > maxnumberinbin)
maxnumberinbin = bins[i];
}
/*
* now a list of the values inside the bins are put into the
* matrixes, therefore we need as many rows as bins and a column
* number high enough to hold the major number of values hold inside
* a bin.
*/
theSplit.initValues(head, maxnumberinbin);
int index = minPosition;
for( int j = 0; j < head; j++ ) {
for( int k = 0; k < theSplit.splitIndex[j]; k++ ) {
theSplit.splitValues1[j][k] = U[index];
theSplit.splitValues2[j][k] = T[index];
index++;
}
}
}
if (binNum < 2)
binStep = 0;
return binStep;
}
public static double doubleNMoment( double[] m, int nh, double mean, double NN, IJGTProgressMonitor pm ) {
double moment = 0.0, n;
n = 0;
if (NN == 1.0) {
for( int i = 0; i < nh; i++ ) {
if (!isNovalue(m[i])) {
moment += m[i];
n++;
}
}
if (n >= 1) {
moment /= n;
} else {
pm.errorMessage("No valid data were processed, setting moment value to zero.");
moment = 0.0;
}
} else if (NN == 2.0) {
for( int i = 0; i < nh; i++ ) {
if (!isNovalue(m[i])) {
moment += (m[i]) * (m[i]);
n++;
}
}
if (n >= 1) {
moment = (moment / n - mean * mean);
} else {
pm.errorMessage("No valid data were processed, setting moment value to zero.");
moment = 0.0;
}
} else {
for( int i = 0; i < nh; i++ ) {
if (!isNovalue(m[i])) {
moment += pow((m[i] - mean), NN);
n++;
}
}
if (n >= 1) {
moment /= n;
} else {
pm.errorMessage("No valid data were processed, setting moment value to zero.");
moment = 0.0;
}
}
return moment;
}
/**
* this method numerating every stream
*/
public static WritableRaster netNumbering( List nstream, RandomIter flowIter, RandomIter networkIter, int width,
int height, IJGTProgressMonitor pm ) {
int[] flow = new int[2];
int gg = 0, n = 0, f;
WritableRaster netnumWR = CoverageUtilities.createDoubleWritableRaster(width, height, null, null, null);
WritableRandomIter netnumIter = RandomIterFactory.createWritable(netnumWR, null);
/* numerating every stream */
GearsMessageHandler msg = GearsMessageHandler.getInstance();
pm.beginTask(msg.message("utils.numbering_stream"), height);
for( int j = 0; j < height; j++ ) {
for( int i = 0; i < width; i++ ) {
flow[0] = i;
flow[1] = j;
if (!isNovalue(networkIter.getSampleDouble(i, j, 0)) && flowIter.getSampleDouble(i, j, 0) != 10.0
&& netnumIter.getSampleDouble(i, j, 0) == 0.0) {
f = 0;
for( int k = 1; k <= 8; k++ ) {
if (flowIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0) == dirIn[k][2]
&& !isNovalue(networkIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0))) {
break;
} else
f++;
}
// if the pixel is a source...
if (f == 8) {
n++;
nstream.add(n);
netnumIter.setSample(i, j, 0, n);
if (!go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
while( !isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))
&& netnumIter.getSampleDouble(flow[0], flow[1], 0) == 0 ) {
gg = 0;
for( int k = 1; k <= 8; k++ ) {
if (!isNovalue(networkIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0))
&& flowIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0) == dirIn[k][2]) {
gg++;
}
}
if (gg >= 2) {
n++;
nstream.add(n);
netnumIter.setSample(flow[0], flow[1], 0, n);
} else {
netnumIter.setSample(flow[0], flow[1], 0, n);
}
if (!go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
}
}
}
}
pm.worked(1);
}
pm.done();
return netnumWR;
}
/**
* this method numerating every stream and subdivide the stream when tca is
* greater than a threshold
*/
public static WritableRaster netNumberingWithTca( List nstream, RandomIter mRandomIter, RandomIter netRandomIter,
RandomIter tcaRandomIter, int cols, int rows, double tcaTh, IJGTProgressMonitor pm ) {
int[] flow = new int[2];
int gg = 0, n = 0, f;
WritableRaster outImage = CoverageUtilities.createDoubleWritableRaster(cols, rows, null, null, null);
WritableRandomIter oMatrixRandomIter = RandomIterFactory.createWritable(outImage, null);
double tcaValue = 0;
pm.beginTask(msg.message("utils.numbering_stream"), rows);
/* numerating every stream */
for( int j = 0; j < rows; j++ ) {
// ShowPercent.getPercent(copt, i, rows - 1, 1);
for( int i = 0; i < cols; i++ ) {
flow[0] = i;
flow[1] = j;
if (!isNovalue(netRandomIter.getSampleDouble(i, j, 0)) && mRandomIter.getSampleDouble(i, j, 0) != 10.0
&& oMatrixRandomIter.getSampleDouble(i, j, 0) == 0.0) {
f = 0;
for( int k = 1; k <= 8; k++ ) {
if (mRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0) == dirIn[k][2]
&& !isNovalue(netRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0))) {
break;
} else
f++;
}
// if the pixel is a source...
if (f == 8) {
n++;
nstream.add(n);
tcaValue = tcaRandomIter.getSampleDouble(i, j, 0);
oMatrixRandomIter.setSample(i, j, 0, n);
if (!go_downstream(flow, mRandomIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
while( !isNovalue(mRandomIter.getSampleDouble(flow[0], flow[1], 0))
&& oMatrixRandomIter.getSampleDouble(flow[0], flow[1], 0) == 0 ) {
gg = 0;
for( int k = 1; k <= 8; k++ ) {
if (!isNovalue(netRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0))
&& mRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0) == dirIn[k][2]) {
gg++;
}
}
if (gg >= 2) {
// it is a node
n++;
nstream.add(n);
oMatrixRandomIter.setSample(flow[0], flow[1], 0, n);
tcaValue = tcaRandomIter.getSampleDouble(flow[0], flow[1], 0);
} else if (tcaRandomIter.getSampleDouble(flow[0], flow[1], 0) - tcaValue > tcaTh) {
// tca greater than threshold
n++;
nstream.add(n);
oMatrixRandomIter.setSample(flow[0], flow[1], 0, n);
tcaValue = tcaRandomIter.getSampleDouble(flow[0], flow[1], 0);
} else {
// normal point
oMatrixRandomIter.setSample(flow[0], flow[1], 0, n);
}
if (!go_downstream(flow, mRandomIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
}
}
}
}
pm.worked(1);
}
pm.done();
return outImage;
}
/**
* this method numerating every stream dividing the channels in fixed points
* @throws TransformException
* @throws InvalidGridGeometryException
*/
public static WritableRaster netNumberingWithPoints( List nstream, RandomIter mRandomIter, RandomIter netRandomIter,
int rows, int cols, List> attributePoints, List geomVect, GridGeometry2D gridGeometry,
IJGTProgressMonitor pm ) throws InvalidGridGeometryException, TransformException {
int[] flow = new int[2];
int gg = 0, n = 0, f;
WritableRaster outImage = CoverageUtilities.createDoubleWritableRaster(cols, rows, null, null, null);
WritableRandomIter oMatrixRandomIter = RandomIterFactory.createWritable(outImage, null);
Rectangle2D regionBox = gridGeometry.getEnvelope2D().getBounds2D();
List points = new ArrayList();
// new rectangle for active region
Number nodoId;
int l = 0;
int numGeometry = 0;
// insert the points in a Vector of points
for( Geometry pointV : geomVect ) {
for( int i = 0; i < pointV.getNumGeometries(); i++ ) {
GridCoordinates2D gridCoordinate = gridGeometry.worldToGrid(new DirectPosition2D(pointV.getCoordinates()[0].x,
pointV.getCoordinates()[0].y));
nodoId = (Number) attributePoints.get(numGeometry).get("RETE_ID");
if (nodoId == null) {
throw new ModelsIllegalargumentException("Field RETE_ID not found", "");
}
if (nodoId.intValue() != -1
&& regionBox.contains(new Point2D.Double(pointV.getCoordinates()[0].x, pointV.getCoordinates()[0].y))) {
points.add(new Point4d(gridCoordinate.x, gridCoordinate.y, nodoId.doubleValue(), 0));
l++;
}
}
numGeometry++;
}
// if the points isn't on the channel net, move the point
int p = 0;
for( Point4d point4d : points ) {
if (netRandomIter.getSampleDouble((int) point4d.x, (int) point4d.y, 0) != point4d.z) {
for( int i = 1; i < 9; i++ ) {
int indexI = (int) point4d.x + dirIn[i][1];
int indexJ = (int) point4d.y + dirIn[i][0];
if (netRandomIter.getSampleDouble(indexI, indexJ, 0) == point4d.z) {
point4d.x = indexI;
point4d.y = indexJ;
}
}
}
}
for( Point4d point4d : points ) {
if (netRandomIter.getSampleDouble((int) point4d.x, (int) point4d.y, 0) == point4d.z) {
p++;
}
}
pm.beginTask(msg.message("utils.numbering_stream"), rows);
/* Selects every node and go downstream */
for( int j = 0; j < rows; j++ ) {
// ShowPercent.getPercent(copt, i, rows - 1, 1);
for( int i = 0; i < cols; i++ ) {
flow[0] = i;
flow[1] = j;
if (!isNovalue(netRandomIter.getSampleDouble(i, j, 0)) && mRandomIter.getSampleDouble(i, j, 0) != 10.0
&& oMatrixRandomIter.getSampleDouble(i, j, 0) == 0.0) {
f = 0;
// look for the source...
for( int k = 1; k <= 8; k++ ) {
if (mRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0) == dirIn[k][2]
&& !isNovalue(netRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0))) {
break;
} else
f++;
}
// if the pixel is a source...starts to assign a number to
// every stream
if (f == 8) {
n++;
nstream.add(n);
oMatrixRandomIter.setSample(i, j, 0, n);
if (!go_downstream(flow, mRandomIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
for( Point4d point4d : points ) {
if (point4d.x == flow[0] && point4d.y == flow[1]) {
n++;
nstream.add(n);
point4d.w = n - 1;
/*
* omatrix.getSampleDouble(i,j) = n; if
* (!FluidUtils.go_downstream(flow,
* m.getSampleDouble(flow[0],flow[1]), copt)) ;
*/
}
}
while( !isNovalue(mRandomIter.getSampleDouble(flow[0], flow[1], 0))
&& oMatrixRandomIter.getSampleDouble(flow[0], flow[1], 0) == 0
&& mRandomIter.getSampleDouble(flow[0], flow[1], 0) != 10 ) {
gg = 0;
for( int k = 1; k <= 8; k++ ) {
if (!isNovalue(netRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0))
&& mRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0) == dirIn[k][2]) {
gg++;
}
}
if (gg >= 2) {
n++;
nstream.add(n);
oMatrixRandomIter.setSample(flow[0], flow[1], 0, n);
} else {
oMatrixRandomIter.setSample(flow[0], flow[1], 0, n);
}
if (!go_downstream(flow, mRandomIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
for( Point4d point4d : points ) {
if (point4d.x == flow[0] && point4d.y == flow[1]) {
n++;
nstream.add(n);
point4d.w = n - 1;
}
}
}
}
}
}
pm.worked(1);
}
pm.done();
return outImage;
}
/**
* this method numerating every stream dividing the channels in fixed points
* @param out
* @throws TransformException
* @throws InvalidGridGeometryException
*/
public static WritableRaster netNumberingWithPointsAndTca( List nstream, RandomIter mRandomIter,
RandomIter netRandomIter, RandomIter tcaRandomIter, double tcaTh, int rows, int cols,
List> attributePoints, List geomVect, GridGeometry2D gridGeometry,
IJGTProgressMonitor pm ) throws InvalidGridGeometryException, TransformException {
int[] flow = new int[2];
int gg = 0, n = 0, f;
double tcaValue = 0;
List points = new ArrayList();
// new rectangle for active region
Rectangle2D regionBox = gridGeometry.getEnvelope2D().getBounds2D();
Number nodoId;
int l = 0;
int numGeometry = 0;
// insert the points in a Vector of points
for( Geometry pointV : geomVect ) {
for( int i = 0; i < pointV.getNumGeometries(); i++ ) {
GridCoordinates2D gridCoordinate = gridGeometry.worldToGrid(new DirectPosition2D(pointV.getCoordinates()[0].x,
pointV.getCoordinates()[0].y));
nodoId = (Number) attributePoints.get(numGeometry).get("RETE_ID");
if (nodoId == null) {
throw new ModelsIllegalargumentException("Field RETE_ID not found", "");
}
if (nodoId.intValue() != -1
&& regionBox.contains(new Point2D.Double(pointV.getCoordinates()[0].x, pointV.getCoordinates()[0].y))) {
points.add(new Point4d(gridCoordinate.x, gridCoordinate.y, nodoId.doubleValue(), 0));
l++;
}
}
numGeometry++;
}
// if the points isn't on the channel net, move the point
int p = 0;
WritableRaster outImage = CoverageUtilities.createDoubleWritableRaster(cols, rows, null, null, null);
WritableRandomIter oRandomIter = RandomIterFactory.createWritable(outImage, null);
for( Point4d point4d : points ) {
if (netRandomIter.getSampleDouble((int) point4d.x, (int) point4d.y, 0) != point4d.z) {
for( int i = 1; i < 9; i++ ) {
int indexI = (int) point4d.x + dirIn[i][1];
int indexJ = (int) point4d.y + dirIn[i][0];
if (netRandomIter.getSampleDouble(indexI, indexJ, 0) == point4d.z) {
point4d.x = indexI;
point4d.y = indexJ;
}
}
}
}
for( Point4d point4d : points ) {
if (netRandomIter.getSampleDouble((int) point4d.x, (int) point4d.y, 0) == point4d.z) {
p++;
}
}
pm.beginTask(msg.message("utils.numbering_stream"), rows);
/* Selects every node and go downstream */
for( int j = 0; j < rows; j++ ) {
// ShowPercent.getPercent(copt, i, rows - 1, 1);
for( int i = 0; i < cols; i++ ) {
flow[0] = i;
flow[1] = j;
if (!isNovalue(netRandomIter.getSampleDouble(i, j, 0)) && mRandomIter.getSampleDouble(i, j, 0) != 10.0
&& oRandomIter.getSampleDouble(i, j, 0) == 0.0) {
f = 0;
// look for the source...
for( int k = 1; k <= 8; k++ ) {
if (mRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0) == dirIn[k][2]
&& !isNovalue(netRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0))) {
break;
} else
f++;
}
// if the pixel is a source...starts to assigne a number to
// every stream
if (f == 8) {
n++;
nstream.add(n);
oRandomIter.setSample(i, j, 0, n);
if (!go_downstream(flow, mRandomIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
for( Point4d point4d : points ) {
if (point4d.y == flow[1] && point4d.x == flow[0]) {
n++;
nstream.add(n);
point4d.w = n - 1;
/*
* omatrix.getValueAt(i,j) = n; if
* (!FluidUtils.go_downstream(flow,
* m.getValueAt(flow[0],flow[1]), copt)) ;
*/
}
}
while( !isNovalue(mRandomIter.getSampleDouble(flow[0], flow[1], 0))
&& oRandomIter.getSampleDouble(flow[0], flow[1], 0) == 0
&& mRandomIter.getSampleDouble(flow[0], flow[1], 0) != 10 ) {
gg = 0;
for( int k = 1; k <= 8; k++ ) {
if (!isNovalue(netRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0))
&& mRandomIter.getSampleDouble(flow[0] + dirIn[k][1], flow[1] + dirIn[k][0], 0) == dirIn[k][2]) {
gg++;
}
}
if (gg >= 2) {
// it is a node
n++;
oRandomIter.setSample(flow[0], flow[1], 0, n);
tcaValue = tcaRandomIter.getSampleDouble(flow[0], flow[1], 0);
} else if (tcaRandomIter.getSampleDouble(flow[0], flow[1], 0) - tcaValue > tcaTh) {
// tca greater than threshold
n++;
nstream.add(n);
oRandomIter.setSample(flow[0], flow[1], 0, n);
tcaValue = tcaRandomIter.getSampleDouble(flow[0], flow[1], 0);
} else {
// normal point
oRandomIter.setSample(flow[0], flow[1], 0, n);
}
if (!go_downstream(flow, mRandomIter.getSampleDouble(flow[0], flow[1], 0)))
return null;
for( Point4d point4d : points ) {
if (point4d.y == flow[1] && point4d.x == flow[0]) {
n++;
nstream.add(n);
point4d.w = n - 1;
}
}
}
}
}
}
pm.worked(1);
}
pm.done();
oRandomIter.done();
tcaRandomIter.done();
// mRandomIter.done();
// netRandomIter.done();
return outImage;
}
/**
* Extract the subbasins of a raster map.
*
* @param flowIter the map of flowdirections.
* @param netRandomIter the network map.
* @param netNumberIter the netnumber map.
* @param rows rows of the region.
* @param cols columns of the region.
* @param pm
* @return the map of extracted subbasins.
*/
public static WritableRaster extractSubbasins( WritableRandomIter flowIter, RandomIter netRandomIter,
WritableRandomIter netNumberIter, int rows, int cols, IJGTProgressMonitor pm ) {
for( int r = 0; r < rows; r++ ) {
for( int c = 0; c < cols; c++ ) {
if (!isNovalue(netRandomIter.getSampleDouble(c, r, 0)))
flowIter.setSample(c, r, 0, 10);
}
}
WritableRaster subbImage = go2channel(flowIter, netNumberIter, cols, rows, pm);
WritableRandomIter subbRandomIter = RandomIterFactory.createWritable(subbImage, null);
for( int r = 0; r < rows; r++ ) {
for( int c = 0; c < cols; c++ ) {
double netValue = netRandomIter.getSampleDouble(c, r, 0);
double netNumberValue = netNumberIter.getSampleDouble(c, r, 0);
if (!isNovalue(netValue)) {
subbRandomIter.setSample(c, r, 0, netNumberValue);
}
if (NumericsUtilities.dEq(netNumberValue, 0)) {
netNumberIter.setSample(c, r, 0, JGTConstants.doubleNovalue);
}
double subbValue = subbRandomIter.getSampleDouble(c, r, 0);
if (NumericsUtilities.dEq(subbValue, 0))
subbRandomIter.setSample(c, r, 0, JGTConstants.doubleNovalue);
}
}
return subbImage;
}
/**
* Moves from every source pixel to the outlet.
*
* @param flowIter map of flow direction.
* @param attributeIter map of attributes.
* @param cols
* @param rows
* @param pm
* @return the calculated distance map.
*/
public static WritableRaster go2channel( RandomIter flowIter, RandomIter attributeIter, int cols, int rows,
IJGTProgressMonitor pm ) {
int[] flowColRow = new int[2];
double value = 0.0;
WritableRaster dist = CoverageUtilities.createDoubleWritableRaster(cols, rows, null, null, null);
WritableRandomIter distIter = RandomIterFactory.createWritable(dist, null);
pm.beginTask("Calculating the distance along the flowstream...", rows - 2);
for( int r = 1; r < rows - 1; r++ ) {
for( int c = 1; c < cols - 1; c++ ) {
flowColRow[0] = c;
flowColRow[1] = r;
// Rectangle aroundSample = new Rectangle(i - 1, j - 1, 3, 3);
// Raster aroundRaster = flowImage.getData(aroundSample);
if (!isNovalue(flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0))
&& isSourcePixel(flowIter, flowColRow[0], flowColRow[1])) {
/*
* if in a source pixel, go downstream until you get
* to a novalue or an exit.
*/
while( !isNovalue(flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0))
&& flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0) != 10.0 ) {
if (!go_downstream(flowColRow, flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0)))
return null;
}
/*
* get the value that the basin should have
*/
if (isNovalue(flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0))) {
throw new ModelsIllegalargumentException("No proper outlets were found in the flow file", "ModelsEngine");
} else if (flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0) == 10) {
value = attributeIter.getSampleDouble(flowColRow[0], flowColRow[1], 0);
} else {
throw new ModelsIllegalargumentException("Undefined situation while go2channel", "ModelsEngine");
}
/*
* and start over again, setting the whole downstream to that value == basin number
*/
flowColRow[0] = c;
flowColRow[1] = r;
distIter.setSample(c, r, 0, value);
while( !isNovalue(flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0))
&& flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0) != 10.0 ) {
distIter.setSample(flowColRow[0], flowColRow[1], 0, value);
if (!go_downstream(flowColRow, flowIter.getSampleDouble(flowColRow[0], flowColRow[1], 0)))
return null;
}
}
}
pm.worked(1);
}
pm.done();
return dist;
}
/**
* Verifies if the point is a source pixel in the supplied flow raster.
*
* @param flowIter the {@link RandomIter iterator} of the flowdirections.
* @param col the col of the point to check.
* @param row the row of the point to check.
* @return true if the point identified by col and row is a source pixel.
*/
public static boolean isSourcePixel( RandomIter flowIter, int col, int row ) {
double flowDirection = flowIter.getSampleDouble(col, row, 0);
if (flowDirection < 9.0 && flowDirection > 0.0) {
for( int k = 1; k <= 8; k++ ) {
if (flowIter.getSampleDouble(col + dirIn[k][1], row + dirIn[k][0], 0) == dirIn[k][2]) {
return false;
}
}
return true;
} else {
return false;
}
}
/**
* Returns the flow direction value for a given point as indexes (i, j) of the dir matrix.
*
* @param i
* @param j
* @return
*/
public static int getFlowDirection( int i, int j ) {
int flow = -1;
for( int k = 1; k < 9; k++ ) {
if (ModelsSupporter.DIR[k][0] == i && ModelsSupporter.DIR[k][1] == j) {
flow = k;
}
}
return flow;
}
/**
* Linear interpolation between two values
*
* @param data
* - matrix of values to interpolate
* @param x
* - value to interpolate
* @param nx
* - column of data in which you find the x values
* @param ny
* - column of data in which you find the y values
* @return
*/
public static double width_interpolate( double[][] data, double x, int nx, int ny ) {
int rows = data.length;
double xuno = 0, xdue = 0, yuno = 0, ydue = 0, y = 0;
// if 0, interpolate between 0 and the first value of data
if (x >= 0 && x < data[0][nx]) {
xuno = 0;
xdue = data[0][nx];
yuno = 0;
ydue = data[0][ny];
y = ((ydue - yuno) / (xdue - xuno)) * (x - xuno) + yuno;
}
// if it is less than 0 and bigger than the maximum, throw error
if (x > data[(rows - 1)][nx] || x < 0) {
throw new RuntimeException(MessageFormat.format(
"Error in the interpolation algorithm: entering with x = {0} (min = 0.0 max = {1}", x, data[(rows - 1)][nx]));
}
/* trovo i valori limite entro i quali effettuo l'interpolazione lineare */
for( int i = 0; i < rows - 1; i++ ) {
if (x > data[i][nx] && x <= data[(i + 1)][nx]) {
xuno = data[i][nx];
xdue = data[(i + 1)][nx];
yuno = data[i][ny];
ydue = data[(i + 1)][ny];
y = ((ydue - yuno) / (xdue - xuno)) * (x - xuno) + yuno;
}
}
return y;
}
/**
* Interpolates the width function in a given tp.
*
* @param data
* @param tp
* @return
*/
public static double henderson( double[][] data, int tp ) {
int rows = data.length;
int j = 1, n = 0;
double dt = 0, muno, mdue, a, b, x, y, ydue, s_uno, s_due, smax = 0, tstar;
for( int i = 1; i < rows; i++ ) {
if (data[i][0] + tp <= data[(rows - 1)][0]) {
/**
* ***trovo parametri geometrici del segmento di retta y=muno
* x+a******
*/
muno = (data[i][1] - data[(i - 1)][1]) / (data[i][0] - data[(i - 1)][0]);
a = data[i][1] - (data[i][0] + tp) * muno;
/**
* ***trovo i valori di x per l'intersezione tra y=(muno x+tp)+a
* e y=mdue x+b ******
*/
for( j = 1; j <= (rows - 1); j++ ) {
mdue = (data[j][1] - data[(j - 1)][1]) / (data[j][0] - data[(j - 1)][0]);
b = data[j][1] - data[j][0] * mdue;
x = (a - b) / (mdue - muno);
y = muno * x + a;
if (x >= data[(j - 1)][0] && x <= data[j][0] && x - tp >= data[(i - 1)][0] && x - tp <= data[i][0]) {
ydue = width_interpolate(data, x - tp, 0, 1);
n++;
s_uno = width_interpolate(data, x - tp, 0, 2);
s_due = width_interpolate(data, x, 0, 2);
if (s_due - s_uno > smax) {
smax = s_due - s_uno;
dt = x - tp;
tstar = x;
}
}
}
}
}
return dt;
}
/**
* The Gamma function.
*
* @param x
* @return the calculated gamma function.
*/
public static double gamma( double x ) {
double tmp = (x - 0.5) * log(x + 4.5) - (x + 4.5);
double ser = 1.0 + 76.18009173 / (x + 0) - 86.50532033 / (x + 1) + 24.01409822 / (x + 2) - 1.231739516 / (x + 3)
+ 0.00120858003 / (x + 4) - 0.00000536382 / (x + 5);
double gamma = exp(tmp + log(ser * sqrt(2 * PI)));
return gamma;
}
/**
* Calculates the sum of the values of a specified quantity from every point to the outlet.
*
* During the calculation the drainage directions are followed.
*
* @param flowIter the map of flowdirections.
* @param mapToSumIter the map for which to sum downstream.
* @param width the width of the resulting map.
* @param height the height of the resulting map.
* @param upperThreshold the upper threshold, values above that are excluded.
* @param lowerThreshold the lower threshold, values below that are excluded.
* @param pm the monitor.
* @return The map of downstream summed values.
*/
public static WritableRaster sumDownstream( RandomIter flowIter, RandomIter mapToSumIter, int width, int height,
Double upperThreshold, Double lowerThreshold, IJGTProgressMonitor pm ) {
final int[] point = new int[2];
WritableRaster summedMapWR = CoverageUtilities.createDoubleWritableRaster(width, height, null, null, null);
WritableRandomIter summedMapIter = RandomIterFactory.createWritable(summedMapWR, null);
double uThres = Double.POSITIVE_INFINITY;
if (upperThreshold != null) {
uThres = upperThreshold;
}
double lThres = Double.NEGATIVE_INFINITY;
if (lowerThreshold != null) {
lThres = lowerThreshold;
}
pm.beginTask("Calculating downstream sum...", height);
for( int r = 0; r < height; r++ ) {
for( int c = 0; c < width; c++ ) {
double mapToSumValue = mapToSumIter.getSampleDouble(c, r, 0);
if (!isNovalue(flowIter.getSampleDouble(c, r, 0)) && //
mapToSumValue < uThres && //
mapToSumValue > lThres //
) {
point[0] = c;
point[1] = r;
while( flowIter.getSampleDouble(point[0], point[1], 0) < 9
&& //
!isNovalue(flowIter.getSampleDouble(point[0], point[1], 0))
&& (checkRange(mapToSumIter.getSampleDouble(point[0], point[1], 0), uThres, lThres)) ) {
double sumValue = summedMapIter.getSampleDouble(point[0], point[1], 0)
+ mapToSumIter.getSampleDouble(c, r, 0);
summedMapIter.setSample(point[0], point[1], 0, sumValue);
if (!go_downstream(point, flowIter.getSampleDouble(point[0], point[1], 0)))
return null;
}
double sumValue = summedMapIter.getSampleDouble(point[0], point[1], 0)
+ mapToSumIter.getSampleDouble(c, r, 0);
summedMapIter.setSample(point[0], point[1], 0, sumValue);
} else {
summedMapIter.setSample(c, r, 0, doubleNovalue);
}
}
pm.worked(1);
}
pm.done();
return summedMapWR;
}
private static boolean checkRange( double value, double upper, double lower ) {
if (value < upper && value > lower) {
return true;
}
return false;
}
/**
* Compare two value of tca and distance.
*
*
* It's used to evaluate some special distance (as hacklength). In these case, the value of the distance is a property of the path, and so when
* two pixel drain in a same pixel the actual value is calculate from the pixel that have the maximum value. So this method evaluate if the distance is already evaluate, throghout another path, and
* if the value of the old path is greater than the next path.
*
* @param flowIterator the flow direction iterator map.
* @param tcaIterator the tca direction iterator map.
* @param dist the dis direction iterator map (it can be hacklength).
* @param colsAndRows the position in the map (x and y value)
* @param maz the upper limit value, is the value of the next path pixel.
* @param diss the distance upper limit, is the value of the next path pixel.
* @return true if the value in the next path is greater than the old one.
*/
public static boolean tcaMax( RandomIter flowIterator, RandomIter tcaIterator, RandomIter dist, int[] colsAndRows,
double maz, double diss ) {
for( int k = 1; k <= 8; k++ ) {
if (flowIterator.getSample(colsAndRows[0] + dirIn[k][1], colsAndRows[1] + dirIn[k][0], 0) == dirIn[k][2]) {
if (tcaIterator.getSample(colsAndRows[0] + dirIn[k][1], colsAndRows[1] + dirIn[k][0], 0) >= maz) {
if (tcaIterator.getSample(colsAndRows[0] + dirIn[k][1], colsAndRows[1] + dirIn[k][0], 0) == maz) {
if (dist.getSample(colsAndRows[0] + dirIn[k][1], colsAndRows[1] + dirIn[k][0], 0) > diss)
return false;
} else
return false;
}
}
}
return true;
}
/**
* Calculating the inverse of the sun vector.
*
* @param sunVector
* @return
*/
public static double[] calcInverseSunVector( double[] sunVector ) {
double m = Math.max(Math.abs(sunVector[0]), Math.abs(sunVector[1]));
return new double[]{-sunVector[0] / m, -sunVector[1] / m, -sunVector[2] / m};
}
/**
* Calculating the normal to the sun vector.
*
* @param sunVector
* @return
*/
public static double[] calcNormalSunVector( double[] sunVector ) {
double[] normalSunVector = new double[3];
normalSunVector[2] = Math.sqrt(Math.pow(sunVector[0], 2) + Math.pow(sunVector[1], 2));
normalSunVector[0] = -sunVector[0] * sunVector[2] / normalSunVector[2];
normalSunVector[1] = -sunVector[1] * sunVector[2] / normalSunVector[2];
return normalSunVector;
}
/**
* Compute the dot product.
*
* @param a
* is a vector.
* @param b
* is a vector.
* @return the dot product of a and b.
*/
public static double scalarProduct( double[] a, double[] b ) {
double c = 0;
for( int i = 0; i < a.length; i++ ) {
c = c + a[i] * b[i];
}
return c;
}
/**
* Evaluate the shadow map calling the shadow method.
*
* @param h
* the height of the raster.
* @param w
* the width of the raster.
* @param sunVector
* @param inverseSunVector
* @param normalSunVector
* @param demWR
* the elevation map.
* @param dx
* the resolution of the elevation map.
* @return the shadow map.
*/
public static WritableRaster calculateFactor( int h, int w, double[] sunVector, double[] inverseSunVector,
double[] normalSunVector, WritableRaster demWR, double dx ) {
double casx = 1e6 * sunVector[0];
double casy = 1e6 * sunVector[1];
int f_i = 0;
int f_j = 0;
if (casx <= 0) {
f_i = 0;
} else {
f_i = w - 1;
}
if (casy <= 0) {
f_j = 0;
} else {
f_j = h - 1;
}
WritableRaster sOmbraWR = CoverageUtilities.createDoubleWritableRaster(w, h, null, null, 1.0);
int j = f_j;
for( int i = 0; i < sOmbraWR.getWidth(); i++ ) {
shadow(i, j, sOmbraWR, demWR, dx, normalSunVector, inverseSunVector);
}
int i = f_i;
for( int k = 0; k < sOmbraWR.getHeight(); k++ ) {
shadow(i, k, sOmbraWR, demWR, dx, normalSunVector, inverseSunVector);
}
return sOmbraWR;
}
/**
* Evaluate the shadow map.
*
* @param i
* the x axis index.
* @param j
* the y axis index.
* @param tmpWR
* the output shadow map.
* @param demWR
* the elevation map.
* @param res
* the resolution of the elevation map.
* @param normalSunVector
* @param inverseSunVector
* @return
*/
private static WritableRaster shadow( int i, int j, WritableRaster tmpWR, WritableRaster demWR, double res,
double[] normalSunVector, double[] inverseSunVector ) {
int n = 0;
double zcompare = -Double.MAX_VALUE;
double dx = (inverseSunVector[0] * n);
double dy = (inverseSunVector[1] * n);
int nCols = tmpWR.getWidth();
int nRows = tmpWR.getHeight();
int idx = (int) Math.round(i + dx);
int jdy = (int) Math.round(j + dy);
double vectorToOrigin[] = new double[3];
while( idx >= 0 && idx <= nCols - 1 && jdy >= 0 && jdy <= nRows - 1 ) {
vectorToOrigin[0] = dx * res;
vectorToOrigin[1] = dy * res;
int tmpY = (int) (j + dy);
if (tmpY < 0) {
tmpY = 0;
} else if (tmpY > nRows) {
tmpY = nRows - 1;
}
int tmpX = (int) (i + dx);
if (tmpX < 0) {
tmpX = 0;
} else if (tmpY > nCols) {
tmpX = nCols - 1;
}
vectorToOrigin[2] = demWR.getSampleDouble(idx, jdy, 0);
// vectorToOrigin[2] = (pitRandomIter.getSampleDouble(idx, jdy, 0) +
// pitRandomIter
// .getSampleDouble(tmpX, tmpY, 0)) / 2;
double zprojection = scalarProduct(vectorToOrigin, normalSunVector);
if ((zprojection < zcompare)) {
tmpWR.setSample(idx, jdy, 0, 0);
} else {
zcompare = zprojection;
}
n = n + 1;
dy = (inverseSunVector[1] * n);
dx = (inverseSunVector[0] * n);
idx = (int) Math.round(i + dx);
jdy = (int) Math.round(j + dy);
}
return tmpWR;
}
/**
* Verify if the current station (i) is already into the arrays.
*
* @param xStation the x coordinate of the stations
* @param yStation the y coordinate of the stations
* @param zStation the z coordinate of the stations
* @param hStation the h value of the stations
* @param xTmp
* @param yTmp
* @param zTmp
* @param hTmp
* @param i the current index
* @param doMean if the h value of a double station have different value then do the mean.
* @param pm
* @return true if there is already this station.
* @throws Exception
*/
public static boolean verifyDoubleStation( double[] xStation, double[] yStation, double[] zStation, double[] hStation,
double xTmp, double yTmp, double zTmp, double hTmp, int i, boolean doMean, IJGTProgressMonitor pm ) throws Exception {
for( int j = 0; j < i - 1; j++ ) {
if (dEq(xTmp, xStation[j]) && dEq(yTmp, yStation[j]) && dEq(zTmp, zStation[j]) && dEq(hTmp, hStation[j])) {
if (!doMean) {
throw new IllegalArgumentException(msg.message("verifyStation.equalsStation1") + xTmp + "/" + yTmp);
}
return true;
} else if (dEq(xTmp, xStation[j]) && dEq(yTmp, yStation[j]) && dEq(zTmp, zStation[j])) {
if (!doMean) {
throw new IllegalArgumentException(msg.message("verifyStation.equalsStation2") + xTmp + "/" + yTmp);
}
if (!isNovalue(hStation[j]) && !isNovalue(hTmp)) {
hStation[j] = (hStation[j] + hTmp) / 2;
} else {
hStation[j] = doubleNovalue;
}
return true;
}
}
return false;
}
/**
* Return the mean of a column of a matrix.
*
* @param matrix matrix of the value to calculate.
* @param column index of the column to calculate the variance.
* @return mean.
*/
public static double meanDoublematrixColumn( double[][] matrix, int column ) {
double mean;
mean = 0;
int length = matrix.length;
for( int i = 0; i < length; i++ ) {
mean += matrix[i][column];
}
return mean / length;
}
/**
* Return the variance of a column of a matrix.
*
* @param matrix matrix of the value to calculate.
* @param column index of the column to calculate the variance.
* @param mean the mean value of the column.
* @return variance.
*/
public static double varianceDoublematrixColumn( double[][] matrix, int column, double mean )
{
double variance;
variance = 0;
for( int i = 0; i < matrix.length; i++ ) {
variance += (matrix[i][column] - mean) * (matrix[i][column] - mean);
}
return variance / matrix.length;
}
/**
* Sum columns.
*
*
* Store in a matrix (at index coulumn), the sum of the column of another
* matrix. It's necessary to specify the initial and final index of the
* coluns to sum.
*
*
*
* @param coolIndex index of the matrix2 where to put the result.
* @param matrixToSum contains the value to sum.
* @param resultMatrix where to put the result.
* @param firstRowIndex initial index of the colum to sum.
* @param lastRowIndex final index of the colum to sum.
* @return maximum value of the colum index of the matrix2.
*/
public static double sumDoublematrixColumns( int coolIndex, double[][] matrixToSum, double[][] resultMatrix,
int firstRowIndex, int lastRowIndex, IJGTProgressMonitor pm ) {
double maximum;
maximum = 0;
if (matrixToSum.length != resultMatrix.length) {
pm.errorMessage(msg.message("trentoP.error.matrix")); //$NON-NLS-1$
throw new ArithmeticException(msg.message("trentoP.error.matrix")); //$NON-NLS-1$
}
if (firstRowIndex < 0 || lastRowIndex < firstRowIndex) {
pm.errorMessage(msg.message("trentoP.error.nCol")); //$NON-NLS-1$
throw new ArithmeticException(msg.message("trentoP.error.nCol")); //$NON-NLS-1$
}
for( int i = 0; i < matrixToSum.length; ++i ) {
resultMatrix[i][coolIndex] = 0; /* Initializes element */
for( int j = firstRowIndex; j <= lastRowIndex; ++j ) {
resultMatrix[i][coolIndex] += matrixToSum[i][j];
}
if (resultMatrix[i][coolIndex] >= maximum) /* Saves maximum value */
{
maximum = resultMatrix[i][coolIndex];
}
}
return maximum;
}
/**
* Calculates the distance of every pixel of the basin from the outlet (in meter),
* calculated along the drainage directions
*
* @param flowIter the flow map.
* @param pitIter the pit map (if available distance is calculated in 3d).
* @param distanceToOutIter the resulting outlet distance map.
* @param region the region parameters.
* @param pm the monitor.
*/
public static void topologicalOutletdistance( RandomIter flowIter, RandomIter pitIter, WritableRandomIter distanceToOutIter,
RegionMap region, IJGTProgressMonitor pm ) {
int activeCols = region.getCols();
int activeRows = region.getRows();
double dx = region.getXres();
double dy = region.getYres();
int[] flow = new int[2];
int[] flow_p = new int[2];
double oldir = 0.0;
double[] grid = new double[11];
double count = 0.0;
grid[0] = grid[9] = grid[10] = 0;
grid[1] = grid[5] = abs(dx);
grid[3] = grid[7] = abs(dy);
grid[2] = grid[4] = grid[6] = grid[8] = sqrt(dx * dx + dy * dy);
pm.beginTask("Calculating topological outlet distance...", activeRows);
for( int r = 0; r < activeRows; r++ ) {
for( int c = 0; c < activeCols; c++ ) {
flow[0] = c;
flow[1] = r;
if (isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))) {
distanceToOutIter.setSample(flow[0], flow[1], 0, doubleNovalue);
} else {
if (isSourcePixel(flowIter, flow[0], flow[1])) {
count = 0;
oldir = flowIter.getSampleDouble(flow[0], flow[1], 0);
flow_p[0] = flow[0];
flow_p[1] = flow[1];
go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0));
while( !isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))
&& !isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))
&& flowIter.getSampleDouble(flow[0], flow[1], 0) != 10.0
&& distanceToOutIter.getSampleDouble(flow[0], flow[1], 0) <= 0 ) {
if (pitIter != null) {
double dz = pitIter.getSampleDouble(flow_p[0], flow_p[1], 0)
- pitIter.getSampleDouble(flow[0], flow[1], 0);
count += sqrt(pow(grid[(int) oldir], 2) + pow(dz, 2));
} else {
count += grid[(int) oldir];
}
oldir = flowIter.getSampleDouble(flow[0], flow[1], 0);
flow_p[0] = flow[0];
flow_p[1] = flow[1];
go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0));
}
if (distanceToOutIter.getSampleDouble(flow[0], flow[1], 0) > 0) {
if (pitIter != null) {
double dz = pitIter.getSampleDouble(flow_p[0], flow_p[1], 0)
- pitIter.getSampleDouble(flow[0], flow[1], 0);
count += sqrt(pow(grid[(int) oldir], 2) + pow(dz, 2))
+ distanceToOutIter.getSampleDouble(flow[0], flow[1], 0);
} else {
count += grid[(int) oldir] + distanceToOutIter.getSampleDouble(flow[0], flow[1], 0);
}
distanceToOutIter.setSample(c, r, 0, count);
} else if (flowIter.getSampleDouble(flow[0], flow[1], 0) > 9) {
distanceToOutIter.setSample(flow[0], flow[1], 0, 0);
if (pitIter != null) {
double dz = pitIter.getSampleDouble(flow_p[0], flow_p[1], 0)
- pitIter.getSampleDouble(flow[0], flow[1], 0);
count += sqrt(pow(grid[(int) oldir], 2) + pow(dz, 2));
} else {
count += grid[(int) oldir];
}
distanceToOutIter.setSample(c, r, 0, count);
}
flow[0] = c;
flow[1] = r;
oldir = flowIter.getSampleDouble(flow[0], flow[1], 0);
flow_p[0] = flow[0];
flow_p[1] = flow[1];
go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0));
while( !isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))
&& !isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))
&& flowIter.getSampleDouble(flow[0], flow[1], 0) != 10.0
&& distanceToOutIter.getSampleDouble(flow[0], flow[1], 0) <= 0 ) {
if (pitIter != null) {
double dz = pitIter.getSampleDouble(flow_p[0], flow_p[1], 0)
- pitIter.getSampleDouble(flow[0], flow[1], 0);
count -= sqrt(pow(grid[(int) oldir], 2) + pow(dz, 2));
} else {
count -= grid[(int) oldir];
}
if (count < 0) {
distanceToOutIter.setSample(flow[0], flow[1], 0, 0);
} else {
distanceToOutIter.setSample(flow[0], flow[1], 0, count);
}
oldir = flowIter.getSampleDouble(flow[0], flow[1], 0);
flow_p[0] = flow[0];
flow_p[1] = flow[1];
go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0));
}
}
}
}
pm.worked(1);
}
pm.done();
}
/**
* Calculates the distance of every pixel of the basin from the outlet (in map units),
* calculated along the drainage directions
*
* @param flowIter the flow map.
* @param distanceToOutIter the resulting outlet distance map.
* @param region the region parameters.
* @param pm the monitor.
*/
public static void outletdistance( RandomIter flowIter, WritableRandomIter distanceToOutIter, RegionMap region,
IJGTProgressMonitor pm ) {
int cols = region.getCols();
int rows = region.getRows();
int[] flow = new int[2];
double count = 0.0;
pm.beginTask("Calculating outlet distance...", rows);
for( int r = 0; r < rows; r++ ) {
for( int c = 0; c < cols; c++ ) {
flow[0] = c;
flow[1] = r;
if (isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))) {
distanceToOutIter.setSample(flow[0], flow[1], 0, doubleNovalue);
} else {
flow[0] = c;
flow[1] = r;
if (isSourcePixel(flowIter, flow[0], flow[1])) {
count = 0;
go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0));
while( !isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))
&& flowIter.getSampleDouble(flow[0], flow[1], 0) != 10.0
&& distanceToOutIter.getSampleDouble(flow[0], flow[1], 0) <= 0 ) {
count += 1;
go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0));
}
if (distanceToOutIter.getSampleDouble(flow[0], flow[1], 0) > 0) {
count += 1 + distanceToOutIter.getSampleDouble(flow[0], flow[1], 0);
distanceToOutIter.setSample(c, r, 0, count);
} else if (flowIter.getSampleDouble(flow[0], flow[1], 0) > 9) {
distanceToOutIter.setSample(flow[0], flow[1], 0, 0);
count += 1;
distanceToOutIter.setSample(c, r, 0, count);
}
flow[0] = c;
flow[1] = r;
go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0));
while( !isNovalue(flowIter.getSampleDouble(flow[0], flow[1], 0))
&& flowIter.getSampleDouble(flow[0], flow[1], 0) != 10.0
&& distanceToOutIter.getSampleDouble(flow[0], flow[1], 0) <= 0 ) {
count -= 1;
distanceToOutIter.setSample(flow[0], flow[1], 0, count);
go_downstream(flow, flowIter.getSampleDouble(flow[0], flow[1], 0));
}
}
}
}
pm.worked(1);
}
pm.done();
}
/**
* Approximate a value to a multiple of a divisor value.
*
*
* It evaluates a multiple of the divisor (which is the nearest number to valueToApproximate).
*
*
* @param valueToApproximate value to approximate
* @param divisor the unit value, it's the divisor number.
* @return the largest value less than or equal to valueToApproximate and divisible to divisor.
*/
public static double approximate2Multiple( double valueToApproximate, double divisor ) {
return valueToApproximate - abs(valueToApproximate % divisor);
}
}