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));
            }));
        }