/// <summary> /// Creates a new instance of DrawArgs /// </summary> public MapDrawArgs(Graphics inGraphics, Rectangle clipRectangle, IMapFrame inMapFrame) { _graphics = inGraphics; _geoGraphics = new MapArgs(clipRectangle, inMapFrame.ViewExtents); _clipRectangle = clipRectangle; }
/// <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<Extent> regions, IList<Rectangle> clipRectangles) { Graphics g = args.Device; int numBounds = Math.Min(regions.Count, clipRectangles.Count); for (int i = 0; i < numBounds; i++) { Bitmap bmp = DataSet.GetBitmap(regions[i], clipRectangles[i].Size); if (bmp != null) g.DrawImage(bmp, clipRectangles[i]); } if (args.Device == null) g.Dispose(); }
/// <summary> /// Draw features /// </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) { this.DrawUsingChunks(args, indices, clipRectangles, useChunks, DrawFeatures); }
// 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 = TextRenderingHint.AntiAlias; g.SmoothingMode = SmoothingMode.AntiAlias; FeatureType 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 FeatureType.Polygon: DrawPolygonFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels); break; case FeatureType.Line: DrawLineFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels); break; case FeatureType.Point: DrawPointFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels); break; } } } if (e.Device == null) { g.Dispose(); } }
private static void BuildLineString(GraphicsPath path, double[] vertices, ShapeRange shpx, MapArgs args, Rectangle clipRect) { var minX = args.MinX; var maxY = args.MaxY; var dx = args.Dx; var dy = args.Dy; foreach (var prtx in shpx.Parts) { var points = prtx.Select(v => new Vertex((v.X - minX) * dx, (maxY - v.Y) * dy)).ToList(); List<List<Vertex>> multiLinestrings; if (!shpx.Extent.Within(args.GeographicExtents)) { multiLinestrings = CohenSutherland.ClipLinestring(points, clipRect.Left, clipRect.Top, clipRect.Right, clipRect.Bottom); } else { multiLinestrings = new List<List<Vertex>> { points }; } foreach (var linestring in multiLinestrings) { var intPoints = DuplicationPreventer.Clean(linestring).ToArray(); if (intPoints.Length < 2) continue; path.StartFigure(); path.AddLines(intPoints); } } }
/// <summary> /// Appends the specified polygon to the graphics path. /// </summary> private static void BuildPolygon(double[] vertices, ShapeRange shpx, GraphicsPath borderPath, MapArgs args, SoutherlandHodgman shClip) { double minX = args.MinX; double maxY = args.MaxY; double dx = args.Dx; double dy = args.Dy; for (int prt = 0; prt < shpx.Parts.Count; prt++) { PartRange prtx = shpx.Parts[prt]; int start = prtx.StartIndex; int end = prtx.EndIndex; var points = new List<double[]>(end - start + 1); for (int i = start; i <= end; i++) { var pt = new[] { (vertices[i*2] - minX)*dx, (maxY - vertices[i*2 + 1])*dy }; points.Add(pt); } if (null != shClip) { points = shClip.Clip(points); } var intPoints = DuplicationPreventer.Clean(points).ToArray(); if (intPoints.Length < 2) { continue; } borderPath.StartFigure(); borderPath.AddLines(intPoints); } }
private void DrawFeatures(MapArgs e, IEnumerable <int> indices, bool selected) { if (selected && !DrawnStatesNeeded) { return; } Graphics g = e.Device ?? Graphics.FromImage(BackBuffer); g.SetClip(new Rectangle(0, 0, e.ImageRectangle.Width, e.ImageRectangle.Height)); var indiceList = indices as IList <int> ?? indices.ToList(); Action <GraphicsPath, Rectangle, IEnumerable <int> > drawFeature = (graphPath, clipRect, features) => { foreach (int shp in features) { ShapeRange shape = DataSet.ShapeIndices[shp]; BuildLineString(graphPath, DataSet.Vertex, shape, e, clipRect); } }; if (DrawnStatesNeeded) { FastDrawnState[] states = DrawnStates; if (indiceList.Max() >= states.Length) { AssignFastDrawnStates(); states = DrawnStates; } Rectangle rTest = Rectangle.Empty; DotSpatial.Controls.Core.CGX_Mask cgxMask = DotSpatial.Controls.Core.CGX_Mask_List.GetMasks(this.Name); if (cgxMask != null) { foreach (DotSpatial.Controls.Core.CGX_MaskBounds mask in cgxMask.Masks) { RectangleF rectBounds = mask.Bounds; if (rectBounds.IsEmpty) { if (mask.Center != null) { Point pTest1 = e.ProjToPixel(mask.Center); pTest1.X -= (int)(mask.Width / 2); pTest1.Y -= (int)(mask.Height / 2); rectBounds = new RectangleF(pTest1, new SizeF((float)mask.Width, (float)mask.Height)); } } if (!rectBounds.IsEmpty) { float cx = rectBounds.X + (int)(mask.Width / 2); float cy = rectBounds.Y + +(int)(mask.Height / 2); System.Drawing.Drawing2D.Matrix oldTrans = g.Transform.Clone(); g.ResetTransform(); g.TranslateTransform(-cx, -cy, MatrixOrder.Append); g.RotateTransform((float)mask.Rotation, MatrixOrder.Append); g.TranslateTransform(cx, cy, MatrixOrder.Append); RectangleF rectWithMargin = new RectangleF( (float)((rectBounds.Location.X - cgxMask.OffsetLeft + 1)), (float)((rectBounds.Location.Y - cgxMask.OffsetTop + 1)), (float)((rectBounds.Width + cgxMask.OffsetLeft + cgxMask.OffsetRight)), (float)((rectBounds.Height + cgxMask.OffsetTop + cgxMask.OffsetBottom))); g.ExcludeClip(Rectangle.Round(rectWithMargin)); g.Transform = oldTrans; } } cgxMask.ResetBounds(); } if (selected && !states.Any(_ => _.Selected)) { return; } foreach (ILineCategory category in Symbology.Categories) { // Define the symbology based on the category and selection state ILineSymbolizer ls = selected ? category.SelectionSymbolizer : category.Symbolizer; var features = GetFeatures(indiceList, states, category, selected); DrawPath(g, ls, e, drawFeature, features); } g.ResetClip(); } else { // Selection state is disabled and there is only one category ILineSymbolizer ls = Symbology.Categories[0].Symbolizer; DrawPath(g, ls, e, drawFeature, indiceList); } if (e.Device == null) { g.Dispose(); } }
/* private static Extent FromBruTileExtent(BruTile.Extent extent) { return new Extent(extent.MinX, extent.MinY, extent.MaxX, extent.MaxY); } */ /// <summary> /// This draws content from the specified geographic regions onto the specified graphics /// object specified by MapArgs. /// </summary> public void DrawRegions(MapArgs args, List<Extent> regions) { System.Windows.Threading.Dispatcher dispatcher = System.Windows.Application.Current.Dispatcher; BruTile.Extent extent = ToBrutileExtent(args.GeographicExtents); double pixelSize = extent.Width / args.ImageRectangle.Width; int level = Utilities.GetNearestLevel(TileSource.Schema.Resolutions, pixelSize); IList<TileInfo> tiles = TileSource.Schema.GetTilesInView(extent, level); IList<WaitHandle> waitHandles = new List<WaitHandle>(); foreach (TileInfo info in tiles) { if (TileCache.Find(info.Index) != null) continue; AutoResetEvent waitHandle = new AutoResetEvent(false); waitHandles.Add(waitHandle); ThreadPool.QueueUserWorkItem(GetTileOnThread, new object[] { TileSource.Provider, info, TileCache, waitHandle }); } foreach (WaitHandle handle in waitHandles) handle.WaitOne(); foreach (TileInfo info in tiles) { using (Image bitmap = Image.FromStream(new MemoryStream(TileCache.Find(info.Index)))) { PointF min = args.ProjToPixel(new Coordinate(info.Extent.MinX, info.Extent.MinY)); PointF max = args.ProjToPixel(new Coordinate(info.Extent.MaxX, info.Extent.MaxY)); min = new PointF((float)Math.Round(min.X), (float)Math.Round(min.Y)); max = new PointF((float)Math.Round(max.X), (float)Math.Round(max.Y)); args.Device.DrawImage(bitmap, new Rectangle((int)min.X, (int)max.Y, (int)(max.X - min.X), (int)(min.Y - max.Y)), 0, 0, TileSource.Schema.Width, TileSource.Schema.Height, GraphicsUnit.Pixel); } } }
/// <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 = DataSet.Extent; var bounds = new RectangleF { X = Convert.ToSingle((catBounds.MinX - e.MinX) * e.Dx), Y = Convert.ToSingle((e.MaxY - catBounds.MaxY) * e.Dy) }; float r = Convert.ToSingle((catBounds.MaxX - e.MinX) * e.Dx); bounds.Width = r - bounds.X; float b = Convert.ToSingle((e.MaxY - catBounds.MinY) * 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 == ScaleMode.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; catBounds = CategoryExtents.Keys.Contains(category) ? CategoryExtents[category] : CalculateCategoryExtent(category); if (catBounds == null) catBounds = Extent; var bounds = new RectangleF { X = Convert.ToSingle((catBounds.MinX - e.MinX) * e.Dx), Y = Convert.ToSingle((e.MaxY - catBounds.MaxY) * e.Dy) }; float r = Convert.ToSingle((catBounds.MaxX - e.MinX) * e.Dx); bounds.Width = r - bounds.X; float b = Convert.ToSingle((e.MaxY - catBounds.MinY) * 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; } if (paths[index] != null) { paths[index].FillMode = FillMode.Winding; pattern.FillPath(g, paths[index]); } } double scale = 1; if (ps.ScaleMode == ScaleMode.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 } if (e.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); 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; } Rectangle clipRect = ComputeClippingRectangle(e, ls); // 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) { BuildLineString(graphPath, DataSet.Vertex, f.ShapeIndex, e, clipRect); } double scale = 1; if (ls.ScaleMode == ScaleMode.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(); } }
/// <summary> /// Draws the GraphicsPaths. Before we were effectively "re-creating" the same geometric. /// </summary> /// <param name="e">The map arguments.</param> /// <param name="paths">The graphics path.</param> /// <param name="selected">Indicates whether to draw the normal colored features or the selection colored features.</param> private void DrawPaths(MapArgs e, Dictionary <FastDrawnState, GraphicsPath> paths, bool selected) { Graphics g = e.Device ?? Graphics.FromImage(BackBuffer); foreach (var kvp in paths) { var category = kvp.Key.Category; if (kvp.Key.Category == null) { continue; } Extent catBounds = (CategoryExtents.Keys.Contains(category) ? CategoryExtents[category] : CalculateCategoryExtent(category)) ?? Extent; var bounds = new RectangleF { X = Convert.ToSingle((catBounds.MinX - e.MinX) * e.Dx), Y = Convert.ToSingle((e.MaxY - catBounds.MaxY) * e.Dy) }; float r = Convert.ToSingle((catBounds.MaxX - e.MinX) * e.Dx); bounds.Width = r - bounds.X; float b = Convert.ToSingle((e.MaxY - catBounds.MinY) * e.Dy); bounds.Height = b - bounds.Y; var ps = (selected && kvp.Key.Selected ? category.SelectionSymbolizer : category.Symbolizer) as PolygonSymbolizer; if (ps == null) { continue; } g.SmoothingMode = ps.GetSmoothingMode(); foreach (IPattern pattern in ps.Patterns) { IGradientPattern gp = pattern as IGradientPattern; if (gp != null) { gp.Bounds = bounds; } pattern.FillPath(g, kvp.Value); } double scale = ps.GetScale(e); // CGX if (MapFrame != null && (MapFrame as IMapFrame).ReferenceScale > 1.0 && (MapFrame as IMapFrame).CurrentScale > 0.0) { double dReferenceScale = (MapFrame as IMapFrame).ReferenceScale; double dCurrentScale = (MapFrame as IMapFrame).CurrentScale; scale = dReferenceScale / dCurrentScale; } // Fin CGX foreach (IPattern pattern in ps.Patterns) { if (pattern.UseOutline) { pattern.DrawPath(g, kvp.Value, scale); } } } if (e.Device == null) { g.Dispose(); } }
private static RectangleF PlaceLineLabel(IBasicGeometry lineString, Func <SizeF> labelSize, MapArgs e, ILabelSymbolizer symb) { ILineString ls = Geometry.FromBasicGeometry(lineString) as ILineString; if (ls == null) { return(RectangleF.Empty); } Coordinate c; if (symb.LabelPlacementMethod == LabelPlacementMethod.Centroid) { c = ls.Centroid.Coordinate; } else if (symb.LabelPlacementMethod == LabelPlacementMethod.InteriorPoint) { c = ls.InteriorPoint.Coordinate; } else { c = ls.Envelope.Center(); } var lz = labelSize(); PointF adjustment = Position(symb, lz); 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, lz.Width, lz.Height)); }
// This draws the individual point features private void DrawFeatures(MapArgs e, IEnumerable <int> indices, bool selected) { if (selected && (!DrawnStatesNeeded || !DrawnStates.Any(_ => _.Selected))) { return; // there are no selected features } Graphics g = e.Device ?? Graphics.FromImage(BackBuffer); Matrix origTransform = g.Transform; FeatureType featureType = DataSet.FeatureType; if (!DrawnStatesNeeded) { if (Symbology == null || Symbology.Categories.Count == 0) { return; } FastDrawnState state = new FastDrawnState(false, Symbology.Categories[0]); IPointSymbolizer ps = (state.Category as IPointCategory)?.Symbolizer; if (ps == null) { return; } double[] vertices = DataSet.Vertex; foreach (int index in indices) { if (featureType == FeatureType.Point) { DrawPoint(vertices[index * 2], vertices[(index * 2) + 1], e, ps, g, origTransform); } else { // multi-point ShapeRange range = DataSet.ShapeIndices[index]; for (int i = range.StartIndex; i <= range.EndIndex(); i++) { DrawPoint(vertices[i * 2], vertices[(i * 2) + 1], e, ps, g, origTransform); } } } } else { FastDrawnState[] states = DrawnStates; var indexList = indices as IList <int> ?? indices.ToList(); if (indexList.Max() >= states.Length) { AssignFastDrawnStates(); states = DrawnStates; } double[] vertices = DataSet.Vertex; foreach (int index in indexList) { if (index >= states.Length) { break; } FastDrawnState state = states[index]; if (!state.Visible || state.Category == null) { continue; } if (selected && !state.Selected) { continue; } IPointCategory pc = state.Category as IPointCategory; if (pc == null) { continue; } IPointSymbolizer ps = selected ? pc.SelectionSymbolizer : pc.Symbolizer; if (ps == null) { continue; } if (featureType == FeatureType.Point) { DrawPoint(vertices[index * 2], vertices[(index * 2) + 1], e, ps, g, origTransform); } else { ShapeRange range = DataSet.ShapeIndices[index]; for (int i = range.StartIndex; i <= range.EndIndex(); i++) { DrawPoint(vertices[i * 2], vertices[(i * 2) + 1], e, ps, g, origTransform); } } } } if (e.Device == null) { g.Dispose(); } else { g.Transform = origTransform; } }
/// <summary> /// Draws a label on a line with various different methods /// </summary> public static void DrawLineFeature(MapArgs e, Graphics g, IFeature f, ILabelCategory category, bool selected, List <RectangleF> existingLabels) { if (f == null) { return; } 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; } Func <SizeF> labelSize = () => g.MeasureString(txt, _caches.GetFont(symb)); if (f.NumGeometries == 1) { RectangleF labelBounds = PlaceLineLabel(f.BasicGeometry, labelSize, e, symb); CollisionDraw(txt, g, symb, f, e, labelBounds, existingLabels); } else { //Depending on the labeling strategy we do diff things if (symb.PartsLabelingMethod == PartLabelingMethod.LabelAllParts) { for (int n = 0; n < f.NumGeometries; n++) { RectangleF labelBounds = PlaceLineLabel(f.GetBasicGeometryN(n), labelSize, e, symb); CollisionDraw(txt, g, symb, f, 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, f, e, labelBounds, existingLabels); } } }
// This draws the individual point features private void DrawFeatures(MapArgs e, IEnumerable <IFeature> features) { Graphics g = e.Device ?? Graphics.FromImage(BackBuffer); Matrix origTransform = g.Transform; 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; foreach (Coordinate c in feature.Coordinates) { Point pt = new Point { X = Convert.ToInt32((c.X - minX) * dx), Y = Convert.ToInt32((maxY - c.Y) * dy) }; double scaleSize = 1; if (ps.ScaleMode == ScaleMode.Geographic) { scaleSize = e.ImageRectangle.Width / e.GeographicExtents.Width; } Matrix shift = origTransform.Clone(); shift.Translate(pt.X, pt.Y); g.Transform = shift; ps.Draw(g, scaleSize); } } } if (e.Device == null) { g.Dispose(); } else { g.Transform = origTransform; } }
// This draws the individual point features private void DrawFeatures(MapArgs e, IEnumerable <int> indices) { Graphics g = e.Device ?? Graphics.FromImage(BackBuffer); Matrix origTransform = g.Transform; FeatureType featureType = DataSet.FeatureType; 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 != null && DrawnStates.Length > index) { if (!DrawnStates[index].Visible) { continue; } } if (featureType == FeatureType.Point) { var pt = new Point { X = Convert.ToInt32((vertices[index * 2] - minX) * dx), Y = Convert.ToInt32((maxY - vertices[index * 2 + 1]) * dy) }; double scaleSize = 1; if (ps.ScaleMode == ScaleMode.Geographic) { scaleSize = e.ImageRectangle.Width / e.GeographicExtents.Width; } Matrix shift = origTransform.Clone(); shift.Translate(pt.X, pt.Y); g.Transform = shift; ps.Draw(g, scaleSize); } else { // multi-point ShapeRange range = DataSet.ShapeIndices[index]; for (int i = range.StartIndex; i <= range.EndIndex(); i++) { var pt = new Point { X = Convert.ToInt32((vertices[i * 2] - minX) * dx), Y = Convert.ToInt32((maxY - vertices[i * 2 + 1]) * dy) }; double scaleSize = 1; if (ps.ScaleMode == ScaleMode.Geographic) { scaleSize = e.ImageRectangle.Width / e.GeographicExtents.Width; } Matrix shift = origTransform.Clone(); shift.Translate(pt.X, pt.Y); g.Transform = shift; ps.Draw(g, scaleSize); } } } } 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 == ScaleMode.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) + 1, (int)(size.Height * scaleSize) + 1); Graphics bg = Graphics.FromImage(normalSymbol); bg.SmoothingMode = category.Symbolizer.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None; Matrix trans = bg.Transform; // keenedge: // added ' * scaleSize ' to fix a problme when ploted using ScaleMode=Geographic. however, it still // appeared to be shifted up and left by 1 pixel so I also added the one pixel shift to the NW. // trans.Translate((float)size.Width / 2, (float)size.Height / 2); trans.Translate(((float)(size.Width * scaleSize) / 2 - 1), (float)(size.Height * scaleSize) / 2 - 1); 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)(selSize.Width * scaleSize + 1), (int)(selSize.Height * scaleSize + 1)); Graphics sg = Graphics.FromImage(selectedSymbol); sg.SmoothingMode = category.SelectionSymbolizer.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None; Matrix trans2 = sg.Transform; trans2.Translate((float)selSize.Width / 2, (float)selSize.Height / 2); sg.Transform = trans2; category.SelectionSymbolizer.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 (featureType == FeatureType.Point) { var pt = new Point { X = Convert.ToInt32((vertices[index * 2] - minX) * dx), Y = Convert.ToInt32((maxY - vertices[index * 2 + 1]) * dy) }; Matrix shift = origTransform.Clone(); shift.Translate(pt.X, pt.Y); g.Transform = shift; g.DrawImageUnscaled(bmp, -bmp.Width / 2, -bmp.Height / 2); } else { ShapeRange range = DataSet.ShapeIndices[index]; for (int i = range.StartIndex; i <= range.EndIndex(); i++) { var pt = new Point { X = Convert.ToInt32((vertices[i * 2] - minX) * dx), Y = Convert.ToInt32((maxY - vertices[i * 2 + 1]) * dy) }; Matrix shift = origTransform.Clone(); shift.Translate(pt.X, pt.Y); g.Transform = shift; g.DrawImageUnscaled(bmp, -bmp.Width / 2, -bmp.Height / 2); } } } } } if (e.Device == null) { g.Dispose(); } else { g.Transform = origTransform; } }
// This draws the individual polygon 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> /// Adds the line string to the path. /// </summary> /// <param name="path">Path to add the line string to.</param> /// <param name="vertices">Vertices of the line string.</param> /// <param name="shpx">Shape range of the line string.</param> /// <param name="args">The map arguments.</param> /// <param name="clipRect">The clip rectangle.</param> internal static void BuildLineString(GraphicsPath path, double[] vertices, ShapeRange shpx, MapArgs args, Rectangle clipRect) { double minX = args.MinX; double maxY = args.MaxY; double dx = args.Dx; double dy = args.Dy; for (int prt = 0; prt < shpx.Parts.Count; prt++) { PartRange prtx = shpx.Parts[prt]; int start = prtx.StartIndex; int end = prtx.EndIndex; var points = new List <double[]>(end - start + 1); for (int i = start; i <= end; i++) { var pt = new[] { (vertices[i * 2] - minX) * dx, (maxY - vertices[(i * 2) + 1]) * dy }; points.Add(pt); } AddLineStringToPath(path, args, shpx.Extent, points, clipRect); } }
/// <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<Extent> regions) { List<Rectangle> clipRects = args.ProjToPixel(regions); DrawWindows(args, regions, clipRects); }
// This draws the individual line features private void DrawFeatures(MapArgs e, IEnumerable <IFeature> features, bool selected) { if (selected && !DrawingFilter.DrawnStates.Any(_ => _.Value.IsSelected)) { return; } Graphics g = e.Device ?? Graphics.FromImage(BackBuffer); var featureList = features as IList <IFeature> ?? features.ToList(); Action <GraphicsPath, Rectangle, IEnumerable <IFeature> > drawFeature = (graphPath, clipRect, featList) => { foreach (IFeature f in featList) { var geo = f.Geometry as LineString; if (geo != null) { BuildLineString(graphPath, geo, e, clipRect); } else { var col = f.Geometry as GeometryCollection; if (col != null) { foreach (var c1 in col.Geometries.OfType <LineString>()) { BuildLineString(graphPath, c1, e, clipRect); } } } } }; foreach (ILineCategory category in Symbology.Categories) { // Define the symbology based on the category and selection state ILineSymbolizer ls = selected ? category.SelectionSymbolizer : category.Symbolizer; // Determine the subset of the specified features that are visible and match the category ILineCategory lineCategory = category; Func <IDrawnState, bool> isMember; if (selected) { // get only selected features isMember = state => state.SchemeCategory == lineCategory && state.IsVisible && state.IsSelected; } else { // get all features isMember = state => state.SchemeCategory == lineCategory && state.IsVisible; } var drawnFeatures = from feature in featureList where isMember(DrawingFilter[feature]) select feature; DrawPath(g, ls, e, drawFeature, drawnFeatures); } if (e.Device == null) { g.Dispose(); } }
// This draws the individual polygon features private void DrawFeatures(MapArgs e, IEnumerable<IFeature> features) { List<GraphicsPath> paths; // 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); foreach (var path in paths) { path.Dispose(); } }
internal static void BuildLineString(GraphicsPath path, double[] vertices, ShapeRange shpx, MapArgs args, Rectangle clipRect) { double minX = args.MinX; double maxY = args.MaxY; double dx = args.Dx; double dy = args.Dy; 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); } List<List<double[]>> multiLinestrings; if (!shpx.Extent.Within(args.GeographicExtents)) { multiLinestrings = CohenSutherland.ClipLinestring(points, clipRect.Left, clipRect.Top, clipRect.Right, clipRect.Bottom); } else { multiLinestrings = new List<List<double[]>>(); multiLinestrings.Add(points); } foreach (List<double[]> linestring in multiLinestrings) { List<Point> intPoints = DuplicationPreventer.Clean(linestring); if (intPoints.Count < 2) { points.Clear(); continue; } path.StartFigure(); Point[] pointArray = intPoints.ToArray(); path.AddLines(pointArray); } } }
private void BuildPaths(MapArgs e, IEnumerable<IFeature> features, out List<GraphicsPath> borderPaths) { borderPaths = new List<GraphicsPath>(); Rectangle clipRect = ComputeClippingRectangle(e); Extent drawExtents = e.PixelToProj(clipRect); SoutherlandHodgman shClip = new SoutherlandHodgman(clipRect); 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) { BuildPolygon(DataSet.Vertex, f.ShapeIndex, borderPath, e, drawExtents.Contains(f.Envelope) ? null : shClip); } borderPaths.Add(borderPath); } } }
public void DrawRegions(MapArgs args, List<Extent> regions) { // Assert that the map has the same size as the DotSpatial map var size = args.ImageRectangle.Size; _map.Size = size; // Make sure the map is zoomed to the same extent var env = Topology.GeometryConverter.ToGeoAPI(args.GeographicExtents); _map.ZoomToBox(env); // Always render the whole map to the device _map.RenderMap(args.Device); /* * This is not suitable because we might draw to printer/plotter * which will make for a huge Image */ #region //using (var mapImage = _map.GetMap()) //{ // foreach (var region in regions) // { // var loc = args.ProjToPixel(region); // args.Device.DrawImage(mapImage, loc, // loc.X, loc.Y, loc.Width, loc.Height, // GraphicsUnit.Pixel); // } //} #endregion }
/// <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 virtual void DrawRegions(MapArgs args, List<Extent> 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 (Extent 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 (Extent region in regions) { if (!shapes[shp].Extent.Intersects(region)) continue; drawList.Add(shp); break; } } DrawFeatures(args, drawList, clipRects, true); } }
// 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 = TextRenderingHint.AntiAlias; g.SmoothingMode = SmoothingMode.AntiAlias; FeatureType 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 FeatureType.Polygon: DrawPolygonFeature(e, g, feature, drawStates[feature].Category, drawStates[feature].Selected, ExistingLabels); break; case FeatureType.Line: DrawLineFeature(e, g, feature, drawStates[feature].Category, drawStates[feature].Selected, ExistingLabels); break; case FeatureType.Point: DrawPointFeature(e, g, feature, drawStates[feature].Category, drawStates[feature].Selected, ExistingLabels); break; } } } if (e.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); 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; } Rectangle clipRect = ComputeClippingRectangle(e, ls); // 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) { BuildLineString(graphPath, DataSet.Vertex, f.ShapeIndex, e, clipRect); } double scale = 1; if (ls.ScaleMode == ScaleMode.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(); }
/// <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 <Extent> 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++) { // 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 = RectangleExt.ExpandBy(clipRectangles[i], dx * 2); if (r.X < 0) { r.X = 0; } if (r.Y < 0) { r.Y = 0; } if (r.Width > 2 * clipRectangles[i].Width) { r.Width = 2 * clipRectangles[i].Width; } if (r.Height > 2 * clipRectangles[i].Height) { r.Height = 2 * clipRectangles[i].Height; } Extent env = regions[i].Reproportion(clipRectangles[i], r); Bitmap bmp; try { bmp = DataSet.GetBitmap(env, r); } catch { continue; } if (bmp == null) { continue; } g.DrawImage(bmp, r); bmp.Dispose(); } if (args.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<Extent> 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++) { // 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 = RectangleExt.ExpandBy(clipRectangles[i], dx * 2); if (r.X < 0) r.X = 0; if (r.Y < 0) r.Y = 0; if (r.Width > 2 * clipRectangles[i].Width) r.Width = 2 * clipRectangles[i].Width; if (r.Height > 2 * clipRectangles[i].Height) r.Height = 2 * clipRectangles[i].Height; Extent env = regions[i].Reproportion(clipRectangles[i], r); Bitmap bmp; try { bmp = DataSet.GetBitmap(env, r); } catch { continue; } if (bmp == null) continue; g.DrawImage(bmp, r); bmp.Dispose(); } if (args.Device == null) g.Dispose(); }
/// <inheritdoc/> public virtual void Print(MapArgs args, List <Extent> regions, bool selected) { DrawRegions(args, regions, selected); }
/// <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 <Extent> 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++) { // 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; } if (r.Width > 2 * clipRectangles[i].Width) { r.Width = 2 * clipRectangles[i].Width; } if (r.Height > 2 * clipRectangles[i].Height) { r.Height = 2 * clipRectangles[i].Height; } Extent env = regions[i].Reproportion(clipRectangles[i], r); Bitmap bmp = null; try { bmp = DataSet.GetBitmap(env, r); if (!_transparent.Name.Equals("0")) { bmp.MakeTransparent(_transparent); } } catch { if (bmp != null) { bmp.Dispose(); } continue; } if (bmp == null) { continue; } if (this.Symbolizer != null && this.Symbolizer.Opacity < 1) { ColorMatrix matrix = new ColorMatrix(); //draws the image not completely opaque matrix.Matrix33 = Symbolizer.Opacity; ImageAttributes attributes = new ImageAttributes(); attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(bmp, r, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes); attributes.Dispose(); } else { g.DrawImage(bmp, r); } bmp.Dispose(); } if (args.Device == null) { g.Dispose(); } }
/// <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 = DataSet.Extent; var bounds = new RectangleF { X = Convert.ToSingle((catBounds.MinX - e.MinX) * e.Dx), Y = Convert.ToSingle((e.MaxY - catBounds.MaxY) * e.Dy) }; float r = Convert.ToSingle((catBounds.MaxX - e.MinX) * e.Dx); bounds.Width = r - bounds.X; float b = Convert.ToSingle((e.MaxY - catBounds.MinY) * 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 == ScaleMode.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; catBounds = CategoryExtents.Keys.Contains(category) ? CategoryExtents[category] : CalculateCategoryExtent(category); if (catBounds == null) { catBounds = Extent; } var bounds = new RectangleF { X = Convert.ToSingle((catBounds.MinX - e.MinX) * e.Dx), Y = Convert.ToSingle((e.MaxY - catBounds.MaxY) * e.Dy) }; float r = Convert.ToSingle((catBounds.MaxX - e.MinX) * e.Dx); bounds.Width = r - bounds.X; float b = Convert.ToSingle((e.MaxY - catBounds.MinY) * 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; } if (paths[index] != null) { paths[index].FillMode = FillMode.Winding; pattern.FillPath(g, paths[index]); } } double scale = 1; if (ps.ScaleMode == ScaleMode.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 } if (e.Device == null) { g.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> public virtual void DrawRegions(MapArgs args, List<Extent> regions) { // First determine the number of features we are talking about based on region. var clipRects = args.ProjToPixel(regions); var drawList = new List<int>(); for (var shp = 0; shp < DataSet.Count; shp++) { var pointExtent = DataSet.GetFeatureExtent(shp); if (regions.Any(pointExtent.Intersects)) { drawList.Add(shp); } } DrawFeatures(args, drawList, clipRects, true); }
private void BuildPaths(MapArgs e, IEnumerable <int> indices, out List <GraphicsPath> paths) { paths = new List <GraphicsPath>(); Extent drawExtents = e.GeographicExtents; Rectangle clipRect = e.ProjToPixel(e.GeographicExtents); SoutherlandHodgman shClip = new SoutherlandHodgman(clipRect); List <GraphicsPath> graphPaths = new List <GraphicsPath>(); 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); graphPaths.Add(border); } } paths.AddRange(graphPaths); List <ShapeRange> shapes = DataSet.ShapeIndices; double[] vertices = DataSet.Vertex; if (ProgressReportingEnabled) { ProgressMeter = new ProgressMeter(ProgressHandler, "Building Paths", indices.Count()); } if (!DrawnStatesNeeded) { FastDrawnState state = new FastDrawnState(false, Symbology.Categories[0]); foreach (int shp in indices) { if (ProgressReportingEnabled) { ProgressMeter.Next(); } ShapeRange shape = shapes[shp]; if (!shape.Extent.Intersects(e.GeographicExtents)) { return; } if (shp >= shapes.Count) { return; } if (!borders.ContainsKey(state)) { return; } BuildPolygon(vertices, shapes[shp], borders[state], e, drawExtents.Contains(shape.Extent) ? null : shClip); } } else { FastDrawnState[] states = DrawnStates; foreach (GraphicsPath borderPath in borders.Values) { if (borderPath != null) { borderPath.FillMode = FillMode.Winding; } } foreach (int shp in indices) { if (ProgressReportingEnabled) { ProgressMeter.Next(); } if (shp >= shapes.Count) { return; } 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, null); } else { FastDrawnState state = states[shp]; if (!borders.ContainsKey(state)) { continue; } BuildPolygon(vertices, shapes[shp], borders[state], e, shClip); } } } if (ProgressReportingEnabled) { ProgressMeter.Reset(); } }
private void DrawFeatures(MapArgs e, List<int> indices) { var g = e.Device ?? Graphics.FromImage(BackBuffer); var origTransform = g.Transform; var minX = e.MinX; var maxY = e.MaxY; var dx = e.Dx; var dy = e.Dy; var states = DrawnStates; foreach (var category in Symbology.Categories) { var normalSymbol = GetSymbolizerBitmap(category.Symbolizer, e); var selectedSymbol = GetSymbolizerBitmap(category.SelectionSymbolizer, e); foreach (var index in indices) { var state = states[index]; if (!state.Visible) continue; var pc = state.Category as IPointCategory; if (pc == null) continue; if (pc != category) continue; var bmp = state.Selected? selectedSymbol : normalSymbol; if (bmp == null) continue; var shape = DataSet.GetShape(index, false); foreach (var part in shape.Range.Parts) { foreach (var vertex in part) { var pt = new Point { X = Convert.ToInt32((vertex.X - minX)*dx), Y = Convert.ToInt32((maxY - vertex.Y)*dy) }; var shift = origTransform.Clone(); shift.Translate(pt.X, pt.Y); g.Transform = shift; g.DrawImageUnscaled(bmp, -bmp.Width/2, -bmp.Height/2); } } } } if (e.Device == null) g.Dispose(); else g.Transform = origTransform; }
/// <summary> /// Initializes a new instance of the <see cref="MapDrawArgs"/> class. /// </summary> /// <param name="inGraphics">The graphics object used for drawing.</param> /// <param name="clipRectangle">The clip rectangle.</param> /// <param name="inGeoGraphics">The map args.</param> public MapDrawArgs(Graphics inGraphics, Rectangle clipRectangle, MapArgs inGeoGraphics) { _graphics = inGraphics; _clipRectangle = clipRectangle; _geoGraphics = inGeoGraphics; }
/// <summary> /// Appends the specified polygon to the graphics path. /// </summary> private static void BuildPolygon(double[] vertices, ShapeRange shpx, GraphicsPath borderPath, MapArgs args, SoutherlandHodgman shClip) { double minX = args.MinX; double maxY = args.MaxY; double dx = args.Dx; double dy = args.Dy; 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 (null != shClip) { points = shClip.Clip(points); } List<Point> intPoints = DuplicationPreventer.Clean(points); if (intPoints.Count < 2) { points.Clear(); continue; } //Would be nice to figure out how to get rid of this lock lock (lock1) { borderPath.StartFigure(); Point[] pointArray = intPoints.ToArray(); borderPath.AddLines(pointArray); } points.Clear(); } }
// This draws the individual point features private void DrawFeatures(MapArgs e, IEnumerable <int> indices) { Graphics g = e.Device ?? Graphics.FromImage(BackBuffer); Matrix origTransform = g.Transform; FeatureType featureType = DataSet.FeatureType; if (!DrawnStatesNeeded) { if (Symbology == null || Symbology.Categories.Count == 0) { return; } FastDrawnState state = new FastDrawnState(false, Symbology.Categories[0]); IPointCategory pc = state.Category as IPointCategory; if (pc == null) { return; } IPointSymbolizer ps = pc.Symbolizer; if (ps == null) { return; } double[] vertices = DataSet.Vertex; foreach (int index in indices) { if (DrawnStates != null && DrawnStates.Length > index && !DrawnStates[index].Visible) { continue; } if (featureType == FeatureType.Point) { DrawPoint(vertices[index * 2], vertices[index * 2 + 1], e, ps, g, origTransform); } else { // multi-point ShapeRange range = DataSet.ShapeIndices[index]; for (int i = range.StartIndex; i <= range.EndIndex(); i++) { DrawPoint(vertices[i * 2], vertices[i * 2 + 1], e, ps, g, origTransform); } } } } else { FastDrawnState[] states = DrawnStates; double[] vertices = DataSet.Vertex; foreach (int index in indices) { if (index >= states.Length) { break; } FastDrawnState state = states[index]; if (!state.Visible || state.Category == null) { continue; } IPointCategory pc = state.Category as IPointCategory; if (pc == null) { continue; } IPointSymbolizer ps = state.Selected ? pc.SelectionSymbolizer : pc.Symbolizer; if (ps == null) { continue; } if (featureType == FeatureType.Point) { DrawPoint(vertices[index * 2], vertices[index * 2 + 1], e, ps, g, origTransform); } else { ShapeRange range = DataSet.ShapeIndices[index]; for (int i = range.StartIndex; i <= range.EndIndex(); i++) { DrawPoint(vertices[i * 2], vertices[i * 2 + 1], e, ps, g, origTransform); } } } } if (e.Device == null) { g.Dispose(); } else { g.Transform = origTransform; } }
/// <summary> /// This draws to the back buffer. If the back buffer 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<Extent> 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++) { using (Bitmap bmp = BitmapGetter.GetBitmap(regions[i], clipRectangles[i])) { if (bmp != null) g.DrawImage(bmp, clipRectangles[i]); } } if (args.Device == null) g.Dispose(); }
/// <summary> /// Adds the line string to the path. /// </summary> /// <param name="path">Path to add the line string to.</param> /// <param name="vertices">Vertices of the line string.</param> /// <param name="shpx">Shape range of the line string.</param> /// <param name="args">The map arguments.</param> /// <param name="clipRect">The clip rectangle.</param> internal static void BuildLineString(GraphicsPath path, double[] vertices, ShapeRange shpx, MapArgs args, Rectangle clipRect) { double minX = args.MinX; double maxY = args.MaxY; double dx = args.Dx; double dy = args.Dy; for (int prt = 0; prt < shpx.Parts.Count; prt++) { PartRange prtx = shpx.Parts[prt]; int start = prtx.StartIndex; int end = prtx.EndIndex; var points = new List <double[]>(end - start + 1); for (int i = start; i <= end; i++) { var pt = new[] { (vertices[i * 2] - minX) * dx, (maxY - vertices[(i * 2) + 1]) * dy }; points.Add(pt); } List <List <double[]> > multiLinestrings; if (!shpx.Extent.Within(args.GeographicExtents)) { multiLinestrings = CohenSutherland.ClipLinestring(points, clipRect.Left, clipRect.Top, clipRect.Right, clipRect.Bottom); } else { multiLinestrings = new List <List <double[]> > { points }; } foreach (List <double[]> linestring in multiLinestrings) { var intPoints = DuplicationPreventer.Clean(linestring).ToArray(); if (intPoints.Length < 2) { continue; } path.StartFigure(); path.AddLines(intPoints); } } }
/// <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 virtual void DrawRegions(MapArgs args, List<Extent> regions) { List<Rectangle> clipRects = args.ProjToPixel(regions); if (EditMode) { List<IFeature> drawList = new List<IFeature>(); drawList = regions.Where(region => region != null).Aggregate(drawList, (current, region) => current.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 (Extent region in regions) { if (!shapes[shp].Extent.Intersects(region)) continue; drawList.Add(shp); break; } } DrawFeatures(args, drawList, clipRects, true); } }
private void DrawFeatures(MapArgs e, IEnumerable <int> indices) { Graphics g = e.Device ?? Graphics.FromImage(BackBuffer); if (DrawnStatesNeeded) { FastDrawnState[] states = DrawnStates; var indiceList = indices as IList <int> ?? indices.ToList(); int max = indiceList.Max(); if (max >= states.Length) { AssignFastDrawnStates(); states = DrawnStates; } 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; } g.SmoothingMode = ls.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None; // Compute a clipping rectangle that accounts for symbology Rectangle clipRect = ComputeClippingRectangle(e, ls); // Determine the subset of the specified features that are visible and match the category ILineCategory lineCategory = category; int i = selectState; List <int> drawnFeatures = new List <int>(); foreach (int index in indiceList) { if (index >= states.Length) { break; } FastDrawnState state = states[index]; if (state.Category == lineCategory && state.Selected == (i == 1) && state.Visible) { drawnFeatures.Add(index); } } GraphicsPath graphPath = new GraphicsPath(); foreach (int shp in drawnFeatures) { ShapeRange shape = DataSet.ShapeIndices[shp]; BuildLineString(graphPath, DataSet.Vertex, shape, e, clipRect); } double scale = 1; if (ls.ScaleMode == ScaleMode.Geographic) { scale = e.ImageRectangle.Width / e.GeographicExtents.Width; } foreach (IStroke stroke in ls.Strokes) { stroke.DrawPath(g, graphPath, scale); } graphPath.Dispose(); } } } else { // Selection state is disabled // Category is only the very first category ILineCategory category = Symbology.Categories[0]; ILineSymbolizer ls = category.Symbolizer; g.SmoothingMode = ls.Smoothing ? SmoothingMode.AntiAlias : SmoothingMode.None; Rectangle clipRect = ComputeClippingRectangle(e, ls); // Determine the subset of the specified features that are visible and match the category GraphicsPath graphPath = new GraphicsPath(); foreach (int shp in indices) { ShapeRange shape = DataSet.ShapeIndices[shp]; BuildLineString(graphPath, DataSet.Vertex, shape, e, clipRect); } double scale = 1; if (ls.ScaleMode == ScaleMode.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> 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 (var path in paths) { path.Dispose(); } }
/// <summary> /// Places the label according to the selected LabelPlacementMethode. /// </summary> /// <param name="lineString">LineString, whose label gets drawn.</param> /// <param name="labelSize">Function that calculates the size of the label.</param> /// <param name="e"></param> /// <param name="symb">Symbolizer to figure out the look of the label.</param> /// <param name="angle">Angle in degree the label gets rotated by.</param> /// <returns>The RectangleF that is needed to draw the label.</returns> private static RectangleF PlaceLineLabel(IGeometry lineString, Func <SizeF> labelSize, MapArgs e, ILabelSymbolizer symb, float angle) { LineString ls = lineString as LineString; if (ls == null) { return(Rectangle.Empty); } ls = GetSegment(ls, symb); if (ls == null) { return(Rectangle.Empty); } return(PlaceLabel(ls.Centroid.Coordinate, e, labelSize, symb, angle)); }
private void BuildPaths(MapArgs e, IEnumerable<int> indices, out List<GraphicsPath> paths) { paths = new List<GraphicsPath>(); Extent drawExtents = e.GeographicExtents; Rectangle clipRect = e.ProjToPixel(e.GeographicExtents); SoutherlandHodgman shClip = new SoutherlandHodgman(clipRect); List<GraphicsPath> graphPaths = new List<GraphicsPath>(); 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); graphPaths.Add(border); } } paths.AddRange(graphPaths); List<ShapeRange> shapes = DataSet.ShapeIndices; double[] vertices = DataSet.Vertex; if (ProgressReportingEnabled) { ProgressMeter = new ProgressMeter(ProgressHandler, "Building Paths", indices.Count()); } if (!DrawnStatesNeeded) { FastDrawnState state = new FastDrawnState(false, Symbology.Categories[0]); foreach (int shp in indices) { if (ProgressReportingEnabled) ProgressMeter.Next(); ShapeRange shape = shapes[shp]; if (!shape.Extent.Intersects(e.GeographicExtents)) return; if (shp >= shapes.Count) return; if (!borders.ContainsKey(state)) return; BuildPolygon(vertices, shapes[shp], borders[state], e, drawExtents.Contains(shape.Extent) ? null : shClip); } } else { FastDrawnState[] states = DrawnStates; foreach (GraphicsPath borderPath in borders.Values) { if (borderPath != null) { borderPath.FillMode = FillMode.Winding; } } foreach (int shp in indices) { if (ProgressReportingEnabled) ProgressMeter.Next(); if (shp >= shapes.Count) return; 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, null); } else { FastDrawnState state = states[shp]; if (!borders.ContainsKey(state)) continue; BuildPolygon(vertices, shapes[shp], borders[state], e, shClip); } } } if (ProgressReportingEnabled) ProgressMeter.Reset(); }
private static RectangleF PlacePointLabel(IGeometry f, MapArgs e, Func <SizeF> labelSize, ILabelSymbolizer symb, float angle) { Coordinate c = f.GetGeometryN(1).Coordinates[0]; return(PlaceLabel(c, e, labelSize, symb, angle)); }
private static Rectangle ComputeClippingRectangle(MapArgs args) { const int maxSymbologyFuzz = 50; var clipRect = new Rectangle(args.ImageRectangle.Location.X, args.ImageRectangle.Location.Y, args.ImageRectangle.Width, args.ImageRectangle.Height); clipRect.Inflate(maxSymbologyFuzz, maxSymbologyFuzz); return clipRect; }
/// <summary> /// Draws the given text if it is on screen. If PreventCollision is set only labels that don't collide with existingLables are drawn. /// </summary> /// <param name="txt">Text that should be drawn.</param> /// <param name="g">Graphics object that does the drawing.</param> /// <param name="symb">Symbolizer to figure out the look of the label.</param> /// <param name="f">Feature, the label belongs to.</param> /// <param name="e"></param> /// <param name="labelBounds"></param> /// <param name="existingLabels">List with labels that were already drawn.</param> /// <param name="angle">Angle in degree the label gets rotated by.</param> private static void CollisionDraw(string txt, Graphics g, ILabelSymbolizer symb, IFeature f, MapArgs e, RectangleF labelBounds, List <RectangleF> existingLabels, float angle) { if (labelBounds.IsEmpty || !e.ImageRectangle.IntersectsWith(labelBounds)) { return; } if (symb.PreventCollisions) { if (!Collides(labelBounds, existingLabels)) { DrawLabel(g, txt, labelBounds, symb, f, angle); existingLabels.Add(labelBounds); } } else { DrawLabel(g, txt, labelBounds, symb, f, angle); } }
/// <summary> /// Draws the LiDAR data points in the currently visible map display /// </summary> /// <param name="args">Information about the map display</param> /// <param name="regions">Information about the visible regions</param> public void DrawRegions(MapArgs args, List<Extent> regions) { throw new NotImplementedException(); }
/// <summary> /// Draws the labels for the given features. /// </summary> /// <param name="e">MapArgs to get Graphics object from.</param> /// <param name="features">Indizes of the features whose labels get drawn.</param> private void DrawFeatures(MapArgs e, IEnumerable <int> features) { // Check that exists at least one category with Expression if (Symbology.Categories.All(_ => string.IsNullOrEmpty(_.Expression))) { return; } Graphics g = e.Device ?? Graphics.FromImage(_backBuffer); Matrix origTransform = g.Transform; // 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 = TextRenderingHint.AntiAlias; g.SmoothingMode = SmoothingMode.AntiAlias; Action <int, IFeature> drawFeature; switch (FeatureSet.FeatureType) { case FeatureType.Polygon: drawFeature = (fid, feature) => DrawPolygonFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels); break; case FeatureType.Line: drawFeature = (fid, feature) => DrawLineFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels); break; case FeatureType.Point: case FeatureType.MultiPoint: drawFeature = (fid, feature) => DrawPointFeature(e, g, feature, drawStates[fid].Category, drawStates[fid].Selected, ExistingLabels); break; default: return; // Can't draw something else } foreach (var category in Symbology.Categories) { category.UpdateExpressionColumns(FeatureSet.DataTable.Columns); var 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 (var fid in catFeatures) { if (!FeatureLayer.DrawnStates[fid].Visible) { continue; } var feature = FeatureSet.GetFeature(fid); drawFeature(fid, feature); } } if (e.Device == null) { g.Dispose(); } else { g.Transform = origTransform; } }
/// <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); Application.DoEvents(); // this.StartDrawing(); } } }
/// <summary> /// Draws the labels for the given features. /// </summary> /// <param name="e">MapArgs to get Graphics object from.</param> /// <param name="features">Features, whose labels get drawn.</param> private void DrawFeatures(MapArgs e, IEnumerable <IFeature> features) { // Check that exists at least one category with Expression if (Symbology.Categories.All(_ => string.IsNullOrEmpty(_.Expression))) { return; } Graphics g = e.Device ?? Graphics.FromImage(_backBuffer); Matrix origTransform = g.Transform; // 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 = TextRenderingHint.AntiAlias; g.SmoothingMode = SmoothingMode.AntiAlias; Action <IFeature> drawFeature; switch (features.First().FeatureType) { case FeatureType.Polygon: drawFeature = f => DrawPolygonFeature(e, g, f, drawStates[f].Category, drawStates[f].Selected, ExistingLabels); break; case FeatureType.Line: drawFeature = f => DrawLineFeature(e, g, f, drawStates[f].Category, drawStates[f].Selected, ExistingLabels); break; case FeatureType.Point: case FeatureType.MultiPoint: drawFeature = f => DrawPointFeature(e, g, f, drawStates[f].Category, drawStates[f].Selected, ExistingLabels); break; default: return; // Can't draw something else } foreach (ILabelCategory category in Symbology.Categories) { category.UpdateExpressionColumns(FeatureSet.DataTable.Columns); var cat = category; // prevent access to unmodified closure problems List <IFeature> catFeatures = new List <IFeature>(); foreach (IFeature f in features) { if (drawStates.ContainsKey(f) && 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(); } } } for (int i = 0; i < catFeatures.Count; i++) { if (!FeatureLayer.DrawnStates[i].Visible) { continue; } drawFeature(catFeatures[i]); } } if (e.Device == null) { g.Dispose(); } else { g.Transform = origTransform; } }
private void DrawFeatures(MapArgs e, IEnumerable<int> indices) { Graphics g = e.Device ?? Graphics.FromImage(_backBuffer); if (DrawnStatesNeeded) { FastDrawnState[] states = DrawnStates; int max = indices.Max(); if (max >= states.Length) { AssignFastDrawnStates(); states = DrawnStates; } 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; } // Compute a clipping rectangle that accounts for symbology Rectangle clipRect = ComputeClippingRectangle(e, ls); // Determine the subset of the specified features that are visible and match the category ILineCategory lineCategory = category; int i = selectState; List<int> drawnFeatures = new List<int>(); foreach (int index in indices) { FastDrawnState state = states[index]; if (state.Category == lineCategory && state.Selected == (i == 1) && state.Visible) { drawnFeatures.Add(index); } } GraphicsPath graphPath = new GraphicsPath(); foreach (int shp in drawnFeatures) { ShapeRange shape = DataSet.ShapeIndices[shp]; BuildLineString(graphPath, DataSet.Vertex, shape, e, clipRect); } double scale = 1; if (ls.ScaleMode == ScaleMode.Geographic) { scale = e.ImageRectangle.Width / e.GeographicExtents.Width; } foreach (IStroke stroke in ls.Strokes) { stroke.DrawPath(g, graphPath, scale); } graphPath.Dispose(); } } } else { // Selection state is disabled // Category is only the very first category ILineCategory category = Symbology.Categories[0]; ILineSymbolizer ls = category.Symbolizer; if (ls.Smoothing) { g.SmoothingMode = SmoothingMode.AntiAlias; } else { g.SmoothingMode = SmoothingMode.None; } Rectangle clipRect = ComputeClippingRectangle(e, ls); // Determine the subset of the specified features that are visible and match the category GraphicsPath graphPath = new GraphicsPath(); foreach (int shp in indices) { ShapeRange shape = DataSet.ShapeIndices[shp]; BuildLineString(graphPath, DataSet.Vertex, shape, e, clipRect); } double scale = 1; if (ls.ScaleMode == ScaleMode.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(); }
/// <summary> /// Appends the specified polygon to the graphics path. /// </summary> /// <param name="vertices">The vertices.</param> /// <param name="shpx">The shape range.</param> /// <param name="borderPath">The border path.</param> /// <param name="args">The map arguments.</param> /// <param name="shClip">The southerland hodgmen polygon clipper.</param> private static void BuildPolygon(double[] vertices, ShapeRange shpx, GraphicsPath borderPath, MapArgs args, SoutherlandHodgman shClip) { double minX = args.MinX; double maxY = args.MaxY; double dx = args.Dx; double dy = args.Dy; for (int prt = 0; prt < shpx.Parts.Count; prt++) { PartRange prtx = shpx.Parts[prt]; int start = prtx.StartIndex; int end = prtx.EndIndex; var points = new List <double[]>(end - start + 1); for (int i = start; i <= end; i++) { var pt = new[] { (vertices[i * 2] - minX) * dx, (maxY - vertices[(i * 2) + 1]) * dy }; points.Add(pt); } if (shClip != null) { points = shClip.Clip(points); } var intPoints = DuplicationPreventer.Clean(points).ToArray(); if (intPoints.Length < 2) { continue; } borderPath.StartFigure(); borderPath.AddLines(intPoints); } }
private static Rectangle ComputeClippingRectangle(MapArgs args, ILineSymbolizer ls) { // Compute a clipping rectangle that accounts for symbology int maxLineWidth = 2 * (int)Math.Ceiling(ls.GetWidth()); Rectangle clipRect = new Rectangle(args.ImageRectangle.Location.X, args.ImageRectangle.Location.Y, args.ImageRectangle.Width, args.ImageRectangle.Height); clipRect.Inflate(maxLineWidth, maxLineWidth); return clipRect; }
private void BuildPaths(MapArgs e, IEnumerable <int> indices, out Dictionary <FastDrawnState, GraphicsPath> paths, bool selected) { paths = new Dictionary <FastDrawnState, GraphicsPath>(); var indiceList = indices as IList <int> ?? indices.ToList(); FastDrawnState[] states = DrawnStatesNeeded ? DrawnStates : new FastDrawnState[0]; if (DrawnStatesNeeded && indiceList.Max() >= states.Length) { AssignFastDrawnStates(); states = DrawnStates; } if (selected && (!DrawnStatesNeeded || !DrawnStates.Any(_ => _.Selected))) { return; } if (ProgressReportingEnabled) { ProgressMeter = new ProgressMeter(ProgressHandler, "Building Paths", indiceList.Count); } FastDrawnState state = new FastDrawnState(selected, Symbology.Categories[0]); Extent drawExtents = e.GeographicExtents; Rectangle clipRect = e.ProjToPixel(e.GeographicExtents); SoutherlandHodgman shClip = new SoutherlandHodgman(clipRect); List <ShapeRange> shapes = DataSet.ShapeIndices; double[] vertices = DataSet.Vertex; foreach (int shp in indiceList) { if (ProgressReportingEnabled) { ProgressMeter.Next(); } if (shp >= shapes.Count) { return; } ShapeRange shape = shapes[shp]; if (!shape.Extent.Intersects(e.GeographicExtents)) { continue; } if (DrawnStatesNeeded) { if (!states[shp].Visible || (selected && !states[shp].Selected)) { continue; } state = new FastDrawnState(selected, states[shp].Category); } if (!paths.ContainsKey(state)) { paths.Add(state, new GraphicsPath(FillMode.Winding)); } BuildPolygon(vertices, shapes[shp], paths[state], e, drawExtents.Contains(shape.Extent) ? null : shClip); } if (ProgressReportingEnabled) { ProgressMeter.Reset(); } }
/// <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<Extent> regions) { List<Rectangle> clipRects = args.ProjToPixel(regions); for (int i = clipRects.Count - 1; i >= 0; i--) { if (clipRects[i].Width != 0 && clipRects[i].Height != 0) continue; regions.RemoveAt(i); clipRects.RemoveAt(i); } DrawWindows(args, regions, clipRects); }
/// <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 <Extent> regions) { List <Rectangle> clipRects = args.ProjToPixel(regions); DrawWindows(args, regions, clipRects); }
/// <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 virtual void DrawRegions(MapArgs args, List<Extent> regions) { double minX = args.MinX; double maxY = args.MaxY; double dx = args.Dx; double dy = args.Dy; if (Double.IsInfinity(dx) || Double.IsInfinity(dy)) return; foreach (Extent boundingBox in regions) { Graphics g = args.Device ?? Graphics.FromImage(_backBuffer); Matrix origTransform = g.Transform; FeatureType featureType = FeatureType.Point; //reads the point array from the data source //DataSet implements or uses IShapeSource to read the points that are within the bounding box double[] vertices = DataSet.GetPointArray(boundingBox); //setup the point symbol Color randomColor = CreateRandomColor(); Bitmap normalSymbol = CreateDefaultSymbol(randomColor, 4); //run the drawing operation int numPoints = vertices.Length / 2; for (int index = 0; index < numPoints; index++) { Bitmap bmp = normalSymbol; if (featureType == FeatureType.Point) { Point pt = new Point(); pt.X = Convert.ToInt32((vertices[index * 2] - minX) * dx); pt.Y = Convert.ToInt32((maxY - vertices[index * 2 + 1]) * dy); Matrix shift = origTransform.Clone(); shift.Translate(pt.X, pt.Y); g.Transform = shift; g.DrawImageUnscaled(bmp, -bmp.Width / 2, -bmp.Height / 2); } } if (args.Device == null) g.Dispose(); else g.Transform = origTransform; } }
/// <summary> /// This draws to the back buffer. If the back buffer doesn't exist, this will create one. /// This will not flip the back buffer to the front. /// </summary> /// <param name="args">The map arguments.</param> /// <param name="regions">The regions </param> /// <param name="clipRectangles">The clip rectangles.</param> private void DrawWindows(MapArgs args, IList <Extent> regions, IList <Rectangle> clipRectangles) { if (DataSet == null || regions.Count == 0 || regions.Count != clipRectangles.Count) { return; } 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); if (Symbolizer != null && Symbolizer.Opacity < 1) { ColorMatrix matrix = new ColorMatrix { Matrix33 = Symbolizer.Opacity // draws the image not completely opaque }; using (var attributes = new ImageAttributes()) { for (int i = 0; i < numBounds; i++) { using (Bitmap bmp = DataSet.GetBitmap(regions[i], clipRectangles[i])) { if (bmp != null) { attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(bmp, clipRectangles[i], 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes); } } } } } else { for (int i = 0; i < numBounds; i++) { using (Bitmap bmp = DataSet.GetBitmap(regions[i], clipRectangles[i])) { if (bmp != null) { g.DrawImage(bmp, clipRectangles[i]); } } } } if (args.Device == null) { g.Dispose(); } }