Click here to Skip to main content
15,886,110 members
Articles / Web Development / ASP.NET

GHeat .NET

Rate me:
Please Sign up or sign in to vote.
5.00/5 (15 votes)
21 Jun 2010CPOL3 min read 222.9K   5.7K   53  
gheat ported to C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using GMap.NET;

namespace gheat
{
    /// <summary>
    /// Gets a single tile
    /// NOTE: Blank tiles are cached so don't dispose them
    /// </summary>
    public class Tile
    {
        
        private static Dictionary<string, Bitmap> _emptyTile = new Dictionary<string, Bitmap>();
        private static object _emptyTileLocker = new Object();
        private static int[] _zoomOpacity = null;
        private static Tile _thisInstance = new Tile(); 

        private Tile()
        {
            Opacity o = new Opacity();
            _zoomOpacity = o.BuildZoomMapping(); 
        }

        /// <summary>
        /// Generates a tile
        /// 
        /// For blank Tiles:
        /// You must NOT modify the image. Don't Dispose it!!! It is cached, so if you dispose it you have nothing!!
        /// </summary>
        /// <param name="colorScheme">Image Color scheme</param>
        /// <param name="dot">Image dot</param>
        /// <param name="zoom">Current zoom level</param>
        /// <param name="tileX">Tile x coordinante</param>
        /// <param name="tileY">Tile y coordinante</param>
        /// <param name="points">Points to add</param>
        /// <param name="changeOpacityWithZoom">If false the default opacity is used instead of a changing value</param>
        /// <param name="defaultOpacity">Used when change opacity with zoom is false</param>
        /// <returns></returns>
        public static Bitmap Generate(Bitmap colorScheme, Bitmap dot, int zoom,int tileX, int tileY, GMap.NET.Point[] points, bool changeOpacityWithZoom,int defaultOpacity)
        {
            int expandedWidth;
            int expandedHeight;
            int dotHalfSize;
            int pad;

            int x1;
            int x2;
            int y1;
            int y2;

            if(defaultOpacity < Opacity.TRANSPARENT || defaultOpacity > Opacity.OPAQUE)
                throw new Exception("The default opacity of '" + defaultOpacity.ToString() + "' doesn't fall between '" + Opacity.TRANSPARENT.ToString() + "' and '" + Opacity.OPAQUE.ToString() + "'") ;

            //Translate tile to pixel coords.
            x1 = tileX * GHeat.SIZE;
            x2 = x1 + 255;
            y1 = tileY * GHeat.SIZE;
            y2 = y1 + 255;

            dotHalfSize = dot.Width;
            pad = dotHalfSize;
            int extraPad = dot.Width * 2;

            //Expand bounds by one dot width.
            x1 = x1 - extraPad;
            x2 = x2 + extraPad;
            y1 = y1 - extraPad;
            y2 = y2 + extraPad;
            expandedWidth = x2 - x1;
            expandedHeight = y2 - y1;

            Bitmap tile;
            if (points.Length == 0)
            {
                if (changeOpacityWithZoom)
                    tile = GetEmptyTile(colorScheme, _zoomOpacity[zoom]);
                else
                    tile = GetEmptyTile(colorScheme, defaultOpacity);
            }
            else
            {
                tile = GetBlankImage(expandedHeight, expandedWidth);
                tile = AddPoints(tile, dot, points);
                tile = Trim(tile, dot);
                if (changeOpacityWithZoom)
                    tile = Colorize(tile, colorScheme, _zoomOpacity[zoom]);
                else
                    tile = Colorize(tile, colorScheme, defaultOpacity);
            }
            return tile;
        }

        /// <summary>
        /// Takes the gray scale and applies the color scheme to it.
        /// </summary>
        /// <param name="tile"></param>
        /// <returns></returns>
        public static Bitmap Colorize(Bitmap tile, Bitmap colorScheme,int zoomOpacity)
        {
            Color tilePixelColor;
            Color colorSchemePixel;
           
            for(int x=0;x< tile.Width ;x++)
            {
                for (int y = 0; y < tile.Height; y++)
                {
                    //Get color for this intensity
                    tilePixelColor = tile.GetPixel(x, y);

                    //Get the color of the scheme from the intensity on the tile
                    //Only need to get one color in the tile, because it is grayscale, so each color will have the same intensity
                    colorSchemePixel = colorScheme.GetPixel(0, tilePixelColor.R);

                    zoomOpacity = (int)(
                        (
                            ((float)zoomOpacity / 255.0f)
                            *
                            ((float)colorSchemePixel.A / 255.0f)
                        ) * 255f
                        );
                    tile.SetPixel(x, y, Color.FromArgb(zoomOpacity, colorSchemePixel));   
                 }
            }
            return tile;       
        }

        /// <summary>
        /// Trim the larger tile to the correct size
        /// </summary>
        /// <param name="tile"></param>
        /// <returns></returns>
        public static Bitmap Trim(Bitmap tile,Bitmap dot)
        {
            Bitmap croppedTile = new Bitmap(GHeat.SIZE, GHeat.SIZE, PixelFormat.Format32bppArgb);
            Graphics g = Graphics.FromImage(croppedTile);
            int adjPad = dot.Width + (dot.Width / 2);

            g.DrawImage(
                        tile, // Source Image
                        new System.Drawing.Rectangle(0, 0, GHeat.SIZE, GHeat.SIZE),
                        adjPad, // source x, adjusted for padded amount
                        adjPad, // source y, adjusted for padded amount
                        GHeat.SIZE, //source width
                        GHeat.SIZE, // source height
                        GraphicsUnit.Pixel
                        );
            return croppedTile;
        }

        /// <summary>
        /// Add all of the points to the tile
        /// </summary>
        /// <param name="tile"></param>
        /// <param name="points"></param>
        /// <returns></returns>
        public static Bitmap AddPoints(Bitmap tile,Bitmap dot, GMap.NET.Point[] points)
        {
            KVImage.ImageBlender blender = new KVImage.ImageBlender();
            
            for (int i = 0; i < points.Length; i++)
            {
                if (points[i].Weight.HasValue && points[i].Weight.Value == 0)
                {
                    //Skip a value of zero, it scored so low it should not show up.
                }
                else
                {
                    //Blend each dot to the existing images
                    blender.BlendImages(
                                tile, // Destination Image
                                points[i].X + dot.Width, //Dest x
                                points[i].Y + dot.Width, //Dest y
                                dot.Width, // Dest width
                                dot.Height,  // Dest height
                        //If their is a weight then change the dot so it reflects that intensity
                                points[i].Weight.HasValue ? ApplyWeightToImage(dot, points[i].Weight.Value) : dot, // Src Image
                                0, // Src x
                                0, // Src y
                                KVImage.ImageBlender.BlendOperation.Blend_Multiply);
                }
            }
            return tile;
        }

        /// <summary>
        /// Change the intensity of the image
        /// </summary>
        /// <param name="image">Dot image</param>
        /// <param name="weight">Weight to apply</param>
        /// <returns></returns>
        private static Bitmap ApplyWeightToImage(Bitmap image, decimal weight)
        {
            Graphics graphic;
            float tempWeight;
            Bitmap tempImage = new Bitmap(image.Width,image.Height,PixelFormat.Format32bppArgb );

            graphic = Graphics.FromImage(tempImage);

            //I want to make the color more intense (White/bright)
            
            tempWeight = (float)(weight);
            // ColorMatrix elements
            float[][] ptsArray =
                {
                new float[] {tempWeight, 0, 0, 0, 0},
                new float[] {0, tempWeight, 0, 0, 0},
                new float[] {0, 0,tempWeight, 0, 0},
                new float[] {0, 0, 0, 1, 0},
                new float[] {0, 0, 0, 0, 1}
                };


            // Create a ColorMatrix
            ColorMatrix clrMatrix = new ColorMatrix(ptsArray);
            // Create ImageAttributes
            ImageAttributes imgAttribs = new ImageAttributes();
            // Set color matrix
            //imgAttribs.SetColorMatrix(clrMatrix,
            //            //I dont know why, but when i tell it to Skip the Grays the color altering
            //            // works on all computers. Otherwise it does not shade correctly.
            //            ColorMatrixFlag.SkipGrays,
            //            ColorAdjustType.Bitmap);
            //http://www.c-sharpcorner.com/UploadFile/puranindia/610/
            //Gamma values range from 0.1 to 5.0 (normally 0.1 to 2.2), with 0.1 being the brightest and 5.0 the darkest.
            //Convert the 100% to a range of 0-5 by multiplying it by 5
            imgAttribs.SetGamma((tempWeight == 0 ? .1f : (tempWeight * 5)), ColorAdjustType.Bitmap);

            // Draw Image with the attributes
            graphic.DrawImage(image,
                            new System.Drawing.Rectangle(0, 0, image.Width, image.Height),
                            0, 0, image.Width, image.Height,
                            GraphicsUnit.Pixel, imgAttribs);
            
            //New dot with a different intensity
            return tempImage;
        }

        /// <summary>
        /// Gets a blank image / canvas
        /// </summary>
        /// <returns></returns>
        public static Bitmap GetBlankImage(int height, int width)
        {
            Bitmap newImage;
            Graphics g;

            //Create a blank tile that is 32 bit and has an alpha
            newImage = new Bitmap(width, height, PixelFormat.Format32bppArgb);
            g = Graphics.FromImage(newImage);
            //Background must be white so the dots can blend
            g.FillRectangle(Brushes.White, new System.Drawing.Rectangle(0, 0, width, height));
            return newImage;
        }

        /// <summary>
        /// Empty tile with no points on it.
        /// NOTE: You must not modify this image. Don't Dispose it!!!
        /// </summary>
        /// <returns></returns>
        public static Bitmap GetEmptyTile(Bitmap colorScheme,int zoomOpacity)
        {
            Color colorSchemePixelColor;
            Bitmap tile;
            Graphics graphic;
            SolidBrush solidBrush;

            //If we have already created the empty tile then return it
            if (_emptyTile.ContainsKey(colorScheme.GetHashCode().ToString() + "_" + zoomOpacity.ToString() ))
                return _emptyTile[colorScheme.GetHashCode() + "_" + zoomOpacity.ToString()];

            //Create a blank tile that is 32 bit and has an alpha
            tile = new Bitmap(GHeat.SIZE, GHeat.SIZE, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            graphic = Graphics.FromImage(tile);

            //Get the first pixel of the color scheme, on the dark side 
            colorSchemePixelColor = colorScheme.GetPixel(0, colorScheme.Height - 1);

            zoomOpacity = (int)((
                            (zoomOpacity / 255.0f) //# From Configuration
                            *
                            (colorSchemePixelColor.A / 255.0f) //#From per-pixel alpha
                            ) * 255.0f);

            solidBrush = new SolidBrush(Color.FromArgb(zoomOpacity, colorSchemePixelColor.R, colorSchemePixelColor.G, colorSchemePixelColor.B));
            graphic.FillRectangle(solidBrush, 0, 0, GHeat.SIZE, GHeat.SIZE);
            graphic.Dispose();

            //Save the newly created empty tile
            //There is a empty tile for each scheme and zoom level
            lock (_emptyTileLocker)
            { 
                //Double check it does not already exists
                if (!_emptyTile.ContainsKey(colorScheme.GetHashCode().ToString()))
                    _emptyTile.Add(colorScheme.GetHashCode().ToString() , tile);
            }
            return tile;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
Graduate of University of Louisiana at Lafayette in computer science.

Comments and Discussions