Explorar el Código

shape consistent transform

Johann hace 6 años
padre
commit
6a28fb86ba

+ 25 - 15
lazpaint/utoolbasic.pas

@@ -84,11 +84,12 @@ type
     FShiftState: TShiftState;
     FRightDown, FLeftDown: boolean;
     FLastPos: TPointF;
+    FLastShapeTransform: TAffineMatrix;
     function CreateShape: TVectorShape; virtual; abstract;
     function UseOriginal: boolean; virtual;
     function GetCustomShapeBounds(ADestBounds: TRect; AMatrix: TAffineMatrix; {%H-}ADraft: boolean): TRect; virtual;
     procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); virtual;
-    procedure AssignShapeStyle; virtual;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); virtual;
     procedure QuickDefineShape(AStart,AEnd: TPointF); virtual;
     function RoundCoordinate(ptF: TPointF): TPointF; virtual;
     function GetIsSelectingTool: boolean; override;
@@ -216,7 +217,7 @@ var
   diff: TComposedImageDifference;
   layerId: LongInt;
   replaceDiff: TReplaceLayerByVectorOriginalDifference;
-  invTransform: TAffineMatrix;
+  transf: TAffineMatrix;
 begin
   if Assigned(FShape) then
   begin
@@ -230,11 +231,12 @@ begin
         Manager.Image.AddUndo(TAddShapeToVectorOriginalDifference.Create(Manager.Image.CurrentState,layerId,FShape))
       else
       begin
+        transf := VectorTransform;
         diff := TComposedImageDifference.Create;
         replaceDiff := TReplaceLayerByVectorOriginalDifference.Create(Manager.Image.CurrentState,Manager.Image.CurrentLayerIndex);
         diff.Add(replaceDiff);
-        invTransform := AffineMatrixInverse(VectorTransform);
-        QuickDefineShape(invTransform*FQuickDefineStartPoint, invTransform*FQuickDefineEndPoint);
+        transf := AffineMatrixInverse(VectorTransform)*transf;
+        FShape.Transform(transf);
         diff.Add(TAddShapeToVectorOriginalDifference.Create(Manager.Image.CurrentState,layerId,FShape));
         Manager.Image.AddUndo(diff);
       end;
@@ -277,17 +279,19 @@ begin
   FShape.Render(ADest,AMatrix,ADraft);
 end;
 
-procedure TVectorialTool.AssignShapeStyle;
+procedure TVectorialTool.AssignShapeStyle(AMatrix: TAffineMatrix);
 var
   f: TVectorShapeFields;
+  zoom: Single;
 begin
+  zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
   f:= FShape.Fields;
   if vsfPenFill in f then
   begin
     if Manager.ToolOptionDrawShape then
     begin
       if (not (vsfBackFill in f) or not Manager.ToolOptionFillShape) and (Manager.GetToolTexture <> nil) then
-        FShape.PenFill.SetTexture(Manager.GetToolTexture,AffineMatrixIdentity,Manager.ToolTextureOpacity)
+        FShape.PenFill.SetTexture(Manager.GetToolTexture,AMatrix,Manager.ToolTextureOpacity)
       else
       begin
         if FSwapColor then
@@ -298,7 +302,7 @@ begin
     end else
       FShape.PenFill.Clear;
   end;
-  if vsfPenWidth in f then FShape.PenWidth := Manager.ToolPenWidth;
+  if vsfPenWidth in f then FShape.PenWidth := zoom*Manager.ToolPenWidth;
   if vsfPenStyle in f Then FShape.PenStyle := PenStyleToBGRA(Manager.ToolPenStyle);
   if vsfJoinStyle in f then FShape.JoinStyle:= Manager.ToolJoinStyle;
   if vsfBackFill in f then
@@ -393,7 +397,6 @@ var
   viewPt: TPointF;
   cur: TOriginalEditorCursor;
   handled: boolean;
-  invTransform: TAffineMatrix;
 begin
   result := EmptyRect;
   FRightDown := rightBtn;
@@ -425,9 +428,12 @@ begin
       FQuickDefine := true;
       FQuickDefineStartPoint := RoundCoordinate(ptF);
       FQuickDefineEndPoint := FQuickDefineStartPoint;
-      AssignShapeStyle;
-      invTransform := AffineMatrixInverse(VectorTransform);
-      QuickDefineShape(invTransform*FQuickDefineStartPoint,invTransform*FQuickDefineEndPoint);
+      FShape.BeginUpdate;
+        QuickDefineShape(FQuickDefineStartPoint,FQuickDefineEndPoint);
+        FLastShapeTransform := AffineMatrixInverse(VectorTransform);
+        FShape.Transform(FLastShapeTransform);
+        AssignShapeStyle(FLastShapeTransform);
+      FShape.EndUpdate;
       FShape.OnChange:= @ShapeChange;
       FShape.OnEditingChange:=@ShapeEditingChange;
       result := RectUnion(result, UpdateShape(toolDest));
@@ -443,7 +449,6 @@ var
   viewPt: TPointF;
   handled: boolean;
   cur: TOriginalEditorCursor;
-  invTransform: TAffineMatrix;
 begin
   FLastPos := ptF;
   if FQuickDefine then
@@ -456,8 +461,12 @@ begin
       if s.x > 0 then FQuickDefineEndPoint.x := FQuickDefineStartPoint.x + avg else FQuickDefineEndPoint.x := FQuickDefineStartPoint.x - avg;
       if s.y > 0 then FQuickDefineEndPoint.y := FQuickDefineStartPoint.y + avg else FQuickDefineEndPoint.y := FQuickDefineStartPoint.y - avg;
     end;
-    invTransform := AffineMatrixInverse(VectorTransform);
-    QuickDefineShape(invTransform*FQuickDefineStartPoint, invTransform*FQuickDefineEndPoint);
+    FShape.BeginUpdate;
+      QuickDefineShape(FQuickDefineStartPoint, FQuickDefineEndPoint);
+      FLastShapeTransform := AffineMatrixInverse(VectorTransform);
+      FShape.Transform(FLastShapeTransform);
+      AssignShapeStyle(FLastShapeTransform);
+    FShape.EndUpdate;
     result := OnlyRenderChange;
   end else
   begin
@@ -472,7 +481,7 @@ end;
 
 function TVectorialTool.DoToolUpdate(toolDest: TBGRABitmap): TRect;
 begin
-  if Assigned(FShape) then AssignShapeStyle;
+  if Assigned(FShape) then AssignShapeStyle(FLastShapeTransform);
   result := EmptyRect;
 end;
 
@@ -484,6 +493,7 @@ begin
   FEditor.GridMatrix := AffineMatrixScale(0.5,0.5);
   FEditor.Focused := true;
   FPreviousEditorBounds := EmptyRect;
+  FLastShapeTransform := AffineMatrixIdentity;
 end;
 
 function TVectorialTool.ToolUp: TRect;

+ 2 - 2
lazpaint/utoolfloodfill.pas

@@ -26,7 +26,7 @@ type
   TToolGradient = class(TVectorialTool)
   protected
     function CreateShape: TVectorShape; override;
-    procedure AssignShapeStyle; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     procedure QuickDefineShape(AStart,AEnd: TPointF); override;
     function SlowShape: boolean; override;
     function GetStatusText: string; override;
@@ -47,7 +47,7 @@ begin
   result.Usermode := vsuEditBackFill;
 end;
 
-procedure TToolGradient.AssignShapeStyle;
+procedure TToolGradient.AssignShapeStyle(AMatrix: TAffineMatrix);
 begin
   with FShape.BackFill.Gradient do
   begin

+ 18 - 7
lazpaint/utoolphong.pas

@@ -13,28 +13,39 @@ type
 
   TToolPhong = class(TVectorialTool)
   protected
+    FMatrix: TAffineMatrix;
+    constructor Create(AManager: TToolManager); override;
     procedure ShapeChange({%H-}ASender: TObject; ABounds: TRectF); override;
-    procedure AssignShapeStyle; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     function CreateShape: TVectorShape; override;
     function SlowShape: boolean; override;
   end;
 
 implementation
 
-uses ugraph, Graphics, LazPaintType, LCVectorRectShapes;
+uses ugraph, Graphics, LazPaintType, LCVectorRectShapes, BGRATransform;
 
 { TToolPhong }
 
+constructor TToolPhong.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FMatrix := AffineMatrixIdentity;
+end;
+
 procedure TToolPhong.ShapeChange(ASender: TObject; ABounds: TRectF);
+var
+  posF: TPointF;
 begin
-  with (FShape as TPhongShape) do
-    Manager.ToolLightPosition := Point(round(LightPosition.X),round(LightPosition.Y));
+  posF := AffineMatrixInverse(FMatrix)*(FShape as TPhongShape).LightPosition;
+  Manager.ToolLightPosition := posF.Round;
   inherited ShapeChange(ASender, ABounds);
 end;
 
-procedure TToolPhong.AssignShapeStyle;
+procedure TToolPhong.AssignShapeStyle(AMatrix: TAffineMatrix);
 begin
-  inherited AssignShapeStyle;
+  inherited AssignShapeStyle(AMatrix);
+  FMatrix := AMatrix;
   with (FShape as TPhongShape) do
   begin
     if Manager.ToolShapeType = 'RoundRectangle' then ShapeKind:= pskRoundRectangle else
@@ -44,7 +55,7 @@ begin
     if Manager.ToolShapeType = 'VerticalCylinder' then ShapeKind := pskVertCylinder else
     if Manager.ToolShapeType = 'HorizontalCylinder' then ShapeKind := pskHorizCylinder
     else ShapeKind := pskRectangle;
-    LightPosition := PointF(Manager.ToolLightPosition.X,Manager.ToolLightPosition.Y);
+    LightPosition := AMatrix*PointF(Manager.ToolLightPosition.X,Manager.ToolLightPosition.Y);
     ShapeAltitudePercent := Manager.ToolShapeAltitude;
     BorderSizePercent:= Manager.ToolShapeBorderSize;
   end;

+ 2 - 2
lazpaint/utoolselect.pas

@@ -14,7 +14,7 @@ type
   TVectorialSelectTool = class(TVectorialTool)
   protected
     function GetIsSelectingTool: boolean; override;
-    procedure AssignShapeStyle; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     function RoundCoordinate(ptF: TPointF): TPointF; override;
     function UpdateShape(toolDest: TBGRABitmap): TRect; override;
     procedure QuickDefineEnd; override;
@@ -140,7 +140,7 @@ begin
   Result:= true;
 end;
 
-procedure TVectorialSelectTool.AssignShapeStyle;
+procedure TVectorialSelectTool.AssignShapeStyle(AMatrix: TAffineMatrix);
 var
   f: TVectorShapeFields;
 begin

+ 18 - 6
lazpaint/utooltext.pas

@@ -14,6 +14,7 @@ type
 
   TToolText = class(TVectorialTool)
   protected
+    FMatrix: TAffineMatrix;
     FPrevShadow: boolean;
     FPrevShadowOffset: TPoint;
     FPrevShadowRadius: single;
@@ -23,10 +24,11 @@ type
     procedure DrawCustomShape(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); override;
     procedure ShapeChange(ASender: TObject; ABounds: TRectF); override;
     procedure ShapeEditingChange(ASender: TObject); override;
-    procedure AssignShapeStyle; override;
+    procedure AssignShapeStyle(AMatrix: TAffineMatrix); override;
     function SlowShape: boolean; override;
     procedure QuickDefineEnd; override;
   public
+    constructor Create(AManager: TToolManager); override;
     function ToolKeyDown(var key: Word): TRect; override;
     function ToolCopy: boolean; override;
     function ToolCut: boolean; override;
@@ -120,9 +122,10 @@ end;
 procedure TToolText.ShapeChange(ASender: TObject; ABounds: TRectF);
 var
   r: TRect;
+  posF: TPointF;
 begin
-  with (FShape as TTextShape) do
-    Manager.ToolLightPosition := Point(round(LightPosition.X),round(LightPosition.Y));
+  posF := AffineMatrixInverse(FMatrix)*(FShape as TTextShape).LightPosition;
+  Manager.ToolLightPosition := posF.Round;
   with ABounds do r := rect(floor(Left),floor(Top),ceil(Right),ceil(Bottom));
   IncludeShadowBounds(r);
   inherited ShapeChange(ASender, RectF(r.Left,r.Top,r.Right,r.Bottom));
@@ -135,14 +138,17 @@ begin
   inherited ShapeEditingChange(ASender);
 end;
 
-procedure TToolText.AssignShapeStyle;
+procedure TToolText.AssignShapeStyle(AMatrix: TAffineMatrix);
 var
   r: TRect;
   toolDest: TBGRABitmap;
+  zoom: Single;
 begin
+  FMatrix := AMatrix;
   with TTextShape(FShape) do
   begin
-    FontEmHeight:= Manager.ToolTextFont.Size*ScreenInfo.PixelsPerInchY/72;
+    zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
+    FontEmHeight:= zoom*Manager.ToolTextFont.Size*ScreenInfo.PixelsPerInchY/72;
     FontName:= Manager.ToolTextFont.Name;
     FontStyle:= Manager.ToolTextFont.Style;
 
@@ -168,7 +174,7 @@ begin
     else
       OutlineFill.Clear;
 
-    LightPosition := PointF(Manager.ToolLightPosition.X,Manager.ToolLightPosition.Y);
+    LightPosition := AMatrix*PointF(Manager.ToolLightPosition.X,Manager.ToolLightPosition.Y);
     AltitudePercent:= Manager.ToolShapeAltitude;
     ParagraphAlignment:= Manager.ToolTextAlign;
     PenPhong := Manager.ToolTextPhong;
@@ -193,6 +199,12 @@ begin
   FShape.Usermode := vsuEditText;
 end;
 
+constructor TToolText.Create(AManager: TToolManager);
+begin
+  inherited Create(AManager);
+  FMatrix := AffineMatrixIdentity;
+end;
+
 function TToolText.ToolKeyDown(var key: Word): TRect;
 var
   keyUtf8: TUTF8Char;

+ 17 - 2
lazpaintcontrols/lcvectororiginal.pas

@@ -57,8 +57,6 @@ type
     procedure SetId(AValue: integer);
     procedure SetOutlineWidth(AValue: single);
   protected
-    procedure BeginUpdate;
-    procedure EndUpdate;
     procedure BeginEditingUpdate;
     procedure EndEditingUpdate;
     procedure DoOnChange(ABoundsBefore: TRectF); virtual;
@@ -91,6 +89,8 @@ type
     constructor Create(AContainer: TVectorOriginal); virtual;
     class function CreateFromStorage(AStorage: TBGRACustomOriginalStorage; AContainer: TVectorOriginal): TVectorShape;
     destructor Destroy; override;
+    procedure BeginUpdate;
+    procedure EndUpdate;
     procedure QuickDefine(const APoint1,APoint2: TPointF); virtual; abstract;
     //one of the two Render functions must be overriden
     procedure Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); virtual;
@@ -117,6 +117,7 @@ type
     class function StorageClassName: RawByteString; virtual; abstract;
     function GetIsSlow({%H-}AMatrix: TAffineMatrix): boolean; virtual;
     function GetUsedTextures: ArrayOfBGRABitmap;
+    procedure Transform(AMatrix: TAffineMatrix); virtual;
     class function Fields: TVectorShapeFields; virtual;
     class function Usermodes: TVectorShapeUsermodes; virtual;
     class function PreferPixelCentered: boolean; virtual;
@@ -532,6 +533,20 @@ begin
   setlength(result, nb);
 end;
 
+procedure TVectorShape.Transform(AMatrix: TAffineMatrix);
+var
+  zoom: Single;
+begin
+  if IsAffineMatrixIdentity(AMatrix) then exit;
+  BeginUpdate;
+  if vsfBackFill in Fields then BackFill.Transform(AMatrix);
+  if vsfPenFill in Fields then PenFill.Transform(AMatrix);
+  zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
+  if vsfPenWidth in Fields then PenWidth := zoom*PenWidth;
+  if vsfOutlineFill in Fields then OutlineWidth := zoom*OutlineWidth;
+  EndUpdate;
+end;
+
 class function TVectorShape.Fields: TVectorShapeFields;
 begin
   result := [];

+ 12 - 0
lazpaintcontrols/lcvectorpolyshapes.pas

@@ -57,6 +57,7 @@ type
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure ConfigureCustomEditor(AEditor: TBGRAOriginalEditor); override;
+    procedure Transform(AMatrix: TAffineMatrix); override;
     class function Usermodes: TVectorShapeUsermodes; override;
     property Points[AIndex:integer]: TPointF read GetPoint write SetPoint;
     property PointCount: integer read GetPointCount;
@@ -569,6 +570,17 @@ begin
   end;
 end;
 
+procedure TCustomPolypointShape.Transform(AMatrix: TAffineMatrix);
+var
+  i: Integer;
+begin
+  BeginUpdate;
+  inherited Transform(AMatrix);
+  for i := 0 to PointCount-1 do
+    FPoints[i].coord := AMatrix*FPoints[i].coord;
+  EndUpdate;
+end;
+
 { TPolylineShape }
 
 function TPolylineShape.PenVisible(AAssumePenFill: boolean): boolean;

+ 21 - 7
lazpaintcontrols/lcvectorrectshapes.pas

@@ -50,6 +50,7 @@ type
     function GetRenderBounds({%H-}ADestRect: TRect; AMatrix: TAffineMatrix; {%H-}AOptions: TRenderBoundsOptions = []): TRectF; override;
     procedure ConfigureCustomEditor(AEditor: TBGRAOriginalEditor); override;
     function GetAffineBox(AMatrix: TAffineMatrix; APixelCentered: boolean): TAffineBox;
+    procedure Transform(AMatrix: TAffineMatrix); override;
     property Origin: TPointF read FOrigin write SetOrigin;
     property XAxis: TPointF read FXAxis;
     property YAxis: TPointF read FYAxis;
@@ -130,6 +131,7 @@ type
     function GetRenderBounds({%H-}ADestRect: TRect; AMatrix: TAffineMatrix; AOptions: TRenderBoundsOptions = []): TRectF; override;
     function PointInShape(APoint: TPointF): boolean; override;
     function GetIsSlow(AMatrix: TAffineMatrix): boolean; override;
+    procedure Transform(AMatrix: TAffineMatrix); override;
     class function StorageClassName: RawByteString; override;
     property ShapeKind: TPhongShapeKind read FShapeKind write SetShapeKind;
     property LightPosition: TPointF read FLightPosition write SetLightPosition;
@@ -150,13 +152,7 @@ begin
   if FOrigin=AValue then Exit;
   BeginUpdate;
   delta := AValue - FOrigin;
-  FOrigin := AValue;
-  FXAxis += delta;
-  FYAxis += delta;
-  if vsfBackFill in Fields then
-    BackFill.Transform(AffineMatrixTranslation(delta.x, delta.y));
-  if vsfPenFill in Fields then
-    PenFill.Transform(AffineMatrixTranslation(delta.x, delta.y));
+  Transform(AffineMatrixTranslation(delta.x, delta.y));
   EndUpdate;
 end;
 
@@ -447,6 +443,16 @@ begin
       FXAxis - (FYAxis - FOrigin), FYAxis - (FXAxis - FOrigin));
 end;
 
+procedure TCustomRectShape.Transform(AMatrix: TAffineMatrix);
+begin
+  BeginUpdate;
+  FOrigin := AMatrix*FOrigin;
+  FXAxis := AMatrix*FXAxis;
+  FYAxis := AMatrix*FYAxis;
+  inherited Transform(AMatrix);
+  EndUpdate;
+end;
+
 function TCustomRectShape.GetOrthoRect(AMatrix: TAffineMatrix; out ARect: TRectF): boolean;
 var
   sx,sy: single;
@@ -1318,6 +1324,14 @@ begin
   result := ab.Surface > 320*240;
 end;
 
+procedure TPhongShape.Transform(AMatrix: TAffineMatrix);
+begin
+  BeginUpdate;
+  inherited Transform(AMatrix);
+  LightPosition := AMatrix*LightPosition;
+  EndUpdate;
+end;
+
 class function TPhongShape.StorageClassName: RawByteString;
 begin
   result := 'phong';

+ 13 - 0
lazpaintcontrols/lcvectortextshapes.pas

@@ -93,6 +93,7 @@ type
     function CopySelection: boolean;
     function CutSelection: boolean;
     function PasteSelection: boolean;
+    procedure Transform(AMatrix: TAffineMatrix); override;
     property HasSelection: boolean read GetHasSelection;
     property CanPasteSelection: boolean read GetCanPasteSelection;
     property Text: string read FText write SetText;
@@ -1355,6 +1356,18 @@ begin
     result := false;
 end;
 
+procedure TTextShape.Transform(AMatrix: TAffineMatrix);
+var
+  zoom: Single;
+begin
+  BeginUpdate;
+  inherited Transform(AMatrix);
+  zoom := (VectLen(AMatrix[1,1],AMatrix[2,1])+VectLen(AMatrix[1,2],AMatrix[2,2]))/2;
+  FontEmHeight:= zoom*FontEmHeight;
+  LightPosition := AMatrix*LightPosition;
+  EndUpdate;
+end;
+
 class function TTextShape.StorageClassName: RawByteString;
 begin
   result := 'text';