Browse Source

VectorPath, Matrix3X3 and more wip

flabbet 2 years ago
parent
commit
b2f0280988
100 changed files with 1038 additions and 38 deletions
  1. 1 0
      src/ChunkyImageLib/Chunk.cs
  2. 1 0
      src/ChunkyImageLib/ChunkyImage.cs
  3. 1 0
      src/ChunkyImageLib/ChunkyImageEx.cs
  4. 1 0
      src/ChunkyImageLib/CommittedChunkStorage.cs
  5. 3 1
      src/ChunkyImageLib/DataHolders/ShapeCorners.cs
  6. 2 1
      src/ChunkyImageLib/DataHolders/ShapeData.cs
  7. 1 0
      src/ChunkyImageLib/IReadOnlyChunkyImage.cs
  8. 1 0
      src/ChunkyImageLib/Operations/BresenhamLineHelper.cs
  9. 1 0
      src/ChunkyImageLib/Operations/BresenhamLineOperation.cs
  10. 1 0
      src/ChunkyImageLib/Operations/ChunkyImageOperation.cs
  11. 1 0
      src/ChunkyImageLib/Operations/ClearPathOperation.cs
  12. 1 0
      src/ChunkyImageLib/Operations/ClearRegionOperation.cs
  13. 1 0
      src/ChunkyImageLib/Operations/EllipseHelper.cs
  14. 1 0
      src/ChunkyImageLib/Operations/EllipseOperation.cs
  15. 1 0
      src/ChunkyImageLib/Operations/IDrawOperation.cs
  16. 1 0
      src/ChunkyImageLib/Operations/ImageOperation.cs
  17. 1 0
      src/ChunkyImageLib/Operations/OperationHelper.cs
  18. 13 9
      src/ChunkyImageLib/Operations/PathOperation.cs
  19. 1 0
      src/ChunkyImageLib/Operations/PixelOperation.cs
  20. 1 0
      src/ChunkyImageLib/Operations/PixelsOperation.cs
  21. 1 0
      src/ChunkyImageLib/Operations/RectangleOperation.cs
  22. 1 0
      src/ChunkyImageLib/Operations/ReplaceColorOperation.cs
  23. 1 0
      src/ChunkyImageLib/Operations/ResizeOperation.cs
  24. 1 0
      src/ChunkyImageLib/Operations/SkiaLineOperation.cs
  25. 1 0
      src/ChunkyImageLib/Surface.cs
  26. 1 0
      src/ChunkyImageLibTest/ChunkyImageTests.cs
  27. 1 0
      src/ChunkyImageLibTest/ClearRegionOperationTests.cs
  28. 1 0
      src/ChunkyImageLibTest/ImageOperationTests.cs
  29. 1 0
      src/ChunkyImageLibTest/OperationHelperTests.cs
  30. 1 0
      src/ChunkyImageLibTest/RectITests.cs
  31. 1 0
      src/ChunkyImageLibTest/RectangleOperationTests.cs
  32. 1 0
      src/ChunkyImageLibVis/MainWindow.xaml.cs
  33. 3 1
      src/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/LayerImageChunks_ChangeInfo.cs
  34. 3 1
      src/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/MaskChunks_ChangeInfo.cs
  35. 3 1
      src/PixiEditor.ChangeableDocument/ChangeInfos/Root/Size_ChangeInfo.cs
  36. 1 0
      src/PixiEditor.ChangeableDocument/Changeables/Document.cs
  37. 1 0
      src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyDocument.cs
  38. 1 0
      src/PixiEditor.ChangeableDocument/Changeables/Layer.cs
  39. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Drawing/ApplyLayerMask_Change.cs
  40. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/ChangeBrightness_UpdateableChange.cs
  41. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/ClearSelectedArea_Change.cs
  42. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Drawing/CombineStructureMembersOnto_Change.cs
  43. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawEllipse_UpdateableChange.cs
  44. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawLine_UpdateableChange.cs
  45. 3 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawRectangle_UpdateableChange.cs
  46. 3 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawingChangeHelper.cs
  47. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillChunkCache.cs
  48. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillHelper.cs
  49. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFill_Change.cs
  50. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/LineBasedPen_UpdateableChange.cs
  51. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/PasteImage_UpdateableChange.cs
  52. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/PathBasedPen_UpdateableChange.cs
  53. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Drawing/PixelPerfectPen_UpdateableChange.cs
  54. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/ReplaceColor_Change.cs
  55. 3 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/ShiftLayer_UpdateableChange.cs
  56. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelectedArea_UpdateableChange.cs
  57. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Root/ResizeCanvas_Change.cs
  58. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Root/ResizeImage_Change.cs
  59. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Selection/SelectEllipse_UpdateableChange.cs
  60. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Selection/SelectLasso_UpdateableChange.cs
  61. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Selection/SelectRectangle_UpdateableChange.cs
  62. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Selection/SelectionChangeHelper.cs
  63. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Selection/TransformSelectionPath_UpdateableChange.cs
  64. 3 1
      src/PixiEditor.ChangeableDocument/Enums/ResizeAnchorEx.cs
  65. 1 0
      src/PixiEditor.ChangeableDocument/Rendering/ChunkRenderer.cs
  66. 4 1
      src/PixiEditor.DrawingApi.Core/Bridge/IDrawingBackend.cs
  67. 9 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IMatrix3x3Implementation.cs
  68. 24 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IVectorPathImplementation.cs
  69. 8 1
      src/PixiEditor.DrawingApi.Core/Bridge/Operations/ICanvasOperations.cs
  70. 705 0
      src/PixiEditor.DrawingApi.Core/Numerics/Matrix3X3.cs
  71. 3 2
      src/PixiEditor.DrawingApi.Core/Numerics/RectD.cs
  72. 3 2
      src/PixiEditor.DrawingApi.Core/Numerics/RectI.cs
  73. 3 2
      src/PixiEditor.DrawingApi.Core/Numerics/VecD.cs
  74. 3 2
      src/PixiEditor.DrawingApi.Core/Numerics/VecI.cs
  75. 28 0
      src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs
  76. 14 0
      src/PixiEditor.DrawingApi.Core/Surface/NativeObject.cs
  77. 14 0
      src/PixiEditor.DrawingApi.Core/Surface/Vector/PathConvexity.cs
  78. 17 0
      src/PixiEditor.DrawingApi.Core/Surface/Vector/PathFillType.cs
  79. 19 0
      src/PixiEditor.DrawingApi.Core/Surface/Vector/PathSegmentMask.cs
  80. 60 0
      src/PixiEditor.DrawingApi.Core/Surface/Vector/VectorPath.cs
  81. 1 0
      src/PixiEditor.Zoombox/Operations/ManipulationOperation.cs
  82. 1 0
      src/PixiEditor.Zoombox/Operations/MoveDragOperation.cs
  83. 1 0
      src/PixiEditor.Zoombox/Operations/RotateDragOperation.cs
  84. 1 0
      src/PixiEditor.Zoombox/Operations/ZoomDragOperation.cs
  85. 1 0
      src/PixiEditor.Zoombox/ViewportRoutedEventArgs.cs
  86. 1 0
      src/PixiEditor.Zoombox/Zoombox.xaml.cs
  87. 1 0
      src/PixiEditor/Helpers/DocumentViewModelBuilder.cs
  88. 1 0
      src/PixiEditor/Helpers/SurfaceHelpers.cs
  89. 1 0
      src/PixiEditor/Models/Controllers/ClipboardController.cs
  90. 1 0
      src/PixiEditor/Models/Controllers/MouseInputFilter.cs
  91. 1 0
      src/PixiEditor/Models/DataHolders/DocumentSizeChangedEventArgs.cs
  92. 1 0
      src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs
  93. 1 0
      src/PixiEditor/Models/DocumentModels/ChangeExecutionController.cs
  94. 1 0
      src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs
  95. 1 0
      src/PixiEditor/Models/DocumentModels/Public/DocumentEventsModule.cs
  96. 1 0
      src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs
  97. 1 0
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/BrightnessToolExecutor.cs
  98. 1 0
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EllipseToolExecutor.cs
  99. 1 0
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs
  100. 1 0
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/FloodFillToolExecutor.cs

+ 1 - 0
src/ChunkyImageLib/Chunk.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.PixelE;
 

+ 1 - 0
src/ChunkyImageLib/ChunkyImage.cs

@@ -4,6 +4,7 @@ using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
 using OneOf;
 using OneOf.Types;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 [assembly: InternalsVisibleTo("ChunkyImageLibTest")]

+ 1 - 0
src/ChunkyImageLib/ChunkyImageEx.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib;

+ 1 - 0
src/ChunkyImageLib/CommittedChunkStorage.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib;

+ 3 - 1
src/ChunkyImageLib/DataHolders/ShapeCorners.cs

@@ -1,4 +1,6 @@
-namespace ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace ChunkyImageLib.DataHolders;
 public struct ShapeCorners
 {
     public ShapeCorners(VecD center, VecD size)

+ 2 - 1
src/ChunkyImageLib/DataHolders/ShapeData.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace ChunkyImageLib.DataHolders;
 

+ 1 - 0
src/ChunkyImageLib/IReadOnlyChunkyImage.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib;

+ 1 - 0
src/ChunkyImageLib/Operations/BresenhamLineHelper.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/BresenhamLineOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/ChunkyImageOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/ClearPathOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/ClearRegionOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/EllipseHelper.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace ChunkyImageLib.Operations;
 public class EllipseHelper

+ 1 - 0
src/ChunkyImageLib/Operations/EllipseOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/IDrawOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace ChunkyImageLib.Operations;
 

+ 1 - 0
src/ChunkyImageLib/Operations/ImageOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/OperationHelper.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 13 - 9
src/ChunkyImageLib/Operations/PathOperation.cs

@@ -1,28 +1,32 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;
 internal class PathOperation : IDrawOperation
 {
-    private readonly SKPath path;
+    private readonly VectorPath path;
 
-    private readonly SKPaint paint;
+    private readonly Paint paint;
     private readonly RectI bounds;
 
     public bool IgnoreEmptyChunks => false;
 
-    public PathOperation(SKPath path, SKColor color, float strokeWidth, SKStrokeCap cap, SKBlendMode blendMode, RectI? customBounds = null)
+    public PathOperation(VectorPath path, Color color, float strokeWidth, StrokeCap cap, BlendMode blendMode, RectI? customBounds = null)
     {
-        this.path = new SKPath(path);
-        paint = new() { Color = color, Style = SKPaintStyle.Stroke, StrokeWidth = strokeWidth, StrokeCap = cap, BlendMode = blendMode };
+        this.path = new VectorPath(path);
+        paint = new() { Color = color, Style = PaintStyle.Stroke, StrokeWidth = strokeWidth, StrokeCap = cap, BlendMode = blendMode };
 
-        RectI floatBounds = customBounds ?? (RectI)((RectD)path.TightBounds).RoundOutwards();
+        RectI floatBounds = customBounds ?? (RectI)(path.TightBounds).RoundOutwards();
         bounds = floatBounds.Inflate((int)Math.Ceiling(strokeWidth) + 1);
     }
 
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     {
-        paint.IsAntialias = chunk.Resolution != ChunkResolution.Full;
+        paint.IsAntiAliased = chunk.Resolution != ChunkResolution.Full;
         var surf = chunk.Surface.DrawingSurface;
         surf.Canvas.Save();
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
@@ -38,8 +42,8 @@ internal class PathOperation : IDrawOperation
 
     public IDrawOperation AsMirrored(int? verAxisX, int? horAxisY)
     {
-        var matrix = SKMatrix.CreateScale(verAxisX is not null ? -1 : 1, horAxisY is not null ? -1 : 1, verAxisX ?? 0, horAxisY ?? 0);
-        using var copy = new SKPath(path);
+        var matrix = Matrix3X3.CreateScale(verAxisX is not null ? -1 : 1, horAxisY is not null ? -1 : 1, verAxisX ?? 0, horAxisY ?? 0);
+        using var copy = new VectorPath(path);
         copy.Transform(matrix);
 
         RectI newBounds = bounds;

+ 1 - 0
src/ChunkyImageLib/Operations/PixelOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/PixelsOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/RectangleOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/ReplaceColorOperation.cs

@@ -8,6 +8,7 @@ using System.Threading.Tasks;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Shaders;
 using ComputeSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Operations/ResizeOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace ChunkyImageLib.Operations;
 

+ 1 - 0
src/ChunkyImageLib/Operations/SkiaLineOperation.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace ChunkyImageLib.Operations;

+ 1 - 0
src/ChunkyImageLib/Surface.cs

@@ -2,6 +2,7 @@
 using System.Runtime.InteropServices;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.PixelE;
 using SkiaSharp;

+ 1 - 0
src/ChunkyImageLibTest/ChunkyImageTests.cs

@@ -2,6 +2,7 @@
 using System.IO;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 using Xunit;
 

+ 1 - 0
src/ChunkyImageLibTest/ClearRegionOperationTests.cs

@@ -2,6 +2,7 @@
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.Numerics;
 using Xunit;
 
 namespace ChunkyImageLibTest;

+ 1 - 0
src/ChunkyImageLibTest/ImageOperationTests.cs

@@ -2,6 +2,7 @@
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.Numerics;
 using Xunit;
 
 namespace ChunkyImageLibTest;

+ 1 - 0
src/ChunkyImageLibTest/OperationHelperTests.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.Numerics;
 using Xunit;
 
 namespace ChunkyImageLibTest;

+ 1 - 0
src/ChunkyImageLibTest/RectITests.cs

@@ -1,5 +1,6 @@
 using System;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using Xunit;
 
 namespace ChunkyImageLibTest;

+ 1 - 0
src/ChunkyImageLibTest/RectangleOperationTests.cs

@@ -2,6 +2,7 @@
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 using Xunit;
 

+ 1 - 0
src/ChunkyImageLibVis/MainWindow.xaml.cs

@@ -8,6 +8,7 @@ using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Shapes;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace ChunkyImageLibVis;
 

+ 3 - 1
src/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/LayerImageChunks_ChangeInfo.cs

@@ -1,3 +1,5 @@
-namespace PixiEditor.ChangeableDocument.ChangeInfos.Drawing;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.ChangeInfos.Drawing;
 
 public record class LayerImageChunks_ChangeInfo(Guid GuidValue, HashSet<VecI> Chunks) : IChangeInfo;

+ 3 - 1
src/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/MaskChunks_ChangeInfo.cs

@@ -1,3 +1,5 @@
-namespace PixiEditor.ChangeableDocument.ChangeInfos.Drawing;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.ChangeInfos.Drawing;
 
 public record class MaskChunks_ChangeInfo(Guid GuidValue, HashSet<VecI> Chunks) : IChangeInfo;

+ 3 - 1
src/PixiEditor.ChangeableDocument/ChangeInfos/Root/Size_ChangeInfo.cs

@@ -1,3 +1,5 @@
-namespace PixiEditor.ChangeableDocument.ChangeInfos.Root;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.ChangeInfos.Root;
 
 public record class Size_ChangeInfo(VecI Size, int VerticalSymmetryAxisX, int HorizontalSymmetryAxisY) : IChangeInfo;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Document.cs

@@ -1,6 +1,7 @@
 using System.Collections.Immutable;
 using System.Diagnostics.CodeAnalysis;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changeables;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyDocument.cs

@@ -1,5 +1,6 @@
 using System.Collections.Immutable;
 using System.Diagnostics.CodeAnalysis;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Layer.cs

@@ -1,4 +1,5 @@
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changeables;
 

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/ApplyLayerMask_Change.cs

@@ -1,4 +1,5 @@
 using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class ApplyLayerMask_Change : Change

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/ChangeBrightness_UpdateableChange.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/ClearSelectedArea_Change.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class ClearSelectedArea_Change : Change

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/CombineStructureMembersOnto_Change.cs

@@ -1,4 +1,5 @@
 using PixiEditor.ChangeableDocument.Rendering;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawEllipse_UpdateableChange.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class DrawEllipse_UpdateableChange : UpdateableChange

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawLine_UpdateableChange.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 

+ 3 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawRectangle_UpdateableChange.cs

@@ -1,4 +1,6 @@
-namespace PixiEditor.ChangeableDocument.Changes.Drawing;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 
 internal class DrawRectangle_UpdateableChange : UpdateableChange
 {

+ 3 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawingChangeHelper.cs

@@ -1,4 +1,6 @@
-namespace PixiEditor.ChangeableDocument.Changes.Drawing;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal static class DrawingChangeHelper
 {
     public static HashSet<VecI> ApplyStoredChunksDisposeAndSetToNull(Document target, Guid memberGuid, bool drawOnMask, ref CommittedChunkStorage? storage)

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillChunkCache.cs

@@ -1,5 +1,6 @@
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing.FloodFill;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillHelper.cs

@@ -3,6 +3,7 @@ using ChunkyImageLib.Operations;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using SkiaSharp;
 using ChunkyImageLib;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing.FloodFill;
 

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFill_Change.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing.FloodFill;
 

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/LineBasedPen_UpdateableChange.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class LineBasedPen_UpdateableChange : UpdateableChange

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/PasteImage_UpdateableChange.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class PasteImage_UpdateableChange : UpdateableChange

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/PathBasedPen_UpdateableChange.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class PathBasedPen_UpdateableChange : UpdateableChange

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/PixelPerfectPen_UpdateableChange.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/ReplaceColor_Change.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class ReplaceColor_Change : Change

+ 3 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/ShiftLayer_UpdateableChange.cs

@@ -1,4 +1,6 @@
-namespace PixiEditor.ChangeableDocument.Changes.Drawing;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class ShiftLayer_UpdateableChange : UpdateableChange
 {
     private readonly Guid layerGuid;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelectedArea_UpdateableChange.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.Operations;
 using PixiEditor.ChangeableDocument.Changes.Selection;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Root/ResizeCanvas_Change.cs

@@ -1,5 +1,6 @@
 using PixiEditor.ChangeableDocument.ChangeInfos.Root;
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Root;
 

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Root/ResizeImage_Change.cs

@@ -1,5 +1,6 @@
 using PixiEditor.ChangeableDocument.ChangeInfos.Root;
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Root;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Selection/SelectEllipse_UpdateableChange.cs

@@ -1,4 +1,5 @@
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Selection/SelectLasso_UpdateableChange.cs

@@ -1,4 +1,5 @@
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Selection/SelectRectangle_UpdateableChange.cs

@@ -1,4 +1,5 @@
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Selection/SelectionChangeHelper.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Selection/TransformSelectionPath_UpdateableChange.cs

@@ -1,4 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;
 internal class TransformSelectionPath_UpdateableChange : UpdateableChange

+ 3 - 1
src/PixiEditor.ChangeableDocument/Enums/ResizeAnchorEx.cs

@@ -1,4 +1,6 @@
-namespace PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Enums;
 
 internal static class ResizeAnchorEx
 {

+ 1 - 0
src/PixiEditor.ChangeableDocument/Rendering/ChunkRenderer.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.Operations;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Rendering;

+ 4 - 1
src/PixiEditor.DrawingApi.Core/Bridge/IDrawingBackend.cs

@@ -1,4 +1,5 @@
-using PixiEditor.DrawingApi.Core.Bridge.Operations;
+using PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+using PixiEditor.DrawingApi.Core.Bridge.Operations;
 
 namespace PixiEditor.DrawingApi.Core.Bridge
 {
@@ -9,5 +10,7 @@ namespace PixiEditor.DrawingApi.Core.Bridge
         public IImageOperations ImageOperations { get; }
         public ICanvasOperations CanvasOperations { get; }
         public IPaintOperations PaintOperations { get; set; }
+        public IVectorPathImplementation PathImplementation { get; set; }
+        public IMatrix3X3Implementation MatrixImplementation { get; set; }
     }
 }

+ 9 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IMatrix3x3Implementation.cs

@@ -0,0 +1,9 @@
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+
+public interface IMatrix3X3Implementation
+{
+    public bool TryInvert(Matrix3X3 matrix, out Matrix3X3 inversedResult);
+    public Matrix3X3 Concat(in Matrix3X3 first, in Matrix3X3 second);
+}

+ 24 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IVectorPathImplementation.cs

@@ -0,0 +1,24 @@
+using System;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
+
+namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+
+public interface IVectorPathImplementation
+{
+    public PathFillType GetFillType(VectorPath path);
+    public void SetFillType(VectorPath path, PathFillType fillType);
+    public PathConvexity GetConvexity(VectorPath path);
+    public void SetConvexity(VectorPath path, PathConvexity convexity);
+    public void Dispose(VectorPath path);
+    public bool IsPathOval(VectorPath path);
+    public bool IsRoundRect(VectorPath path);
+    public bool IsLine(VectorPath path);
+    public bool IsRect(VectorPath path);
+    public PathSegmentMask GetSegmentMasks(VectorPath path);
+    public int GetVerbCount(VectorPath path);
+    public int GetPointCount(VectorPath path);
+    public IntPtr Create();
+    public IntPtr Clone(VectorPath other);
+    public RectD GetTightBounds(VectorPath vectorPath);
+}

+ 8 - 1
src/PixiEditor.DrawingApi.Core/Bridge/Operations/ICanvasOperations.cs

@@ -1,4 +1,6 @@
-using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 
 namespace PixiEditor.DrawingApi.Core.Bridge.Operations
 {
@@ -7,5 +9,10 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
         public void DrawPixel(int posX, int posY, Paint drawingPaint);
         public void DrawSurface(DrawingSurface drawingSurface, int x, int y);
         public void DrawImage(Image image, int x, int y);
+        public int Save();
+        public void Restore();
+        public void Scale(float multiplier);
+        public void Translate(VecI vector);
+        public void DrawPath(VectorPath path, Paint paint);
     }
 }

+ 705 - 0
src/PixiEditor.DrawingApi.Core/Numerics/Matrix3X3.cs

@@ -0,0 +1,705 @@
+using System;
+using System.ComponentModel;
+using PixiEditor.DrawingApi.Core.Bridge;
+using SkiaSharp;
+
+namespace PixiEditor.DrawingApi.Core.Numerics;
+
+/// <summary>A 3x3 transformation matrix with perspective.</summary>
+/// <remarks>
+///     It extends the traditional 2D affine transformation matrix with three perspective components that allow simple
+///     3D effects to be created with it. Those components must be manually set by using the
+///     <see cref="P:SkiaSharp.Matrix3x3.Persp0" />, <see cref="P:SkiaSharp.Matrix3x3.Persp1" />,
+///     <see cref="P:SkiaSharp.Matrix3x3.Persp2" /> fields of the matrix.
+/// </remarks>
+public struct Matrix3X3 : IEquatable<Matrix3X3>
+{
+    internal const float DegreesToRadians = 0.017453292f;
+
+    public static readonly Matrix3X3 Identity = new() { ScaleX = 1f, ScaleY = 1f, Persp2 = 1f };
+    
+    public static readonly Matrix3X3 Empty = default;
+
+    /// <summary>Gets or sets the scaling in the x-direction.</summary>
+    /// <value />
+    public float ScaleX { get; set; }
+
+    /// <summary>Gets or sets the skew in the x-direction.</summary>
+    /// <value />
+    public float SkewX { get; set; }
+
+    /// <summary>Get or sets the translation in the x-direction.</summary>
+    /// <value />
+    public float TransX { get; set; }
+
+    /// <summary>Gets or sets the skew in the y-direction.</summary>
+    /// <value />
+    public float SkewY { get; set; }
+
+    /// <summary>Gets or sets the scaling in the y-direction.</summary>
+    /// <value />
+    public float ScaleY { get; set; }
+
+    /// <summary>Get or sets the translation in the y-direction.</summary>
+    /// <value />
+    public float TransY { get; set; }
+
+    /// <summary>Gets or sets the x-perspective.</summary>
+    /// <value />
+    public float Persp0 { get; set; }
+
+    /// <summary>Gets or sets the y-perspective.</summary>
+    /// <value />
+    public float Persp1 { get; set; }
+
+    /// <summary>Gets or sets the z-perspective.</summary>
+    /// <value />
+    public float Persp2 { get; set; }
+
+    public readonly bool Equals(Matrix3X3 obj)
+    {
+        return ScaleX == (double)obj.ScaleX && SkewX == (double)obj.SkewX &&
+               TransX == (double)obj.TransX && SkewY == (double)obj.SkewY &&
+               ScaleY == (double)obj.ScaleY && TransY == (double)obj.TransY &&
+               Persp0 == (double)obj.Persp0 && Persp1 == (double)obj.Persp1 &&
+               Persp2 == (double)obj.Persp2;
+    }
+
+    public override readonly bool Equals(object obj)
+    {
+        return obj is Matrix3X3 Matrix3x3 && Equals(Matrix3x3);
+    }
+
+    public static bool operator ==(Matrix3X3 left, Matrix3X3 right)
+    {
+        return left.Equals(right);
+    }
+
+    public static bool operator !=(Matrix3X3 left, Matrix3X3 right)
+    {
+        return !left.Equals(right);
+    }
+
+    public override readonly int GetHashCode()
+    {
+        var hashCode = new HashCode();
+        hashCode.Add(ScaleX);
+        hashCode.Add(SkewX);
+        hashCode.Add(TransX);
+        hashCode.Add(SkewY);
+        hashCode.Add(ScaleY);
+        hashCode.Add(TransY);
+        hashCode.Add(Persp0);
+        hashCode.Add(Persp1);
+        hashCode.Add(Persp2);
+        return hashCode.ToHashCode();
+    }
+
+    public Matrix3X3(float[] values)
+    {
+        if (values == null)
+        {
+            throw new ArgumentNullException(nameof(values));
+        }
+
+        ScaleX = values.Length == 9
+            ? values[0]
+            : throw new ArgumentException(string.Format("The matrix array must have a length of {0}.", 9),
+                nameof(values));
+        SkewX = values[1];
+        TransX = values[2];
+        SkewY = values[3];
+        ScaleY = values[4];
+        TransY = values[5];
+        Persp0 = values[6];
+        Persp1 = values[7];
+        Persp2 = values[8];
+    }
+
+    public Matrix3X3(
+        float scaleX,
+        float skewX,
+        float transX,
+        float skewY,
+        float scaleY,
+        float transY,
+        float persp0,
+        float persp1,
+        float persp2)
+    {
+        ScaleX = scaleX;
+        SkewX = skewX;
+        TransX = transX;
+        SkewY = skewY;
+        ScaleY = scaleY;
+        TransY = transY;
+        Persp0 = persp0;
+        Persp1 = persp1;
+        Persp2 = persp2;
+    }
+    
+    public readonly bool IsIdentity => Equals(Identity);
+
+    /// <summary>
+    ///     Gets or sets the matrix as a flat array: [ScaleX, SkewX, TransX, SkewY, ScaleY, TransY, Persp0, Persp1,
+    ///     Persp2].
+    /// </summary>
+    /// <value />
+    public float[] Values
+    {
+        readonly get => new float[9] {ScaleX, SkewX, TransX, SkewY, ScaleY, TransY, Persp0, Persp1, Persp2};
+        set
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(nameof(Values));
+            }
+
+            ScaleX = value.Length == 9
+                ? value[0]
+                : throw new ArgumentException(string.Format("The matrix array must have a length of {0}.", 9),
+                    nameof(Values));
+            SkewX = value[1];
+            TransX = value[2];
+            SkewY = value[3];
+            ScaleY = value[4];
+            TransY = value[5];
+            Persp0 = value[6];
+            Persp1 = value[7];
+            Persp2 = value[8];
+        }
+    }
+
+    /// <param name="values">The array to populate.</param>
+    /// <summary>Populates the specified array with the matrix values.</summary>
+    /// <remarks>The result will be the same as <see cref="P:SkiaSharp.Matrix3x3.Values" />.</remarks>
+    public readonly void GetValues(float[] values)
+    {
+        if (values == null)
+        {
+            throw new ArgumentNullException(nameof(values));
+        }
+
+        if (values.Length != 9)
+        {
+            throw new ArgumentException(string.Format("The matrix array must have a length of {0}.", 9),
+                nameof(values));
+        }
+
+        values[0] = ScaleX;
+        values[1] = SkewX;
+        values[2] = TransX;
+        values[3] = SkewY;
+        values[4] = ScaleY;
+        values[5] = TransY;
+        values[6] = Persp0;
+        values[7] = Persp1;
+        values[8] = Persp2;
+    }
+
+    public static Matrix3X3 CreateIdentity()
+    {
+        return new Matrix3X3() {ScaleX = 1f, ScaleY = 1f, Persp2 = 1f};
+    }
+
+    public static Matrix3X3 CreateTranslation(float x, float y)
+    {
+        if (x == 0.0 && y == 0.0)
+        {
+            return Identity;
+        }
+
+        return new Matrix3X3
+        {
+            ScaleX = 1f,
+            ScaleY = 1f,
+            TransX = x,
+            TransY = y,
+            Persp2 = 1f
+        };
+    }
+    
+    public static Matrix3X3 CreateScale(float x, float y)
+    {
+        if (x == 1.0 && y == 1.0)
+        {
+            return Identity;
+        }
+
+        return new Matrix3X3 {ScaleX = x, ScaleY = y, Persp2 = 1f};
+    }
+    
+    public static Matrix3X3 CreateScale(float x, float y, float pivotX, float pivotY)
+    {
+        if (x == 1.0 && y == 1.0)
+        {
+            return Identity;
+        }
+
+        var num1 = pivotX - (x * pivotX);
+        var num2 = pivotY - (y * pivotY);
+        return new Matrix3X3
+        {
+            ScaleX = x,
+            ScaleY = y,
+            TransX = num1,
+            TransY = num2,
+            Persp2 = 1f
+        };
+    }
+    
+    public static Matrix3X3 CreateRotation(float radians)
+    {
+        if (radians == 0.0)
+        {
+            return Identity;
+        }
+
+        var sin = (float)Math.Sin(radians);
+        var cos = (float)Math.Cos(radians);
+        var identity = Identity;
+        SetSinCos(ref identity, sin, cos);
+        return identity;
+    }
+    
+    public static Matrix3X3 CreateRotation(float radians, float pivotX, float pivotY)
+    {
+        if (radians == 0.0)
+        {
+            return Identity;
+        }
+
+        var sin = (float)Math.Sin(radians);
+        var cos = (float)Math.Cos(radians);
+        var identity = Identity;
+        SetSinCos(ref identity, sin, cos, pivotX, pivotY);
+        return identity;
+    }
+
+
+    public static Matrix3X3 CreateRotationDegrees(float degrees)
+    {
+        return degrees == 0.0 ? Identity : CreateRotation(degrees * ((float)Math.PI / 180f));
+    }
+    
+    public static Matrix3X3 CreateRotationDegrees(float degrees, float pivotX, float pivotY)
+    {
+        return degrees == 0.0 ? Identity : CreateRotation(degrees * ((float)Math.PI / 180f), pivotX, pivotY);
+    }
+    
+    public static Matrix3X3 CreateSkew(float x, float y)
+    {
+        if (x == 0.0 && y == 0.0)
+        {
+            return Identity;
+        }
+
+        return new Matrix3X3
+        {
+            ScaleX = 1f,
+            SkewX = x,
+            SkewY = y,
+            ScaleY = 1f,
+            Persp2 = 1f
+        };
+    }
+    
+    public static Matrix3X3 CreateScaleTranslation(float sx, float sy, float tx, float ty)
+    {
+        if (sx == 0.0 && sy == 0.0 && tx == 0.0 && ty == 0.0)
+        {
+            return Identity;
+        }
+
+        return new Matrix3X3
+        {
+            ScaleX = sx,
+            SkewX = 0.0f,
+            TransX = tx,
+            SkewY = 0.0f,
+            ScaleY = sy,
+            TransY = ty,
+            Persp0 = 0.0f,
+            Persp1 = 0.0f,
+            Persp2 = 1f
+        };
+    }
+
+    public readonly bool IsInvertible => TryInvert(out _);
+
+    /// <param name="inverse">The destination value to store the inverted matrix if the matrix can be inverted.</param>
+    /// <summary>Attempts to invert the matrix, if possible the inverse matrix contains the result.</summary>
+    /// <returns>
+    ///     True if the matrix can be inverted, and the inverse parameter is initialized with the inverted matrix, false
+    ///     otherwise.
+    /// </returns>
+    public readonly bool TryInvert(out Matrix3X3 inverse)
+    {
+        return DrawingBackendApi.Current.MatrixImplementation.TryInvert(this, out inverse);
+    }
+    
+    public readonly Matrix3X3 Invert() => TryInvert(out var inverse) ? inverse : Matrix3X3.Empty;
+
+    public static Matrix3X3 Concat(Matrix3X3 first, Matrix3X3 second)
+    {
+        return DrawingBackendApi.Current.MatrixImplementation.Concat(in first, in second);
+    }
+    
+    public readonly unsafe Matrix3X3 PreConcat(Matrix3X3 matrix)
+    {
+        var Matrix3x3 = this;
+        SkiaApi.sk_matrix_pre_concat(&Matrix3x3, &matrix);
+        return Matrix3x3;
+    }
+    
+    public readonly unsafe Matrix3X3 PostConcat(Matrix3X3 matrix)
+    {
+        var Matrix3x3 = this;
+        SkiaApi.sk_matrix_post_concat(&Matrix3x3, &matrix);
+        return Matrix3x3;
+    }
+
+    /// <param name="target">The result matrix value.</param>
+    /// <param name="first">The first matrix to concatenate.</param>
+    /// <param name="second">The second matrix to concatenate.</param>
+    /// <summary>Concatenates the specified matrices into the resulting target matrix.</summary>
+    /// <remarks>Either source matrices can also be the target matrix.</remarks>
+    public static unsafe void Concat(ref Matrix3X3 target, Matrix3X3 first, Matrix3X3 second)
+    {
+        fixed (Matrix3X3* result = &target)
+        {
+            SkiaApi.sk_matrix_concat(result, &first, &second);
+        }
+    }
+
+    /// <param name="target">The result matrix value.</param>
+    /// <param name="first">The first matrix to concatenate.</param>
+    /// <param name="second">The second matrix to concatenate.</param>
+    /// <summary>Concatenates the specified matrices into the resulting target matrix.</summary>
+    /// <remarks>Either source matrices can also be the target matrix.</remarks>
+    public static unsafe void Concat(ref Matrix3X3 target, ref Matrix3X3 first, ref Matrix3X3 second)
+    {
+        fixed (Matrix3X3* result = &target)
+        fixed (Matrix3X3* first1 = &first)
+        fixed (Matrix3X3* second1 = &second)
+        {
+            SkiaApi.sk_matrix_concat(result, first1, second1);
+        }
+    }
+
+    /// <param name="target">The target matrix.</param>
+    /// <param name="matrix">The matrix to be post-concatenated.</param>
+    /// <summary>Pre-concatenates the matrix to the target matrix.</summary>
+    /// <remarks>This represents: result = target * matrix</remarks>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    [Obsolete("Use PreConcat(Matrix3x3) instead.")]
+    public static unsafe void PreConcat(ref Matrix3X3 target, Matrix3X3 matrix)
+    {
+        fixed (Matrix3X3* result = &target)
+        {
+            SkiaApi.sk_matrix_pre_concat(result, &matrix);
+        }
+    }
+
+    /// <param name="target">The target matrix.</param>
+    /// <param name="matrix">The matrix to be post-concatenated.</param>
+    /// <summary>Pre-concatenates the matrix to the target matrix.</summary>
+    /// <remarks>This represents: result = target * matrix</remarks>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    [Obsolete("Use PreConcat(Matrix3x3) instead.")]
+    public static unsafe void PreConcat(ref Matrix3X3 target, ref Matrix3X3 matrix)
+    {
+        fixed (Matrix3X3* result = &target)
+        fixed (Matrix3X3* matrix1 = &matrix)
+        {
+            SkiaApi.sk_matrix_pre_concat(result, matrix1);
+        }
+    }
+
+    /// <param name="target">The target matrix.</param>
+    /// <param name="matrix">The matrix to be post-concatenated.</param>
+    /// <summary>Post-concatenates the matrix to the target matrix.</summary>
+    /// <remarks>This represents: result = matrix * target</remarks>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    [Obsolete("Use PostConcat(Matrix3x3) instead.")]
+    public static unsafe void PostConcat(ref Matrix3X3 target, Matrix3X3 matrix)
+    {
+        fixed (Matrix3X3* result = &target)
+        {
+            SkiaApi.sk_matrix_post_concat(result, &matrix);
+        }
+    }
+
+    /// <param name="target">The target matrix.</param>
+    /// <param name="matrix">The matrix to be post-concatenated.</param>
+    /// <summary>Post-concatenates the matrix to the target matrix.</summary>
+    /// <remarks>This represents: result = matrix * target</remarks>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    [Obsolete("Use PostConcat(Matrix3x3) instead.")]
+    public static unsafe void PostConcat(ref Matrix3X3 target, ref Matrix3X3 matrix)
+    {
+        fixed (Matrix3X3* result = &target)
+        fixed (Matrix3X3* matrix1 = &matrix)
+        {
+            SkiaApi.sk_matrix_post_concat(result, matrix1);
+        }
+    }
+
+    /// <param name="source">The source rectangle to map.</param>
+    /// <summary>Applies the matrix to a rectangle.</summary>
+    /// <returns>Returns the mapped rectangle.</returns>
+    /// <remarks />
+    public readonly unsafe SKRect MapRect(SKRect source)
+    {
+        SKRect skRect;
+        fixed (Matrix3X3* matrix = &this)
+        {
+            SkiaApi.sk_matrix_map_rect(matrix, &skRect, &source);
+        }
+
+        return skRect;
+    }
+
+    /// <param name="matrix">The transformation matrix.</param>
+    /// <param name="dest">The mapped rectangle.</param>
+    /// <param name="source">The source rectangle to map.</param>
+    /// <summary>Applies the matrix to a rectangle.</summary>
+    /// <remarks />
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    [Obsolete("Use MapRect(SKRect) instead.")]
+    public static unsafe void MapRect(ref Matrix3X3 matrix, out SKRect dest, ref SKRect source)
+    {
+        fixed (Matrix3X3* matrix1 = &matrix)
+        fixed (SKRect* dest1 = &dest)
+        fixed (SKRect* source1 = &source)
+        {
+            SkiaApi.sk_matrix_map_rect(matrix1, dest1, source1);
+        }
+    }
+
+    /// <param name="point">The point to map.</param>
+    /// <summary>Applies the matrix to a point.</summary>
+    /// <returns>Returns the mapped point.</returns>
+    /// <remarks>
+    ///     Mapping points uses all components of the matrix. Use
+    ///     <see cref="M:SkiaSharp.Matrix3x3.MapVector(System.Single,System.Single)" /> to ignore the translation.
+    /// </remarks>
+    public readonly SKPoint MapPoint(SKPoint point)
+    {
+        return MapPoint(point.X, point.Y);
+    }
+
+    /// <param name="x">The x-coordinate.</param>
+    /// <param name="y">The y-coordinate.</param>
+    /// <summary>Applies the matrix to a point.</summary>
+    /// <returns>Returns the mapped point.</returns>
+    /// <remarks>
+    ///     Mapping points uses all components of the matrix. Use
+    ///     <see cref="M:SkiaSharp.Matrix3x3.MapVector(System.Single,System.Single)" /> to ignore the translation.
+    /// </remarks>
+    public readonly unsafe SKPoint MapPoint(float x, float y)
+    {
+        SKPoint skPoint;
+        fixed (Matrix3X3* matrix = &this)
+        {
+            SkiaApi.sk_matrix_map_xy(matrix, x, y, &skPoint);
+        }
+
+        return skPoint;
+    }
+
+    /// <param name="result">
+    ///     The array where the mapped results will be stored (needs to have the same number of elements of
+    ///     the <paramref name="points" /> array).
+    /// </param>
+    /// <param name="points">The array of points to be mapped.</param>
+    /// <summary>Applies the matrix to an array of points.</summary>
+    /// <remarks>
+    ///     Mapping points uses all components of the matrix. Use
+    ///     <see cref="M:SkiaSharp.Matrix3x3.MapVectors(SkiaSharp.SKPoint[],SkiaSharp.SKPoint[])" /> to ignore the translation.
+    /// </remarks>
+    public readonly unsafe void MapPoints(SKPoint[] result, SKPoint[] points)
+    {
+        if (result == null)
+        {
+            throw new ArgumentNullException(nameof(result));
+        }
+
+        if (points == null)
+        {
+            throw new ArgumentNullException(nameof(points));
+        }
+
+        if (result.Length != points.Length)
+        {
+            throw new ArgumentException("Buffers must be the same size.");
+        }
+
+        fixed (Matrix3X3* matrix = &this)
+        fixed (SKPoint* dst = result)
+        fixed (SKPoint* src = points)
+        {
+            SkiaApi.sk_matrix_map_points(matrix, dst, src, result.Length);
+        }
+    }
+
+    /// <param name="points">The array of points to be mapped.</param>
+    /// <summary>Applies the matrix to an array of points.</summary>
+    /// <returns>Returns the new array allocated with the mapped results.</returns>
+    /// <remarks>
+    ///     Mapping points uses all components of the matrix. Use
+    ///     <see cref="M:SkiaSharp.Matrix3x3.MapVectors(SkiaSharp.SKPoint[])" /> to ignore the translation.
+    /// </remarks>
+    public readonly SKPoint[] MapPoints(SKPoint[] points)
+    {
+        var result = points != null ? new SKPoint[points.Length] : throw new ArgumentNullException(nameof(points));
+        MapPoints(result, points);
+        return result;
+    }
+
+    /// <param name="vector">To be added.</param>
+    /// <summary>To be added.</summary>
+    /// <returns>To be added.</returns>
+    /// <remarks>To be added.</remarks>
+    public readonly SKPoint MapVector(SKPoint vector)
+    {
+        return MapVector(vector.X, vector.Y);
+    }
+
+    /// <param name="x">The x-component of the vector.</param>
+    /// <param name="y">The y-component of the vector.</param>
+    /// <summary>Applies the matrix to a vector, ignoring translation.</summary>
+    /// <returns>Returns the mapped point.</returns>
+    /// <remarks>
+    ///     Mapping vectors ignores the translation component in the matrix. Use
+    ///     <see cref="M:SkiaSharp.Matrix3x3.MapXY(System.Single,System.Single)" /> to take the translation into consideration.
+    /// </remarks>
+    public readonly unsafe SKPoint MapVector(float x, float y)
+    {
+        SKPoint skPoint;
+        fixed (Matrix3X3* matrix = &this)
+        {
+            SkiaApi.sk_matrix_map_vector(matrix, x, y, &skPoint);
+        }
+
+        return skPoint;
+    }
+
+    /// <param name="result">
+    ///     The array where the mapped results will be stored (needs to have the same number of elements of
+    ///     the <paramref name="vectors" /> array).
+    /// </param>
+    /// <param name="vectors">The array of vectors to map.</param>
+    /// <summary>Apply the to the array of vectors and return the mapped results..</summary>
+    /// <remarks>
+    ///     Mapping vectors ignores the translation component in the matrix. Use
+    ///     <see cref="M:SkiaSharp.Matrix3x3.MapPoints(SkiaSharp.SKPoint[],SkiaSharp.SKPoint[])" /> to take the translation
+    ///     into consideration.
+    /// </remarks>
+    public readonly unsafe void MapVectors(SKPoint[] result, SKPoint[] vectors)
+    {
+        if (result == null)
+        {
+            throw new ArgumentNullException(nameof(result));
+        }
+
+        if (vectors == null)
+        {
+            throw new ArgumentNullException(nameof(vectors));
+        }
+
+        if (result.Length != vectors.Length)
+        {
+            throw new ArgumentException("Buffers must be the same size.");
+        }
+
+        fixed (Matrix3X3* matrix = &this)
+        fixed (SKPoint* dst = result)
+        fixed (SKPoint* src = vectors)
+        {
+            SkiaApi.sk_matrix_map_vectors(matrix, dst, src, result.Length);
+        }
+    }
+
+    /// <param name="vectors">The array of vectors to map.</param>
+    /// <summary>Applies the matrix to the array of vectors, ignoring translation, and returns the mapped results.</summary>
+    /// <returns>Returns the new array allocated with the mapped results.</returns>
+    /// <remarks>
+    ///     Mapping vectors ignores the translation component in the matrix. Use
+    ///     <see cref="M:SkiaSharp.Matrix3x3.MapPoints(SkiaSharp.SKPoint[])" /> to take the translation into consideration.
+    /// </remarks>
+    public readonly SKPoint[] MapVectors(SKPoint[] vectors)
+    {
+        var result = vectors != null ? new SKPoint[vectors.Length] : throw new ArgumentNullException(nameof(vectors));
+        MapVectors(result, vectors);
+        return result;
+    }
+
+    /// <param name="radius">The radius to map.</param>
+    /// <summary>Calculates the mean radius of a circle after it has been mapped by this matrix.</summary>
+    /// <returns>Returns the mean radius.</returns>
+    /// <remarks />
+    public readonly unsafe float MapRadius(float radius)
+    {
+        fixed (Matrix3X3* matrix = &this)
+        {
+            return SkiaApi.sk_matrix_map_radius(matrix, radius);
+        }
+    }
+
+    private static void SetSinCos(ref Matrix3X3 matrix, float sin, float cos)
+    {
+        matrix.ScaleX = cos;
+        matrix.SkewX = -sin;
+        matrix.TransX = 0.0f;
+        matrix.SkewY = sin;
+        matrix.ScaleY = cos;
+        matrix.TransY = 0.0f;
+        matrix.Persp0 = 0.0f;
+        matrix.Persp1 = 0.0f;
+        matrix.Persp2 = 1f;
+    }
+
+    private static void SetSinCos(
+        ref Matrix3X3 matrix,
+        float sin,
+        float cos,
+        float pivotx,
+        float pivoty)
+    {
+        var c = 1f - cos;
+        matrix.ScaleX = cos;
+        matrix.SkewX = -sin;
+        matrix.TransX = Dot(sin, pivoty, c, pivotx);
+        matrix.SkewY = sin;
+        matrix.ScaleY = cos;
+        matrix.TransY = Dot(-sin, pivotx, c, pivoty);
+        matrix.Persp0 = 0.0f;
+        matrix.Persp1 = 0.0f;
+        matrix.Persp2 = 1f;
+    }
+
+    private static float Dot(float a, float b, float c, float d)
+    {
+        return (float)((a * (double)b) + (c * (double)d));
+    }
+
+    private static float Cross(float a, float b, float c, float d)
+    {
+        return (float)((a * (double)b) - (c * (double)d));
+    }
+
+    private class Indices
+    {
+        public const int ScaleX = 0;
+        public const int SkewX = 1;
+        public const int TransX = 2;
+        public const int SkewY = 3;
+        public const int ScaleY = 4;
+        public const int TransY = 5;
+        public const int Persp0 = 6;
+        public const int Persp1 = 7;
+        public const int Persp2 = 8;
+        public const int Count = 9;
+    }
+}

+ 3 - 2
src/ChunkyImageLib/DataHolders/RectD.cs → src/PixiEditor.DrawingApi.Core/Numerics/RectD.cs

@@ -1,6 +1,7 @@
-using SkiaSharp;
+using System;
+using SkiaSharp;
 
-namespace ChunkyImageLib.DataHolders;
+namespace PixiEditor.DrawingApi.Core.Numerics;
 public struct RectD : IEquatable<RectD>
 {
     public static RectD Empty { get; } = new RectD();

+ 3 - 2
src/ChunkyImageLib/DataHolders/RectI.cs → src/PixiEditor.DrawingApi.Core/Numerics/RectI.cs

@@ -1,6 +1,7 @@
-using SkiaSharp;
+using System;
+using SkiaSharp;
 
-namespace ChunkyImageLib.DataHolders;
+namespace PixiEditor.DrawingApi.Core.Numerics;
 public struct RectI : IEquatable<RectI>
 {
     public static RectI Empty { get; } = new RectI();

+ 3 - 2
src/ChunkyImageLib/DataHolders/VecD.cs → src/PixiEditor.DrawingApi.Core/Numerics/VecD.cs

@@ -1,6 +1,7 @@
-using SkiaSharp;
+using System;
+using SkiaSharp;
 
-namespace ChunkyImageLib.DataHolders;
+namespace PixiEditor.DrawingApi.Core.Numerics;
 
 public struct VecD : IEquatable<VecD>
 {

+ 3 - 2
src/ChunkyImageLib/DataHolders/VecI.cs → src/PixiEditor.DrawingApi.Core/Numerics/VecI.cs

@@ -1,6 +1,7 @@
-using PixiEditor.PixelE;
+using System;
+using SkiaSharp;
 
-namespace ChunkyImageLib.DataHolders;
+namespace PixiEditor.DrawingApi.Core.Numerics;
 
 public struct VecI : IEquatable<VecI>
 {

+ 28 - 0
src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs

@@ -1,4 +1,7 @@
 using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
+using SkiaSharp;
 
 namespace PixiEditor.DrawingApi.Core.Surface
 {
@@ -10,5 +13,30 @@ namespace PixiEditor.DrawingApi.Core.Surface
             => DrawingBackendApi.Current.CanvasOperations.DrawSurface(original, x, y);
 
         public void DrawImage(Image image, int x, int y) => DrawingBackendApi.Current.CanvasOperations.DrawImage(image, x, y);
+
+        public int Save()
+        {
+            return DrawingBackendApi.Current.CanvasOperations.Save();
+        }
+
+        public void Restore()
+        {
+            DrawingBackendApi.Current.CanvasOperations.Restore();
+        }
+
+        public void Scale(float multiplier)
+        {
+            DrawingBackendApi.Current.CanvasOperations.Scale(multiplier);
+        }
+
+        public void Translate(VecI vector)
+        {
+            DrawingBackendApi.Current.CanvasOperations.Translate(vector);
+        }
+
+        public void DrawPath(VectorPath path, Paint paint)
+        {
+            DrawingBackendApi.Current.CanvasOperations.DrawPath(path, paint);
+        }
     }
 }

+ 14 - 0
src/PixiEditor.DrawingApi.Core/Surface/NativeObject.cs

@@ -0,0 +1,14 @@
+using System;
+
+namespace PixiEditor.DrawingApi.Core.Surface;
+
+public abstract class NativeObject : IDisposable
+{
+    public IntPtr ObjectPointer { get; protected set; }
+    public abstract void Dispose();
+    
+    internal NativeObject(IntPtr objPtr)
+    {
+        ObjectPointer = objPtr;
+    }
+}

+ 14 - 0
src/PixiEditor.DrawingApi.Core/Surface/Vector/PathConvexity.cs

@@ -0,0 +1,14 @@
+namespace PixiEditor.DrawingApi.Core.Surface.Vector;
+
+/// <summary>Convexity for paths.</summary>
+public enum PathConvexity
+{
+    /// <summary>The path's convexity is unknown.</summary>
+    Unknown,
+    
+    /// <summary>The path is convex.</summary>
+    Convex,
+    
+    /// <summary>The path is concave.</summary>
+    Concave,
+}

+ 17 - 0
src/PixiEditor.DrawingApi.Core/Surface/Vector/PathFillType.cs

@@ -0,0 +1,17 @@
+namespace PixiEditor.DrawingApi.Core.Surface.Vector;
+
+/// <summary>Possible path fill type values.</summary>
+public enum PathFillType
+{
+    /// <summary>Specifies that "inside" is computed by a non-zero sum of signed edge crossings.</summary>
+    Winding,
+    
+    /// <summary>Specifies that "inside" is computed by an odd number of edge crossings.</summary>
+    EvenOdd,
+    
+    /// <summary>Same as <see cref="F:SkiaSharp.SKPathFillType.Winding" />, but draws outside of the path, rather than inside.</summary>
+    InverseWinding,
+    
+    /// <summary>Same as <see cref="F:SkiaSharp.SKPathFillType.EvenOdd" />, but draws outside of the path, rather than inside.</summary>
+    InverseEvenOdd,
+}

+ 19 - 0
src/PixiEditor.DrawingApi.Core/Surface/Vector/PathSegmentMask.cs

@@ -0,0 +1,19 @@
+using System;
+
+namespace PixiEditor.DrawingApi.Core.Surface.Vector;
+
+[Flags]
+public enum PathSegmentMask
+{
+    /// <summary>The path contains one or more line segments.</summary>
+    Line = 1,
+    
+    /// <summary>The path contains one or more quad segments.</summary>
+    Quad = 2,
+    
+    /// <summary>The path contains one or more conic segments.</summary>
+    Conic = 4,
+    
+    /// <summary>The path contains one or more cubic segments.</summary>
+    Cubic = 8,
+}

+ 60 - 0
src/PixiEditor.DrawingApi.Core/Surface/Vector/VectorPath.cs

@@ -0,0 +1,60 @@
+using System;
+using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.DrawingApi.Core.Surface.Vector;
+
+/// <summary>An interface for native compound geometric path implementations.</summary>
+/// <remarks>A path encapsulates compound (multiple contour) geometric paths consisting of straight line segments, quadratic curves, and cubic curves.</remarks>
+public class VectorPath : NativeObject
+{
+    public PathFillType FillType
+    {
+        get => DrawingBackendApi.Current.PathImplementation.GetFillType(this);
+        set => DrawingBackendApi.Current.PathImplementation.SetFillType(this, value);
+    }
+
+    public PathConvexity Convexity 
+    {
+        get => DrawingBackendApi.Current.PathImplementation.GetConvexity(this);
+        set => DrawingBackendApi.Current.PathImplementation.SetConvexity(this, value);
+    }
+
+    /// <summary>Gets a value indicating whether the path is a single oval or circle.</summary>
+    public bool IsOval => DrawingBackendApi.Current.PathImplementation.IsPathOval(this);
+
+    /// <summary>Gets a value indicating whether the path is a single, round rectangle.</summary>
+    public bool IsRoundRect => DrawingBackendApi.Current.PathImplementation.IsRoundRect(this);
+
+    /// <summary>Gets a value indicating whether the path is a single, straight line.</summary>
+    public bool IsLine => DrawingBackendApi.Current.PathImplementation.IsLine(this);
+
+    /// <summary>Gets a value indicating whether the path is a single rectangle.</summary>
+    public bool IsRect => DrawingBackendApi.Current.PathImplementation.IsRect(this);
+
+    /// <summary>Gets a set of flags indicating if the path contains one or more segments of that type.</summary>
+    public PathSegmentMask SegmentMasks => DrawingBackendApi.Current.PathImplementation.GetSegmentMasks(this);
+
+    /// <summary>Gets the number of verbs in the path.</summary>
+    public int VerbCount => DrawingBackendApi.Current.PathImplementation.GetVerbCount(this);
+
+    /// <summary>Gets the number of points on the path.</summary>
+    public int PointCount => DrawingBackendApi.Current.PathImplementation.GetPointCount(this);
+    
+    /// <summary>Gets the "tight" bounds of the path. the control points of curves are excluded.</summary>
+    /// <value>The tight bounds of the path.</value>
+    public RectD TightBounds => DrawingBackendApi.Current.PathImplementation.GetTightBounds(this);
+
+    public VectorPath() : base(DrawingBackendApi.Current.PathImplementation.Create())
+    {
+    }
+
+    public VectorPath(VectorPath other) : base(DrawingBackendApi.Current.PathImplementation.Clone(other))
+    {
+    }
+
+    public override void Dispose()
+    {
+        DrawingBackendApi.Current.PathImplementation.Dispose(this);
+    }
+}

+ 1 - 0
src/PixiEditor.Zoombox/Operations/ManipulationOperation.cs

@@ -2,6 +2,7 @@
 using System.Linq;
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.Zoombox.Operations;
 

+ 1 - 0
src/PixiEditor.Zoombox/Operations/MoveDragOperation.cs

@@ -1,5 +1,6 @@
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.Zoombox.Operations;
 

+ 1 - 0
src/PixiEditor.Zoombox/Operations/RotateDragOperation.cs

@@ -1,6 +1,7 @@
 using System.Windows;
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.Zoombox.Operations;
 

+ 1 - 0
src/PixiEditor.Zoombox/Operations/ZoomDragOperation.cs

@@ -2,6 +2,7 @@
 using System.Windows;
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.Zoombox.Operations;
 

+ 1 - 0
src/PixiEditor.Zoombox/ViewportRoutedEventArgs.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using System.Windows;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.Zoombox;
 

+ 1 - 0
src/PixiEditor.Zoombox/Zoombox.xaml.cs

@@ -6,6 +6,7 @@ using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Markup;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Zoombox.Operations;
 
 namespace PixiEditor.Zoombox;

+ 1 - 0
src/PixiEditor/Helpers/DocumentViewModelBuilder.cs

@@ -3,6 +3,7 @@ using System.IO;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
 namespace PixiEditor.Helpers;

+ 1 - 0
src/PixiEditor/Helpers/SurfaceHelpers.cs

@@ -3,6 +3,7 @@ using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 
 namespace PixiEditor.Helpers;

+ 1 - 0
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -7,6 +7,7 @@ using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.IO;

+ 1 - 0
src/PixiEditor/Models/Controllers/MouseInputFilter.cs

@@ -1,6 +1,7 @@
 using System.Windows;
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Events;
 
 namespace PixiEditor.Models.Controllers;

+ 1 - 0
src/PixiEditor/Models/DataHolders/DocumentSizeChangedEventArgs.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
 namespace PixiEditor.Models.DataHolders;

+ 1 - 0
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -4,6 +4,7 @@ using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.ChangeInfos;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Rendering;
 using PixiEditor.Models.Rendering.RenderInfos;
 using PixiEditor.ViewModels.SubViewModels.Document;

+ 1 - 0
src/PixiEditor/Models/DocumentModels/ChangeExecutionController.cs

@@ -1,6 +1,7 @@
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;

+ 1 - 0
src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs

@@ -7,6 +7,7 @@ using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
 using PixiEditor.ChangeableDocument.ChangeInfos.Root;
 using PixiEditor.ChangeableDocument.ChangeInfos.Structure;
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.Models.Enums;

+ 1 - 0
src/PixiEditor/Models/DocumentModels/Public/DocumentEventsModule.cs

@@ -1,6 +1,7 @@
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Events;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.Views.UserControls.SymmetryOverlay;

+ 1 - 0
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -2,6 +2,7 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.Models.Enums;

+ 1 - 0
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/BrightnessToolExecutor.cs

@@ -1,4 +1,5 @@
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;

+ 1 - 0
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EllipseToolExecutor.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
 

+ 1 - 0
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs

@@ -1,6 +1,7 @@
 #nullable enable
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;

+ 1 - 0
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/FloodFillToolExecutor.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions.Undo;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;

Some files were not shown because too many files changed in this diff