/// <summary> /// Convert given context with Mapbox GL styling layer to a Mapsui Style list /// </summary> /// <param name="context">Context to use while evaluating style</param> /// <param name="styleLayer">Mapbox GL style layer</param> /// <param name="spriteAtlas">Dictionary with availible sprites</param> /// <returns>A list of Mapsui Styles</returns> public IList <IStyle> Convert(EvaluationContext context, StyleLayer styleLayer, Dictionary <string, Styles.Sprite> spriteAtlas, SymbolProvider symbolProvider) { switch (styleLayer.Type) { case "fill": return(ConvertFillLayer(context, styleLayer, spriteAtlas)); case "line": return(ConvertLineLayer(context, styleLayer, spriteAtlas)); case "symbol": return(ConvertSymbolLayer(context, styleLayer, spriteAtlas, symbolProvider)); case "circle": return(new List <IStyle>()); case "raster": // Shouldn't get here, because raster are directly handled by ConvertRasterLayer break; case "background": return(new List <IStyle>()); } return(new List <IStyle>()); }
public MapboxGLThemeStyle(StyleLayerConverter converter, StyleLayer styleLayer, Dictionary <string, Styles.Sprite> sprites, Viewport viewport, SymbolProvider symbolProvider) { _converter = converter; _styleLayer = styleLayer; _sprites = sprites; _viewport = viewport; _symbolProvider = symbolProvider; // Do this only once if (_viewport != null) { _viewport.ViewportChanged += (s, e) => { Zoom = FromResolution(_viewport.Resolution); ZoomLevel = (int)Math.Floor(Zoom); } } ; }
public IStyle ConvertRasterLayer(float contextZoom, StyleLayer styleLayer) { // visibility // Optional enum. One of visible, none. Defaults to visible. // The display of this layer. none hides this layer. if (styleLayer.Layout?.Visibility != null && styleLayer.Layout.Visibility.Equals("none")) { return(null); } var paint = styleLayer.Paint; var styleRaster = new RasterStyle(); // raster-opacity // Optional number. Defaults to 1. // The opacity at which the image will be drawn. if (paint?.RasterOpacity != null) { styleRaster.Opacity = paint.RasterOpacity.Evaluate(contextZoom); } // raster-hue-rotate // Optional number. Units in degrees. Defaults to 0. // Rotates hues around the color wheel. // raster-brightness-min // Optional number.Defaults to 0. // Increase or reduce the brightness of the image. The value is the minimum brightness. // raster-brightness-max // Optional number. Defaults to 1. // Increase or reduce the brightness of the image. The value is the maximum brightness. // raster-saturation // Optional number.Defaults to 0. // Increase or reduce the saturation of the image. // raster-contrast // Optional number. Defaults to 0. // Increase or reduce the contrast of the image. // raster-fade-duration // Optional number.Units in milliseconds.Defaults to 300. // Fade duration when a new tile is added. return(styleRaster); }
private MGLVectorStyleLayer GetStyleLayer(StyleLayer styleLayer, NSString id) { if (string.IsNullOrEmpty(styleLayer.SourceId)) { return(null); } var sourceId = styleLayer.SourceId.ToCustomId(); var source = MapView.Style.SourceWithIdentifier(sourceId); if (source == null) { return(null); } if (styleLayer is CircleLayer circleLayer) { var newLayer = new MGLCircleStyleLayer(id, source) { CircleColor = MGLStyleValue.ValueWithRawValue(circleLayer.CircleColor.ToUIColor()), CircleOpacity = MGLStyleValue.ValueWithRawValue(NSNumber.FromDouble(circleLayer.CircleOpacity)), CircleRadius = MGLStyleValue.ValueWithRawValue(NSNumber.FromDouble(circleLayer.CircleRadius)) }; if (circleLayer.StrokeColor is Color strokeColor) { newLayer.CircleStrokeColor = MGLStyleValue.ValueWithRawValue(strokeColor.ToUIColor()); newLayer.CircleStrokeOpacity = MGLStyleValue.ValueWithRawValue(NSNumber.FromDouble(circleLayer.StrokeOpacity)); newLayer.CircleStrokeWidth = MGLStyleValue.ValueWithRawValue(NSNumber.FromDouble(circleLayer.StrokeWidth)); } return(newLayer); } if (styleLayer is LineLayer lineLayer) { var newLayer = new MGLLineStyleLayer(id, source) { LineWidth = MGLStyleValue.ValueWithRawValue(NSNumber.FromDouble(lineLayer.LineWidth)), LineColor = MGLStyleValue.ValueWithRawValue(lineLayer.LineColor.ToUIColor()) }; if (lineLayer.Dashes != null && lineLayer.Dashes.Length != 0) { var arr = new NSMutableArray <NSNumber>(); foreach (double dash in lineLayer.Dashes) { arr.Add(NSNumber.FromDouble(dash)); } newLayer.LineDashPattern = MGLStyleValue.ValueWithRawValue(arr); } //TODO lineCap return(newLayer); } if (styleLayer is FillLayer fl) { var newLayer = new MGLFillStyleLayer(id, source) { FillColor = MGLStyleValue.ValueWithRawValue(fl.FillColor.ToUIColor()), FillOpacity = MGLStyleValue.ValueWithRawValue(NSNumber.FromDouble(fl.FillOpacity)) }; return(newLayer); } if (styleLayer is SymbolLayer sl) { var newLayer = new MGLSymbolStyleLayer(id, source) { IconImageName = MGLConstantStyleValue.ValueWithRawValue((NSString)sl.IconImageName), IconOpacity = MGLStyleValue.ValueWithRawValue(NSNumber.FromDouble(sl.IconOpacity)) }; return(newLayer); } return(null); }
StyleLayer CreateStyleLayer(StyleLayer vectorLayer, string layerId = null) { return(null); }
public IList <IStyle> ConvertFillLayer(EvaluationContext context, StyleLayer styleLayer, Dictionary <string, Styles.Sprite> spriteAtlas) { // Height of building isn't used (that's what Point contains in tags here) if (context.Feature.GeometryType == GeometryType.Point) { return(null); } List <IStyle> result = new List <IStyle>(); // visibility // Optional enum. One of visible, none. Defaults to visible. // The display of this layer. none hides this layer. if (styleLayer.Layout?.Visibility != null && styleLayer.Layout.Visibility.Equals("none")) { return(result); } var paint = styleLayer.Paint; var styleVector = new VectorStyle(); var line = new Pen { Width = 1, PenStrokeCap = PenStrokeCap.Butt, }; // fill-color // Optional color. Defaults to #000000. Disabled by fill-pattern. Exponential. // The color of the filled part of this layer.This color can be specified as // rgba with an alpha component and the color's opacity will not affect the // opacity of the 1px stroke, if it is used. if (paint?.FillColor != null) { styleVector.Fill = new Styles.Brush(paint.FillColor.Evaluate(context.Zoom)) { FillStyle = FillStyle.Solid }; if (paint?.FillOutlineColor == null) { line.Color = styleVector.Fill.Color; } } // fill-outline-color // Optional color. Disabled by fill-pattern. Requires fill-antialias = true. Exponential. // The outline color of the fill. Matches the value of fill-color if unspecified. if (paint?.FillOutlineColor != null) // && paint.FillOutlineColor is string) { line.Color = paint.FillOutlineColor.Evaluate(context.Zoom); } // fill-opacity // Optional number. Defaults to 1. Exponential. // The opacity of the entire fill layer. In contrast to the fill-color, this // value will also affect the 1px stroke around the fill, if the stroke is used. if (paint?.FillOpacity != null) { var opacity = paint.FillOpacity; styleVector.Fill.Color = Color.Opacity(styleVector.Fill.Color, opacity); line.Color = Color.Opacity(line.Color, opacity); } // fill-antialias // Optional boolean. Defaults to true. Interval. // Whether or not the fill should be antialiased. // fill-translate // Optional array. Units in pixels. Defaults to 0,0. Exponential. // The geometry's offset. Values are [x, y] where negatives indicate left and up, // respectively. // fill-translate-anchor // Optional enum. One of map, viewport. Defaults to map. Requires fill-translate. Interval. // Control whether the translation is relative to the map (north) or viewport (screen) // fill-pattern // Optional string. Interval. // Name of image in sprite to use for drawing image fills. For seamless patterns, // image width and height must be a factor of two(2, 4, 8, …, 512). if (paint?.FillPattern != null) { var name = ReplaceFields(paint.FillPattern.Evaluate(context.Zoom), context.Feature.Tags); if (!string.IsNullOrEmpty(name) && spriteAtlas.ContainsKey(name) && spriteAtlas[name].Atlas >= 0) { styleVector.Fill.BitmapId = spriteAtlas[name].Atlas; } else { // No sprite found styleVector.Fill.BitmapId = -1; // Log information Logging.Logger.Log(Logging.LogLevel.Information, $"Fill pattern {name} not found"); } } if (context.Feature.GeometryType == GeometryType.Polygon) { styleVector.Outline = line; } else if (context.Feature.GeometryType == GeometryType.LineString) { styleVector.Line = line; } styleVector.Enabled = true; result.Add(styleVector); return(result); }
public IList <IStyle> ConvertSymbolLayer(EvaluationContext context, StyleLayer styleLayer, Dictionary <string, Styles.Sprite> spriteAtlas, SymbolProvider symbolProvider) { string styleLabelText = string.Empty; List <IStyle> result = new List <IStyle>(); if (context.Feature.GeometryType == GeometryType.LineString) { styleLabelText = ""; } //return result; // visibility // Optional enum. One of visible, none. Defaults to visible. // The display of this layer. none hides this layer. if (styleLayer.Layout?.Visibility != null && styleLayer.Layout.Visibility.Equals("none")) { return(result); } var paint = styleLayer.Paint; var layout = styleLayer.Layout; var styleLabel = new LabelStyle { Enabled = false, Halo = new Pen { Color = Color.Transparent, Width = 0 }, CollisionDetection = true, BackColor = null, }; styleLabel.Font.Size = 16; var styleSymbol = new SymbolStyle { Enabled = false, }; // symbol-placement // Optional enum. One of point, line. Defaults to point. Interval. // Label placement relative to its geometry. line can only be used on // LineStrings and Polygons. if (layout?.SymbolPlacement != null) { switch (layout.SymbolPlacement.Evaluate(context.Zoom)) { case "point": break; case "line": // symbol-spacing // Optional number. Units in pixels. Defaults to 250. Requires symbol-placement = line. Exponential. // Distance between two symbol anchors. if (layout?.SymbolSpacing != null) { styleLabel.Spacing = layout.SymbolSpacing.Evaluate(context.Zoom); } break; } } // symbol-avoid-edges // Optional boolean. Defaults to false. Interval. // If true, the symbols will not cross tile edges to avoid mutual collisions. // Recommended in layers that don't have enough padding in the vector tile to prevent // collisions, or if it is a point symbol layer placed after a line symbol layer. // text-field // Optional string. Interval. // Value to use for a text label. Feature properties are specified using tokens like {field_name}. if (layout?.TextField != null) { styleLabelText = ReplaceFields(layout.TextField.Trim(), context.Feature.Tags); // text-transform // Optional enum. One of none, uppercase, lowercase. Defaults to none. Requires text-field. Interval. // Specifies how to capitalize text, similar to the CSS text-transform property. if (layout?.TextTransform != null) { switch (layout.TextTransform) { case "uppercase": styleLabelText = styleLabelText.ToUpper(); break; case "lowercase": styleLabelText = styleLabelText.ToLower(); break; } } styleLabel.Text = styleLabelText; // text-color // Optional color. Defaults to #000000. Requires text-field. Exponential. // The color with which the text will be drawn. if (paint?.TextColor != null) { styleLabel.ForeColor = paint.TextColor.Evaluate(context.Zoom); } // text-opacity // Optional number. Defaults to 1. Requires text-field. Exponential. // The opacity at which the text will be drawn. if (paint?.TextOpacity != null) { } // text-halo-color // Optional color. Defaults to rgba(0, 0, 0, 0). Requires text-field. Exponential. // The color of the text's halo, which helps it stand out from backgrounds. if (paint?.TextHaloColor != null) { styleLabel.Halo.Color = paint.TextHaloColor.Evaluate(context.Zoom); } //text-halo-width // Optional number. Units in pixels. Defaults to 0. Requires text-field. Exponential. // Distance of halo to the font outline. Max text halo width is 1/4 of the font-size. if (paint?.TextHaloWidth != null) { styleLabel.Halo.Width = paint.TextHaloWidth.Evaluate(context.Zoom); } // text-font // Optional array. Defaults to Open Sans Regular, Arial Unicode MS Regular. Requires text-field. Interval. // Font stack to use for displaying text. if (layout?.TextFont != null) { var fontName = string.Empty; foreach (var font in layout.TextFont) { // TODO: Check for fonts //if (font.exists) { fontName = (string)font; break; } } if (!string.IsNullOrWhiteSpace(fontName)) { styleLabel.Font.FontFamily = fontName; } } // text-size // Optional number. Units in pixels. Defaults to 16. Requires text-field. Exponential. // Font size. if (layout?.TextSize != null) { styleLabel.Font.Size = layout.TextSize.Evaluate(context.Zoom); } // text-rotation-alignment // Optional enum. One of map, viewport. Defaults to viewport. Requires text-field. Interval. // Orientation of text when map is rotated. // text-translate // Optional array. Units in pixels. Defaults to 0, 0. Requires text-field. Exponential. // Distance that the text's anchor is moved from its original placement.Positive values // indicate right and down, while negative values indicate left and up. if (paint?.TextTranslate != null) { var offset = new Offset { X = paint.TextTranslate.Count > 0 ? -paint.TextTranslate[0] : 0, Y = paint.TextTranslate.Count > 1 ? -paint.TextTranslate[1] : 0 }; styleLabel.Offset = offset; // text-translate-anchor // Optional enum. One of map, viewport. Defaults to map. Requires text-field. Requires text-translate. Interval. // Control whether the translation is relative to the map(north) or viewport(screen). // TODO: Don't know, how to do this in the moment } // text-max-width // Optional number. Units in em. Defaults to 10. Requires text-field. Exponential. // The maximum line width for text wrapping. if (layout?.TextMaxWidth != null) { styleLabel.MaxWidth = layout.TextMaxWidth.Evaluate(context.Zoom); } // text-line-height // Optional number. Units in em. Defaults to 1.2. Requires text-field. Exponential. // Text leading value for multi-line text. // text-letter-spacing // Optional number. Units in em. Defaults to 0. Requires text-field. Exponential. // Text tracking amount. // text-justify // Optional enum. One of left, center, right. Defaults to center. Requires text-field. Interval. // Text justification options. if (layout?.TextJustify != null) { switch (layout.TextJustify) { case "left": styleLabel.Justify = LabelStyle.HorizontalAlignmentEnum.Left; break; case "right": styleLabel.Justify = LabelStyle.HorizontalAlignmentEnum.Right; break; default: styleLabel.Justify = LabelStyle.HorizontalAlignmentEnum.Center; break; } } // text-anchor // Optional enum. One of center, left, right, top, bottom, top-left, top-right, bottom-left, // bottom-right. Defaults to center. Requires text-field. Interval. // Part of the text placed closest to the anchor. if (layout?.TextAnchor != null) { switch (layout.TextAnchor) { case "left": styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Center; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Left; break; case "right": styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Center; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Right; break; case "top": styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Top; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center; break; case "bottom": styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Bottom; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center; break; case "top-left": styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Top; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Left; break; case "top-right": styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Top; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Right; break; case "bottom-left": styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Bottom; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Left; break; case "bottom-right": styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Bottom; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Right; break; default: styleLabel.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Center; styleLabel.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center; break; } } // text-max-angle // Optional number. Units in degrees. Defaults to 45. Requires text-field. // Requires symbol-placement = line. Exponential. // Maximum angle change between adjacent characters. // text-rotate // Optional number. Units in degrees. Defaults to 0. Requires text-field. Exponential. // Rotates the text clockwise. // text-padding // Optional number. Units in pixels. Defaults to 2. Requires text-field. Exponential. // Size of the additional area around the text bounding box used for detecting symbol collisions. // text-keep-upright // Optional boolean. Defaults to true. Requires text-field. Requires text-rotation-alignment = map. // Requires symbol-placement = line. Interval. // If true, the text may be flipped vertically to prevent it from being rendered upside-down. // text-offset // Optional array. Units in ems. Defaults to 0,0. Requires text-field. Exponential. // Offset distance of text from its anchor. Positive values indicate right and down, // while negative values indicate left and up. if (layout?.TextOffset != null) { var x = layout.TextOffset[0] * styleLabel.Font.Size; var y = layout.TextOffset[1] * styleLabel.Font.Size; styleLabel.Offset = new Offset(x, y, false); } // text-allow-overlap // Optional boolean. Defaults to false. Requires text-field. Interval. // If true, the text will be visible even if it collides with other previously drawn symbols. if (layout?.TextAllowOverlap != null) { // TODO layout.TextAllowOverlap.Evaluate(context.Zoom); } // text-ignore-placement // Optional boolean. Defaults to false. Requires text-field. Interval. // If true, other symbols can be visible even if they collide with the text. if (layout?.TextIgnorePlacement != null) { // TODO layout.TextIgnorePlacement.Evaluate(context.Zoom); } // text-optional // Optional boolean. Defaults to false. Requires text-field. Requires icon-image. Interval. // If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not. if (layout?.TextOptional != null) { // TODO layout.TextOptional.Evaluate(context.Zoom); } // text-halo-blur // Optional number. Units in pixels. Defaults to 0. Requires text-field. Exponential. // The halo's fadeout distance towards the outside. } // icon-image // Optional string. // A string with { tokens } replaced, referencing the data property to pull from. Interval. if (layout?.IconImage != null) { var name = ReplaceFields(layout.IconImage.Evaluate(context.Zoom), context.Feature.Tags); if (!string.IsNullOrEmpty(name) && spriteAtlas.ContainsKey(name) && spriteAtlas[name].Atlas >= 0) { styleSymbol.BitmapId = spriteAtlas[name].Atlas; } else { // No sprite found styleSymbol.BitmapId = -1; // Log information Logging.Logger.Log(Logging.LogLevel.Information, $"Sprite {name} not found"); } // icon-allow-overlap // Optional boolean. Defaults to false. Requires icon-image. Interval. // If true, the icon will be visible even if it collides with other previously drawn symbols. if (layout?.IconAllowOverlap != null) { // TODO layout.IconAllowOverlap.Evaluate(context.Zoom); } // icon-ignore-placement // Optional boolean. Defaults to false. Requires icon-image. Interval. // If true, other symbols can be visible even if they collide with the icon. if (layout?.IconIgnorePlacement != null) { // TODO layout.IconIgnorePlacement.Evaluate(context.Zoom); } // icon-optional // Optional boolean. Defaults to false. Requires icon-image. Requires text-field. Interval. // If true, text will display without their corresponding icons when the icon collides // with other symbols and the text does not. if (layout?.IconOptional != null) { // TODO layout.IconOptional.Evaluate(context.Zoom); } // icon-rotation-alignment // Optional enum. One of map, viewport. Defaults to viewport. Requires icon-image. Interval. // Orientation of icon when map is rotated. // icon-size // Optional number. Defaults to 1. Requires icon-image. Exponential. // Scale factor for icon. 1 is original size, 3 triples the size. if (layout?.IconSize != null) { styleSymbol.SymbolScale = layout.IconSize.Evaluate(context.Zoom); } // icon-rotate // Optional number. Units in degrees. Defaults to 0. Requires icon-image. Exponential. // Rotates the icon clockwise. // icon-padding // Optional number. Units in pixels. Defaults to 2. Requires icon-image. Exponential. // Size of the additional area around the icon bounding box used for detecting symbol collisions. // icon-keep-upright // Optional boolean. Defaults to false. Requires icon-image. Requires icon-rotation-alignment = map. Interval. // Requires symbol-placement = line. // If true, the icon may be flipped to prevent it from being rendered upside-down. // icon-offset // Optional array. Defaults to 0,0. Requires icon-image. Exponential. // Offset distance of icon from its anchor. Positive values indicate right and down, // while negative values indicate left and up. if (layout?.IconOffset != null) { var x = layout.IconOffset[0]; var y = layout.IconOffset[1]; styleSymbol.SymbolOffset = new Offset(x, y, false); } // icon-opacity // Optional number. Defaults to 1. Requires icon-image. Exponential. // The opacity at which the icon will be drawn. if (layout?.IconOpacity != null) { styleSymbol.Opacity = layout.IconOpacity.Evaluate(context.Zoom); } // icon-color // Optional color. Defaults to #000000. Requires icon-image. Exponential. // The color of the icon. This can only be used with sdf icons. // icon-halo-color // Optional color. Defaults to rgba(0, 0, 0, 0). Requires icon-image. Exponential. // The color of the icon's halo. Icon halos can only be used with sdf icons. // icon-halo-width // Optional number. Units in pixels. Defaults to 0. Requires icon-image. Exponential. // Distance of halo to the icon outline. // icon-halo-blur // Optional number. Units in pixels. Defaults to 0. Requires icon-image. Exponential. // Fade out the halo towards the outside. // icon-translate // Optional array. Units in pixels. Defaults to 0, 0. Requires icon-image. Exponential. // Distance that the icon's anchor is moved from its original placement. // Positive values indicate right and down, while negative values indicate left and up. // icon-translate-anchor // Optional enum. One of map, viewport. Defaults to map. Requires icon-image. Requires icon-translate. Interval. // Control whether the translation is relative to the map(north) or viewport(screen). } if (!string.IsNullOrEmpty(styleLabelText)) { styleLabel.Enabled = true; result.Add(styleLabel); } if (styleSymbol.BitmapId >= 0) { styleSymbol.Enabled = true; result.Add(styleSymbol); } if (symbolProvider != null) { symbolProvider.Symbols.Add(new Symbol { Feature = context.Feature, }); // If there is an SymbolLayer, than it handles drawing of symbols result = null; } return(result); }
public IList <IStyle> ConvertLineLayer(EvaluationContext context, StyleLayer styleLayer, Dictionary <string, Styles.Sprite> spriteAtlas) { List <IStyle> result = new List <IStyle>(); // visibility // Optional enum. One of visible, none. Defaults to visible. // The display of this layer. none hides this layer. if (styleLayer.Layout?.Visibility != null && styleLayer.Layout.Visibility.Equals("none")) { return(result); } var paint = styleLayer.Paint; var layout = styleLayer.Layout; var styleVector = new VectorStyle(); var line = new Pen { Width = 1, PenStrokeCap = PenStrokeCap.Butt, }; // line-cap // Optional enum. One of butt, round, square. Defaults to butt. Interval. // The display of line endings. if (layout?.LineCap != null) { switch (layout.LineCap) { case "butt": line.PenStrokeCap = PenStrokeCap.Butt; break; case "round": line.PenStrokeCap = PenStrokeCap.Round; break; case "square": line.PenStrokeCap = PenStrokeCap.Square; break; default: line.PenStrokeCap = PenStrokeCap.Butt; break; } } // line-join // Optional enum. One of bevel, round, miter. Defaults to miter. Interval. // The display of lines when joining. if (layout?.LineJoin != null) { switch (layout.LineJoin) { case "bevel": line.StrokeJoin = StrokeJoin.Bevel; break; case "round": line.StrokeJoin = StrokeJoin.Round; break; case "mitter": line.StrokeJoin = StrokeJoin.Miter; break; default: line.StrokeJoin = StrokeJoin.Miter; break; } } // line-color // Optional color. Defaults to #000000. Disabled by line-pattern. Exponential. // The color with which the line will be drawn. if (paint?.LineColor != null) { line.Color = paint.LineColor.Evaluate(context.Zoom); } // line-width // Optional number.Units in pixels.Defaults to 1. Exponential. // Stroke thickness. if (paint?.LineWidth != null) { line.Width = paint.LineWidth.Evaluate(context.Zoom); } // line-opacity // Optional number. Defaults to 1. Exponential. // The opacity at which the line will be drawn. if (paint?.LineOpacity != null) { line.Color = new Color(line.Color.R, line.Color.G, line.Color.B, (int)Math.Round(paint.LineOpacity.Evaluate(context.Zoom) * 255.0)); } // line-dasharray // Optional array. Units in line widths.Disabled by line-pattern. Interval. // Specifies the lengths of the alternating dashes and gaps that form the dash pattern. // The lengths are later scaled by the line width.To convert a dash length to pixels, // multiply the length by the current line width. if (paint?.LineDasharray != null) { if (paint.LineDasharray is JArray jsonDashArray) { var dashArray = new float[jsonDashArray.Count]; for (int i = 0; i < jsonDashArray.Count; i++) { dashArray[i] = jsonDashArray[i].Value <float>(); } line.PenStyle = PenStyle.UserDefined; line.DashArray = dashArray; } } // line-miter-limit // Optional number. Defaults to 2. Requires line-join = miter. Exponential. // Used to automatically convert miter joins to bevel joins for sharp angles. // line-round-limit // Optional number. Defaults to 1.05. Requires line-join = round. Exponential. // Used to automatically convert round joins to miter joins for shallow angles. // line-translate // Optional array. Units in pixels.Defaults to 0,0. Exponential. // The geometry's offset. Values are [x, y] where negatives indicate left and up, // respectively. // line-translate-anchor // Optional enum. One of map, viewport.Defaults to map. Requires line-translate. Interval. // Control whether the translation is relative to the map (north) or viewport (screen) // line-gap-width // Optional number.Units in pixels.Defaults to 0. Exponential. // Draws a line casing outside of a line's actual path.Value indicates the width of // the inner gap. // line-offset // Optional number. Units in pixels. Defaults to 0. Exponential. // The line's offset perpendicular to its direction. Values may be positive or negative, // where positive indicates "rightwards" (if you were moving in the direction of the line) // and negative indicates "leftwards". // line-blur // Optional number. Units in pixels.Defaults to 0. Exponential. // Blur applied to the line, in pixels. // line-pattern // Optional string. Interval. // Name of image in sprite to use for drawing image lines. For seamless patterns, image // width must be a factor of two (2, 4, 8, …, 512). if (context.Feature.GeometryType == GeometryType.Polygon) { styleVector.Outline = line; } else if (context.Feature.GeometryType == GeometryType.LineString) { styleVector.Line = line; } styleVector.Enabled = true; result.Add(styleVector); return(result); }