Browse Source

Fixed shapes affected area on transform

flabbet 11 months ago
parent
commit
60a6c8917f

+ 3 - 5
src/ChunkyImageLib/Operations/EllipseOperation.cs

@@ -143,12 +143,10 @@ internal class EllipseOperation : IMirroredDrawOperation
         var chunks = OperationHelper.FindChunksTouchingRectangle(bounds, ChunkyImage.FullChunkSize);
         if (fillColor.A == 0)
         {
-            // TODO: Implement ellipse fill optimization for rotated ellipses
-            /*
-            chunks.ExceptWith(OperationHelper.FindChunksFullyInsideEllipse
-                (location.Center, location.Width / 2.0 - strokeWidth * 2, location.Height / 2.0 - strokeWidth * 2, ChunkyImage.FullChunkSize));
-        */
+             chunks.ExceptWith(OperationHelper.FindChunksFullyInsideEllipse
+                (location.Center, location.Width / 2.0 - strokeWidth * 2, location.Height / 2.0 - strokeWidth * 2, ChunkyImage.FullChunkSize, rotation));
         }
+        
         return new AffectedArea(chunks, bounds);
     }
 

+ 6 - 2
src/ChunkyImageLib/Operations/OperationHelper.cs

@@ -176,15 +176,19 @@ public static class OperationHelper
         return chunks;
     }
 
-    public static HashSet<VecI> FindChunksFullyInsideEllipse(VecD pos, double radiusX, double radiusY, int chunkSize)
+    public static HashSet<VecI> FindChunksFullyInsideEllipse(VecD pos, double radiusX, double radiusY, int chunkSize,
+        double rotation)
     {
         double stretchX = radiusX / radiusY;
         var (left, right) = CreateStretchedHexagon(pos, radiusY, stretchX);
+        left = left.AsRotated(rotation, pos);
+        right = right.AsRotated(rotation, pos);
+        
         var chunks = FindChunksFullyInsideQuadrilateral(left, chunkSize);
         chunks.UnionWith(FindChunksFullyInsideQuadrilateral(right, chunkSize));
         return chunks;
     }
-
+    
     public static HashSet<VecI> FindChunksTouchingQuadrilateral(ShapeCorners corners, int chunkSize)
     {
         if (corners.IsRect && Math.Abs(corners.RectRotation) < 0.0001)

+ 1 - 1
src/PixiEditor.ChangeableDocument/ChangeInfos/Vectors/VectorShape_ChangeInfo.cs

@@ -3,4 +3,4 @@ using PixiEditor.Numerics;
 
 namespace PixiEditor.ChangeableDocument.ChangeInfos.Vectors;
 
-    public record VectorShape_ChangeInfo(Guid LayerId) : IChangeInfo;
+    public record VectorShape_ChangeInfo(Guid LayerId, AffectedArea Affected) : IChangeInfo;

+ 4 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/VectorLayerNode.cs

@@ -93,7 +93,10 @@ public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorN
     {
         base.DeserializeAdditionalData(target, data);
         ShapeData = (ShapeVectorData)data["ShapeData"];
-        return new VectorShape_ChangeInfo(Id);
+        var affected = new AffectedArea(OperationHelper.FindChunksTouchingRectangle(
+            (RectI)ShapeData.TransformedAABB, ChunkyImage.FullChunkSize));
+        
+        return new VectorShape_ChangeInfo(Id, affected);
     }
 
     protected override bool CacheChanged(RenderingContext context)

+ 10 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelected_UpdateableChange.cs

@@ -31,6 +31,7 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
     private bool hasEnqueudImages = false;
     private int frame;
     private bool appliedOnce;
+    private AffectedArea lastAffectedArea;
 
     private static Paint RegularPaint { get; } = new() { BlendMode = BlendMode.SrcOver };
 
@@ -292,6 +293,13 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
                 member.TransformableObject.TransformationMatrix = member.LocalMatrix;
 
                 AffectedArea translationAffectedArea = GetTranslationAffectedArea();
+                var tmp = new AffectedArea(translationAffectedArea);
+                if (lastAffectedArea.Chunks != null)
+                {
+                    translationAffectedArea.UnionWith(lastAffectedArea);
+                }
+
+                lastAffectedArea = tmp;
                 infos.Add(new TransformObject_ChangeInfo(member.MemberId, translationAffectedArea));
             }
         }
@@ -375,7 +383,8 @@ internal class TransformSelected_UpdateableChange : UpdateableChange
             }
         }
 
-        return new AffectedArea(chunks);
+        var final = new AffectedArea(chunks);
+        return final;
     }
 
     private AffectedArea DrawImage(MemberTransformationData data, ChunkyImage memberImage)

+ 26 - 4
src/PixiEditor.ChangeableDocument/Changes/Vectors/SetShapeGeometry_UpdateableChange.cs

@@ -1,6 +1,8 @@
-using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
+using ChunkyImageLib.Operations;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
 using PixiEditor.ChangeableDocument.ChangeInfos.Vectors;
+using PixiEditor.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Vectors;
 
@@ -10,6 +12,8 @@ internal class SetShapeGeometry_UpdateableChange : UpdateableChange
     public ShapeVectorData Data { get; set; }
 
     private ShapeVectorData? originalData;
+    
+    private AffectedArea lastAffectedArea;
 
     [GenerateUpdateableChangeActions]
     public SetShapeGeometry_UpdateableChange(Guid targetId, ShapeVectorData data)
@@ -40,7 +44,19 @@ internal class SetShapeGeometry_UpdateableChange : UpdateableChange
         var node = target.FindNode<VectorLayerNode>(TargetId);
         node.ShapeData = Data;
 
-        return new VectorShape_ChangeInfo(node.Id);
+        var affected = new AffectedArea(OperationHelper.FindChunksTouchingRectangle(
+            (RectI)node.ShapeData.TransformedAABB, ChunkyImage.FullChunkSize));
+
+        var tmp = new AffectedArea(affected);
+        
+        if (lastAffectedArea.Chunks != null)
+        {
+            affected.UnionWith(lastAffectedArea);
+        }
+        
+        lastAffectedArea = tmp;
+        
+        return new VectorShape_ChangeInfo(node.Id, affected);
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply,
@@ -49,8 +65,11 @@ internal class SetShapeGeometry_UpdateableChange : UpdateableChange
         ignoreInUndo = false;
         var node = target.FindNode<VectorLayerNode>(TargetId);
         node.ShapeData = Data;
+        
+        var affected = new AffectedArea(OperationHelper.FindChunksTouchingRectangle(
+            (RectI)node.ShapeData.TransformedAABB, ChunkyImage.FullChunkSize));
 
-        return new VectorShape_ChangeInfo(node.Id);
+        return new VectorShape_ChangeInfo(node.Id, affected);
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
@@ -58,6 +77,9 @@ internal class SetShapeGeometry_UpdateableChange : UpdateableChange
         var node = target.FindNode<VectorLayerNode>(TargetId);
         node.ShapeData = originalData;
 
-        return new VectorShape_ChangeInfo(node.Id);
+        var affected = new AffectedArea(OperationHelper.FindChunksTouchingRectangle(
+            (RectI)node.ShapeData.TransformedAABB, ChunkyImage.FullChunkSize));
+        
+        return new VectorShape_ChangeInfo(node.Id, affected);
     }
 }

+ 5 - 2
src/PixiEditor/Models/Rendering/AffectedAreasGatherer.cs

@@ -164,8 +164,8 @@ internal class AffectedAreasGatherer
                     AddWholeCanvasToMainImage();
                     break;
                 case VectorShape_ChangeInfo info:
-                    AddAllToMainImage(info.LayerId, ActiveFrame, false);
-                    AddAllToImagePreviews(info.LayerId, ActiveFrame, false);
+                    AddToMainImage(info.Affected);
+                    AddToImagePreviews(info.LayerId, info.Affected);
                     break;
             }
         }
@@ -232,6 +232,9 @@ internal class AffectedAreasGatherer
             {
                 var affectedArea = new AffectedArea(
                     OperationHelper.FindChunksTouchingRectangle((RectI)tightBounds.Value, ChunkyImage.FullChunkSize));
+                
+                var lastArea = new AffectedArea(affectedArea);
+                
                 AddToMainImage(affectedArea);
             }
             else

+ 1 - 1
src/PixiEditor/ViewModels/Tools/Tools/SelectToolViewModel.cs

@@ -58,7 +58,7 @@ internal class SelectToolViewModel : ToolViewModel, ISelectToolHandler
     public SelectionShape SelectShape => GetValue<SelectionShape>();
 
     public override BrushShape BrushShape => BrushShape.Pixel;
-    public override Type[]? SupportedLayerTypes { get; } = [];
+    public override Type[]? SupportedLayerTypes { get; } = null;
 
     public override LocalizedString Tooltip => new LocalizedString("SELECT_TOOL_TOOLTIP", Shortcut);