public static async Task <GeoReferencedImage> Create(List <ISqlGeometryAware> points, Func <ISqlGeometryAware, double> valueFunc, int width, int height, DiscreteRangeColor ranges, double?maxDistance) { return(await Task.Run <GeoReferencedImage>(() => { var boundingBox = SqlGeometryExtensions.GetBoundingBox(points.Select(p => p.TheSqlGeometry).ToList()); //scale var scaleX = width / boundingBox.Width; var scaleY = height / boundingBox.Height; var scale = Math.Min(scaleX, scaleY); width = (int)(scale *boundingBox.Width); height = (int)(scale *boundingBox.Height); //create empty raster Bitmap result = new Bitmap(width, height); List <Point3D> pointSet = points.Select(p => new Point3D(p.TheSqlGeometry.STX.Value, p.TheSqlGeometry.STY.Value, valueFunc(p))).ToList(); var maxValue = pointSet.Max(p => p.Z); var minValue = pointSet.Min(p => p.Z); var rangeValue = maxValue - minValue; var midValue = rangeValue / 2.0 + minValue; //ContinousRangeColor ranges = new ContinousRangeColor(values, colors); //DiscreteRangeColor ranges = new DiscreteRangeColor(values, colors); var stopwatch = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { var x = boundingBox.XMin + j / scale; var y = boundingBox.YMax - i / scale; var value = IRI.Msh.Common.Analysis.Interpolation.Idw.Calculate(pointSet, new Msh.Common.Primitives.Point(x, y), maxDistance); if (value.HasValue) { try { result.SetPixel(j, i + 0, ranges.Interpolate(value.Value)); } catch (Exception ex) { } } else { //result.SetPixel(j, i, Color.Transparent); } } } stopwatch.Stop(); var ellapsedtime = stopwatch.ElapsedMilliseconds; stopwatch.Restart(); return new GeoReferencedImage(ImageUtility.AsByteArray(result), boundingBox.Transform(IRI.Msh.CoordinateSystem.MapProjection.MapProjects.WebMercatorToGeodeticWgs84)); })); }