HeatmapProcess implements VectorProcess { @DescribeResult(name = "result", description = "Output raster") public GridCoverage2D execute( @DescribeParameter(name = "data", description = "Input features") SimpleFeatureCollection obsFeatures, @DescribeParameter(name = "radiusPixels", description = "Radius of the density kernel in pixels") Integer argRadiusPixels, @DescribeParameter(name = "weightAttr", description = "Name of the attribute to use for data point weight", min = 0, max = 1) String valueAttr, @DescribeParameter(name = "pixelsPerCell", description = "Resolution at which to compute the heatmap (in pixels). Default = 1", defaultValue="1", min = 0, max = 1) Integer argPixelsPerCell, @DescribeParameter(name = "outputBBOX", description = "Bounding box of the output") ReferencedEnvelope argOutputEnv, @DescribeParameter(name = "outputWidth", description = "Width of output raster in pixels") Integer argOutputWidth, @DescribeParameter(name = "outputHeight", description = "Height of output raster in pixels") Integer argOutputHeight, ProgressListener monitor) throws ProcessException { int pixelsPerCell = 1; if (argPixelsPerCell != null && argPixelsPerCell > 1) { pixelsPerCell = argPixelsPerCell; } int outputWidth = argOutputWidth; int outputHeight = argOutputHeight; int gridWidth = outputWidth; int gridHeight = outputHeight; if (pixelsPerCell > 1) { gridWidth = outputWidth / pixelsPerCell; gridHeight = outputHeight / pixelsPerCell; } CoordinateReferenceSystem srcCRS = obsFeatures.getSchema().getCoordinateReferenceSystem(); CoordinateReferenceSystem dstCRS = argOutputEnv.getCoordinateReferenceSystem(); MathTransform trans = null; try { trans = CRS.findMathTransform(srcCRS, dstCRS); } catch (FactoryException e) { throw new ProcessException(e); } int radiusCells = 100; if (argRadiusPixels != null) radiusCells = argRadiusPixels; if (pixelsPerCell > 1) { radiusCells /= pixelsPerCell; } HeatmapSurface heatMap = new HeatmapSurface(radiusCells, argOutputEnv, gridWidth, gridHeight); try { extractPoints(obsFeatures, valueAttr, trans, heatMap); } catch (CQLException e) { throw new ProcessException(e); } float[][] heatMapGrid = heatMap.computeSurface(); heatMapGrid = flipXY(heatMapGrid); float[][] outGrid = heatMapGrid; if (pixelsPerCell > 1) outGrid = upsample(heatMapGrid, -999, outputWidth, outputHeight); GridCoverageFactory gcf = CoverageFactoryFinder.getGridCoverageFactory(GeoTools.getDefaultHints()); GridCoverage2D gridCov = gcf.create("Process Results", outGrid, argOutputEnv); return gridCov; }  @DescribeResult(name = "result", description = "Output raster") GridCoverage2D execute(

            // process data
            @DescribeParameter(name = "data", description = "Input features") SimpleFeatureCollection obsFeatures,

            // process parameters
            @DescribeParameter(name = "radiusPixels", description = "Radius of the density kernel in pixels") Integer argRadiusPixels,
            @DescribeParameter(name = "weightAttr", description = "Name of the attribute to use for data point weight", min = 0, max = 1) String valueAttr,
            @DescribeParameter(name = "pixelsPerCell", description = "Resolution at which to compute the heatmap (in pixels). Default = 1", defaultValue="1", min = 0, max = 1) Integer argPixelsPerCell,

            // output image parameters
            @DescribeParameter(name = "outputBBOX", description = "Bounding box of the output") ReferencedEnvelope argOutputEnv,
            @DescribeParameter(name = "outputWidth", description = "Width of output raster in pixels") Integer argOutputWidth,
            @DescribeParameter(name = "outputHeight", description = "Height of output raster in pixels") Integer argOutputHeight,

            ProgressListener monitor); Query invertQuery(
            @DescribeParameter(name = "radiusPixels", description = "Radius to use for the kernel", min = 0, max = 1) Integer argRadiusPixels,
            // output image parameters
            @DescribeParameter(name = "outputBBOX", description = "Georeferenced bounding box of the output") ReferencedEnvelope argOutputEnv,
            @DescribeParameter(name = "outputWidth", description = "Width of the output raster") Integer argOutputWidth,
            @DescribeParameter(name = "outputHeight", description = "Height of the output raster") Integer argOutputHeight,

            Query targetQuery, GridGeometry targetGridGeometry); static void extractPoints(SimpleFeatureCollection obsPoints, String attrName,
            MathTransform trans, HeatmapSurface heatMap);  }
@Test public void testSimpleSurface() { ReferencedEnvelope bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); Coordinate[] data = new Coordinate[] { new Coordinate(4, 4), new Coordinate(4, 6), new Coordinate(100, 100) }; SimpleFeatureCollection fc = createPoints(data, bounds); ProgressListener monitor = null; HeatmapProcess process = new HeatmapProcess(); GridCoverage2D cov = process.execute(fc, 20, null, 1, bounds, 100, 100, monitor ); float center1 = coverageValue(cov, 4, 4); float center2 = coverageValue(cov, 4, 6); float midway = coverageValue(cov, 4, 5); float far = coverageValue(cov, 9, 9); float peakDiff = Math.abs(center1 - center2); assert(peakDiff < center1 / 10); assertTrue(midway > center1 / 2); assertTrue(far < center1 / 1000); }