protected override void DrawScene(SKCanvas canvas, Func <Vector2d, Vector2f> ViewTransformF) { Random jitter = new Random(313377); Func <Vector2d> jitterF = () => { return(Vector2d.Zero); }; //{ return 0.1 * new Vector2d(jitter.NextDouble(), jitter.NextDouble()); }; canvas.Clear(SkiaUtil.Color(255, 255, 255, 255)); Func <Vector2d, SKPoint> SceneToSkiaF = (v) => { Vector2f p = ViewTransformF(v); return(new SKPoint(p.x, p.y)); }; using (var paint = new SKPaint()) { paint.IsAntialias = true; paint.StrokeWidth = 1; paint.Style = SKPaintStyle.Stroke; foreach (var g in GPolygons) { DrawPolygon(canvas, paint, g, SceneToSkiaF); } foreach (var g in Graphs) { DrawGraph(canvas, paint, g, SceneToSkiaF); } } }
public PathShape ToFillPathShape(IToolContext context, IBaseShape shape) { using (var geometry = ToPath(context, shape)) { if (geometry != null) { var style = context.DocumentContainer?.StyleLibrary?.Get(shape.StyleId); if (style == null) { style = context.DocumentContainer?.StyleLibrary?.CurrentItem; } using (var disposable = new CompositeDisposable()) { var path = SkiaUtil.ToFillPath(context, style.FillPaint, shape.Effects, geometry, disposable.Disposables); if (path != null) { disposable.Disposables.Add(path); var union = SkiaUtil.Op(SKPathOp.Union, new[] { path, path }); if (union != null && !union.IsEmpty) { disposable.Disposables.Add(union); return(SkiaUtil.ToPathShape(context, union, context.DocumentContainer?.StyleLibrary?.CurrentItem, context?.DocumentContainer?.PointTemplate)); } } } } } return(null); }
public void Import(IToolContext context, string path, IContainerView containerView) { try { var picture = SkiaUtil.ToSKPicture(path); if (picture != null) { var image = new ImageShape() { Points = new ObservableCollection <IPointShape>(), StartPoint = new PointShape(0.0, 0.0, context?.DocumentContainer?.PointTemplate), Point = new PointShape(picture.CullRect.Width, picture.CullRect.Height, context?.DocumentContainer?.PointTemplate), Path = path, StretchMode = StretchMode.Center, Text = new Text(), StyleId = context.DocumentContainer?.StyleLibrary?.CurrentItem?.Title, }; image.StartPoint.Owner = image; image.Point.Owner = image; picture.Dispose(); context.DocumentContainer?.ContainerView?.CurrentContainer.Shapes.Add(image); context.DocumentContainer?.ContainerView?.InputService?.Redraw?.Invoke(); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); System.Diagnostics.Debug.WriteLine(ex.StackTrace); } }
public void DrawSymbol(SvgSymbol svgSymbol, bool ignoreDisplay) { if (!CanDraw(svgSymbol, ignoreDisplay)) { return; } _skCanvas.Save(); float x = 0f; float y = 0f; float width = svgSymbol.ViewBox.Width; float height = svgSymbol.ViewBox.Height; if (svgSymbol.CustomAttributes.TryGetValue("width", out string?_widthString)) { if (new SvgUnitConverter().ConvertFrom(_widthString) is SvgUnit _width) { width = _width.ToDeviceValue(null, UnitRenderingType.Horizontal, svgSymbol); } } if (svgSymbol.CustomAttributes.TryGetValue("height", out string?heightString)) { if (new SvgUnitConverter().ConvertFrom(heightString) is SvgUnit _height) { height = _height.ToDeviceValue(null, UnitRenderingType.Vertical, svgSymbol); } } var skRectBounds = SKRect.Create(x, y, width, height); var skMatrixViewBox = SkiaUtil.GetSvgViewBoxTransform(svgSymbol.ViewBox, svgSymbol.AspectRatio, x, y, width, height); var skMatrix = SkiaUtil.GetSKMatrix(svgSymbol.Transforms); SKMatrix.PreConcat(ref skMatrix, ref skMatrixViewBox); SetTransform(skMatrix); SetClipPath(svgSymbol, _disposable); var skPaintOpacity = SetOpacity(svgSymbol, _disposable); var skPaintFilter = SetFilter(svgSymbol, _disposable); foreach (var svgElement in svgSymbol.Children) { Draw(svgElement, ignoreDisplay); } if (skPaintFilter != null) { _skCanvas.Restore(); } if (skPaintOpacity != null) { _skCanvas.Restore(); } _skCanvas.Restore(); }
private IList <SKPath> ToPaths(IToolContext context, IList <IBaseShape> shapes) { if (shapes == null || shapes.Count <= 0) { return(null); } var paths = new List <SKPath>(); for (int i = 0; i < shapes.Count; i++) { var fillType = SKPathFillType.Winding; if (shapes[i] is PathShape pathShape) { fillType = SkiaUtil.ToSKPathFillType(pathShape.FillType); } var path = new SKPath() { FillType = fillType }; var result = SkiaUtil.AddShape(context, shapes[i], 0.0, 0.0, path); if (result == true && path.IsEmpty == false) { paths.Add(path); } else { path.Dispose(); } } return(paths); }
public void DrawForeignObject(SvgForeignObject svgForeignObject, bool ignoreDisplay) { if (!CanDraw(svgForeignObject, ignoreDisplay)) { return; } _skCanvas.Save(); var skMatrix = SkiaUtil.GetSKMatrix(svgForeignObject.Transforms); SetTransform(skMatrix); SetClipPath(svgForeignObject, _disposable); var skPaintOpacity = SetOpacity(svgForeignObject, _disposable); var skPaintFilter = SetFilter(svgForeignObject, _disposable); // TODO: if (skPaintFilter != null) { _skCanvas.Restore(); } if (skPaintOpacity != null) { _skCanvas.Restore(); } _skCanvas.Restore(); }
private SKPath ToPath(IToolContext context, IBaseShape shape) { var fillType = SKPathFillType.Winding; if (shape is PathShape pathShape) { fillType = SkiaUtil.ToSKPathFillType(pathShape.FillType); } var geometry = new SKPath() { FillType = fillType }; if (SkiaUtil.AddShape(context, shape, 0.0, 0.0, geometry) == true) { return(geometry); } else { geometry.Dispose(); } return(null); }
public PathShape Op(IToolContext context, PathOp op, ICollection <IBaseShape> selected) { var path = default(PathShape); var shapes = GetShapes(selected); if (shapes != null && shapes.Count > 0) { var paths = ToPaths(context, shapes); if (paths != null && paths.Count > 0) { var result = SkiaUtil.Op(SkiaUtil.ToSKPathOp(op), paths); if (result != null) { if (!result.IsEmpty) { var style = context.DocumentContainer?.StyleLibrary?.Get(shapes[0].StyleId); if (style == null) { style = context.DocumentContainer?.StyleLibrary?.CurrentItem; } path = SkiaUtil.ToPathShape(context, result, style, context?.DocumentContainer?.PointTemplate); } result.Dispose(); } for (int i = 0; i < paths.Count; i++) { paths[i].Dispose(); } } } return(path); }
public List <PolyLine2d> GetPolylinesForLayer(int layer) { ToolpathSet pathSetIn = Paths; SKColor extrudeColor = SkiaUtil.Color(0, 0, 0, 255); Interval1d layer_zrange = Layers.GetLayerZInterval(layer); List <PolyLine2d> polylines = new List <PolyLine2d>(); Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { Vector3d v0 = polyPath.Start.Position; if (layer_zrange.Contains(v0.z) == false) { return; } if (polyPath.Type != ToolpathTypes.Deposition) { return; } PolyLine2d pline = new PolyLine2d(); for (int i = 0; i < polyPath.VertexCount; ++i) { pline.AppendVertex(polyPath[i].Position.xy); } polylines.Add(pline); }; ProcessLinearPaths(pathSetIn, drawPath3F); return(polylines); }
protected override void DrawScene(SKCanvas canvas, Func <Vector2d, Vector2f> ViewTransformF) { Random jitter = new Random(313377); Func <Vector2d> jitterF = () => { return(Vector2d.Zero); }; //{ return 0.1 * new Vector2d(jitter.NextDouble(), jitter.NextDouble()); }; canvas.Clear(SkiaUtil.Color(255, 255, 255, 255)); // update scene xform SceneXFormF = (pOrig) => { pOrig += jitterF(); return(ViewTransformF(pOrig)); }; // figure out dimension scaling factor Vector2f a = SceneXFormF(Vector2d.Zero), b = SceneXFormF(Vector2d.AxisX); dimensionScale = (b.x - a.x); using (var paint = new SKPaint()) { paint.IsAntialias = true; paint.StrokeWidth = 1; paint.Style = SKPaintStyle.Stroke; if (Slices != null) { DrawLayerSlice(Slices, canvas, paint); } if (ShowDepositMoves) { DrawLayerPaths(Paths, canvas, paint); } if (ShowFillArea) { //DrawFill(Paths, canvas); DrawFillOverlaps(Paths, canvas); //DrawFillOverlapsIntegrate(Paths, canvas); } if (ShowAllPathPoints) { DrawLayerPoints(Paths, canvas, paint); } if (NumberMode == NumberModes.PathNumbers) { DrawPathLabels(Paths, canvas, paint); } DrawLayerInfo(canvas, paint); } }
public PathShape ToPathShape(IToolContext context, string svgPathData) { if (!string.IsNullOrWhiteSpace(svgPathData)) { using var path = SkiaUtil.ToPath(svgPathData); return(SkiaUtil.ToPathShape(context, path, context.DocumentContainer?.StyleLibrary?.CurrentItem, context?.DocumentContainer?.PointTemplate)); } return(null); }
public void DrawText(object dc, TextShape text, string styleId, double dx, double dy, double scale) { var geometry = new SKPath() { FillType = SKPathFillType.Winding }; SkiaUtil.AddText(null, text, dx, dy, geometry); _rootNodes[_currentRootNode].Children.Add(new ChildNode(text, styleId, dx, dy, scale, geometry)); }
internal void SetClipPath(SvgVisualElement svgVisualElement, CompositeDisposable disposable) { var skPathClip = SkiaUtil.GetSvgVisualElementClipPath(svgVisualElement, disposable); if (skPathClip != null && !skPathClip.IsEmpty) { bool antialias = SkiaUtil.IsAntialias(svgVisualElement); _skCanvas.ClipPath(skPathClip, SKClipOperation.Intersect, antialias); } }
public void Draw(object context, double width, double height, double dx, double dy, double zx, double zy, double renderScaling) { using var renderer = new SkiaShapeRenderer(_context, _view, _view.SelectionState); using var disposable = new CompositeDisposable(); using var background = SkiaUtil.ToSKPaint(_view.PrintBackground, null, zx, disposable.Disposables); var canvas = context as SKCanvas; canvas.DrawRect(SkiaUtil.ToSKRect(dx, dy, _view.Width + dx, _view.Height + dy), background); _view.CurrentContainer.Draw(canvas, renderer, dx, dy, zx, null, null); }
public void DrawArc(object dc, ArcShape arc, string styleId, double dx, double dy, double scale) { var geometry = new SKPath() { FillType = SKPathFillType.Winding }; SkiaUtil.AddArc(null, arc, dx, dy, geometry); _rootNodes[_currentRootNode].Children.Add(new ChildNode(arc, styleId, dx, dy, scale, geometry)); }
public void DrawCircle(object dc, CircleShape circle, string styleId, double dx, double dy, double scale) { var geometry = new SKPath() { FillType = SKPathFillType.Winding }; SkiaUtil.AddCircle(null, circle, dx, dy, geometry); _rootNodes[_currentRootNode].Children.Add(new ChildNode(circle, styleId, dx, dy, scale, geometry)); }
public void DrawPath(object dc, PathShape path, string styleId, double dx, double dy, double scale) { var geometry = new SKPath() { FillType = SkiaUtil.ToSKPathFillType(path.FillType) }; SkiaUtil.AddPath(null, path, dx, dy, geometry); _rootNodes[_currentRootNode].Children.Add(new ChildNode(path, styleId, dx, dy, scale, geometry)); }
public void DrawQuadraticBezier(object dc, QuadraticBezierShape quadraticBezier, string styleId, double dx, double dy, double scale) { var geometry = new SKPath() { FillType = SKPathFillType.Winding }; SkiaUtil.AddQuad(null, quadraticBezier, dx, dy, geometry); _rootNodes[_currentRootNode].Children.Add(new ChildNode(quadraticBezier, styleId, dx, dy, scale, geometry)); }
public void DrawOval(object dc, OvalShape oval, string styleId, double dx, double dy, double scale) { var geometry = new SKPath() { FillType = SKPathFillType.Winding }; SkiaUtil.AddOval(null, oval, dx, dy, geometry); _rootNodes[_currentRootNode].Children.Add(new ChildNode(oval, styleId, dx, dy, scale, geometry)); }
internal void DrawMarkers(SvgMarkerElement svgMarkerElement, SKPath sKPath) { var pathTypes = SkiaUtil.GetPathTypes(sKPath); var pathLength = pathTypes.Count; if (svgMarkerElement.MarkerStart != null) { var refPoint1 = pathTypes[0].Point; var index = 1; while (index < pathLength && pathTypes[index].Point == refPoint1) { ++index; } var refPoint2 = pathTypes[index].Point; var marker = svgMarkerElement.OwnerDocument.GetElementById <SvgMarker>(svgMarkerElement.MarkerStart.ToString()); DrawMarker(marker, svgMarkerElement, refPoint1, refPoint1, refPoint2, true); } if (svgMarkerElement.MarkerMid != null) { var marker = svgMarkerElement.OwnerDocument.GetElementById <SvgMarker>(svgMarkerElement.MarkerMid.ToString()); int bezierIndex = -1; for (int i = 1; i <= pathLength - 2; i++) { // for Bezier curves, the marker shall only been shown at the last point if ((pathTypes[i].Type & (byte)PathPointType.PathTypeMask) == (byte)PathPointType.Bezier) { bezierIndex = (bezierIndex + 1) % 3; } else { bezierIndex = -1; } if (bezierIndex == -1 || bezierIndex == 2) { DrawMarker(marker, svgMarkerElement, pathTypes[i].Point, pathTypes[i - 1].Point, pathTypes[i].Point, pathTypes[i + 1].Point); } } } if (svgMarkerElement.MarkerEnd != null) { var marker = svgMarkerElement.OwnerDocument.GetElementById <SvgMarker>(svgMarkerElement.MarkerEnd.ToString()); var index = pathLength - 1; var refPoint1 = pathTypes[index].Point; --index; while (index > 0 && pathTypes[index].Point == refPoint1) { --index; } var refPoint2 = pathTypes[index].Point; DrawMarker(marker, svgMarkerElement, refPoint1, refPoint2, pathTypes[pathLength - 1].Point, false); } }
public void DrawEllipse(SvgEllipse svgEllipse, bool ignoreDisplay) { if (!CanDraw(svgEllipse, ignoreDisplay)) { return; } float cx = svgEllipse.CenterX.ToDeviceValue(null, UnitRenderingType.Horizontal, svgEllipse); float cy = svgEllipse.CenterY.ToDeviceValue(null, UnitRenderingType.Vertical, svgEllipse); float rx = svgEllipse.RadiusX.ToDeviceValue(null, UnitRenderingType.Other, svgEllipse); float ry = svgEllipse.RadiusY.ToDeviceValue(null, UnitRenderingType.Other, svgEllipse); if (rx <= 0f || ry <= 0f) { return; } var skRectBounds = SKRect.Create(cx - rx, cy - ry, rx + rx, ry + ry); _skCanvas.Save(); var skMatrix = SkiaUtil.GetSKMatrix(svgEllipse.Transforms); SetTransform(skMatrix); SetClipPath(svgEllipse, _disposable); var skPaintOpacity = SetOpacity(svgEllipse, _disposable); var skPaintFilter = SetFilter(svgEllipse, _disposable); if (SkiaUtil.IsValidFill(svgEllipse)) { var skPaintFill = SkiaUtil.GetFillSKPaint(svgEllipse, _skSize, skRectBounds, _disposable); _skCanvas.DrawOval(cx, cy, rx, ry, skPaintFill); } if (SkiaUtil.IsValidStroke(svgEllipse)) { var skPaintStroke = SkiaUtil.GetStrokeSKPaint(svgEllipse, _skSize, skRectBounds, _disposable); _skCanvas.DrawOval(cx, cy, rx, ry, skPaintStroke); } if (skPaintFilter != null) { _skCanvas.Restore(); } if (skPaintOpacity != null) { _skCanvas.Restore(); } _skCanvas.Restore(); }
private void DrawFill(ToolpathSet pathSetIn, SKCanvas baseCanvas) { SKColor fillColor = SkiaUtil.Color(255, 0, 255, 255); SKRect bounds = baseCanvas.LocalClipBounds; SKBitmap blitBitmap = new SKBitmap(PixelDimensions.x, PixelDimensions.y, SkiaUtil.ColorType(), SKAlphaType.Premul); IntPtr len; using (var skSurface = SKSurface.Create(blitBitmap.Info.Width, blitBitmap.Info.Height, SkiaUtil.ColorType(), SKAlphaType.Premul, blitBitmap.GetPixels(out len), blitBitmap.Info.RowBytes)) { var canvas = skSurface.Canvas; canvas.Clear(SkiaUtil.Color(255, 255, 255, 255)); using (var paint = new SKPaint()) { paint.IsAntialias = true; paint.StrokeWidth = dimensionScale * PathDiameterMM; paint.Style = SKPaintStyle.Stroke; paint.StrokeCap = SKStrokeCap.Round; paint.StrokeJoin = SKStrokeJoin.Round; paint.Color = fillColor; Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { if (polyPath.Type != ToolpathTypes.Deposition) { return; } Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha != 255) { return; } SKPath path = MakePath(polyPath, SceneToSkiaF); canvas.DrawPath(path, paint); }; ProcessLinearPaths(pathSetIn, drawPath3F); } } SKPaint blitPaint = new SKPaint(); blitPaint.IsAntialias = false; blitPaint.BlendMode = SKBlendMode.SrcOver; blitPaint.Color = SkiaUtil.Color(0, 0, 0, 64); baseCanvas.DrawBitmap(blitBitmap, 0, 0, blitPaint); blitPaint.Dispose(); blitBitmap.Dispose(); }
internal SKPaint?SetFilter(SvgVisualElement svgVisualElement, CompositeDisposable disposable) { if (svgVisualElement.Filter != null) { var skPaint = new SKPaint(); skPaint.Style = SKPaintStyle.StrokeAndFill; SkiaUtil.SetFilter(svgVisualElement, skPaint, disposable); _skCanvas.SaveLayer(skPaint); disposable.Add(skPaint); return(skPaint); } return(null); }
internal SKPicture Load(SvgFragment svgFragment) { var skSize = SkiaUtil.GetDimensions(svgFragment); var cullRect = SKRect.Create(skSize); using (var skPictureRecorder = new SKPictureRecorder()) using (var skCanvas = skPictureRecorder.BeginRecording(cullRect)) using (var renderer = new SKSvgRenderer(skCanvas, skSize)) { renderer.DrawFragment(svgFragment, false); return(skPictureRecorder.EndRecording()); } }
public void DrawPolygon(SvgPolygon svgPolygon, bool ignoreDisplay) { if (!CanDraw(svgPolygon, ignoreDisplay)) { return; } _skCanvas.Save(); var skMatrix = SkiaUtil.GetSKMatrix(svgPolygon.Transforms); SetTransform(skMatrix); SetClipPath(svgPolygon, _disposable); var skPaintOpacity = SetOpacity(svgPolygon, _disposable); var skPaintFilter = SetFilter(svgPolygon, _disposable); var skPath = SkiaUtil.ToSKPath(svgPolygon.Points, svgPolygon.FillRule, true, _disposable); if (skPath != null && !skPath.IsEmpty) { var skBounds = skPath.Bounds; if (SkiaUtil.IsValidFill(svgPolygon)) { var skPaint = SkiaUtil.GetFillSKPaint(svgPolygon, _skSize, skBounds, _disposable); _skCanvas.DrawPath(skPath, skPaint); } if (SkiaUtil.IsValidStroke(svgPolygon)) { var skPaint = SkiaUtil.GetStrokeSKPaint(svgPolygon, _skSize, skBounds, _disposable); _skCanvas.DrawPath(skPath, skPaint); } DrawMarkers(svgPolygon, skPath); } if (skPaintFilter != null) { _skCanvas.Restore(); } if (skPaintOpacity != null) { _skCanvas.Restore(); } _skCanvas.Restore(); }
public string ToSvgPathData(IToolContext context, ICollection <IBaseShape> selected) { var sb = new StringBuilder(); var shapes = GetShapes(selected); if (shapes != null && shapes.Count > 0) { foreach (var shape in shapes) { SkiaUtil.ToSvgPathData(context, shape, sb); } } return(sb.ToString()); }
private void GetSKPaintFill(IPaint fillPaint, IPaintEffects effects, double scale, out SKPaint brush) { if (fillPaint.IsTreeDirty() || !_paintCache.TryGetValue(fillPaint, out var brushCached)) { fillPaint.Invalidate(); brushCached = SkiaUtil.ToSKPaint(fillPaint, effects, scale, _disposable.Disposables); _paintCache[fillPaint] = brushCached; } else { SkiaUtil.ToSKPaintUpdate(brushCached, fillPaint, effects, scale, _disposable.Disposables); } brush = brushCached; }
public PathShape ToPathShape(IToolContext context, IBaseShape shape) { using (var geometry = ToPath(context, shape)) { if (geometry != null) { var style = context.DocumentContainer?.StyleLibrary?.Get(shape.StyleId); if (style == null) { style = context.DocumentContainer?.StyleLibrary?.CurrentItem; } return(SkiaUtil.ToPathShape(context, geometry, style, context?.DocumentContainer?.PointTemplate)); } } return(null); }
/// <summary> /// Point of this function is to be same as DrawFill (ie draw 'tubes') but to draw /// in such a way that overlap regions are highlighted. However it does not work yet, /// need to draw continuous SKPaths as much as possible but break at direction changes. /// </summary> private void DrawFillOverlapsIntegrate(ToolpathSet pathSetIn, SKCanvas baseCanvas) { SKColor fillColor = SkiaUtil.Color(255, 0, 255, 5); float path_diam = dimensionScale * PathDiameterMM; float spot_r = path_diam * 0.5f; float spacing = 1.0f / dimensionScale; using (var paint = new SKPaint()) { paint.IsAntialias = true; paint.StrokeWidth = 1.0f; paint.Style = SKPaintStyle.Fill; paint.Color = fillColor; Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { if (polyPath.Type != ToolpathTypes.Deposition) { return; } Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha != 255) { return; } // draw each segment separately. results in lots of duplicate-circles, no good for (int i = 1; i < polyPath.VertexCount; i++) { Vector2d a = polyPath[i - 1].Position.xy; Vector2d b = polyPath[i].Position.xy; double len = a.Distance(b); int n = (int)(len / spacing) + 1; int stop = (i == polyPath.VertexCount - 1) ? n : n - 1; for (int k = 0; k <= stop; ++k) { double t = (double)k / (double)n; Vector2d p = Vector2d.Lerp(a, b, t); SKPoint pk = SceneToSkiaF(p); baseCanvas.DrawCircle(pk.X, pk.Y, spot_r, paint); } } }; ProcessLinearPaths(pathSetIn, drawPath3F); } }
/// <summary> /// Point of this function is to be same as DrawFill (ie draw 'tubes') but to draw /// in such a way that overlap regions are highlighted. However it does not work yet, /// need to draw continuous SKPaths as much as possible but break at direction changes. /// </summary> private void DrawFillOverlaps(ToolpathSet pathSetIn, SKCanvas baseCanvas) { SKColor fillColor = SkiaUtil.Color(255, 0, 255, 64); using (var paint = new SKPaint()) { paint.IsAntialias = true; paint.StrokeWidth = dimensionScale * PathDiameterMM; paint.Style = SKPaintStyle.Stroke; paint.StrokeCap = SKStrokeCap.Round; paint.StrokeJoin = SKStrokeJoin.Round; paint.Color = fillColor; Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { if (polyPath.Type != ToolpathTypes.Deposition) { return; } Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha != 255) { return; } // draw each segment separately. results in lots of duplicate-circles, no good //for (int i = 1; i < polyPath.VertexCount; i++) { // SKPoint a = SceneToSkiaF(polyPath[i - 1].Position.xy); // SKPoint b = SceneToSkiaF(polyPath[i].Position.xy); // baseCanvas.DrawLine(a.X, a.Y, b.X, b.Y, paint); //} // draw full path in one shot. Only shows overlaps between separate paths. //SKPath path = MakePath(polyPath, SceneToSkiaF); //baseCanvas.DrawPath(path, paint); // draw w/ angle threshold List <SKPath> paths = MakePathSegments(polyPath, SceneToSkiaF, 45); foreach (var path in paths) { baseCanvas.DrawPath(path, paint); } }; ProcessLinearPaths(pathSetIn, drawPath3F); } }