/// <summary>
 /// Creates a new instance of DrawArgs
 /// </summary>
 public MapDrawArgs(Graphics inGraphics, Rectangle clipRectangle, IMapFrame inMapFrame)
 {
     _graphics = inGraphics;
     _geoGraphics = new MapArgs(clipRectangle, inMapFrame.Extents);
    
     _clipRectangle = clipRectangle;
 }
        public void DrawRegions(MapArgs args, List<IEnvelope> regions)
        {
            // To get information on the pixel resolution you can use
            Rectangle mapRegion = args.ImageRectangle;
            // Handle tile management here based on geographic extent and pixel resolution from mapRegion

        }
        // This draws the individual line features
        private void DrawFeatures(MapArgs e, IEnumerable<int> indices)
        {
            Graphics g = e.Device ?? Graphics.FromImage(_backBuffer);

            double minX = e.MinX;
            double maxY = e.MaxY;
            double dx = e.Dx;
            double dy = e.Dy;
            if(!DrawnStatesNeeded)
            {
                if(Symbology == null || Symbology.Categories.Count == 0) return;
                FastDrawnState state = new FastDrawnState(false, Symbology.Categories[0]);
                IPointCategory pc = state.Category as IPointCategory;
                IPointSymbolizer ps = null;
                if(pc != null && pc.Symbolizer !=null) ps = pc.Symbolizer;
                if (ps == null) return;
                g.SmoothingMode = ps.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None;
                double[] vertices = DataSet.Vertex;
                foreach (int index in indices)
                {
                    if(!DrawnStates[index].Visible) continue;
                    if(DataSet.FeatureType == FeatureTypes.Point)
                    {
                        System.Drawing.Point pt = new System.Drawing.Point();
                        pt.X = Convert.ToInt32((vertices[index * 2] - minX) * dx);
                        pt.Y = Convert.ToInt32((maxY - vertices[index * 2 + 1]) * dy);
                        double scaleSize = 1;
                        if (ps.ScaleMode == ScaleModes.Geographic)
                        {
                            scaleSize = e.ImageRectangle.Width / e.GeographicExtents.Width;
                        }
                        Matrix old = g.Transform;
                        Matrix shift = g.Transform;
                        shift.Translate(pt.X, pt.Y);
                        g.Transform = shift;
                        ps.Draw(g, scaleSize);
                        g.Transform = old;
                    }
                    else
                    {
                        // multi-point
                        ShapeRange range = DataSet.ShapeIndices[index];
                        for (int i = range.StartIndex; i <= range.EndIndex(); i++)
                        {
                            System.Drawing.Point pt = new System.Drawing.Point();
                            pt.X = Convert.ToInt32((vertices[i * 2 ] - minX) * dx);
                            pt.Y = Convert.ToInt32((maxY - vertices[i * 2 + 1]) * dy);
                            double scaleSize = 1;
                            if (ps.ScaleMode == ScaleModes.Geographic)
                            {
                                scaleSize = e.ImageRectangle.Width / e.GeographicExtents.Width;
                            }
                            Matrix old = g.Transform;
                            Matrix shift = g.Transform;
                            shift.Translate(pt.X, pt.Y);
                            g.Transform = shift;
                            ps.Draw(g, scaleSize);
                            g.Transform = old;

                        }
                    }
                }
            }
            else
            {
                FastDrawnState[] states = DrawnStates;
                double[] vertices = DataSet.Vertex;
                foreach (IPointCategory category in Symbology.Categories)
                {
                    if (category.Symbolizer == null) continue;
                    
                    double scaleSize = 1;
                    if (category.Symbolizer.ScaleMode == ScaleModes.Geographic)
                    {
                        scaleSize = e.ImageRectangle.Width / e.GeographicExtents.Width;
                    }
                    Size2D size = category.Symbolizer.GetSize();
                    if (size.Width * scaleSize < 1 || size.Height * scaleSize < 1) continue;
                    

                    Bitmap normalSymbol = new Bitmap((int)(size.Width * scaleSize), (int)(size.Height * scaleSize));
                    Graphics bg = Graphics.FromImage(normalSymbol);
                    bg.SmoothingMode = category.Symbolizer.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None;
                    Matrix trans = bg.Transform;
                    trans.Translate((float)size.Width/2, (float)size.Height/2);
                    bg.Transform = trans;
                    category.Symbolizer.Draw(bg, 1);


                    Size2D selSize = category.SelectionSymbolizer.GetSize();
                    if (selSize.Width * scaleSize < 1 || selSize.Height * scaleSize < 1) continue;

                    Bitmap selectedSymbol = new Bitmap((int)(size.Width * scaleSize), (int)(size.Height * scaleSize));
                    Graphics sg = Graphics.FromImage(selectedSymbol);
                    sg.SmoothingMode = category.SelectionSymbolizer.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None;
                    Matrix trans2 = bg.Transform;
                    trans2.Translate((float)size.Width / 2, (float)size.Height / 2);
                    sg.Transform = trans2;
                    category.Symbolizer.Draw(sg, 1);


                    
                    foreach (int index in indices)
                    {
                        
                        FastDrawnState state = states[index];
                        if (!state.Visible) continue;
                        if (state.Category == null) continue;
                        IPointCategory pc = state.Category as IPointCategory;
                        if (pc == null) continue;
                        if (pc != category) continue;
                        Bitmap bmp = normalSymbol;
                        if (state.Selected)
                        {
                            bmp = selectedSymbol;
                        }
                        if (DataSet.FeatureType == FeatureTypes.Point)
                        {
                            System.Drawing.Point pt = new System.Drawing.Point();
                            pt.X = Convert.ToInt32((vertices[index * 2] - minX) * dx);
                            pt.Y = Convert.ToInt32((maxY - vertices[index * 2 + 1]) * dy);
                            
                            Matrix old = g.Transform;
                            Matrix shift = g.Transform;
                            shift.Translate(pt.X, pt.Y);
                            g.Transform = shift;
                            g.DrawImageUnscaled(bmp, -bmp.Width/2,-bmp.Height/2);
                            g.Transform = old;
                        }
                        else
                        {
                            ShapeRange range = DataSet.ShapeIndices[index];
                            for (int i = range.StartIndex; i <= range.EndIndex(); i++)
                            {
                                System.Drawing.Point pt = new System.Drawing.Point();
                                pt.X = Convert.ToInt32((vertices[i*2] - minX)*dx);
                                pt.Y = Convert.ToInt32((maxY - vertices[i*2 + 1])*dy);
                                
                                Matrix old = g.Transform;
                                Matrix shift = g.Transform;
                                shift.Translate(pt.X, pt.Y);
                                g.Transform = shift;
                                g.DrawImageUnscaled(bmp, -bmp.Width / 2, -bmp.Height / 2);
                                g.Transform = old;

                            }
                        }
                    }
                }

                if (e.Device == null) g.Dispose();

            }
            
        }
        /// <summary>
        /// If useChunks is true, then this method
        /// </summary>
        /// <param name="args">The GeoArgs that control how these features should be drawn.</param>
        /// <param name="indices">The features that should be drawn.</param>
        /// <param name="clipRectangles">If an entire chunk is drawn and an update is specified, this clarifies the changed rectangles.</param>
        /// <param name="useChunks">Boolean, if true, this will refresh the buffer in chunks.</param>
        public virtual void DrawFeatures(MapArgs args, List<int> indices, List<Rectangle> clipRectangles, bool useChunks)
        {
            if (useChunks == false)
            {
                DrawFeatures(args, indices);
                return;
            }

            int count = indices.Count;
            int numChunks = (int)Math.Ceiling(count / (double)ChunkSize);

            for (int chunk = 0; chunk < numChunks; chunk++)
            {
                int numFeatures = ChunkSize;
                if (chunk == numChunks - 1) numFeatures = indices.Count - (chunk * ChunkSize);
                DrawFeatures(args, indices.GetRange(chunk * ChunkSize, numFeatures));

                if (numChunks > 0 && chunk < numChunks - 1)
                {
                    // FinishDrawing();
                    OnBufferChanged(clipRectangles);
                    System.Windows.Forms.Application.DoEvents();
                    // this.StartDrawing();
                }
            }
        }
        /// <summary>
        /// Creates a new raster with the specified cell size.  If the cell size
        /// is zero, this will default to the shorter of the width or height
        /// divided by 256.  If the cell size produces a raster that is greater
        /// than 8,000 pixels in either dimension, it will be re-sized to
        /// create an 8,000 length or width raster.
        /// </summary>
        /// <param name="fs">The featureset to convert to a raster</param>
        /// <param name="cellSize">The double extent of the cell.</param>
        /// <param name="fieldName">The integer field index of the file.</param>
        /// <param name="destFilename">The filename of the raster to create</param>
        /// <param name="driverCode">The optional GDAL driver code to use if using GDAL 
        /// for a format that is not discernable from the file extension.  An empty string
        ///  is usually perfectly acceptable here.</param>
        /// <param name="options">For GDAL rasters, they can be created with optional parameters
        ///  passed in as a string array.  In most cases an empty string is perfectly acceptable.</param>
        /// <param name="progressHandler">An interface for handling the progress messages.</param>
        /// <returns>Generates a raster from the vectors.</returns>
        public static IRaster ToRaster(IFeatureSet fs, ref double cellSize, string fieldName, string destFilename, string driverCode, string[] options, IProgressHandler progressHandler)
        {
            IEnvelope env = fs.Envelope;
            if(cellSize == 0)
            {
                if(fs.Envelope.Width < fs.Envelope.Height)
                {
                    cellSize = env.Width/256;
                }
                else
                {
                    cellSize = env.Height/256;
                }
            }
            int w = (int)Math.Ceiling(env.Width/cellSize);
            if (w > 8000)
            {
                w = 8000;
                cellSize = env.Width/8000;
            }
            int h = (int) Math.Ceiling(env.Height/cellSize);
            if (h > 8000)
            {
                cellSize = env.Height/8000;
                h = 8000;
            }
            Bitmap bmp = new Bitmap(w, h);
            Graphics g = Graphics.FromImage(bmp);
            g.Clear(Color.Transparent);
            g.SmoothingMode = SmoothingMode.None;
            g.TextRenderingHint = TextRenderingHint.SingleBitPerPixel;
            g.InterpolationMode = InterpolationMode.NearestNeighbor;
            Hashtable colorTable;
            MapArgs args = new MapArgs(new Rectangle(0, 0, w, h), env, g);

            switch (fs.FeatureType)
            {
                case FeatureTypes.Polygon:
                    {
                        MapPolygonLayer mpl = new MapPolygonLayer(fs);
                        PolygonScheme ps = new PolygonScheme();
                        colorTable = ps.GenerateUniqueColors(fs, fieldName);
                        mpl.Symbology = ps;
                        mpl.DrawRegions(args, new List<IEnvelope> {env});
                    }
                    break;
                case FeatureTypes.Line:
                    {
                        MapLineLayer mpl = new MapLineLayer(fs);
                        LineScheme ps = new LineScheme();
                        colorTable = ps.GenerateUniqueColors(fs, fieldName);
                        mpl.Symbology = ps;
                        mpl.DrawRegions(args, new List<IEnvelope> { env });
                    }
                    break;
                default:
                    {
                        MapPointLayer mpl = new MapPointLayer(fs);
                        PointScheme ps = new PointScheme();
                        colorTable = ps.GenerateUniqueColors(fs, fieldName);
                        mpl.Symbology = ps;
                        mpl.DrawRegions(args, new List<IEnvelope> { env });
                    }
                    break;
            }
            Type tp = fieldName == "FID" ? typeof(int) : fs.DataTable.Columns[fieldName].DataType;
           
            if (tp == typeof(string)) tp = typeof (double); // We will try to convert to double if it is a string
            Raster output = new Raster();
            MWImageData image = new MWImageData(bmp, env);
            ProgressMeter pm = new ProgressMeter(progressHandler, "Converting To Raster Cells", h);
            
            output.CreateNew(destFilename, driverCode, w, h, 1, tp, options);
            output.Bounds = new RasterBounds(h, w, env);
            List<RcIndex> locations = new List<RcIndex>();
            List<string> failureList = new List<string>();
            for (int row = 0; row < h; row++)
            {
                for (int col = 0; col < w; col++)
                {
                    Color c = image.GetColor(row, col);
                    if (c.A == 0)
                    {
                        output.Value[row, col] = output.NoDataValue;
                    }
                    else
                    {
                        if (colorTable.ContainsKey(c) == false)
                        {
                            if (c.A < 125)
                            {
                                output.Value[row, col] = output.NoDataValue;
                                continue;
                            }
                            // Use a color matching distance to pick the closest member
                            object val = GetCellValue(w, h, row, col, image, c, colorTable, locations);

                            output.Value[row, col] = GetDouble(val, failureList);
                        }
                        else
                        {
                            
                            output.Value[row, col] = GetDouble(colorTable[c], failureList);
                        }

                    }


                }
                pm.CurrentValue = row;
            }
            const int maxIterations = 5;
            int iteration = 0;
            while(locations.Count > 0)
            {
                List<RcIndex> newLocations = new List<RcIndex>();
                foreach (RcIndex location in locations)
                {
                    object val = GetCellValue(w, h, location.Row, location.Column, image, image.GetColor(location.Row, location.Column), colorTable, newLocations);
                    output.Value[location.Row, location.Column] = GetDouble(val, failureList);
                }
                locations = newLocations;
                iteration++;
                if(iteration > maxIterations) break;
            }

            pm.Reset();
            return output;
        }
 /// <summary>
 /// This will draw any features that intersect this region.  To specify the features
 /// directly, use OnDrawFeatures.  This will not clear existing buffer content.
 /// For that call Initialize instead.
 /// </summary>
 /// <param name="args">A GeoArgs clarifying the transformation from geographic to image space</param>
 /// <param name="regions">The geographic regions to draw</param>
 /// <returns>The list of rectangular areas that match the specified regions</returns>
 public void DrawRegions(MapArgs args, List<IEnvelope> regions)
 {
     List<Rectangle> clipRects = args.ProjToPixel(regions);
     DrawWindows(args, regions, clipRects);
 }
        private static RectangleF PlaceLineLabel(IBasicGeometry lineString, SizeF labelSize, MapArgs e, ILabelSymbolizer symb)
        {
            ILineString ls = Geometry.FromBasicGeometry(lineString) as ILineString;
            if (ls == null) return RectangleF.Empty;
            Coordinate c;
            if (symb.LabelMethod == LabelMethod.Centroid)
                c = ls.Centroid.Coordinate;
            else if (symb.LabelMethod == LabelMethod.InteriorPoint)
                c = ls.InteriorPoint.Coordinate;
            else
                c = ls.Envelope.Center();

            PointF adjustment = Position(symb, labelSize);
            float x = Convert.ToSingle((c.X - e.MinX)*e.Dx) + adjustment.X;
            float y = Convert.ToSingle((e.MaxY - c.Y)*e.Dy) + adjustment.Y;
            return new RectangleF(x, y, labelSize.Width, labelSize.Height);
        }
 private static RectangleF PlacePointLabel(IBasicGeometry f, MapArgs e, SizeF labelSize, ILabelSymbolizer symb)
 {
     Coordinate c = f.GetBasicGeometryN(1).Coordinates[0];
     if (e.GeographicExtents.Contains(c) == false) return RectangleF.Empty;
     PointF adjustment = Position(symb, labelSize);
     float x = Convert.ToSingle((c.X - e.MinX) * e.Dx) + adjustment.X;
     float y = Convert.ToSingle((e.MaxY - c.Y) * e.Dy) + adjustment.Y;
     return new RectangleF(x, y, labelSize.Width, labelSize.Height);
 }
 private void BuildPaths(MapArgs e, IEnumerable<int> indices, out List<GraphicsPath> paths)
 {
     paths = new List<GraphicsPath>();     
     Extent drawExtents = new Extent(e.PixelToProj(_drawingBounds));
     Dictionary<FastDrawnState, GraphicsPath> borders = new Dictionary<FastDrawnState, GraphicsPath>();
     for (int selectState = 0; selectState < 2; selectState++)
     {
         foreach (IPolygonCategory category in Symbology.Categories)
         {
             FastDrawnState state = new FastDrawnState(selectState == 1, category);
             
             GraphicsPath border = new GraphicsPath();
             borders.Add(state, border);
             paths.Add(border);
         }
     }
     List<ShapeRange> shapes = DataSet.ShapeIndices;
     double[] vertices = DataSet.Vertex;
     if(!DrawnStatesNeeded)
     {
         FastDrawnState state = new FastDrawnState(false, Symbology.Categories[0]);
         foreach (int shp in indices)
         {
             ShapeRange shape = shapes[shp];
             if (!shape.Extent.Intersects(e.GeographicExtents)) continue;
             if(shp >= shapes.Count) continue;
             if (!borders.ContainsKey(state)) continue;
             if (drawExtents.Contains(shape.Extent))
             {
                 BuildPolygon(vertices, shapes[shp], borders[state], e, false);
             }
             else
             {
                 BuildPolygon(vertices, shapes[shp], borders[state], e, true);
             }
         }
     }
     else
     {
         FastDrawnState[] states = DrawnStates;
         foreach (int shp in indices)
         {
             if (shp >= shapes.Count) continue;
             if (shp >= states.Length)
             {
                 AssignFastDrawnStates();
                 states = DrawnStates;
             }
             if (states[shp].Visible == false) continue;
             ShapeRange shape = shapes[shp];
             if (!shape.Extent.Intersects(e.GeographicExtents)) continue;
             if (drawExtents.Contains(shape.Extent))
             {
                 FastDrawnState state = states[shp];
                 if (!borders.ContainsKey(state)) continue;
                 BuildPolygon(vertices, shapes[shp], borders[state], e, false);
             }
             else
             {
                 FastDrawnState state = states[shp];
                 if (!borders.ContainsKey(state)) continue;
                 BuildPolygon(vertices, shapes[shp], borders[state], e, true);
             }
             
         }
        
     }
     
 }
        /// <summary>
        /// Draws the GraphicsPaths.  Before we were effectively "re-creating" the same geometric
        /// </summary>
        /// <param name="e"></param>
        /// <param name="paths"></param>
        private void DrawPaths(MapArgs e, IList<GraphicsPath> paths)
        {
            Graphics g = e.Device ?? Graphics.FromImage(_backBuffer);
            int numCategories = Symbology.Categories.Count;
            
            if(!DrawnStatesNeeded && !EditMode)
            {
                IPolygonSymbolizer ps = Symbolizer;
                g.SmoothingMode = ps.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None;
                Extent catBounds = new Extent(DataSet.Envelope);
                RectangleF bounds = new RectangleF();
                bounds.X = Convert.ToSingle((catBounds.XMin - e.MinX) * e.Dx);
                bounds.Y = Convert.ToSingle((e.MaxY - catBounds.YMax) * e.Dy);
                float r = Convert.ToSingle((catBounds.XMax - e.MinX) * e.Dx);
                bounds.Width = r - bounds.X;
                float b = Convert.ToSingle((e.MaxY - catBounds.YMin) * e.Dy);
                bounds.Height = b - bounds.Y;

                foreach (IPattern pattern in ps.Patterns)
                {
                    IGradientPattern gp = pattern as IGradientPattern;
                    if (gp != null)
                    {
                        gp.Bounds = bounds;
                    }

                    pattern.FillPath(g, paths[0]);
                }

                double scale = 1;
                if (ps.ScaleMode == ScaleModes.Geographic)
                {
                    scale = e.ImageRectangle.Width / e.GeographicExtents.Width;
                }
                foreach (IPattern pattern in ps.Patterns)
                {
                    if (pattern.UseOutline)
                    {
                        pattern.DrawPath(g, paths[0], scale);
                    }
                }
            }
            else
            {
                for (int selectState = 0; selectState < 2; selectState++)
                {
                    int iCategory = 0;
                    foreach (IPolygonCategory category in Symbology.Categories)
                    {
                        Extent catBounds;
                        if (CategoryExtents.Keys.Contains(category))
                        {
                            catBounds = CategoryExtents[category];
                        }
                        else
                        {
                            catBounds = CalculateCategoryExtent(category);
                        }
                        if (catBounds == null) catBounds = new Extent(Envelope);
                        RectangleF bounds = new RectangleF();
                        bounds.X = Convert.ToSingle((catBounds.XMin - e.MinX) * e.Dx);
                        bounds.Y = Convert.ToSingle((e.MaxY - catBounds.YMax) * e.Dy);
                        float r = Convert.ToSingle((catBounds.XMax - e.MinX) * e.Dx);
                        bounds.Width = r - bounds.X;
                        float b = Convert.ToSingle((e.MaxY - catBounds.YMin) * e.Dy);
                        bounds.Height = b - bounds.Y;

                        int index = selectState * numCategories + iCategory;
                        // Define the symbology based on the category and selection state
                        IPolygonSymbolizer ps = category.Symbolizer;
                        if (selectState == SELECTED) ps = category.SelectionSymbolizer;

                        g.SmoothingMode = ps.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None;

                        foreach (IPattern pattern in ps.Patterns)
                        {
                            IGradientPattern gp = pattern as IGradientPattern;
                            if (gp != null)
                            {
                                gp.Bounds = bounds;
                            }
                            paths[index].FillMode = FillMode.Winding;
                            pattern.FillPath(g, paths[index]);
                        }

                        double scale = 1;
                        if (ps.ScaleMode == ScaleModes.Geographic)
                        {
                            scale = e.ImageRectangle.Width / e.GeographicExtents.Width;
                        }
                        foreach (IPattern pattern in ps.Patterns)
                        {
                            if (pattern.UseOutline)
                            {
                                pattern.DrawPath(g, paths[index], scale);
                            }
                        }
                        iCategory++;
                    } // category
                } // selectState
            }

            for (int i = 0; i < Symbology.Categories.Count; i++)
            {
                paths[i].Dispose();
            }
            if(e.Device == null) g.Dispose();
        
        }
 // This draws the individual line features
 private void DrawFeatures(MapArgs e, IEnumerable<int> indices)
 {
     if (DataSet.ShapeIndices == null) return;
     List<GraphicsPath> paths;
     // First, use the coordinates to build the drawing paths
     BuildPaths(e, indices, out paths);
     // Next draw all the paths using the various category symbols.
     DrawPaths(e, paths);
     foreach (GraphicsPath path in paths)
     {
         path.Dispose();
     }
    
 }
        // This draws the individual line features
        private void DrawFeatures(MapArgs e, IEnumerable<IFeature> features)
        {

            List<GraphicsPath> paths;
            Stopwatch sw = new Stopwatch();
            sw.Start();
            // First, use the coordinates to build the drawing paths
            BuildPaths(e, features, out paths);
            // Next draw all the paths using the various category symbols.
            DrawPaths(e, paths);
            sw.Stop();
            Debug.WriteLine("Drawing time: " + sw.ElapsedMilliseconds);
           
            foreach (GraphicsPath path in paths)
            {
                path.Dispose();
            }
        }
        /// <summary>
        /// This will draw any features that intersect this region.  To specify the features
        /// directly, use OnDrawFeatures.  This will not clear existing buffer content.
        /// For that call Initialize instead.
        /// </summary>
        /// <param name="args">A GeoArgs clarifying the transformation from geographic to image space</param>
        /// <param name="regions">The geographic regions to draw</param>
        /// <returns>The list of rectangular areas that match the specified regions</returns>
        public void DrawRegions(MapArgs args, List<IEnvelope> regions)
        {
            List<Rectangle> clipRects = args.ProjToPixel(regions);
            if (EditMode)
            {
                List<IFeature> drawList = new List<IFeature>();
                foreach (IEnvelope region in regions)
                {
                    if (region != null)
                    {
                        // Use union to prevent duplicates.  No sense in drawing more than we have to.
                        drawList = drawList.Union(DataSet.Select(region)).ToList();
                    }
                }
                DrawFeatures(args, drawList, clipRects, true);
            }
            else
            {
                List<int> drawList = new List<int>();
                List<ShapeRange> shapes = DataSet.ShapeIndices;
                for (int shp = 0; shp < shapes.Count; shp++)
                {

                    foreach (IEnvelope region in regions)
                    {
                        if (!shapes[shp].Extent.Intersects(region)) continue;
                        drawList.Add(shp);
                        break;
                    }
                }
                DrawFeatures(args, drawList, clipRects, true);
            }
        }
Example #14
0
 /// <summary>
 /// Creates a new instance of GeoDrawArgs
 /// </summary>
 /// <param name="inGraphics"></param>
 /// <param name="clipRectangle"></param>
 /// <param name="inGeoGraphics"></param>
 public MapDrawArgs(Graphics inGraphics, Rectangle clipRectangle, MapArgs inGeoGraphics)
 {
     _graphics = inGraphics;
     _clipRectangle = clipRectangle;
 }
 private static RectangleF PlacePolygonLabel(IBasicGeometry geom, MapArgs e, SizeF labelSize, ILabelSymbolizer symb)
 {
     
     IPolygon pg = Geometry.FromBasicGeometry(geom) as IPolygon;
     if (pg == null) return RectangleF.Empty;
     Coordinate c;
     switch (symb.LabelMethod)
     {
         case LabelMethod.Centroid:
             c = pg.Centroid.Coordinates[0];
             break;
         case LabelMethod.InteriorPoint:
             c = pg.InteriorPoint.Coordinate;
             break;
         default:
             c = geom.Envelope.Center();
             break;
     }
     if (e.GeographicExtents.Contains(c) == false) return RectangleF.Empty;
     PointF adjustment = Position(symb, labelSize);
     float x = Convert.ToSingle((c.X - e.MinX) * e.Dx) + adjustment.X;
     float y = Convert.ToSingle((e.MaxY - c.Y) * e.Dy) + adjustment.Y;
     RectangleF result = new RectangleF(x, y, labelSize.Width, labelSize.Height);
     return result;
 }
        private void BuildPaths(MapArgs e, IEnumerable<IFeature> features, out List<GraphicsPath> borderPaths)
        {
            borderPaths = new List<GraphicsPath>();
            IEnvelope drawExtents = e.PixelToProj(_drawingBounds);
            for (int selectState = 0; selectState < 2; selectState++)
            {
                foreach (IPolygonCategory category in Symbology.Categories)
                {

                    // Determine the subset of the specified features that are visible and match the category
                    IPolygonCategory polygonCategory = category;
                    int i = selectState;
                    Func<IDrawnState, bool> isMember = state =>
                        state.SchemeCategory == polygonCategory &&
                        state.IsVisible &&
                        state.IsSelected == (i == 1);

                    var drawnFeatures = from feature in features
                                        where isMember(DrawingFilter[feature])
                                        select feature;

                    GraphicsPath borderPath = new GraphicsPath();
                    foreach (IFeature f in drawnFeatures)
                    {

                        if (drawExtents.Contains(f.Envelope))
                        {
                            // This optimization only works if we are zoomed out far enough
                            // that the whole linestring fits in the short integer
                            // drawing window.  Otherwise, we need to crop the line.
                            // FastBuildLine(graphPath, f, minX, maxY, dx, dy);
                            BuildPolygon(DataSet.Vertex, f.ShapeIndex, borderPath, e, false);
                        }
                        else
                        {
                            BuildPolygon(DataSet.Vertex, f.ShapeIndex, borderPath, e, true);
                        }
                    }
                    borderPaths.Add(borderPath);
                }
            }
        }
        private static void DrawPointFeature(MapArgs e, Graphics g, IFeature f, ILabelCategory category, bool selected, List<RectangleF> existingLabels)
        {
            ILabelSymbolizer symb = category.Symbolizer;
            if (selected) symb = category.SelectionSymbolizer;

            //Gets the features text and calculate the label size
            string txt = GetLabelText(f, category);
            if (txt == null) return;
            SizeF labelSize = g.MeasureString(txt, symb.GetFont());

            //Depending on the labeling strategy we do diff things
            if (symb.LabelParts == LabelParts.LabelAllParts)
            {
                for (int n = 0; n < f.NumGeometries; n++)
                {
                    RectangleF labelBounds = PlacePointLabel(f, e, labelSize, symb);
                    CollisionDraw(txt, g, symb, e, labelBounds, existingLabels);
                }
            }
            else
            {
                RectangleF labelBounds = PlacePointLabel(f, e, labelSize, symb);
                CollisionDraw(txt, g, symb, e, labelBounds, existingLabels);
                    
            }
        }
        /// <summary>
        /// Appends the specified polygon to the graphics path.
        /// </summary>
        private static void BuildPolygon(double[] vertices, ShapeRange shpx, GraphicsPath borderPath, MapArgs args, bool clip)
        {
            double minX = args.MinX;
            double maxY = args.MaxY;
            double dx = args.Dx;
            double dy = args.Dy;
            borderPath.FillMode = FillMode.Winding;
            for (int prt = 0; prt < shpx.Parts.Count; prt++)
            {
                PartRange prtx = shpx.Parts[prt];
                int start = prtx.StartIndex;
                int end = prtx.EndIndex;
                List<double[]> points = new List<double[]>();
               
                for (int i = start; i <= end; i++)
                {
                    double[] pt = new double[2];
                    pt[X] = (vertices[i * 2] - minX) * dx;
                    pt[Y] = (maxY - vertices[i*2+1]) * dy;
                    points.Add(pt);
                }
                if (clip)
                {
                    points = SoutherlandHodgman.Clip(points);
                }
                List<System.Drawing.Point> intPoints = DuplicationPreventer.Clean(points);
                if (intPoints.Count < 2)
                {
                    points.Clear();
                    continue;
                }
                borderPath.StartFigure();
                System.Drawing.Point[] pointArray = intPoints.ToArray();
                borderPath.AddLines(pointArray);
                
                points.Clear();

                
            }


        }
        private static void DrawLineFeature(MapArgs e, Graphics g, IFeature f, ILabelCategory category, bool selected, List<RectangleF> existingLabels)
        {
            ILabelSymbolizer symb = category.Symbolizer;
            if (selected) symb = category.SelectionSymbolizer;

            //Gets the features text and calculate the label size
            string txt = GetLabelText(f, category);
            if (txt == null) return;
            SizeF labelSize = g.MeasureString(txt, symb.GetFont());

            if(f.NumGeometries == 1)
            {
                RectangleF labelBounds = PlaceLineLabel(f.BasicGeometry, labelSize, e, symb);
                CollisionDraw(txt, g, symb, e, labelBounds, existingLabels);
                
            }
            else
            {
                //Depending on the labeling strategy we do diff things
                if (symb.LabelParts == LabelParts.LabelAllParts)
                {
                    for (int n = 0; n < f.NumGeometries; n++)
                    {
                        RectangleF labelBounds = PlaceLineLabel(f.GetBasicGeometryN(n), labelSize, e, symb);
                        CollisionDraw(txt, g, symb, e, labelBounds, existingLabels);
                        
                    }
                }
                else
                {
                    double longestLine = 0;
                    int longestIndex = 0;
                    for (int n = 0; n < f.NumGeometries; n++)
                    {
                        ILineString ls = f.GetBasicGeometryN(n) as ILineString;
                        double tempLength = 0;
                        if (ls != null) tempLength = ls.Length;
                        if (longestLine < tempLength)
                        {
                            longestLine = tempLength;
                            longestIndex = n;
                        }
                    }
                    RectangleF labelBounds = PlaceLineLabel(f.GetBasicGeometryN(longestIndex), labelSize, e, symb);
                    CollisionDraw(txt, g, symb, e, labelBounds, existingLabels);

                }
            }

            

        }
 /// <summary>
 /// This will draw any features that intersect this region.  To specify the features
 /// directly, use OnDrawFeatures.  This will not clear existing buffer content.
 /// For that call Initialize instead.
 /// </summary>
 /// <param name="args">A GeoArgs clarifying the transformation from geographic to image space</param>
 /// <param name="regions">The geographic regions to draw</param>
 public void DrawRegions(MapArgs args, List<IEnvelope> regions)
 {
     if (FeatureSet == null) return;
     if(FeatureSet.IndexMode)
     {
         // First determine the number of features we are talking about based on region.
         List<int> drawIndices = new List<int>();
         foreach (IEnvelope region in regions)
         {
             if (region != null)
             {
                 // We need to consider labels that go off the screen.  figure a region
                 // that is larger.
                 IEnvelope sur = new Envelope(region.Copy());
                 sur.ExpandBy(region.Width, region.Height);
                 Extent r = new Extent(sur);
                 // Use union to prevent duplicates.  No sense in drawing more than we have to.
                 drawIndices = drawIndices.Union(FeatureSet.SelectIndices(r)).ToList();
             }
         }
         List<Rectangle> clips = args.ProjToPixel(regions);
         DrawFeatures(args, drawIndices, clips, true);
     }
     else
     {
         // First determine the number of features we are talking about based on region.
         List<IFeature> drawList = new List<IFeature>();
         foreach (IEnvelope region in regions)
         {
             if (region != null)
             {
                 // We need to consider labels that go off the screen.  figure a region
                 // that is larger.
                 IEnvelope r = region.Copy();
                 r.ExpandBy(region.Width, region.Height);
                 // Use union to prevent duplicates.  No sense in drawing more than we have to.
                 drawList = drawList.Union(FeatureSet.Select(r)).ToList();
             }
         }
         List<Rectangle> clipRects = args.ProjToPixel(regions);
         DrawFeatures(args, drawList, clipRects, true);
     }
     
 }
        // This draws the individual line features
        private void DrawFeatures(MapArgs e, IEnumerable<IFeature> features)
        {
            Graphics g;
            if (e.Device != null)
            {
                g = e.Device; // A device on the MapArgs is optional, but overrides the normal buffering behaviors.
            }
            else
            {
                g = Graphics.FromImage(_backBuffer);
            }
            // Only draw features that are currently visible.
            IEnvelope drawExtents = e.PixelToProj(_drawingBounds);

            double minX = e.MinX;
            double maxY = e.MaxY;
            double dx = e.Dx;
            double dy = e.Dy;


            for (int selectState = 0; selectState < 2; selectState++)
            {
                foreach (ILineCategory category in Symbology.Categories)
                {
                    // Define the symbology based on the category and selection state
                    ILineSymbolizer ls = category.Symbolizer;
                    if (selectState == SELECTED) ls = category.SelectionSymbolizer;
                    if (ls.Smoothing)
                    {
                        g.SmoothingMode = SmoothingMode.AntiAlias;
                    }
                    else
                    {
                        g.SmoothingMode = SmoothingMode.None;
                    }
 

                    // Determine the subset of the specified features that are visible and match the category
                    ILineCategory lineCategory = category;
                    int i = selectState;
                    Func<IDrawnState, bool> isMember = state =>
                        state.SchemeCategory == lineCategory &&
                        state.IsVisible &&
                        state.IsSelected == (i == 1);

                    var drawnFeatures = from feature in features
                                        where isMember(DrawingFilter[feature])
                                        select feature;


                    GraphicsPath graphPath = new GraphicsPath();
                    foreach (IFeature f in drawnFeatures)
                    {

                        if (drawExtents.Contains(f.Envelope))
                        {
                            // This optimization only works if we are zoomed out far enough
                            // that the whole linestring fits in the short integer
                            // drawing window.  Otherwise, we need to crop the line.
                            FastBuildLine(graphPath, DataSet.Vertex, f.ShapeIndex, minX, maxY, dx, dy);
                        }
                        else
                        {
                            for (int iPart = 0; iPart < f.NumGeometries; iPart++)
                            {
                                IBasicGeometry geom = f.GetBasicGeometryN(iPart);
                                if (drawExtents.Contains(f.Envelope) == false)
                                {
                                    geom = e.GeographicExtents.Intersection(geom);
                                }
                                // Cropped geometries can be either linestrings or multi-linestrings
                                IBasicLineString bls = geom as IBasicLineString;
                                if (bls != null)
                                {
                                    // the result is definitely in the linestring category
                                    BuildLineString(graphPath, bls, minX, maxY, dx, dy);
                                }
                                else
                                {
                                    IMultiLineString intersect = geom as MultiLineString;
                                    if (intersect == null) continue;
                                    for (int iLine = 0; iLine < intersect.NumGeometries; iLine++)
                                    {
                                        BuildLineString(graphPath, intersect.GetBasicGeometryN(iLine) as IBasicLineString, minX, maxY, dx, dy);
                                    }
                                }
                            }
                        }
                    }
                    double scale = 1;
                    if (ls.ScaleMode == ScaleModes.Geographic)
                    {
                        scale = e.ImageRectangle.Width / e.GeographicExtents.Width;
                    }

                    foreach (IStroke stroke in ls.Strokes)
                    {  
                        
                        stroke.DrawPath(g, graphPath, scale);
                    }
                    
                    graphPath.Dispose();

                }
            }
            if (e.Device == null) g.Dispose();
        }
        // This draws the individual line features
        private void DrawFeatures(MapArgs e, IEnumerable<int> features)
        {
            Graphics g = e.Device ?? Graphics.FromImage(_backBuffer);

            // Only draw features that are currently visible.

            if (FastDrawnStates == null)
            {
                CreateIndexedLabels();
            }
            FastLabelDrawnState[] drawStates = FastDrawnStates;
            if (drawStates == null) return;
            //Sets the graphics objects smoothing modes
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            FeatureTypes type = FeatureSet.FeatureType;
            foreach (ILabelCategory category in Symbology.Categories)
            {
                List<int> catFeatures = new List<int>();
                foreach (int fid in features)
                {
                    if(drawStates[fid] == null || drawStates[fid].Category == null)  continue;
                    if (drawStates[fid].Category == category)
                    {
                        catFeatures.Add(fid);
                    }
                    
                }
                // Now that we are restricted to a certain category, we can look at
                // priority
                if (category.Symbolizer.PriorityField != "FID")
                {
                    Feature.ComparisonField = category.Symbolizer.PriorityField;
                    catFeatures.Sort();
                    // When preventing collisions, we want to do high priority first.
                    // otherwise, do high priority last.
                    if (category.Symbolizer.PreventCollisions)
                    {
                        if (!category.Symbolizer.PrioritizeLowValues)
                        {
                            catFeatures.Reverse();
                        }
                    }
                    else
                    {
                        if (category.Symbolizer.PrioritizeLowValues)
                        {
                            catFeatures.Reverse();
                        }
                    }

                }
                foreach (int fid in catFeatures)
                {
                    IFeature feature = FeatureSet.GetFeature(fid);
                    switch (type)
                    {
                        case FeatureTypes.Polygon:
                            DrawPolygonFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels);
                            break;
                        case FeatureTypes.Line:
                            DrawLineFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels);
                            break;
                        case FeatureTypes.Point:
                            DrawPointFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels);
                            break;

                    }

                }
            }


            if (e.Device == null) g.Dispose();
        }
        /// <summary>
        /// This draws to the back buffer.  If the Backbuffer doesn't exist, this will create one.
        /// This will not flip the back buffer to the front.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="regions"></param>
        /// <param name="clipRectangles"></param>
        private void DrawWindows(MapArgs args, IList<IEnvelope> regions, IList<Rectangle> clipRectangles)
        {
            
            Graphics g;
            if (args.Device != null)
            {
                g = args.Device; // A device on the MapArgs is optional, but overrides the normal buffering behaviors.
            }
            else
            {
                if (_backBuffer == null) _backBuffer = new Bitmap(_bufferRectangle.Width, _bufferRectangle.Height);
                g = Graphics.FromImage(_backBuffer);
            }

            int numBounds = Math.Min(regions.Count, clipRectangles.Count);

            for (int i = 0; i < numBounds; i++)
            {
                Bitmap bmp = _baseImage.GetBitmap(regions[i], clipRectangles[i]);
                if(bmp != null)g.DrawImage(bmp, clipRectangles[i]);
            }
            if (args.Device == null) g.Dispose();
        }
        // This draws the individual line features
        private void DrawFeatures(MapArgs e, IEnumerable<IFeature> features)
        {
            Graphics g = e.Device ?? Graphics.FromImage(_backBuffer);
            
            // Only draw features that are currently visible.

            if (DrawnStates == null || !DrawnStates.ContainsKey(features.First()))
            {
                CreateLabels();
            }
            Dictionary<IFeature, LabelDrawState> drawStates = DrawnStates;
            if (drawStates == null) return;
            //Sets the graphics objects smoothing modes
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            FeatureTypes type = features.First().FeatureType;
            foreach (ILabelCategory category in Symbology.Categories)
            {
                var cat = category; // prevent access to unmodified closure problems
                //List<IFeature> catFeatures = (from feature in features
                //                              where drawStates.ContainsKey(feature) && drawStates[feature].Category == cat
                //                             select feature).ToList();
                List<IFeature> catFeatures = new List<IFeature>();
                foreach(IFeature f in features)
                {
                    if(drawStates.ContainsKey(f))
                    {
                        if(drawStates[f].Category == cat)
                        {
                            catFeatures.Add(f);
                        }
                    }
                }
                // Now that we are restricted to a certain category, we can look at
                // priority
                if(category.Symbolizer.PriorityField != "FID")
                {
                    Feature.ComparisonField = cat.Symbolizer.PriorityField;
                    catFeatures.Sort();
                    // When preventing collisions, we want to do high priority first.
                    // otherwise, do high priority last.
                    if(cat.Symbolizer.PreventCollisions)
                    {
                        if (!cat.Symbolizer.PrioritizeLowValues)
                        {
                            catFeatures.Reverse();
                        }
                    }
                    else
                    {
                        if (cat.Symbolizer.PrioritizeLowValues)
                        {
                            catFeatures.Reverse();
                        }
                    }
                    
                }
                foreach (IFeature feature in catFeatures)
                {
                    switch (type)
                    {
                        case FeatureTypes.Polygon:
                            DrawPolygonFeature(e, g, feature, drawStates[feature].Category, drawStates[feature].Selected, ExistingLabels);
                            break;
                        case FeatureTypes.Line:
                            DrawLineFeature(e, g, feature, drawStates[feature].Category, drawStates[feature].Selected, ExistingLabels);
                            break;
                        case FeatureTypes.Point:
                            DrawPointFeature(e, g, feature, drawStates[feature].Category, drawStates[feature].Selected, ExistingLabels);
                            break;

                    }

                }
            }
            
           
            if (e.Device == null) g.Dispose();
        }
        /// <summary>
        /// If useChunks is true, then this method
        /// </summary>
        /// <param name="args">The GeoArgs that control how these features should be drawn.</param>
        /// <param name="features">The features that should be drawn.</param>
        /// <param name="clipRectangles">If an entire chunk is drawn and an update is specified, this clarifies the changed rectangles.</param>
        /// <param name="useChunks">Boolean, if true, this will refresh the buffer in chunks.</param>
        public virtual void DrawFeatures(MapArgs args, List<IFeature> features, List<Rectangle> clipRectangles, bool useChunks)
        {
            if (useChunks == false || features.Count < ChunkSize)
            {
                DrawFeatures(args, features);
                return;
            }

            int count = features.Count;
            int numChunks = (int)Math.Ceiling(count / (double)ChunkSize);
            for (int chunk = 0; chunk < numChunks; chunk++)
            {
                int groupSize = ChunkSize;
                if(chunk == numChunks-1) groupSize = count - chunk*ChunkSize;
                List<IFeature> subset = features.GetRange(chunk*ChunkSize, groupSize);
                DrawFeatures(args, subset);
                if (numChunks <= 0 || chunk >= numChunks - 1) continue;
                FinishDrawing();
                OnBufferChanged(clipRectangles);
                System.Windows.Forms.Application.DoEvents();
            }
        }
        /// <summary>
        /// Draws a label on a polygon with various different methods
        /// </summary>
        /// <param name="e"></param>
        /// <param name="g"></param>
        /// <param name="f"></param>
        /// <param name="category"></param>
        /// <param name="selected"></param>
        /// <param name="existingLabels"></param>
        private static void DrawPolygonFeature(MapArgs e, Graphics g, IFeature f, ILabelCategory category, bool selected, List<RectangleF> existingLabels)
        {
            ILabelSymbolizer symb = category.Symbolizer;
            if (selected) symb = category.SelectionSymbolizer;

            //Gets the features text and calculate the label size
            string txt = GetLabelText(f, category);
            if (txt == null) return;
            SizeF labelSize = g.MeasureString(txt, symb.GetFont());

            if(f.NumGeometries == 1)
            {
                RectangleF labelBounds = PlacePolygonLabel(f.BasicGeometry, e, labelSize, symb);
                CollisionDraw(txt, g, symb, e, labelBounds, existingLabels);
            }
            else
            {
                if (symb.LabelParts == LabelParts.LabelAllParts)
                {
                    for (int n = 0; n < f.NumGeometries; n++)
                    {
                        RectangleF labelBounds = PlacePolygonLabel(f.GetBasicGeometryN(n), e, labelSize, symb);
                        CollisionDraw(txt, g, symb, e, labelBounds, existingLabels);
                    }
                }
                else
                {
                    double largestArea = 0;
                    IPolygon largest = null;
                    for (int n = 0; n < f.NumGeometries; n++)
                    {
                        IPolygon pg = Geometry.FromBasicGeometry(f.GetBasicGeometryN(n)) as IPolygon;
                        if (pg == null) continue;
                        double tempArea = pg.Area;
                        if (largestArea < tempArea)
                        {
                            largestArea = tempArea;
                            largest = pg;
                        }
                    }
                    RectangleF labelBounds = PlacePolygonLabel(largest, e, labelSize, symb);
                    CollisionDraw(txt, g, symb, e, labelBounds, existingLabels);
                }
            }

            //Depending on the labeling strategy we do diff things
            
        }
        /// <summary>
        /// This will draw any features that intersect this region.  To specify the features
        /// directly, use OnDrawFeatures.  This will not clear existing buffer content.
        /// For that call Initialize instead.
        /// </summary>
        /// <param name="args">A GeoArgs clarifying the transformation from geographic to image space</param>
        /// <param name="regions">The geographic regions to draw</param>
        /// <returns>The list of rectangular areas that match the specified regions</returns>
        public void DrawRegions(MapArgs args, List<IEnvelope> regions)
        {
            // First determine the number of features we are talking about based on region.
            List<Rectangle> clipRects = args.ProjToPixel(regions);
            if (EditMode)
            {
                List<IFeature> drawList = new List<IFeature>();
                foreach (IEnvelope region in regions)
                {
                    if (region != null)
                    {
                        // Use union to prevent duplicates.  No sense in drawing more than we have to.
                        drawList = drawList.Union(DataSet.Select(region)).ToList();
                    }
                }
                DrawFeatures(args, drawList, clipRects, true);
            }
            else
            {
                List<int> drawList = new List<int>();
                List<Extent> extents = new List<Extent>();
                double[] verts = DataSet.Vertex;
                foreach (IEnvelope envelope in regions)
                {
                    extents.Add(new Extent(envelope));
                }
                if (DataSet.FeatureType == FeatureTypes.Point)
                {
                    for(int shp = 0; shp < verts.Length/2; shp++)
                    {
                        foreach (Extent extent in extents)
                        {
                            if(extent.Intersects(verts[shp * 2], verts[shp * 2+ 1]))
                            {
                                drawList.Add(shp);
                            }
                        }
                    }
                }
                else
                {
                    List<ShapeRange> shapes = DataSet.ShapeIndices;
                    for (int shp = 0; shp < shapes.Count; shp++)
                    {

                        foreach (IEnvelope region in regions)
                        {
                            if (!shapes[shp].Extent.Intersects(region)) continue;
                            drawList.Add(shp);
                            break;
                        }
                    }
                }
                DrawFeatures(args, drawList, clipRects, true);
            }
        }
 private static void CollisionDraw(string txt, Graphics g, ILabelSymbolizer symb, MapArgs e, RectangleF labelBounds, List<RectangleF> existingLabels)
 {
     if (labelBounds == RectangleF.Empty || !e.ImageRectangle.IntersectsWith(labelBounds)) return;
     if(symb.PreventCollisions)
     {
         if(!Collides(labelBounds, existingLabels))
         {
             DrawLabel(g, txt, labelBounds, symb);
             existingLabels.Add(labelBounds);
         }
     }
     else
     {
         DrawLabel(g, txt, labelBounds, symb); 
     }
 }
        // This draws the individual line features
        private void DrawFeatures(MapArgs e, IEnumerable<IFeature> features)
        {
            Graphics g = e.Device ?? Graphics.FromImage(_backBuffer);
           
            double minX = e.MinX;
            double maxY = e.MaxY;
            double dx = e.Dx;
            double dy = e.Dy;
            IDictionary<IFeature, IDrawnState> states = DrawingFilter.DrawnStates;
            if (states == null) return;
            foreach (IPointCategory category in Symbology.Categories)
            {
                foreach (IFeature feature in features)
                {
                    if (states.ContainsKey(feature) == false) continue;
                    IDrawnState ds = states[feature];
                    if (ds == null) continue;
                    if (!ds.IsVisible) continue;
                    if (ds.SchemeCategory == null) continue;
                    IPointCategory pc = ds.SchemeCategory as IPointCategory;
                    if (pc == null) continue;
                    if (pc != category) continue;
                    IPointSymbolizer ps = pc.Symbolizer;
                    if (ds.IsSelected)
                    {
                        ps = pc.SelectionSymbolizer;
                    }
                    if (ps == null) continue;
                    g.SmoothingMode = ps.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None;

                    double[] vertices = feature.ParentFeatureSet.Vertex; // necessary to trigger vertex creation
                    ShapeRange range = feature.ShapeIndex;
                    for (int iPart = 0; iPart < range.Parts.Count; iPart++ )
                    {
                        PartRange prt = range.Parts[iPart];
                        vertices = prt.Vertices;
                        for (int i = prt.StartIndex; i <= prt.EndIndex; i++)
                        {
                            System.Drawing.Point pt = new System.Drawing.Point();
                            pt.X = Convert.ToInt32((vertices[i * 2] - minX) * dx);
                            pt.Y = Convert.ToInt32((maxY - vertices[i * 2 + 1]) * dy);
                            double scaleSize = 1;
                            if (ps.ScaleMode == ScaleModes.Geographic)
                            {
                                scaleSize = e.ImageRectangle.Width / e.GeographicExtents.Width;
                            }
                            Matrix old = g.Transform;
                            Matrix shift = g.Transform;
                            shift.Translate(pt.X, pt.Y);
                            g.Transform = shift;
                            ps.Draw(g, scaleSize);
                            g.Transform = old;

                        }
                    }
                        

                }
            }
            
            if(e.Device == null)g.Dispose(); 
         
        }
        /// <summary>
        /// This draws to the back buffer.  If the Backbuffer doesn't exist, this will create one.
        /// This will not flip the back buffer to the front.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="regions"></param>
        /// <param name="clipRectangles"></param>
        private void DrawWindows(MapArgs args, IList<IEnvelope> regions, IList<Rectangle> clipRectangles)
        {
            Graphics g = null;
            if (args.Device != null)
            {
                g = args.Device; // A device on the MapArgs is optional, but overrides the normal buffering behaviors.
            }
            else
            {
                if (_backBuffer == null) _backBuffer = new Bitmap(_bufferRectangle.Width, _bufferRectangle.Height);
                g = Graphics.FromImage(_backBuffer);
            }
            int numBounds = Math.Min(regions.Count, clipRectangles.Count);

            int minX = args.ImageRectangle.X;
            int minY = args.ImageRectangle.Y;
            int maxX = args.ImageRectangle.X + args.ImageRectangle.Width;
            int maxY = args.ImageRectangle.Y + args.ImageRectangle.Height;


            for(int i = 0; i< numBounds; i++)
            {
                // For panning tiles, the region needs to be expanded.
                // This is not always 1 pixel.  When very zoomed in, this could be many pixels,
                // but should correspond to 1 pixel in the source image.
              
                int dx = (int)Math.Ceiling(DataSet.Bounds.AffineCoefficients[1]*clipRectangles[i].Width/regions[i].Width);
                Rectangle r = clipRectangles[i].ExpandBy(dx*2);
                if (r.X < 0) r.X = 0;
                if (r.Y < 0) r.Y = 0;
                IEnvelope env = regions[i].Reproportion(clipRectangles[i], r);
                Bitmap bmp = _baseImage.GetBitmap(env, r);
                if (bmp == null) continue;
                g.DrawImage(bmp, r);
                bmp.Dispose();
            }
            if (args.Device == null) g.Dispose();
        }