/** * For generating Geographically Weighted Statistics * Copyright (C) 2005 Andy Turner, CCG, University of Leeds, UK. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ package uk.ac.leeds.ccg.andyt.gws.core; // java dependencies import java.awt.geom.Point2D; import java.math.BigDecimal; import java.util.HashSet; import java.util.Iterator; import java.util.Vector; // uk.ac.leeds.ccg.andyt.grids dependencies import uk.ac.leeds.ccg.andyt.grids.core.Grid2DSquareCellDouble; import uk.ac.leeds.ccg.andyt.grids.core.Grid2DSquareCellDoubleFactory; import uk.ac.leeds.ccg.andyt.grids.process.Grid2DSquareCellProcessor; import uk.ac.leeds.ccg.andyt.grids.utilities.Kernel; // uk.ac.leeds.ccg.andyt.gws dependencies import uk.ac.leeds.ccg.andyt.gws.utilities.Utilities; import uk.ac.leeds.ccg.andyt.gws.utilities.Point2DBigDecimal; /** * This class contains methods for generating Grid2DSquareCellDoubles that are * spatially weighted statistics known as Fixed Geographically Weighted * Statistics (GWS). They are 'fixed' because the spatial scales over which the * statistics are generalised is the same for every cell in the grid. * * Owing to the fixed nature of the scales, there are a number of relevant * optimisations for improving memory usage and speed of computation. * * The task of calculating Fixed GWS can be readily divided by partitioning the * result space into discrete chunks and using subsets of the loaded points. * By subsetting the points, the points within a fixed distance of a cell * centoid may be identified more speedily. Additionally a memory can be stored * of which points lie in a somewhat larger region, and this can be used to * identify points within a fixed distance of a neighbouring cell centoid more * speedily. * * The optimal way to go about generating results depends as usual on the * available memory and processing speed of the computer hardware being used. * To really optimise one should consider the inherent parallelism and the * utilisation of parallel computing hardware. * * The optimal amount of division depends on the distance or scale at which the * GWS are to be generated, the size of the result, and both of these things * relative to the resolution of the result and the amount of available memory. * The methods in this class are only concerned with optimising for the result * space and points array passed in. */ public class FixedGWS extends GWS { /** * These are generally wanted and so are specified here to avoid having to * pass them around all the time. */ private Point2D.Double point2DDouble; private Point2D.Double[] point2DDoubles; private Point2DDouble_DistanceDouble_IDInt point2DDouble_DistanceDouble_IDInt; private Point2DBigDecimal point2DBigDecimal; private Point2DBigDecimal[] point2DBigDecimals; private Point2DBigDecimal_DistanceBigDecimal_IDInt point2DBigDecimal_DistanceBigDecimal_IDInt; private HashSet pointIDsHashSet; private HashSet inDistancePointDistanceIDsHashSet; private HashSet inSearchDistancePointIDsHashSet; private Iterator ite; private int counter; private double searchDistanceDouble; private double distanceDouble; private BigDecimal distanceBigDecimal; private double sumWeight; private BigDecimal cellsizeBigDecimal; /** Default constructor */ public FixedGWS() { super(); } /** * Returns an Grid2DSquareCellDouble that has values corresponding to * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor. * @param points The Point2DBigDecimal[] array to be used. * @param grid2DSquareCellDouble The Grid2DSquareCellDouble defining the * frame of the result. * @param distance The bandwidth of the fixed kernel. * @param weightIntersect The weight at the centre of the kernal. * @param weightFactor The distance decay factor of the kernel. */ public Grid2DSquareCellDouble getKernelWeightsInDistance( Point2D.Double[] point2DDoubles, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor ) { this.point2DDoubles = point2DDoubles; this.distanceDouble = distanceDouble; this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] dimensions = grid2DSquareCellDouble.getDimensions(); this.pointIDsHashSet = Utilities.getPointsIntersected( point2DDoubles, dimensions ); // Calculate for ( this.row = 0; this.row < nrows; this.row ++ ) { for ( this.col = 0; this.col < ncols; this.col ++ ) { doCell1( result ); } } return result; } /** * Returns an Grid2DSquareCellDouble that has values corresponding to * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor. * @param points The Point2DBigDecimal[] array to be used. * @param grid2DSquareCellDouble The Grid2DSquareCellDouble defining the * frame of the result. * @param distance The bandwidth of the fixed kernel. * @param weightIntersect The weight at the centre of the kernal. * @param weightFactor The distance decay factor of the kernel. */ public Grid2DSquareCellDouble getKernelWeightsInDistance( Point2DBigDecimal[] point2DBigDecimals, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor, int decimalPlaces ) { this.point2DBigDecimals = point2DBigDecimals; this.distanceDouble = distanceDouble; this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] dimensions = grid2DSquareCellDouble.getDimensions(); this.pointIDsHashSet = Utilities.getPointsIntersected( point2DBigDecimals, dimensions ); // Calculate for ( this.row = 0; this.row < nrows; this.row ++ ) { for ( this.col = 0; this.col < ncols; this.col ++ ) { doCell1( result, decimalPlaces ); } } return result; } /** * For evaluating cells in: * getKernelWeightsInDistance( Point2DBigDecimal[], * Grid2DSquareCellDouble, * double, double, double ) * and: * getKernelWeightsInDistance( HashSet, Point2DBigDecimal[], * Grid2DSquareCellDouble, * double, double, double ) */ private void doCell1( Grid2DSquareCellDouble grid2DSquareCellDouble ) { this.point2DDouble = new Point2D.Double( grid2DSquareCellDouble.getCellXDouble( this.col, this.handleOutOfMemoryErrorFalse ), grid2DSquareCellDouble.getCellYDouble( this.row, this.handleOutOfMemoryErrorFalse ) ); this.inDistancePointDistanceIDsHashSet = getInDistancePoint2DDouble_DistanceDouble_IDInts( this.pointIDsHashSet, this.point2DDoubles, this.point2DDouble, this.distanceDouble ); if ( ! this.inDistancePointDistanceIDsHashSet.isEmpty() ) { this.ite = inDistancePointDistanceIDsHashSet.iterator(); this.sumWeight = 0.0d; while ( this.ite.hasNext() ) { this.point2DDouble_DistanceDouble_IDInt = ( Point2DDouble_DistanceDouble_IDInt ) this.ite.next(); this.sumWeight += Kernel.getKernelWeight( this.distanceDouble, this.weightIntersect, this.weightFactor, this.point2DDouble_DistanceDouble_IDInt.distanceDouble ); } //System.out.println("row " + this.row + " col " + this.col ); grid2DSquareCellDouble.setCell( this.row, this.col, this.sumWeight, this.handleOutOfMemoryErrorFalse ); } //grid2DSquareCellDouble.setCell( this.row, this.col, this.sumWeight ); } /** * For evaluating cells in: * getKernelWeightsInDistance( Point2DBigDecimal[], * Grid2DSquareCellDouble, * double, double, double ) * and: * getKernelWeightsInDistance( HashSet, Point2DBigDecimal[], * Grid2DSquareCellDouble, * double, double, double ) */ private void doCell1( Grid2DSquareCellDouble grid2DSquareCellDouble, int decimalPlaces ) { this.point2DBigDecimal = new Point2DBigDecimal( grid2DSquareCellDouble.getCellXBigDecimal( this.col, this.handleOutOfMemoryErrorFalse ), grid2DSquareCellDouble.getCellYBigDecimal( this.row, this.handleOutOfMemoryErrorFalse ) ); this.inDistancePointDistanceIDsHashSet = getInDistancePoint2DBigDecimal_DistanceBigDecimal_IDInts( pointIDsHashSet, this.point2DBigDecimals, this.point2DBigDecimal, this.distanceBigDecimal, decimalPlaces ); if ( ! inDistancePointDistanceIDsHashSet.isEmpty() ) { this.ite = inDistancePointDistanceIDsHashSet.iterator(); this.sumWeight = 0.0d; while ( this.ite.hasNext() ) { this.point2DBigDecimal_DistanceBigDecimal_IDInt = ( Point2DBigDecimal_DistanceBigDecimal_IDInt ) this.ite.next(); this.sumWeight += Kernel.getKernelWeight( this.distanceDouble, this.weightIntersect, this.weightFactor, this.point2DBigDecimal_DistanceBigDecimal_IDInt.getDistanceDouble() ); } grid2DSquareCellDouble.setCell( this.row, this.col, this.sumWeight, this.handleOutOfMemoryErrorFalse ); } //grid2DSquareCellDouble.setCell( this.row, this.col, this.sumWeight ); } /** * Returns an Grid2DSquareCellDouble that has values corresponding * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor. Only the * points with Integer key ids in pointIDsHashSet need be used. * @param pointIDsHashSet HashSet of Integer key ids of points (a subset) * @param points the points array to be used * @param grid the Grid2DSquareCellDouble defining the frame and * @param distance the bandwidth of the fixed kernel * @param weightIntersect the weight at the centre of the kernal * @param weightFactor the distance decay factor of the kernel */ public Grid2DSquareCellDouble getKernelWeightsInDistance( HashSet pointIDsHashSet, Point2D.Double[] point2DDoubles, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor ) { if ( pointIDsHashSet.size() > point2DDoubles.length / 2 ) { return getKernelWeightsInDistance( point2DDoubles, grid2DSquareCellDouble, distanceDouble, weightIntersect, weightFactor ); } else { this.point2DDoubles = point2DDoubles; this.distanceDouble = distanceDouble; this.distanceBigDecimal = BigDecimal.valueOf( distanceDouble ); this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); BigDecimal[] dimensions = new BigDecimal[ 5 ]; dimensions[ 1 ] = grid2DSquareCellDoubleDimensions[ 1 ].subtract( this.distanceBigDecimal ); dimensions[ 2 ] = grid2DSquareCellDoubleDimensions[ 2 ].subtract( this.distanceBigDecimal ); dimensions[ 3 ] = grid2DSquareCellDoubleDimensions[ 3 ].add( this.distanceBigDecimal ); dimensions[ 4 ] = grid2DSquareCellDoubleDimensions[ 4 ].add( this.distanceBigDecimal ); pointIDsHashSet = Utilities.getPointsIntersected( point2DDoubles, dimensions ); // Calculate for ( this.row = 0; this.row < nrows; this.row ++ ) { for ( this.col = 0; this.col < ncols; this.col ++ ) { doCell1( result ); } } return result; } } /** * Returns an Grid2DSquareCellDouble that has values corresponding * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor. Only the * points with Integer key ids in pointIDsHashSet need be used. * @param pointIDsHashSet HashSet of Integer key ids of points (a subset) * @param point2DBigDecimals the Point2DBigDecimal[] to be used * @param grid the Grid2DSquareCellDouble defining the frame and * @param distance the bandwidth of the fixed kernel * @param weightIntersect the weight at the centre of the kernal * @param weightFactor the distance decay factor of the kernel */ public Grid2DSquareCellDouble getKernelWeightsInDistance( HashSet pointIDsHashSet, Point2DBigDecimal[] point2DBigDecimals, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor, int decimalPlaces ) { if ( pointIDsHashSet.size() > point2DDoubles.length / 2 ) { return getKernelWeightsInDistance( point2DBigDecimals, grid2DSquareCellDouble, distanceDouble, weightIntersect, weightFactor, decimalPlaces ); } else { this.point2DBigDecimals = point2DBigDecimals; this.distanceDouble = distanceDouble; this.distanceBigDecimal = BigDecimal.valueOf( distanceDouble ); this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); BigDecimal[] dimensions = new BigDecimal[ 5 ]; dimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].subtract( this.distanceBigDecimal ).toString() ); dimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].subtract( this.distanceBigDecimal ).toString() ); dimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].add( this.distanceBigDecimal ).toString() ); dimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].add( this.distanceBigDecimal ).toString() ); //dimensions[ 1 ] = grid2DSquareCellDoubleDimensions[ 1 ].subtract( this.distanceBigDecimal ); //dimensions[ 2 ] = grid2DSquareCellDoubleDimensions[ 2 ].subtract( this.distanceBigDecimal ); //dimensions[ 3 ] = grid2DSquareCellDoubleDimensions[ 3 ].add( this.distanceBigDecimal ); //dimensions[ 4 ] = grid2DSquareCellDoubleDimensions[ 4 ].add( this.distanceBigDecimal ); pointIDsHashSet = Utilities.getPointsIntersected( point2DBigDecimals, dimensions ); // Calculate for ( this.row = 0; this.row < nrows; this.row ++ ) { for ( this.col = 0; this.col < ncols; this.col ++ ) { doCell1( result, decimalPlaces ); } } return result; } } /** * Returns an Grid2DSquareCellDouble that has values corresponding * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor * @param points the points array to be used * @param grid the Grid2DSquareCellDouble defining the frame and * @param distance the bandwidth of the fixed kernel * @param distanceFactor is used to calculate searchDistance which is used * to store a memory of what points are in a given distance of a * cell centroid. This memory may be used to calculate the result for * neighbouring cells more speedily. It is recomended that a * distanceFactor is set >= 2. * @param weightIntersect the weight at the centre of the kernal * @param weightFactor the distance decay factor of the kernel */ public Grid2DSquareCellDouble getKernelWeightsInDistance( Point2D.Double[] point2DDoubles, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor, int distanceFactor ) { distanceFactor = Math.abs( distanceFactor ); BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); this.cellsizeDouble = grid2DSquareCellDoubleDimensions[ 0 ].doubleValue(); this.searchDistanceDouble = distanceDouble + ( ( double ) distanceFactor * this.cellsizeDouble ); if ( distanceFactor < 2.0d || this.searchDistanceDouble < this.cellsizeDouble * 2.0d ) { return getKernelWeightsInDistance( point2DDoubles, grid2DSquareCellDouble, distanceDouble, weightIntersect, weightFactor ); } else { this.point2DDoubles = point2DDoubles; this.distanceDouble = distanceDouble; this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] dimensions = new BigDecimal[ 5 ]; // TODO: // Is scale and ROUNDING_MODE appropriate? //int scale = grid2DSquareCellDouble.getDimensionsScale() * 2; int scale = 324; int roundingMode = BigDecimal.ROUND_HALF_EVEN; BigDecimal distanceBigDecimal0 = new BigDecimal( distanceDouble ).add( grid2DSquareCellDoubleDimensions[ 0 ].divide( new BigDecimal( "2" ), scale, roundingMode ) ); dimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal0 ).toString() ); dimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal0 ).toString() ); dimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal0 ).toString() ); dimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal0 ).toString() ); //dimensions[ 1 ] = grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal0 ); //dimensions[ 2 ] = grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal0 ); //dimensions[ 3 ] = grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal0 ); //dimensions[ 4 ] = grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal0 ); //HashSet pointIDsHashSet = Utilities.getInBoundPointIDs( point2DDoubles, dimensions ); HashSet pointIDsHashSet = Utilities.getPointsIntersected( point2DDoubles, dimensions ); // Calculate for first cell this.point2DDouble = new Point2D.Double( grid2DSquareCellDouble.getCellXDouble( 0L, this.handleOutOfMemoryErrorFalse ), grid2DSquareCellDouble.getCellYDouble( 0L, this.handleOutOfMemoryErrorFalse ) ); this.inSearchDistancePointIDsHashSet = Utilities.getInDistancePointIDs( pointIDsHashSet, point2DDoubles, this.point2DDouble, this.searchDistanceDouble ); this.counter = 0; this.row = 0; this.col = 0; doCell2( result ); // Calculate for the rest of the first row this.row = 0; for ( this.col = 1; this.col < ncols; this.col ++ ) { doCell3( result ); } // Calculate for the rest of the rows boolean alternator = false; for ( this.row = 1; this.row < nrows; this.row ++ ) { if ( alternator ) { alternator = false; // go right along row for ( this.col = 0; this.col < ncols; this.col ++ ) { doCell3( result ); } } else { alternator = true; // go left along row for ( this.col = ncols - 1; this.col > -1; this.col -- ) { doCell3( result ); } } //System.out.println( "Done row " + this.row ); } return result; } } /** * Returns an Grid2DSquareCellDouble that has values corresponding * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor * @param points the points array to be used * @param grid the Grid2DSquareCellDouble defining the frame and * @param distance the bandwidth of the fixed kernel * @param distanceFactor is used to calculate searchDistance which is used * to store a memory of what points are in a given distance of a * cell centroid. This memory may be used to calculate the result for * neighbouring cells more speedily. It is recomended that a * distanceFactor is set >= 2. * @param weightIntersect the weight at the centre of the kernal * @param weightFactor the distance decay factor of the kernel */ public Grid2DSquareCellDouble getKernelWeightsInDistance( Point2DBigDecimal[] point2DBigDecimals, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor, int distanceFactor, int decimalPlaces ) { distanceFactor = Math.abs( distanceFactor ); BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); this.cellsizeDouble = grid2DSquareCellDoubleDimensions[ 0 ].doubleValue(); this.searchDistanceDouble = distanceDouble + ( ( double ) distanceFactor * this.cellsizeDouble ); if ( distanceFactor < 2.0d || this.searchDistanceDouble < this.cellsizeDouble * 2.0d ) { return getKernelWeightsInDistance( point2DDoubles, grid2DSquareCellDouble, distanceDouble, weightIntersect, weightFactor ); } else { this.point2DBigDecimals = point2DBigDecimals; this.distanceDouble = distanceDouble; this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] dimensions = new BigDecimal[ 5 ]; // TODO: // Is scale and ROUNDING_MODE appropriate? //int scale = grid2DSquareCellDouble.getDimensionsScale() * 2; int scale = 324; int roundingMode = BigDecimal.ROUND_HALF_EVEN; BigDecimal distanceBigDecimal0 = new BigDecimal( distanceDouble ).add( grid2DSquareCellDoubleDimensions[ 0 ].divide( new BigDecimal( "2" ), scale, roundingMode ) ); dimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal0 ).toString() ); dimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal0 ).toString() ); dimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal0 ).toString() ); dimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal0 ).toString() ); //dimensions[ 1 ] = grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal0 ); //dimensions[ 2 ] = grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal0 ); //dimensions[ 3 ] = grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal0 ); //dimensions[ 4 ] = grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal0 ); //HashSet pointIDsHashSet = Utilities.getInBoundPointIDs( point2DBigDecimals, dimensions ); HashSet pointIDsHashSet = Utilities.getPointsIntersected( point2DBigDecimals, dimensions ); // Calculate for first cell this.point2DBigDecimal = new Point2DBigDecimal( grid2DSquareCellDouble.getCellXBigDecimal( 0L, this.handleOutOfMemoryErrorFalse ), grid2DSquareCellDouble.getCellYBigDecimal( 0L, this.handleOutOfMemoryErrorFalse ) ); this.inSearchDistancePointIDsHashSet = Utilities.getInDistancePointIDs( pointIDsHashSet, point2DBigDecimals, this.point2DBigDecimal, this.searchDistanceDouble, decimalPlaces ); this.counter = 0; this.row = 0; this.col = 0; doCell2( result, decimalPlaces ); // Calculate for the rest of the first row this.row = 0; for ( this.col = 1; this.col < ncols; this.col ++ ) { doCell3( result, decimalPlaces ); } // Calculate for the rest of the rows boolean alternator = false; for ( this.row = 1; this.row < nrows; this.row ++ ) { if ( alternator ) { alternator = false; // go right along row for ( this.col = 0; this.col < ncols; this.col ++ ) { doCell3( result, decimalPlaces ); } } else { alternator = true; // go left along row for ( this.col = ncols - 1; this.col > -1; this.col -- ) { doCell3( result, decimalPlaces ); } } //System.out.println( "Done row " + row ); } return result; } } /** * For evaluating cells in: * getKernelWeightsInDistance( Point2D.Double[], * Grid2DSquareCellDouble, * double, double, double, int ) * and: * getKernelWeightsInDistance( HashSet, Point2D.Double[], * Grid2DSquareCellDouble, * double, double, double, int ) */ private void doCell2( Grid2DSquareCellDouble grid2DSquareCellDouble ) { this.inDistancePointDistanceIDsHashSet = getInDistancePoint2DDouble_DistanceDouble_IDInts( this.inSearchDistancePointIDsHashSet, this.point2DDoubles, this.point2DDouble, this.distanceDouble ); this.sumWeight = 0.0d; if ( this.inDistancePointDistanceIDsHashSet.size() > 0 ) { this.ite = inDistancePointDistanceIDsHashSet.iterator(); while ( this.ite.hasNext() ) { this.point2DDouble_DistanceDouble_IDInt = ( Point2DDouble_DistanceDouble_IDInt ) this.ite.next(); this.sumWeight += Kernel.getKernelWeight( this.distanceDouble, this.weightIntersect, this.weightFactor, this.point2DDouble_DistanceDouble_IDInt.distanceDouble ); } grid2DSquareCellDouble.setCell( this.row, this.col, this.sumWeight, this.handleOutOfMemoryErrorFalse ); } //grid2DSquareCellDouble.setCell( this.row, this.col, this.sumWeight ); this.counter ++; } /** * For evaluating cells in: * getKernelWeightsInDistance( Point2D.Double[], * Grid2DSquareCellDouble, * double, double, double, int ) * and: * getKernelWeightsInDistance( HashSet, Point2D.Double[], * Grid2DSquareCellDouble, * double, double, double, int ) */ private void doCell2( Grid2DSquareCellDouble grid2DSquareCellDouble, int decimalPlaces ) { //this.inDistancePointDistanceIDsHashSet = getInDistancePoint2DBigDecimal_DistanceBigDecimal_IDInts( this.inSearchDistancePointIDsHashSet, this.point2DBigDecimals, this.point2DBigDecimal, this.distanceDouble, decimalPlaces ); this.inDistancePointDistanceIDsHashSet = getInDistancePoint2DBigDecimal_DistanceBigDecimal_IDInts( this.inSearchDistancePointIDsHashSet, this.point2DBigDecimals, this.point2DBigDecimal, this.distanceBigDecimal, decimalPlaces ); this.sumWeight = 0.0d; if ( this.inDistancePointDistanceIDsHashSet.size() > 0 ) { this.ite = inDistancePointDistanceIDsHashSet.iterator(); while ( this.ite.hasNext() ) { this.point2DBigDecimal_DistanceBigDecimal_IDInt = ( Point2DBigDecimal_DistanceBigDecimal_IDInt ) this.ite.next(); this.sumWeight += Kernel.getKernelWeight( this.distanceDouble, this.weightIntersect, this.weightFactor, this.point2DBigDecimal_DistanceBigDecimal_IDInt.distanceBigDecimal.doubleValue() ); } grid2DSquareCellDouble.setCell( this.row, this.col, this.sumWeight, this.handleOutOfMemoryErrorFalse ); } //grid2DSquareCellDouble.setCell( this.row, this.col, this.sumWeight ); this.counter ++; } /** * For evaluating cells in: * getKernelWeightsInDistance( Point2D.Double[], * Grid2DSquareCellDouble, * double, double, double, int ) * and: * getKernelWeightsInDistance( HashSet, Point2D.Double[], * Grid2DSquareCellDouble, * double, double, double, int ) */ private void doCell3( Grid2DSquareCellDouble grid2DSquareCellDouble ) { this.point2DDouble = new Point2D.Double( grid2DSquareCellDouble.getCellXDouble( col, this.handleOutOfMemoryErrorFalse ), grid2DSquareCellDouble.getCellYDouble( row, this.handleOutOfMemoryErrorFalse ) ); this.cellsizeDouble = grid2DSquareCellDouble.getCellsizeDouble( this.handleOutOfMemoryErrorFalse ); if ( this.searchDistanceDouble > ( this.distanceDouble + ( this.cellsizeDouble * ( double ) this.counter ) ) ) { doCell2( grid2DSquareCellDouble ); } else { // Recalculate inSearchDistancePointIDsHashSet = Utilities.getInDistancePointIDs( this.pointIDsHashSet, this.point2DDoubles, this.point2DDouble, this.searchDistanceDouble ); this.counter = 0; doCell2( grid2DSquareCellDouble ); } } /** * For evaluating cells in: * getKernelWeightsInDistance( Point2D.Double[], * Grid2DSquareCellDouble, * double, double, double, int ) * and: * getKernelWeightsInDistance( HashSet, Point2D.Double[], * Grid2DSquareCellDouble, * double, double, double, int ) */ private void doCell3( Grid2DSquareCellDouble grid2DSquareCellDouble, int decimalPlaces ) { this.point2DBigDecimal = new Point2DBigDecimal( grid2DSquareCellDouble.getCellXBigDecimal( col, this.handleOutOfMemoryErrorFalse ), grid2DSquareCellDouble.getCellYBigDecimal( row, this.handleOutOfMemoryErrorFalse ) ); this.cellsizeDouble = grid2DSquareCellDouble.getCellsizeDouble( this.handleOutOfMemoryErrorFalse ); if ( this.searchDistanceDouble > ( this.distanceDouble + ( this.cellsizeDouble * ( double ) this.counter ) ) ) { doCell2( grid2DSquareCellDouble, decimalPlaces ); } else { // Recalculate inSearchDistancePointIDsHashSet = Utilities.getInDistancePointIDs( this.pointIDsHashSet, this.point2DBigDecimals, this.point2DBigDecimal, this.searchDistanceDouble, decimalPlaces ); this.counter = 0; doCell2( grid2DSquareCellDouble, decimalPlaces ); } } /** * Returns an Grid2DSquareCellDouble that has values corresponding * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor. Only the * points with Integer key ids in pointIDsHashSet need be used. * @param pointIDsHashSet HashSet of Integer key ids of points (a subset) * @param points the points array to be used * @param grid the Grid2DSquareCellDouble defining the frame and * @param distance the bandwidth of the fixed kernel * @param distanceFactor is used to calculate searchDistance which is used * to store a memory of what points are in a given distance of a cell * centroid. This memory may be used to calculate the result for * neighbouring cells more speedily. It is recomended that a * distanceFactor is set >= 2. * @param weightIntersect the weight at the centre of the kernal * @param weightFactor the distance decay factor of the kernel */ public Grid2DSquareCellDouble getKernelWeightsInDistance( HashSet pointIDsHashSet, Point2D.Double[] point2DDoubles, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor, int distanceFactor ) { if ( pointIDsHashSet.size() > point2DDoubles.length / 2 ) { return getKernelWeightsInDistance( point2DDoubles, grid2DSquareCellDouble, distanceDouble, weightIntersect, weightFactor, distanceFactor ); } else { distanceFactor = Math.abs( distanceFactor ); //this.cellsizeDouble = grid2DSquareCellDouble.getCellsizeDouble(); this.searchDistanceDouble = distanceDouble + ( ( double ) distanceFactor * this.cellsizeDouble ); if ( distanceFactor < 2 || this.searchDistanceDouble < this.cellsizeDouble * 2.0d ) { return getKernelWeightsInDistance( pointIDsHashSet, point2DDoubles, grid2DSquareCellDouble, distanceDouble, weightIntersect, weightFactor ); } else { this.point2DDoubles = point2DDoubles; this.distanceDouble = distanceDouble; this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); BigDecimal[] dimensions = new BigDecimal[ 5 ]; // TODO: // Is scale and ROUNDING_MODE appropriate? int scale = grid2DSquareCellDouble.getDimensionsScale( this.handleOutOfMemoryErrorFalse ) * 2; //int roundingMode = BigDecimal.ROUND_UNNECESSARY; int roundingMode = BigDecimal.ROUND_DOWN; // TODO: // Check logic - is this the correct distance? //Check //BigDecimal distanceBigDecimal = new BigDecimal( distanceDouble ).add( grid2DSquareCellDoubleDimensions[ 0 ].divide( new BigDecimal( "2" ), scale, roundingMode ) ); BigDecimal distanceBigDecimal0 = this.distanceBigDecimal.subtract( grid2DSquareCellDoubleDimensions[ 0 ].divide( new BigDecimal( "2" ), scale, roundingMode ) ); dimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal0 ).toString() ); dimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal0 ).toString() ); dimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal0 ).toString() ); dimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal0 ).toString() ); //this.pointIDsHashSet = Utilities.getPointsIntersected( point2DDoubles, dimensions ); this.pointIDsHashSet = Utilities.getPointsIntersected( pointIDsHashSet, point2DDoubles, dimensions ); // Calculate for first cell this.point2DDouble = new Point2D.Double( grid2DSquareCellDouble.getCellXDouble( 0L, this.handleOutOfMemoryErrorFalse ), grid2DSquareCellDouble.getCellYDouble( 0L, this.handleOutOfMemoryErrorFalse ) ); this.inSearchDistancePointIDsHashSet = Utilities.getInDistancePointIDs( this.pointIDsHashSet, this.point2DDoubles, this.point2DDouble, this.searchDistanceDouble ); this.counter = 0; this.row = 0; this.col = 0; doCell2( result ); // Calculate for the rest of the first row for ( this.col = 1; this.col < ncols; this.col ++ ) { doCell3( result ); } // Calculate for the rest of the rows boolean alternator = false; for ( this.row = 1; this.row < nrows; this.row ++ ) { if ( alternator ) { alternator = false; // go right along row for ( this.col = 0; this.col < ncols; this.col ++ ) { doCell3( result ); } } else { alternator = true; // go left along row for ( this.col = ncols - 1; this.col > -1; this.col -- ) { doCell3( result ); } } //System.out.println( "Done row " + row ); } return result; } } } /** * Returns an Grid2DSquareCellDouble that has values corresponding * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor. Only the * points with Integer key ids in pointIDsHashSet need be used. * @param pointIDsHashSet HashSet of Integer key ids of points (a subset) * @param points the points array to be used * @param grid the Grid2DSquareCellDouble defining the frame and * @param distance the bandwidth of the fixed kernel * @param distanceFactor is used to calculate searchDistance which is used * to store a memory of what points are in a given distance of a * cell centroid. This memory may be used to calculate the result for * neighbouring cells more speedily. It is recomended that a * distanceFactor is set >= 2. * @param weightIntersect the weight at the centre of the kernal * @param weightFactor the distance decay factor of the kernel */ public Grid2DSquareCellDouble getKernelWeightsInDistance( HashSet pointIDsHashSet, Point2DBigDecimal[] point2DBigDecimals, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor, int distanceFactor, int decimalPlaces ) { if ( pointIDsHashSet.size() > point2DDoubles.length / 2 ) { return getKernelWeightsInDistance( point2DBigDecimals, grid2DSquareCellDouble, distanceDouble, weightIntersect, weightFactor, distanceFactor ); } else { distanceFactor = Math.abs( distanceFactor ); this.cellsizeDouble = grid2DSquareCellDouble.getCellsizeDouble( this.handleOutOfMemoryErrorFalse ); this.searchDistanceDouble = distanceDouble + ( ( double ) distanceFactor * this.cellsizeDouble ); if ( distanceFactor < 2 || this.searchDistanceDouble < this.cellsizeDouble * 2.0d ) { return getKernelWeightsInDistance( pointIDsHashSet, point2DBigDecimals, grid2DSquareCellDouble, distanceDouble, weightIntersect, weightFactor, decimalPlaces ); } else { this.point2DBigDecimals = point2DBigDecimals; this.distanceDouble = distanceDouble; this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); BigDecimal[] dimensions = new BigDecimal[ 5 ]; // TODO: // Is scale and ROUNDING_MODE appropriate? int scale = grid2DSquareCellDouble.getDimensionsScale( this.handleOutOfMemoryErrorFalse ) * 2; // TODO: // Check logic - is this the correct distance? //BigDecimal distanceBigDecimal0 = new BigDecimal( distanceDouble ).add( grid2DSquareCellDoubleDimensions[ 0 ].divide( new BigDecimal( "2" ), scale, BigDecimal.ROUND_UNNECESSARY ) ); BigDecimal distanceBigDecimal0 = new BigDecimal( distanceDouble ).subtract( grid2DSquareCellDoubleDimensions[ 0 ].divide( new BigDecimal( "2" ), scale, BigDecimal.ROUND_UNNECESSARY ) ); //dimensions[ 1 ] = grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal0 ); //dimensions[ 2 ] = grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal0 ); //dimensions[ 3 ] = grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal0 ); //dimensions[ 4 ] = grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal0 ); dimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal0 ).toString() ); dimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal0 ).toString() ); dimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal0 ).toString() ); dimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal0 ).toString() ); this.pointIDsHashSet = Utilities.getPointsIntersected( point2DBigDecimals, dimensions ); // Calculate for first cell this.point2DBigDecimal = new Point2DBigDecimal( grid2DSquareCellDouble.getCellXBigDecimal( 0L, this.handleOutOfMemoryErrorFalse ), grid2DSquareCellDouble.getCellYBigDecimal( 0L, this.handleOutOfMemoryErrorFalse ) ); inSearchDistancePointIDsHashSet = Utilities.getInDistancePointIDs( this.pointIDsHashSet, this.point2DDoubles, this.point2DDouble, this.searchDistanceDouble ); this.counter = 0; this.row = 0; this.col = 0; doCell2( result, decimalPlaces ); // Calculate for the rest of the first row for ( this.col = 1; this.col < ncols; this.col ++ ) { doCell3( result, decimalPlaces ); } // Calculate for the rest of the rows boolean alternator = false; for ( this.row = 1; this.row < nrows; this.row ++ ) { if ( alternator ) { alternator = false; // go right along row for ( this.col = 0; this.col < ncols; this.col ++ ) { doCell3( result, decimalPlaces ); } } else { alternator = true; // go left along row for ( this.col = ncols - 1; this.col > -1; this.col -- ) { doCell3( result, decimalPlaces ); } } //System.out.println( "Done row " + row ); } return result; } } } /** * Returns an Grid2DSquareCellDouble that has values corresponding * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor. Only the * points with Integer key ids in pointIDsHashSet need be used. * @param divisions controls the number of times the problem is divided * @param points the points array to be used * @param grid the Grid2DSquareCellDouble defining the frame and * @param distance the bandwidth of the fixed kernel * @param distanceFactor is used to calculate searchDistance which is used * to store a memory of what points are in a given distance of a * cell centroid. This memory may be used to calculate the result for * neighbouring cells more speedily. It is recomended that a * distanceFactor is set >= 2. * @param weightIntersect the weight at the centre of the kernal * @param weightFactor the distance decay factor of the kernel */ public Grid2DSquareCellDouble getKernelWeightsInDistance( int divisions, Point2D.Double[] point2DDoubles, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor, int distanceFactor ) { this.distanceDouble = distanceDouble; this.distanceBigDecimal = new BigDecimal( distanceDouble ); this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); this.cellsizeDouble = grid2DSquareCellDoubleDimensions[ 0 ].doubleValue(); this.cellsizeBigDecimal = grid2DSquareCellDoubleDimensions[ 0 ]; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] dimensions = new BigDecimal[ 5 ]; dimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal ).toString() ); dimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal ).toString() ); dimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal ).toString() ); dimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal ).toString() ); //dimensions[ 1 ] = grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal ); //dimensions[ 2 ] = grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal ); //dimensions[ 3 ] = grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal ); //dimensions[ 4 ] = grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal ); //HashSet pointIDsHashSet = Utilities.getInBoundPointIDs( point2DDoubles, dimensions ); HashSet pointIDsHashSet = Utilities.getPointsIntersected( point2DDoubles, dimensions ); doKernelWeightsInDistance( divisions, pointIDsHashSet, point2DDoubles, grid2DSquareCellDoubleFactory, grid2DSquareCellDouble, distanceFactor, result ); return result; } /** * Returns an Grid2DSquareCellDouble that has values corresponding to * the sum of kernel weights for a fixed kernel with a radius given by * distance and shape given by weightIntersect and weightFactor. Only the * points with Integer key ids in pointIDsHashSet need be used. * @param divisions controls the number of times the problem is divided * @param points the points array to be used * @param grid the Grid2DSquareCellDouble defining the frame and * @param distance the bandwidth of the fixed kernel * @param distanceFactor is used to calculate searchDistance which is used * to store a memory of what points are in a given distance of a * cell centroid. This memory may be used to calculate the result for * neighbouring cells more speedily. It is recomended that a * distanceFactor is set >= 2. * @param weightIntersect the weight at the centre of the kernal * @param weightFactor the distance decay factor of the kernel */ public Grid2DSquareCellDouble getKernelWeightsInDistance( int divisions, Point2DBigDecimal[] point2DBigDecimals, Grid2DSquareCellDouble grid2DSquareCellDouble, double distanceDouble, double weightIntersect, double weightFactor, int distanceFactor ) { this.distanceDouble = distanceDouble; this.weightIntersect = weightIntersect; this.weightFactor = weightFactor; BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); this.cellsizeDouble = grid2DSquareCellDoubleDimensions[ 0 ].doubleValue(); this.cellsizeBigDecimal = grid2DSquareCellDoubleDimensions[ 0 ]; Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory = new Grid2DSquareCellDoubleFactory(); Grid2DSquareCellDouble result = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDouble ); long ncols = result.getNcols(); long nrows = result.getNrows(); BigDecimal[] dimensions = new BigDecimal[ 5 ]; BigDecimal distanceBigDecimal = new BigDecimal( distanceDouble ); dimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal ).toString() ); dimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal ).toString() ); dimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal ).toString() ); dimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal ).toString() ); //dimensions[ 1 ] = grid2DSquareCellDoubleDimensions[ 1 ].subtract( distanceBigDecimal ); //dimensions[ 2 ] = grid2DSquareCellDoubleDimensions[ 2 ].subtract( distanceBigDecimal ); //dimensions[ 3 ] = grid2DSquareCellDoubleDimensions[ 3 ].add( distanceBigDecimal ); //dimensions[ 4 ] = grid2DSquareCellDoubleDimensions[ 4 ].add( distanceBigDecimal ); //HashSet pointIDsHashSet = Utilities.getInBoundPointIDs( point2DBigDecimals, dimensions ); HashSet pointIDsHashSet = Utilities.getPointsIntersected( point2DBigDecimals, dimensions ); doKernelWeightsInDistance( divisions, pointIDsHashSet, point2DBigDecimals, grid2DSquareCellDoubleFactory, grid2DSquareCellDouble, distanceFactor, result ); return result; } /** * For doing divisions in: * getKernelWeightsInDistance( int, Point2D.Double[], * Grid2DSquareCellDouble, double, * double, double, int ) * @param pointIDsHashSet HashSet of Integer key ids of points (a subset) * Only the points with Integer key ids in pointIDsHashSet need be used. */ private void doKernelWeightsInDistance( int divisions, HashSet pointIDsHashSet, Point2D.Double[] point2DDoubles, Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory, Grid2DSquareCellDouble grid2DSquareCellDouble, int distanceFactor, Grid2DSquareCellDouble result ) { if ( ! pointIDsHashSet.isEmpty() ) { //System.out.println( "Level of division " + divisions ); long grid2DSquareCellDoubleNrows = grid2DSquareCellDouble.getNrows(); long grid2DSquareCellDoubleNcols = grid2DSquareCellDouble.getNcols(); //this.cellsizeDouble = grid2DSquareCellDouble.getCellsizeDouble(); long maxNrowsNcols = Math.max( grid2DSquareCellDoubleNrows, grid2DSquareCellDoubleNcols ); if ( divisions == 0 || maxNrowsNcols < ( this.distanceDouble / this.cellsizeDouble ) ) { //System.out.println( "Lowest level of division" ); //System.out.println( grid2DSquareCellDouble.toString() ); // Set cellsize of grid2DSquareCellDouble Grid2DSquareCellDouble divisonResult = getKernelWeightsInDistance( pointIDsHashSet, point2DDoubles, grid2DSquareCellDouble, this.distanceDouble, this.weightIntersect, this.weightFactor, distanceFactor ); //System.out.println( divisonResult.toString() ); // Add to the results grids to save adding multiple times this.grid2DSquareCellProcessor.addToGrid( result, divisonResult, this.handleOutOfMemoryErrorFalse ); } else { // Divide problem in two... int scale = 324; int roundingMode = BigDecimal.ROUND_HALF_EVEN; BigDecimal[] grid2DSquareCellDoubleDimensions = grid2DSquareCellDouble.getDimensions(); Grid2DSquareCellDouble divGrid = null; if ( maxNrowsNcols == grid2DSquareCellDoubleNrows ) { //System.out.println( "Dividing horizontally..." ); //int divRow = ( int ) Math.ceil( ( ( ( double ) gridNrows ) - 1.0d ) / 2.0d ); //long divRow = ( long ) Math.ceil( ( ( ( double ) gridNrows ) - 1.0d ) / 2.0d ); long divRow = grid2DSquareCellDoubleNrows / 2L; BigDecimal[] divGridDimensions = new BigDecimal[ 5 ]; BigDecimal cellsizeDividedBy2BigDecimal = grid2DSquareCellDoubleDimensions[ 0 ].divide( BigDecimal.valueOf( 2.0d ), scale, roundingMode ); BigDecimal divRowCellYBigDecimal = grid2DSquareCellDouble.getCellYBigDecimal( divRow, this.handleOutOfMemoryErrorFalse ); // Bottom part divGridDimensions[ 0 ] = grid2DSquareCellDoubleDimensions[ 0 ]; divGridDimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].toString() ); divGridDimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].toString() ); divGridDimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].toString() ); divGridDimensions[ 4 ] = divRowCellYBigDecimal.add( cellsizeDividedBy2BigDecimal ); divGrid = ( Grid2DSquareCellDouble ) grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( divRow + 1L, grid2DSquareCellDoubleNcols, divGridDimensions ); doKernelWeightsInDistance( divisions - 1, pointIDsHashSet, point2DDoubles, grid2DSquareCellDoubleFactory, divGrid, distanceFactor, result ); // Top part //divGridDimensions[ 0 ] = grid2DSquareCellDoubleDimensions[ 0 ]; //divGridDimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].toString() ); divGridDimensions[ 2 ] = divRowCellYBigDecimal.add( cellsizeDividedBy2BigDecimal ); //divGridDimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].toString() ); divGridDimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].toString() ); divGrid = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDoubleNrows - divRow - 1L, grid2DSquareCellDoubleNcols, divGridDimensions ); doKernelWeightsInDistance( divisions - 1, pointIDsHashSet, point2DDoubles, grid2DSquareCellDoubleFactory, divGrid, distanceFactor, result ); } else { //System.out.println( "Dividing vertically..." ); //int divCol = ( int ) Math.ceil( ( ( ( double ) gridNcols ) - 1.0d ) / 2.0d ); //long divCol = ( int ) Math.ceil( ( ( ( double ) gridNcols ) - 1.0d ) / 2.0d ); long divCol = grid2DSquareCellDoubleNcols / 2L; BigDecimal[] divGridDimensions = new BigDecimal[ 5 ]; BigDecimal cellsizeDividedBy2BigDecimal = grid2DSquareCellDoubleDimensions[ 0 ].divide( BigDecimal.valueOf( 2.0d ), scale, roundingMode ); BigDecimal divColCellXBigDecimal = grid2DSquareCellDouble.getCellXBigDecimal( divCol, this.handleOutOfMemoryErrorFalse ); // Left part divGridDimensions[ 0 ] = grid2DSquareCellDoubleDimensions[ 0 ]; divGridDimensions[ 1 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 1 ].toString() ); divGridDimensions[ 2 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 2 ].toString() ); divGridDimensions[ 3 ] = divColCellXBigDecimal.add( cellsizeDividedBy2BigDecimal ); divGridDimensions[ 4 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 4 ].toString() ); divGrid = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDoubleNrows, divCol + 1, divGridDimensions ); doKernelWeightsInDistance( divisions - 1, pointIDsHashSet, point2DDoubles, grid2DSquareCellDoubleFactory, divGrid, distanceFactor, result ); // Right part //divGridDimensions[ 0 ] = grid2DSquareCellDoubleDimensions[ 0 ]; divGridDimensions[ 1 ] = divColCellXBigDecimal.add( cellsizeDividedBy2BigDecimal ); //divGridDimensions[ 2 ] = grid2DSquareCellDoubleDimensions[ 2 ]; divGridDimensions[ 3 ] = new BigDecimal( grid2DSquareCellDoubleDimensions[ 3 ].toString() ); //divGridDimensions[ 4 ] = grid2DSquareCellDoubleDimensions[ 4 ]; //divGrid = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDoubleNrows, grid2DSquareCellDoubleNcols - divCol - 1L, ( grid.getCellX( divCol ) - ( cellsize / 2.0d ) ), gridYllcorner, cellsize, noDataValue, 1 ); divGrid = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDoubleNrows, grid2DSquareCellDoubleNcols - divCol - 1L, divGridDimensions ); doKernelWeightsInDistance( divisions - 1, pointIDsHashSet, point2DDoubles, grid2DSquareCellDoubleFactory, divGrid, distanceFactor, result ); } } } } /** * For doing divisions in: * getKernelWeightsInDistance( int, Point2D.Double[], * Grid2DSquareCellDouble, double, * double, double, int ) * @param pointIDsHashSet HashSet of Integer key ids of points (a subset) * Only the points with Integer key ids in pointIDsHashSet need be used. */ private void doKernelWeightsInDistance( int divisions, HashSet pointIDsHashSet, Point2DBigDecimal[] point2DBigDecimals, Grid2DSquareCellDoubleFactory grid2DSquareCellDoubleFactory, Grid2DSquareCellDouble grid2DSquareCellDouble, int distanceFactor, Grid2DSquareCellDouble result ) { if ( ! pointIDsHashSet.isEmpty() ) { //System.out.println( "Level of division " + divisions ); long grid2DSquareCellDoubleNrows = grid2DSquareCellDouble.getNrows(); long grid2DSquareCellDoubleNcols = grid2DSquareCellDouble.getNcols(); this.cellsizeDouble = grid2DSquareCellDouble.getCellsizeDouble( this.handleOutOfMemoryErrorFalse ); long maxNrowsNcols = Math.max( grid2DSquareCellDoubleNrows, grid2DSquareCellDoubleNcols ); if ( divisions == 0 || maxNrowsNcols < ( this.distanceDouble / this.cellsizeDouble ) ) { //System.out.println( "Lowest level of division" ); //System.out.println( grid2DSquareCellDouble.toString() ); Grid2DSquareCellDouble divisonResult = getKernelWeightsInDistance( pointIDsHashSet, point2DDoubles, grid2DSquareCellDouble, this.distanceDouble, this.weightIntersect, this.weightFactor, distanceFactor ); //System.out.println( divisonResult.toString() ); // Add to the results grids to save adding multiple times this.grid2DSquareCellProcessor.addToGrid( result, divisonResult, this.handleOutOfMemoryErrorFalse ); } else { // Divide problem in two... Grid2DSquareCellDouble divGrid = null; if ( maxNrowsNcols == grid2DSquareCellDoubleNrows ) { //System.out.println( "Dividing horizontally..." ); //int divRow = ( int ) Math.ceil( ( ( ( double ) gridNrows ) - 1.0d ) / 2.0d ); long divRow = grid2DSquareCellDoubleNrows / 2L; // Top part //divGrid = ( Grid2DSquareCellDouble ) grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( divRow + 1L, grid2DSquareCellDoubleNcols, dimensions ); divGrid = ( Grid2DSquareCellDouble ) grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( divRow + 1L, grid2DSquareCellDoubleNcols ); doKernelWeightsInDistance( divisions - 1, pointIDsHashSet, point2DBigDecimals, grid2DSquareCellDoubleFactory, divGrid, distanceFactor, result ); // Bottom part divGrid = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDoubleNrows - divRow - 1L, grid2DSquareCellDoubleNcols ); doKernelWeightsInDistance( divisions - 1, pointIDsHashSet, point2DBigDecimals, grid2DSquareCellDoubleFactory, divGrid, distanceFactor, result ); } else { //System.out.println( "Dividing vertically..." ); //int divCol = ( int ) Math.ceil( ( ( ( double ) gridNcols ) - 1.0d ) / 2.0d ); long divCol = grid2DSquareCellDoubleNcols / 2L; // Left part divGrid = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDoubleNrows, divCol + 1 ); doKernelWeightsInDistance( divisions - 1, pointIDsHashSet, point2DBigDecimals, grid2DSquareCellDoubleFactory, divGrid, distanceFactor, result ); // Right part //divGrid = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDoubleNrows, grid2DSquareCellDoubleNcols - divCol - 1L, ( grid.getCellX( divCol ) - ( cellsize / 2.0d ) ), gridYllcorner, cellsize, noDataValue, 1 ); divGrid = grid2DSquareCellDoubleFactory.createGrid2DSquareCellDouble( grid2DSquareCellDoubleNrows, grid2DSquareCellDoubleNcols - divCol - 1L ); doKernelWeightsInDistance( divisions - 1, pointIDsHashSet, point2DBigDecimals, grid2DSquareCellDoubleFactory, divGrid, distanceFactor, result ); } } } } }