Kaynağa Gözat

curve support, refactoring

Unknown 7 yıl önce
ebeveyn
işleme
184e9285b8
3 değiştirilmiş dosya ile 101 ekleme ve 40 silme
  1. 6 7
      vectoredit/umain.lfm
  2. 38 21
      vectoredit/umain.pas
  3. 57 12
      vectoredit/uvectororiginal.pas

+ 6 - 7
vectoredit/umain.lfm

@@ -1,5 +1,5 @@
 object Form1: TForm1
-  Left = 535
+  Left = 534
   Height = 410
   Top = 0
   Width = 627
@@ -102,7 +102,7 @@ object Form1: TForm1
       EdgeOuter = esNone
       Images = BGRAImageList1
       TabOrder = 0
-      object ToolButtonRect: TToolButton
+      object ToolButtonRectangle: TToolButton
         Left = 1
         Top = 55
         Caption = 'Rectangle'
@@ -120,24 +120,23 @@ object Form1: TForm1
         OnClick = ToolButtonClick
         Style = tbsCheck
       end
-      object ToolButtonPoly: TToolButton
+      object ToolButtonPolygon: TToolButton
         Left = 1
         Top = 165
-        Caption = 'ToolButtonPoly'
+        Caption = 'Polygon'
         Grouped = True
         ImageIndex = 21
         OnClick = ToolButtonClick
         Style = tbsCheck
       end
-      object ToolButtonCurvedPoly: TToolButton
+      object ToolButtonClosedCurve: TToolButton
         Left = 1
         Top = 220
-        Caption = 'ToolButtonCurvedPoly'
+        Caption = 'Closed curve'
         Grouped = True
         ImageIndex = 22
         OnClick = ToolButtonClick
         Style = tbsCheck
-        Visible = False
       end
       object ToolButtonMove: TToolButton
         Left = 1

+ 38 - 21
vectoredit/umain.pas

@@ -14,7 +14,15 @@ const
   EditorPointSize = 8;
 
 type
+  TPaintTool = (ptHand, ptRectangle, ptEllipse, ptPolyline, ptCurve, ptPolygon, ptClosedCurve);
 
+const
+  PaintToolClass : array[TPaintTool] of TVectorShapeAny =
+    (nil, TRectShape, TEllipseShape, TPolylineShape, TCurveShape, TPolylineShape, TCurveShape);
+
+function IsCreateShapeTool(ATool: TPaintTool): boolean;
+
+type
   { TForm1 }
 
   TForm1 = class(TForm)
@@ -32,9 +40,9 @@ type
     ShapePenColor: TShape;
     ToolBar1: TToolBar;
     ToolButtonMove: TToolButton;
-    ToolButtonCurvedPoly: TToolButton;
-    ToolButtonPoly: TToolButton;
-    ToolButtonRect: TToolButton;
+    ToolButtonClosedCurve: TToolButton;
+    ToolButtonPolygon: TToolButton;
+    ToolButtonRectangle: TToolButton;
     ToolButtonEllipse: TToolButton;
     UpDownPenAlpha: TBCTrackbarUpdown;
     procedure BGRAVirtualScreen1MouseDown(Sender: TObject;
@@ -64,7 +72,7 @@ type
     FLastEditorBounds: TRect;
     FUpdatingFromShape: boolean;
     FUpdatingComboBoxPenStyle, FUpdatingSpinEditPenWidth: boolean;
-    FCurrentTool: TVectorShapeAny;
+    FCurrentTool: TPaintTool;
     function GetBackColor: TBGRAPixel;
     function GetPenColor: TBGRAPixel;
     function GetPenStyle: TBGRAPenStyle;
@@ -75,7 +83,7 @@ type
     procedure OnOriginalChange({%H-}ASender: TObject; AOriginal: TBGRALayerCustomOriginal);
     procedure OnSelectShape(ASender: TObject; AShape: TVectorShape; APreviousShape: TVectorShape);
     procedure SetBackColor(AValue: TBGRAPixel);
-    procedure SetCurrentTool(AValue: TVectorShapeAny);
+    procedure SetCurrentTool(AValue: TPaintTool);
     procedure SetPenColor(AValue: TBGRAPixel);
     procedure SetPenStyle(AValue: TBGRAPenStyle);
     procedure SetPenWidth(AValue: single);
@@ -102,7 +110,7 @@ type
     property backColor: TBGRAPixel read GetBackColor write SetBackColor;
     property penWidth: single read GetPenWidth write SetPenWidth;
     property penStyle: TBGRAPenStyle read GetPenStyle write SetPenStyle;
-    property currentTool: TVectorShapeAny read FCurrentTool write SetCurrentTool;
+    property currentTool: TPaintTool read FCurrentTool write SetCurrentTool;
   end;
 
 var
@@ -112,6 +120,11 @@ implementation
 
 uses math, LCLType, BGRAPen;
 
+function IsCreateShapeTool(ATool: TPaintTool): boolean;
+begin
+  result := PaintToolClass[ATool] <> nil;
+end;
+
 {$R *.lfm}
 
 { TForm1 }
@@ -131,7 +144,7 @@ begin
   backColor := CSSDodgerBlue;
   penWidth := 5;
   penStyle := SolidPenStyle;
-  currentTool:= TRectShape;
+  currentTool:= ptRectangle;
 end;
 
 procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
@@ -213,7 +226,7 @@ begin
   UpdateViewCursor(cur);
 
   ptF := AffineMatrixInverse(vectorTransform)*imgPtF;
-  if justDown and not Assigned(newShape) and Assigned(currentTool) then
+  if justDown and not Assigned(newShape) and IsCreateShapeTool(currentTool) then
   begin
     vectorOriginal.DeselectShape;
     newShape := CreateShape(newStartPoint,ptF);
@@ -247,7 +260,7 @@ begin
 
   if justDown and (Button = newButton) then
   begin
-    if Assigned(currentTool) and (vsuCreate in currentTool.Usermodes) then
+    if IsCreateShapeTool(currentTool) and (vsuCreate in PaintToolClass[currentTool].Usermodes) then
     begin
       vectorOriginal.AddShape(CreateShape(newStartPoint,newStartPoint), vsuCreate);
     end else
@@ -319,11 +332,12 @@ end;
 
 procedure TForm1.ToolButtonClick(Sender: TObject);
 begin
-  currentTool := nil;
-  if ToolButtonEllipse.Down then currentTool:= TEllipseShape;
-  if ToolButtonRect.Down then currentTool:= TRectShape;
-  if ToolButtonPoly.Down then currentTool:= TPolygonShape;
-  if Assigned(currentTool) then
+  currentTool := ptHand;
+  if ToolButtonEllipse.Down then currentTool:= ptEllipse;
+  if ToolButtonRectangle.Down then currentTool:= ptRectangle;
+  if ToolButtonPolygon.Down then currentTool:= ptPolygon;
+  if ToolButtonClosedCurve.Down then currentTool:= ptClosedCurve;
+  if IsCreateShapeTool(currentTool) then
   begin
     if Assigned(vectorOriginal) and (vectorOriginal.SelectedShape <> nil) then vectorOriginal.DeselectShape
     else UpdateToolbarFromShape(nil);
@@ -430,13 +444,14 @@ begin
   end;
 end;
 
-procedure TForm1.SetCurrentTool(AValue: TVectorShapeAny);
+procedure TForm1.SetCurrentTool(AValue: TPaintTool);
 begin
   if FCurrentTool=AValue then Exit;
   FCurrentTool:=AValue;
-  ToolButtonRect.Down := FCurrentTool = TRectShape;
-  ToolButtonEllipse.Down := FCurrentTool = TEllipseShape;
-  ToolButtonPoly.Down := FCurrentTool = TPolygonShape;
+  ToolButtonRectangle.Down := FCurrentTool = ptRectangle;
+  ToolButtonEllipse.Down := FCurrentTool = ptEllipse;
+  ToolButtonPolygon.Down := FCurrentTool = ptPolygon;
+  ToolButtonClosedCurve.Down := FCurrentTool = ptClosedCurve;
 end;
 
 procedure TForm1.SetPenColor(AValue: TBGRAPixel);
@@ -598,7 +613,7 @@ begin
     FUpdatingFromShape := false;
   end else
   begin
-    if Assigned(currentTool) then f := currentTool.Fields else f := [];
+    if IsCreateShapeTool(currentTool) then f := PaintToolClass[currentTool].Fields else f := [];
     FloatSpinEditPenWidth.Enabled := vsfPenWidth in f;
     ComboBoxPenStyle.Enabled:= vsfPenStyle in f;
   end;
@@ -606,13 +621,15 @@ end;
 
 function TForm1.CreateShape(const APoint1,APoint2: TPointF): TVectorShape;
 begin
-  if not Assigned(currentTool) then
+  if not IsCreateShapeTool(currentTool) then
     raise exception.Create('No shape type selected');
-  result := currentTool.Create;
+  result := PaintToolClass[currentTool].Create;
   result.PenColor := penColor;
   result.BackColor := backColor;
   result.PenWidth := penWidth;
   result.PenStyle := penStyle;
+  if currentTool in[ptClosedCurve,ptPolygon] then
+    TCustomPolypointShape(result).Closed := true;
   result.QuickDefine(APoint1,APoint2);
 end;
 

+ 57 - 12
vectoredit/uvectororiginal.pas

@@ -147,6 +147,7 @@ type
 
   TCustomPolypointShape = class(TVectorShape)
   private
+    FClosed: boolean;
     function GetPoint(AIndex: integer): TPointF;
     function GetPointCount: integer;
     procedure SetPoint(AIndex: integer; AValue: TPointF);
@@ -165,6 +166,8 @@ type
     procedure OnStartMove({%H-}ASender: TObject; APointIndex: integer; {%H-}AShift: TShiftState);
     function GetCurve(AMatrix: TAffineMatrix): ArrayOfTPointF; virtual;
     procedure SetUsermode(AValue: TVectorShapeUsermode); override;
+    function GetClosed: boolean; virtual;
+    procedure SetClosed(AValue: boolean); virtual;
     function PointsEqual(const APoint1, APoint2: TPointF): boolean;
   public
     constructor Create;
@@ -179,11 +182,12 @@ type
     class function Usermodes: TVectorShapeUsermodes; override;
     property Points[AIndex:integer]: TPointF read GetPoint write SetPoint;
     property PointCount: integer read GetPointCount;
+    property Closed: boolean read GetClosed write SetClosed;
   end;
 
-  { TPolygonShape }
+  { TPolylineShape }
 
-  TPolygonShape = class(TCustomPolypointShape)
+  TPolylineShape = class(TCustomPolypointShape)
   protected
     function PenVisible: boolean;
     function BackVisible: boolean;
@@ -196,6 +200,15 @@ type
     class function StorageClassName: RawByteString; override;
   end;
 
+  { TCurveShape }
+
+  TCurveShape = class(TPolylineShape)
+  protected
+    function GetCurve(AMatrix: TAffineMatrix): ArrayOfTPointF; override;
+  public
+    class function StorageClassName: RawByteString; override;
+  end;
+
   TVectorOriginalSelectShapeEvent = procedure(ASender: TObject; AShape: TVectorShape; APreviousShape: TVectorShape) of object;
 
   TVectorOriginalEditor = class;
@@ -289,6 +302,22 @@ begin
   VectorShapeClasses[high(VectorShapeClasses)] := AClass;
 end;
 
+{ TCurveShape }
+
+function TCurveShape.GetCurve(AMatrix: TAffineMatrix): ArrayOfTPointF;
+var
+  pts: array of TPointF;
+begin
+  pts := inherited GetCurve(AMatrix);
+  if Closed then result := ComputeClosedSpline(pts, ssCrossingWithEnds)
+  else result := ComputeOpenedSpline(pts, ssCrossingWithEnds);
+end;
+
+class function TCurveShape.StorageClassName: RawByteString;
+begin
+  Result:= 'curve';
+end;
+
 { TVectorOriginalEditor }
 
 constructor TVectorOriginalEditor.Create(AOriginal: TVectorOriginal);
@@ -323,24 +352,24 @@ begin
     FOriginal.SelectedShape.MouseUp(RightButton, Shift, X,Y, ACursor, AHandled);
 end;
 
-{ TPolygonShape }
+{ TPolylineShape }
 
-function TPolygonShape.PenVisible: boolean;
+function TPolylineShape.PenVisible: boolean;
 begin
   result := (PenWidth>0) and (PenColor.alpha>0) and not IsClearPenStyle(PenStyle);
 end;
 
-function TPolygonShape.BackVisible: boolean;
+function TPolylineShape.BackVisible: boolean;
 begin
   result := BackColor.alpha <> 0;
 end;
 
-class function TPolygonShape.Fields: TVectorShapeFields;
+class function TPolylineShape.Fields: TVectorShapeFields;
 begin
   Result:= [vsfPenColor, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackColor];
 end;
 
-procedure TPolygonShape.Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix;
+procedure TPolylineShape.Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix;
   ADraft: boolean);
 var
   pts: array of TPointF;
@@ -364,7 +393,7 @@ begin
   end;
 end;
 
-function TPolygonShape.GetRenderBounds(ADestRect: TRect; AMatrix: TAffineMatrix): TRectF;
+function TPolylineShape.GetRenderBounds(ADestRect: TRect; AMatrix: TAffineMatrix): TRectF;
 var
   i: Integer;
   pts: ArrayOfTPointF;
@@ -402,7 +431,7 @@ begin
   end;
 end;
 
-function TPolygonShape.PointInShape(APoint: TPointF): boolean;
+function TPolylineShape.PointInShape(APoint: TPointF): boolean;
 var
   pts: ArrayOfTPointF;
 begin
@@ -417,18 +446,23 @@ begin
   result := false;
 end;
 
-function TPolygonShape.GetIsSlow(AMatrix: TAffineMatrix): boolean;
+function TPolylineShape.GetIsSlow(AMatrix: TAffineMatrix): boolean;
 begin
   Result:= PointCount > 40;
 end;
 
-class function TPolygonShape.StorageClassName: RawByteString;
+class function TPolylineShape.StorageClassName: RawByteString;
 begin
-  result := 'polygon';
+  result := 'polyline';
 end;
 
 { TCustomPolypointShape }
 
+function TCustomPolypointShape.GetClosed: boolean;
+begin
+  result := FClosed;
+end;
+
 function TCustomPolypointShape.GetPoint(AIndex: integer): TPointF;
 begin
   if (AIndex < 0) or (AIndex >= length(FPoints)) then
@@ -441,6 +475,14 @@ begin
   result:= length(FPoints);
 end;
 
+procedure TCustomPolypointShape.SetClosed(AValue: boolean);
+begin
+  if AValue = FClosed then exit;
+  BeginUpdate;
+  FClosed := AValue;
+  EndUpdate;
+end;
+
 procedure TCustomPolypointShape.SetPoint(AIndex: integer; AValue: TPointF);
 begin
   if (AIndex < 0) or (AIndex > length(FPoints)) then
@@ -549,6 +591,7 @@ constructor TCustomPolypointShape.Create;
 begin
   inherited Create;
   FMousePos := EmptyPointF;
+  FClosed:= false;
 end;
 
 procedure TCustomPolypointShape.AddPoint(const APoint: TPointF);
@@ -610,6 +653,7 @@ begin
     FPoints[i].coord := PointF(x[i],y[i]);
     FPoints[i].editorIndex := -1;
   end;
+  FClosed:= AStorage.Bool['closed'];
   EndUpdate;
 end;
 
@@ -628,6 +672,7 @@ begin
   end;
   AStorage.FloatArray['x'] := x;
   AStorage.FloatArray['y'] := y;
+  AStorage.Bool['closed'] := Closed;
 end;
 
 function TCustomPolypointShape.GetRenderBounds(ADestRect: TRect;