PointStackerProcess implements VectorProcess { @DescribeResult(name = "result", description = "Aggregated feature collection") public SimpleFeatureCollection execute( @DescribeParameter(name = "data", description = "Input feature collection") SimpleFeatureCollection data, @DescribeParameter(name = "cellSize", description = "Grid cell size to aggregate to, in pixels") Integer cellSize, @DescribeParameter(name = "normalize", description = "Indicates whether to add fields normalized to the range 0-1.", defaultValue="false") Boolean argNormalize, @DescribeParameter(name = "preserveLocation", description = "Indicates wheter to preserve the original location of points for single/superimposed points", defaultValue="Never", min=0) PreserveLocation preserveLocation, @DescribeParameter(name = "outputBBOX", description = "Bounding box for target image extent") ReferencedEnvelope outputEnv, @DescribeParameter(name = "outputWidth", description = "Target image width in pixels", minValue = 1) Integer outputWidth, @DescribeParameter(name = "outputHeight", description = "Target image height in pixels", minValue = 1) Integer outputHeight, ProgressListener monitor) throws ProcessException, TransformException { CoordinateReferenceSystem srcCRS = data.getSchema().getCoordinateReferenceSystem(); CoordinateReferenceSystem dstCRS = outputEnv.getCoordinateReferenceSystem(); MathTransform crsTransform = null; MathTransform invTransform = null; try { crsTransform = CRS.findMathTransform(srcCRS, dstCRS); invTransform = crsTransform.inverse(); } catch (FactoryException e) { throw new ProcessException(e); } boolean normalize = false; if(argNormalize!=null){ normalize = argNormalize; } double cellSizeSrc = cellSize * outputEnv.getWidth() / outputWidth; Collection<StackedPoint> stackedPts = stackPoints(data, crsTransform, cellSizeSrc, outputEnv.getMinX(), outputEnv.getMinY()); SimpleFeatureType schema = createType(srcCRS, normalize); ListFeatureCollection result = new ListFeatureCollection(schema); SimpleFeatureBuilder fb = new SimpleFeatureBuilder(schema); GeometryFactory factory = new GeometryFactory(new PackedCoordinateSequenceFactory()); double[] srcPt = new double[2]; double[] dstPt = new double[2]; int maxCount = 0; int maxCountUnique = 0; if(normalize){ for (StackedPoint sp : stackedPts) { if(maxCount<sp.getCount()) maxCount = sp.getCount(); if(maxCountUnique<sp.getCount()) maxCountUnique = sp.getCountUnique(); } } for (StackedPoint sp : stackedPts) { Coordinate pt = getStackedPointLocation(preserveLocation, sp); srcPt[0] = pt.x; srcPt[1] = pt.y; invTransform.transform(srcPt, 0, dstPt, 0, 1); Coordinate psrc = new Coordinate(dstPt[0], dstPt[1]); Geometry point = factory.createPoint(psrc); fb.add(point); fb.add(sp.getCount()); fb.add(sp.getCountUnique()); if(normalize){ fb.add(((double)sp.getCount())/maxCount); fb.add(((double)sp.getCountUnique())/maxCountUnique); } result.add(fb.buildFeature(null)); } return result; }  @DescribeResult(name = "result", description = "Aggregated feature collection") SimpleFeatureCollection execute(

            // process data
            @DescribeParameter(name = "data", description = "Input feature collection") SimpleFeatureCollection data,

            // process parameters
            @DescribeParameter(name = "cellSize", description = "Grid cell size to aggregate to, in pixels") Integer cellSize,
            @DescribeParameter(name = "normalize", description = "Indicates whether to add fields normalized to the range 0-1.", defaultValue="false") Boolean argNormalize,
            @DescribeParameter(name = "preserveLocation", description = "Indicates wheter to preserve the original location of points for single/superimposed points", defaultValue="Never", min=0) PreserveLocation preserveLocation,

            // output image parameters
            @DescribeParameter(name = "outputBBOX", description = "Bounding box for target image extent") ReferencedEnvelope outputEnv,
            @DescribeParameter(name = "outputWidth", description = "Target image width in pixels", minValue = 1) Integer outputWidth,
            @DescribeParameter(name = "outputHeight", description = "Target image height in pixels", minValue = 1) Integer outputHeight,
            

            ProgressListener monitor); static final String ATTR_GEOM; static final String ATTR_COUNT; static final String ATTR_COUNT_UNIQUE; static final String ATTR_NORM_COUNT; static final String ATTR_NORM_COUNT_UNIQUE; }
@Test public void testSimple() throws ProcessException, TransformException { ReferencedEnvelope bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); Coordinate[] data = new Coordinate[] { new Coordinate(4, 4), new Coordinate(4.1, 4.1), new Coordinate(4.1, 4.1), new Coordinate(8, 8) }; SimpleFeatureCollection fc = createPoints(data, bounds); ProgressListener monitor = null; PointStackerProcess psp = new PointStackerProcess(); SimpleFeatureCollection result = psp.execute(fc, 100, null, null, bounds, 1000, 1000, monitor); checkSchemaCorrect(result.getSchema(), false); assertEquals(2, result.size()); checkResultPoint(result, new Coordinate(4, 4), 3, 2, null, null); checkResultPoint(result, new Coordinate(8, 8), 1, 1, null, null); }
@Test public void testNormal() throws ProcessException, TransformException { ReferencedEnvelope bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); Coordinate[] data = new Coordinate[] { new Coordinate(4, 4), new Coordinate(4.1, 4.1), new Coordinate(4.1, 4.1), new Coordinate(8, 8) }; SimpleFeatureCollection fc = createPoints(data, bounds); ProgressListener monitor = null; PointStackerProcess psp = new PointStackerProcess(); SimpleFeatureCollection result = psp.execute(fc, 100, true, null, bounds, 1000, 1000, monitor); checkSchemaCorrect(result.getSchema(), true); assertEquals(2, result.size()); checkResultPoint(result, new Coordinate(4, 4), 3, 2, 1.0d, 1.0d); checkResultPoint(result, new Coordinate(8, 8), 1, 1, 1.0d/3, 1.0d/2); }
@Test public void testPreserveSingle() throws ProcessException, TransformException { ReferencedEnvelope bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); Coordinate[] data = new Coordinate[] { new Coordinate(4, 4), new Coordinate(6.5, 6.5), new Coordinate(6.5, 6.5), new Coordinate(8, 8), new Coordinate(8.3, 8.3) }; SimpleFeatureCollection fc = createPoints(data, bounds); ProgressListener monitor = null; PointStackerProcess psp = new PointStackerProcess(); SimpleFeatureCollection result = psp.execute(fc, 100, true, PreserveLocation.Single, bounds, 1000, 1000, monitor); checkSchemaCorrect(result.getSchema(), true); assertEquals(3, result.size()); checkStackedPoint(new Coordinate(4, 4), 1, 1, getResultPoint(result, new Coordinate(4, 4))); checkStackedPoint(null, 2, 1, getResultPoint(result, new Coordinate(6.5, 6.5))); checkStackedPoint(null, 2, 2, getResultPoint(result, new Coordinate(8, 8))); }
@Test public void testPreserveSuperimposed() throws ProcessException, TransformException { ReferencedEnvelope bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); Coordinate[] data = new Coordinate[] { new Coordinate(4, 4), new Coordinate(6.5, 6.5), new Coordinate(6.5, 6.5), new Coordinate(8, 8), new Coordinate(8.3, 8.3) }; SimpleFeatureCollection fc = createPoints(data, bounds); ProgressListener monitor = null; PointStackerProcess psp = new PointStackerProcess(); SimpleFeatureCollection result = psp.execute(fc, 100, true, PreserveLocation.Superimposed, bounds, 1000, 1000, monitor); checkSchemaCorrect(result.getSchema(), true); assertEquals(3, result.size()); checkStackedPoint(new Coordinate(4, 4), 1, 1, getResultPoint(result, new Coordinate(4, 4))); checkStackedPoint(new Coordinate(6.5, 6.5), 2, 1, getResultPoint(result, new Coordinate(6.5, 6.5))); checkStackedPoint(null, 2, 2, getResultPoint(result, new Coordinate(8, 8))); }
@Test public void testReprojected() throws NoSuchAuthorityCodeException, FactoryException, ProcessException, TransformException { ReferencedEnvelope inBounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); Coordinate[] data = new Coordinate[] { new Coordinate(-121.813201, 48.777343), new Coordinate(-121.813, 48.777) }; SimpleFeatureCollection fc = createPoints(data, inBounds); ProgressListener monitor = null; CoordinateReferenceSystem webMerc = CRS.decode("EPSG:3785"); ReferencedEnvelope outBounds = new ReferencedEnvelope(-1.4045034049133E7, -1.2937920131607E7, 5916835.1504419, 6386464.2521607, webMerc); PointStackerProcess psp = new PointStackerProcess(); SimpleFeatureCollection result = psp.execute(fc, 100, null, null, outBounds, 1810, 768, monitor); checkSchemaCorrect(result.getSchema(), false); assertEquals(1, result.size()); assertEquals(inBounds.getCoordinateReferenceSystem(), result.getBounds().getCoordinateReferenceSystem()); checkResultPoint(result, new Coordinate(-121.813201, 48.777343), 2, 2, null, null); }