
uk.ac.leeds.ccg.grids.d2.util.Grids_Utilities Maven / Gradle / Ivy
/*
* Copyright 2019 Andy Turner, University of Leeds.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.ac.leeds.ccg.grids.d2.util;
import uk.ac.leeds.ccg.grids.d2.grid.Grids_Dimensions;
import uk.ac.leeds.ccg.grids.core.Grids_Environment;
import uk.ac.leeds.ccg.grids.core.Grids_Object;
import uk.ac.leeds.ccg.grids.d2.chunk.d.Grids_ChunkDouble;
import uk.ac.leeds.ccg.grids.d2.grid.d.Grids_GridDouble;
import uk.ac.leeds.ccg.grids.d2.grid.d.Grids_GridFactoryDouble;
import uk.ac.leeds.ccg.grids.process.Grids_Processor;
import uk.ac.leeds.ccg.grids.d2.Grids_2D_ID_int;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.math.BigInteger;
import uk.ac.leeds.ccg.generic.util.Generic_Time;
import uk.ac.leeds.ccg.math.Math_BigDecimal;
/**
* Grid utility methods.
*
* @author Andy Turner
* @version 1.0.0
*/
public class Grids_Utilities extends Grids_Object {
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of Utilities.
*
* @param e The grids environment.
*/
public Grids_Utilities(Grids_Environment e) {
super(e);
}
/**
* @param time Time in milliseconds.
* @return A string representing the number of days, hours, minutes, seconds
* and milliseconds in the input time.
*/
public static String getTime(long time) {
long milliSecondsInDay = 24L * Generic_Time.MilliSecondsInHour;
long days = Math.floorDiv(time, milliSecondsInDay);
int t = (int) (time - (days * milliSecondsInDay));
int hours = Math.floorDiv(t, Generic_Time.MilliSecondsInHour);
t -= hours * Generic_Time.MilliSecondsInHour;
int milliSecondsInMinute = Generic_Time.MilliSecondsInSecond * 60;
int mins = Math.floorDiv(t, milliSecondsInMinute);
t -= mins * milliSecondsInMinute;
int secs = Math.floorDiv(t, Generic_Time.MilliSecondsInSecond);
t -= secs * Generic_Time.MilliSecondsInSecond;
return "days=" + days + ", hours=" + hours + ", mins=" + mins
+ ", secs=" + secs + ", millisecs=" + t;
}
/**
* @param time in milliseconds.
* @return A string representing the number of days, hours, minutes, seconds
* and milliseconds in the input time.
*/
public static String getTime(BigInteger time) {
BigInteger milliSecondsInDay = BigInteger.valueOf(24L
* Generic_Time.MilliSecondsInHour);
BigInteger days = time.divideAndRemainder(milliSecondsInDay)[0];
BigInteger t = time.subtract(days.multiply(milliSecondsInDay));
BigInteger msh = BigInteger.valueOf(Generic_Time.MilliSecondsInHour);
BigInteger hours = t.divideAndRemainder(msh)[0];
t = t.subtract(hours.multiply(msh));
BigInteger msm = BigInteger.valueOf(Generic_Time.MilliSecondsInSecond
* 60);
BigInteger mins = t.divideAndRemainder(msm)[0];
t = t.subtract(mins.multiply(msm));
BigInteger mss = BigInteger.valueOf(1000);
BigInteger secs = t.divideAndRemainder(mss)[0];
t = t.subtract(secs.multiply(mss));
return "days=" + days + ", hours=" + hours + ", mins=" + mins
+ ", secs=" + secs + ", millisecs=" + t;
}
/**
* Deprecated since we can now simply use
* {@link java.lang.Math#nextUp(double)}.
*
* @param v The value for which a larger value is returned.
* @return A number immediately larger than value in the double range.
*/
@Deprecated
public static double getLarger(double v) {
return Math.nextUp(v);
}
/**
* Deprecated since we can now simply use
* {@link java.lang.Math#nextDown(double)}.
*
* @param v The value for which a smaller value is returned.
* @return A number immediately smaller than value in the double range.
*/
@Deprecated
public static double getSmaller(double v) {
return Math.nextDown(v);
}
/**
* For a given point at first from an angle from the y axis and a distance
* maxDistance a new sample point is created. Sample points at nDistances
* from maxDistance towards point from the first sample point are then
* created and added to the result. The process is repeated for nAngles
* going around clockwise from the x-y plane.
*
* @param point point at centre of sampling
* @param angle angle in radians to the vertical (y axis) for first sampling
* @param maxDistance the maximum sampling distance
* @param nDistances the number of sampling distances upto maxDistance
* @param nAngles sets how many samplesPoints to take at each sample
* distance. Always the first sample is at angle from the vertical or
* y-axis. The angles at which samples are taken are all the same.
* @return Sample points.
*/
public static Point2D.Double[][] getSamplePoints(Point2D.Double point,
double angle, double maxDistance, int nDistances, int nAngles) {
Point2D.Double[][] r = new Point2D.Double[nAngles][nDistances];
double sAngle = 2.0d * Math.PI / (double) nAngles;
double sDistance = maxDistance / (double) nDistances;
for (int a = 0; a < nAngles; a++) {
double sina = Math.sin(angle + sAngle * a);
double cosa = Math.cos(angle + sAngle * a);
double distance = maxDistance;
int d = 0;
while (distance >= sDistance) {
double xdiff = sina * distance;
double ydiff = cosa * distance;
r[a][d] = new Point2D.Double(point.x + xdiff, point.y + ydiff);
distance -= sDistance;
d++;
}
}
return r;
}
/**
* @param x1 The x coordinate of the first point.
* @param y1 The y coordinate of the first point.
* @param x2 The x coordinate of the second point.
* @param y2 The y coordinate of the second point.
* @param dp The number of decimal places the result is to be accurate to.
* @param rm The {@link RoundingMode} to use when rounding the result.
*
* @return The distance between two points calculated using
* {@link BigDecimal} arithmetic.
*/
public static final BigDecimal distance(BigDecimal x1, BigDecimal y1,
BigDecimal x2, BigDecimal y2, int dp, RoundingMode rm) {
return Math_BigDecimal.sqrt(((x1.subtract(x2)).pow(2))
.add((y1.subtract(y2)).pow(2)), dp, rm);
}
/**
* @param x1 The x coordinate of the first point.
* @param y1 The y coordinate of the first point.
* @param x2 The x coordinate of the second point.
* @param y2 The y coordinate of the second point.
* @return The distance between two points calculated using {@code double}
* precision floating point numbers.
*/
public static final double distance(double x1, double y1, double x2,
double y2) {
return Math.hypot((x1 - x2), (y1 - y2));
}
/**
* Returns the clockwise angle in radians to the y axis of the line from:
* {@code x1}, {@code y1}; to, {@code x2}, {@code y2}.
*
* @param x1 The x coordinate of the first point.
* @param y1 The y coordinate of the first point.
* @param x2 The x coordinate of the second point.
* @param y2 The y coordinate of the second point.
* @return The clockwise angle in radians to the y axis of the line from x1,
* y1 to x2, y2 calculated using {@code double} precision floating point
* numbers.
*/
public static final double angle(double x1, double y1, double x2,
double y2) {
double xdiff = x1 - x2;
double ydiff = y1 - y2;
double angle;
if (xdiff == 0.0d && ydiff == 0.0d) {
angle = -1.0d;
} else {
if (xdiff <= 0.0d) {
if (xdiff == 0.0d) {
if (ydiff <= 0.0d) {
angle = 0.0d;
} else {
angle = Math.PI;
}
} else {
if (ydiff <= 0.0d) {
if (ydiff == 0.0d) {
angle = Math.PI / 2.0d;
} else {
angle = Math.atan(Math.abs(xdiff / ydiff));
}
} else {
angle = Math.PI - Math.atan(Math.abs(xdiff / ydiff));
}
}
} else {
if (ydiff <= 0.0d) {
if (ydiff == 0.0d) {
angle = 3.0d * Math.PI / 2.0d;
} else {
angle = (2.0d * Math.PI) - Math.atan(Math.abs(xdiff / ydiff));
}
} else {
angle = Math.PI + Math.atan(Math.abs(xdiff / ydiff));
}
}
}
return angle;
}
/**
* Returns a density plot of xGrid values against yGrid values.A density
* plot is like a scatterplot, but rather than plotting individual points,
* each point is aggregated to a cells and the result is a plot of the
* density of points in the cells.The values of yGrid are scaled to be in
* the same range as the values of xGrid and the number of divisions for
* each axis is given by divisions. NB1 For this implementation xGrid and
* yGrid must have the same spatial frame. NB2 The result returned has a set
* cellsize of 1 and origin at ( 0, 0 ) (This enables easy comparison with
* other density plots)
*
* @param xGrid The grid with x values.
* @param yGrid The grid with y values
* @param gp The processor.
* @param divisions The number of divisions in the plot. This has to be less
* than the square root of {@link Integer#MAX_VALUE} ~ 46341 but should in
* practice be smaller than this. A sufficiently detailed picture can often
* be produced from 512.
* @return r[4] where:
*
* - r[0] is a = stdevy
* - r[1] = meany
* - r[2] = numy
* - r[3] = densityPlotGrid;
*
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
*
* @throws Exception If encountered.
* @throws IOException If encountered.
* @throws ClassNotFoundException If encountered.
*/
public static Object[] densityPlot(Grids_GridDouble xGrid,
Grids_GridDouble yGrid, int divisions, Grids_Processor gp, int dp,
RoundingMode rm)
throws IOException, ClassNotFoundException, Exception {
Object[] r = new Object[4];
Grids_GridFactoryDouble gfd = gp.gridFactoryDouble;
long nrows = xGrid.getNRows();
long ncols = xGrid.getNCols();
double xGridNoDataValue = xGrid.getNoDataValue();
double yGridNoDataValue = yGrid.getNoDataValue();
double minx = xGrid.getStats().getMin(true);
double maxx = xGrid.getStats().getMax(true);
double miny = yGrid.getStats().getMin(true);
double maxy = yGrid.getStats().getMax(true);
double cellsize = (maxy - miny) / (double) divisions;
Grids_Dimensions newDimensions = new Grids_Dimensions(
BigDecimal.valueOf(minx), BigDecimal.valueOf(maxx),
BigDecimal.valueOf(miny), BigDecimal.valueOf(maxy),
BigDecimal.valueOf(cellsize));
Grids_GridDouble xGridRescaled;
double value;
double v;
if (minx == miny && maxx == maxy) {
xGridRescaled = (Grids_GridDouble) gfd.create(xGrid);
} else {
xGridRescaled = (Grids_GridDouble) gfd.create(xGrid);
int ncr = xGridRescaled.getNChunkRows();
int ncc = xGridRescaled.getNChunkCols();
for (int cr = 0; cr < ncr; cr++) {
int cnr = xGridRescaled.getChunkNRows(cr);
for (int cc = 0; cc < ncc; cc++) {
Grids_2D_ID_int cid = new Grids_2D_ID_int(cr, cc);
Grids_ChunkDouble chunk = xGridRescaled.getChunk(cid);
int cnc = xGridRescaled.getChunkNCols(cc);
for (int row = 0; row < cnr; row++) {
for (int col = 0; col < cnc; col++) {
value = chunk.getCell(row, col);
if (value != yGridNoDataValue) {
v = (((value - minx) / (maxx - minx))
* (maxy - miny)) + miny;
chunk.setCell(row, col, v);
}
}
}
}
}
}
BigDecimal[] sumy = new BigDecimal[divisions];
BigDecimal[] numy = new BigDecimal[divisions];
BigDecimal[] sumysq = new BigDecimal[divisions];
for (int j = 0; j < divisions; j++) {
sumy[j] = BigDecimal.ZERO;
numy[j] = BigDecimal.ZERO;
sumysq[j] = BigDecimal.ZERO;
}
Grids_GridDouble temp1 = gfd.create(divisions, divisions, newDimensions);
for (long row = 0; row < nrows; row++) {
for (long col = 0; col < ncols; col++) {
double x = xGridRescaled.getCell(row, col);
double y = yGrid.getCell(row, col);
if (y != yGridNoDataValue) {
if (x != xGridNoDataValue) {
BigDecimal xBD = BigDecimal.valueOf(x);
temp1.addToCell(xBD, BigDecimal.valueOf(y), 1.0d);
int division = (int) temp1.getCol(xBD);
if (division >= divisions) {
division = divisions - 1;
}
if (division < 0) {
division = 0;
}
//System.out.println(division);
BigDecimal yd = BigDecimal.valueOf(y);
sumy[division] = sumy[division].add(yd);
numy[division] = numy[division].add(BigDecimal.ONE);
sumysq[division] = sumysq[division].add(yd.multiply(yd));
}
}
}
}
BigDecimal[] stdevy = new BigDecimal[divisions];
BigDecimal[] meany = new BigDecimal[divisions];
for (int j = 0; j < divisions; j++) {
if (numy[j].compareTo(BigDecimal.ZERO) == 1) {
meany[j] = Math_BigDecimal.divideRoundIfNecessary(
sumy[j], numy[j], dp, rm);
if (numy[j].compareTo(BigDecimal.ONE) == 1) {
stdevy[j] = Math_BigDecimal.sqrt(Math_BigDecimal.divideRoundIfNecessary(
((numy[j].multiply(sumysq[j])).subtract(sumy[j].multiply(sumy[j]))),
((numy[j].multiply(numy[j].subtract(BigDecimal.ONE)))), dp, rm), dp, rm);
}
}
// if (numy[j] > 0.0d) {
// meany[j] = sumy[j] / numy[j];
// if (numy[j] > 1.0d) {
// stdevy[j] = Math.sqrt(((numy[j] * sumysq[j])
// - (sumy[j] * sumy[j]))
// / (numy[j] * (numy[j] - 1)));
// }
// }
}
r[0] = stdevy;
r[1] = meany;
r[2] = numy;
double[] normalisers = new double[divisions];
//double d1 = 0.0d;
//double d2 = 0.0d;
for (int j = 0; j < divisions; j++) {
normalisers[j] = 0.0d;
for (int i = 0; i < divisions; i++) {
value = temp1.getCell(i, j);
if (value != xGridNoDataValue) {
normalisers[j] += value;
//d1 += value;
//d2 += 1.0d;
}
}
}
Grids_Dimensions newdimensions = new Grids_Dimensions(BigDecimal.ZERO,
BigDecimal.ZERO, BigDecimal.valueOf(divisions),
BigDecimal.valueOf(divisions), BigDecimal.ONE);
Grids_GridDouble densityPlotGrid = gfd.create(divisions, divisions, newdimensions);
//double average = d1 / d2;
for (int i = 0; i < divisions; i++) {
for (int j = 0; j < divisions; j++) {
if (normalisers[j] != 0.0d) {
value = temp1.getCell(i, j);
if (value != xGridNoDataValue) {
//densityPlotGrid.setCell( i, j, temp1.getCell( i, j )
// / ( normalisers[ j ] + average ) );
densityPlotGrid.setCell(i, j, temp1.getCell(i, j)
/ normalisers[j]);
}
} else {
densityPlotGrid.setCell(i, j, 0.0d);
}
}
}
r[3] = densityPlotGrid;
return r;
}
/**
* Generates a CSV file for a cumulative gains chart of observed and
* indicator NB1. observed and indicator must have same spatial frame.
*/
/*
public static void toGainsChartCSV(Grids_Grid observed,
Grids_Grid indicator, int divisions, File csvFile ) {
int nrows = observed.getNrows();
int ncols = observed.getNcols();
AbstractGridStatistics indicatorStats = indicator.getGridStatistics();
//System.out.println( "mean indicator " + indicatorStats.getMean() );
double numberOfCellsPerDivision = ( nrows * ncols * ( 1 - indicatorStats.getSparseness() ) ) / divisions ;
//System.out.println( "numberOfCellsPerDivision " + numberOfCellsPerDivision );
double indicatorValue;
double indicatorNoDataValue = indicator.getNoDataValue();
double observedValue;
double cumulativeObservedValue = 0;
double observedNoDataValue = observed.getNoDataValue();
TreeSet treeSet = new TreeSet();
for ( int i = 0; i < nrows * ncols; i ++ ) {
indicatorValue = indicator.getCell( i );
if ( indicatorValue != indicatorNoDataValue ) {
treeSet.add( new Double( indicator.getCell( i ) ) );
}
}
double[] observedValueSum = new double[ divisions ];
double[] percentageCumulativeObservedValueSum = new double[ divisions ];
for ( int i = 0; i < divisions; i ++ ) {
observedValueSum[ i ] = 0.0d;
percentageCumulativeObservedValueSum[ i ] = 0.0d;
}
int division = divisions - 1;
double cellCounter = 0;
Iterator iterator = treeSet.iterator();
while ( iterator.hasNext() ) {
indicatorValue = ( ( Double ) iterator.next() ).doubleValue();
for ( int i = 0; i < nrows; i ++ ) {
for ( int j = 0; j < ncols; j ++ ) {
if ( indicator.getCell( i, j ) == indicatorValue ) {
observedValue = observed.getCell( i, j );
if ( observedValue != observedNoDataValue ) {
cellCounter ++;
if ( cellCounter >= numberOfCellsPerDivision ) {
division --;
if ( division <= 0 ) {
division = 0;
}
cellCounter -= numberOfCellsPerDivision;
}
observedValueSum[ division ] += observedValue;
}
}
}
}
}
AbstractGridStatistics observedStats = observed.getGridStatistics();
double sumObserved = observedStats.getSum();
//System.out.println( "mean observed = " + observedStats.getMean() );
//System.out.println( "sum observed = " + sumObserved );
//// Check
//double observedSum = 0.0d;
//for ( int i = 0; i < divisions; i ++ ) {
// observedSum += observedValueSum[ i ];
//}
//if ( observedSum != sumObserved ) {
// System.out.println( "Warning!!!: observedSum != sumObserved" );
//}
//// End Check
percentageCumulativeObservedValueSum[ 0 ] = observedValueSum[ 0 ] * 100.0d / sumObserved;
for ( int i = 1; i < divisions; i ++ ) {
percentageCumulativeObservedValueSum[ i ] = ( observedValueSum[ i ] * 100.0d / sumObserved ) + percentageCumulativeObservedValueSum[ i - 1 ];
}
PrintWriter pw = null;
try {
pw = new PrintWriter( new FileOutputStream( csvFile ) );
} catch ( java.io.IOException e ) {
System.out.println( e );
e.printStackTrace();
}
pw.println( "%cumulativeObservedValueSum,%indicator" );
pw.println( "0,0" );
for ( int i = 0; i < divisions; i ++ ) {
pw.println( percentageCumulativeObservedValueSum[ i ] + "," + ( ( i + 1 ) * 100.0d / divisions ) );
}
pw.flush();
pw.close();
}*/
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy