Преглед на файлове

close polygon easily, add sub poly

add sub poly by holding SHIFT key when clicking, close polygon using
right-click on the last or the first point, or by left-clicking the
first point
johann преди 5 години
родител
ревизия
c8cd7c1c40
променени са 1 файла, в които са добавени 92 реда и са изтрити 21 реда
  1. 92 21
      lazpaintcontrols/lcvectorpolyshapes.pas

+ 92 - 21
lazpaintcontrols/lcvectorpolyshapes.pas

@@ -93,6 +93,8 @@ type
     procedure InsertPointAuto(AShift: TShiftState);
     function ComputeStroke(APoints: ArrayOfTPointF; AClosed: boolean;
       AStrokeMatrix: TAffineMatrix): ArrayOfTPointF; override;
+    function GetLoopStartIndex: integer;
+    function GetLoopPointCount: integer;
   public
     constructor Create(AContainer: TVectorOriginal); override;
     procedure Clear;
@@ -637,17 +639,34 @@ end;
 
 procedure TCustomPolypointShape.DoClickPoint(APointIndex: integer;
   AShift: TShiftState);
+var
+  nb: Integer;
 begin
-  if (APointIndex = 0) and (UserMode = vsuCreate) and not Closed then
+  if FAddingPoint and ((APointIndex = GetLoopStartIndex) or
+     ((APointIndex = PointCount-2) and (ssRight in AShift))) then
   begin
-    if PointCount > 2 then
+    nb := GetLoopPointCount;
+    if nb > 2 then
     begin
+      BeginUpdate;
       RemovePoint(PointCount-1);
-      Closed := true;
+      if APointIndex < PointCount-2 then Closed := true;
+      EndUpdate;
       UserMode := vsuEdit;
     end else
     begin
-      Remove;
+      if GetLoopStartIndex = 0 then
+        Remove
+      else
+      begin
+        BeginUpdate;
+        while nb > 0 do
+        begin
+          RemovePoint(PointCount-1);
+          dec(nb);
+        end;
+        RemovePoint(PointCount-1); //remove separator
+      end;
     end;
   end;
 end;
@@ -659,11 +678,12 @@ end;
 
 procedure TCustomPolypointShape.InsertPointAuto(AShift: TShiftState);
 var
-  bestSegmentIndex, i: Integer;
+  bestSegmentIndex, i,j, loopStart: Integer;
   bestSegmentDist,
   segmentLen, segmentPos: single;
   u, n, bestProjection: TPointF;
   segmentDist: single;
+  isLooping: Boolean;
 begin
   if isEmptyPointF(FMousePos) then exit;
 
@@ -673,11 +693,21 @@ begin
   bestSegmentIndex := -1;
   bestSegmentDist := MaxSingle;
   bestProjection := EmptyPointF;
+  loopStart := 0;
   for i := 0 to PointCount-1 do
   if FAddingPoint and (i >= PointCount-2) then break else
   begin
-    if (i = PointCount-1) and not Closed then break;
-    u := Points[(i+1) mod PointCount] - Points[i];
+    if IsEmptyPointF(Points[i]) then
+    begin
+      loopStart := i+1;
+      continue;
+    end;
+    isLooping := (i = PointCount-1) or IsEmptyPointF(Points[i+1]);
+    if isLooping and not Closed then break;
+    if isLooping then
+      j := loopStart
+      else j := i+1;
+    u := Points[j] - Points[i];
     segmentLen := VectLen(u);
     if segmentLen > 0 then
     begin
@@ -722,6 +752,20 @@ begin
   Stroker.Arrow.EndAsNone;
 end;
 
+function TCustomPolypointShape.GetLoopStartIndex: integer;
+var
+  i: Integer;
+begin
+  for i := PointCount-1 downto 0 do
+    if isEmptyPointF(Points[i]) then exit(i+1);
+  exit(0);
+end;
+
+function TCustomPolypointShape.GetLoopPointCount: integer;
+begin
+  result := PointCount-GetLoopStartIndex;
+end;
+
 constructor TCustomPolypointShape.Create(AContainer: TVectorOriginal);
 begin
   inherited Create(AContainer);
@@ -805,11 +849,25 @@ begin
     end else
       Usermode := vsuEdit;
     AHandled:= true;
+  end else
+  begin
+    if (ssShift in Shift) and (Usermode = vsuEdit) then
+    begin
+      BeginUpdate;
+      AddPoint(EmptyPointF);
+      FMousePos := PointF(X,Y);
+      AddPoint(FMousePos);
+      EndUpdate;
+      USerMode := vsuCreate;
+      AHandled:= true;
+    end;
   end;
 end;
 
 procedure TCustomPolypointShape.KeyDown(Shift: TShiftState; Key: TSpecialKey;
   var AHandled: boolean);
+var
+  nb: Integer;
 begin
   if (Key = skDelete) and (FAddingPoint or ((FHoverPoint >= 0) and (FHoverPoint < PointCount))) then
   begin
@@ -817,7 +875,14 @@ begin
     begin
       BeginUpdate(TCustomPolypointShapeDiff);
       RemovePoint(FHoverPoint);
-      if (FHoverPoint < PointCount) and IsEmptyPointF(Points[FHoverPoint]) then RemovePoint(FHoverPoint);
+      if ((FHoverPoint = PointCount) or IsEmptyPointF(Points[FHoverPoint])) and
+         ((FHoverPoint = 0) or IsEmptyPointF(Points[FHoverPoint-1])) then
+      begin
+        if FHoverPoint < PointCount then
+          RemovePoint(FHoverPoint)
+        else if FHoverPoint > 0 then
+          RemovePoint(FHoverPoint-1);
+      end;
       EndUpdate;
       if PointCount = 0 then self.Remove;
     end;
@@ -825,13 +890,18 @@ begin
   end else
   if (Key = skBackspace) and FAddingPoint then
   begin
-    If PointCount <= 2 then self.Remove else
-    If isEmptyPointF(Points[PointCount-3]) then
+    nb := GetLoopPointCount;
+    if nb > 2 then
+      RemovePoint(PointCount-2)
+    else
     begin
-      RemovePointRange(PointCount-3, PointCount);
-      Usermode:= vsuEdit;
-    end else
-      RemovePoint(PointCount-2);
+      if GetLoopStartIndex = 0 then self.Remove
+      else
+      begin
+        RemovePointRange(PointCount-3, PointCount);
+        Usermode:= vsuEdit;
+      end;
+    end;
     AHandled:= true;
   end else
   if (Key = skInsert) then InsertPointAuto(Shift) else
@@ -903,21 +973,22 @@ end;
 
 procedure TCustomPolypointShape.ConfigureCustomEditor(AEditor: TBGRAOriginalEditor);
 var
-  i, nb: Integer;
+  i, nbTotal: Integer;
 begin
   AEditor.AddStartMoveHandler(@OnStartMove);
   AEditor.AddClickPointHandler(@OnClickPoint);
   AEditor.AddHoverPointHandler(@OnHoverPoint);
-  nb := 0;
+
   FCenterPoint := PointF(0,0);
+  nbTotal := 0;
   for i:= 0 to PointCount-1 do
     if isEmptyPointF(Points[i]) then
       FPoints[i].editorIndex := -1
-    else if (FAddingPoint and (i = PointCount-1) and (PointCount > 1)) then
+    else if (FAddingPoint and (i = PointCount-1) and (GetLoopPointCount > 1)) then
     begin
       FPoints[i].editorIndex := -1;
       FCenterPoint += Points[i];
-      inc(nb);
+      inc(nbTotal);
     end
     else
     begin
@@ -926,12 +997,12 @@ begin
       else
         FPoints[i].editorIndex := AEditor.AddFixedPoint(Points[i], false);
       FCenterPoint += Points[i];
-      inc(nb);
+      inc(nbTotal);
     end;
 
-  if (FAddingPoint and (nb > 2)) or (not FAddingPoint and (nb > 1)) then
+  if (FAddingPoint and (nbTotal > 2)) or (not FAddingPoint and (nbTotal > 1)) then
   begin
-    FCenterPoint *= 1/nb;
+    FCenterPoint *= 1/nbTotal;
     FCenterPointEditorIndex := AEditor.AddPoint(FCenterPoint, @OnMoveCenterPoint, true);
   end;
 end;