⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flexpath.pas

📁 是一套创建矢量图形的VCL组件
💻 PAS
📖 第 1 页 / 共 4 页
字号:
       NeedMove := Selected[Index];
       if not NeedMove and (Index > NodeIndex) then
        // Check control point
        if Index - NodeIndex = 1 then begin
         // First control point - NodeIndex is owner
         NeedMove := Selected[NodeIndex];
        end else begin
         // Second control point - owner is next (or first in figure) node
         if Types[NodeIndex] = ptEndNodeClose then
          // Last node and closed figure - check first node
          NeedMove := Selected[FirstIndex]
         else
         if Types[NodeIndex] <> ptEndNode then
          // Check next node in figure
          NeedMove := Selected[NodeIndex+3];
        end;
       if NeedMove then begin
        inc(Points[Index].x, Offset.x);
        inc(Points[Index].y, Offset.y);
        Result := true; // Points changed
       end;
      end;
     end;
{  pfDelete:
    begin
     DeltaCount := 0;
     Index := 0;
     BreakIndex := 0;
     FirstIndex := -1;
     NodeIndex := -1;
     while Index < Count do begin
      if Index = BreakIndex then FirstIndex := Index;
      if Types[Index] <> ptControl then begin
       NodeIndex := Index;
       if Types[Index] in [ptEndNode, ptEndNodeClose] then
        if (Index < Count-1) and (Types[Index+1] = ptControl)
          then BreakIndex := Index + 3
          else BreakIndex := Index + 1;
       if Selected[Index+DeltaCount] then begin

       end
      end else
       // Skip control points
       inc(Index);
     end;
    end;  }
  pfJoin,
  pfClose:
    begin
     FirstIndex := -1;
     LastIndex := -1;
     SameFigure := true;
     for Index := 0 to Count-1 do begin
      if Selected[Index] then
       if FirstIndex < 0 then
        FirstIndex := Index
       else
       if LastIndex < 0 then begin
        LastIndex := Index;
        break;
       end;
      if (FirstIndex >= 0) and
         (Types[Index] in [ptEndNode, ptEndNodeClose]) then
       SameFigure := false;
     end;
     if (FirstIndex < 0) or (LastIndex < 0) then exit; // can't complete
     if SameFigure then begin
      case Func of
       pfJoin:
         // Join edge points of the figure
         if Types[LastIndex] = ptEndNode then begin
          // Find previous node
          Index := LastIndex -1;
          while (Index >= FirstIndex) and (Types[Index] = ptControl) do
           dec(Index);
          if Index < FirstIndex then exit; // error
          // Close figure and delete last point (join to first)
          Types[Index] := ptEndNodeClose;
          // Calculate middle point
          with Points[FirstIndex] do begin
           p0.x := x + abs(x - Points[LastIndex].x) div 2;
           p0.y := y + abs(y - Points[LastIndex].y) div 2;
          end;
          Points[FirstIndex] := p0;
          ChangeCount(LastIndex, -1);
         end;
       pfClose:
         // Close figure
         if Types[LastIndex] = ptEndNode then begin
          Types[LastIndex] := ptEndNodeClose;
          Result := true; // Points changed
         end;
      end;
      exit;
     end;
     // Define first and end nodes of selected figures
     if not CalcFigure(FirstIndex, First) then exit;
     if not CalcFigure(LastIndex, Second) then exit;
     // Calculate point count between first and second figures
     MoveCount := Second.FirstNode - First.LastPoint -1;
     if MoveCount > 0 then begin
      // Move Second figure after First figure
      DeltaCount := Second.LastPoint - Second.FirstNode +1;
      // Move points
      Size := DeltaCount * SizeOf(Points[0]);
      SetLength(Temp, Size);
      Move(Points[Second.FirstNode], Temp[0], Size);
      Move(Points[First.LastPoint+1], Points[First.LastPoint+1 +DeltaCount],
        MoveCount * SizeOf(Points[0]));
      Move(Temp[0], Points[First.LastPoint+1], Size);
      // Move types
      Size := DeltaCount * SizeOf(Types[0]);
      if Size > Length(Temp) then SetLength(Temp, Size);
      Move(Types[Second.FirstNode], Temp[0], Size);
      Move(Types[First.LastPoint+1], Types[First.LastPoint+1 +DeltaCount],
        MoveCount * SizeOf(Types[0]));
      Move(Temp[0], Types[First.LastPoint+1], Size);
      with Second do begin
       dec(FirstNode, MoveCount);
       dec(EndNode, MoveCount);
       dec(LastPoint, MoveCount);
       dec(LastIndex, MoveCount);
      end;
      Result := true; // Points changed
     end;
     // Check direction of First and Second figures
     if FirstIndex <> First.EndNode then ReverseFigureDirection(First);
     if LastIndex <> Second.FirstNode then ReverseFigureDirection(Second);
     // Complete function
     case Func of
      pfJoin:
        begin
         // Calculate middle point
         with Points[First.EndNode] do begin
          p0.x := x + abs(x - Points[Second.FirstNode].x) div 2;
          p0.y := y + abs(y - Points[Second.FirstNode].y) div 2;
         end;
         // Delete First.EndNode point
         if (First.EndNode < Count-1) and (Types[First.EndNode+1] = ptControl)
          then ChangeCount(First.EndNode, -3)
          else ChangeCount(First.EndNode, -1);
         // Set calculated middle point as result of join
         Points[First.EndNode] := p0;
        end;
      pfClose:
        // Replace ptEndNode type to ptNode (link figures)
        begin
         Types[First.EndNode] := ptNode;
         Result := true; // Points changed
        end;
     end;
    end;
  pfBreak:
    begin
     Index := 0;
     DeltaCount := 0;
     FirstIndex := 0;
     while Index < Count do begin
      BreakIndex := -1;
      // Define last point in figure
      LastIndex := FirstIndex;
      while (LastIndex < Count) and not
            (Types[LastIndex] in [ptEndNode, ptEndNodeClose]) do
       inc(LastIndex);
      if LastIndex = Count then break; // error in point types
      Index := FirstIndex;
      while Index <= LastIndex do begin
       if Selected[Index+DeltaCount] then
        if Types[Index] <> ptControl then begin
         // Break selected point
         ChangeCount(Index, 1);
         Types[Index] := ptEndNode;
         inc(LastIndex);
         inc(Index);
         dec(DeltaCount);
         BreakIndex := Index;
        end;
       inc(Index);
      end;
      // Check figure breaking
      if (BreakIndex >= 0) and (Types[LastIndex] = ptEndNodeClose) then begin
       Types[LastIndex] := ptNode;
       // Define last point of the figure
       if (LastIndex < Count-1) and (Types[LastIndex+1] = ptControl) then
        inc(LastIndex, 2);
       // Move points after last breaked before first point of the figure
       MoveCount := LastIndex - BreakIndex +1;
       // Move points
       Size := MoveCount * SizeOf(Points[0]);
       SetLength(Temp, Size);
       Move(Points[BreakIndex], Temp[0], Size);
       Move(Points[FirstIndex], Points[FirstIndex+MoveCount],
         (BreakIndex - FirstIndex) * SizeOf(Points[0]));
       Move(Temp[0], Points[FirstIndex], Size);
       // Move types
       Size := MoveCount * SizeOf(Types[0]);
       if Size > Length(Temp) then SetLength(Temp, Size);
       Move(Types[BreakIndex], Temp[0], Size);
       Move(Types[FirstIndex], Types[FirstIndex+MoveCount],
         (BreakIndex - FirstIndex) * SizeOf(Types[0]));
       Move(Temp[0], Types[FirstIndex], Size);
      end;
      FirstIndex := Index;
     end;
    end;
  pfToCurve:
    begin
     Index := 0;
     DeltaCount := 0;
     FirstIndex := 0;
     while Index < Count do begin
      // Define last point in figure
      LastIndex := FirstIndex;
      while (LastIndex < Count) and not
            (Types[LastIndex] in [ptEndNode, ptEndNodeClose]) do
       inc(LastIndex);
      if LastIndex = Count then break; // error in point types
      Index := FirstIndex;
      while Index <= LastIndex do begin
       if Selected[Index+DeltaCount] and
          ((Index >= Count-1) or (Types[Index+1] <> ptControl)) then begin
        // Define line points
        Error := false;
        p0 := Points[Index];
        if Types[Index] = ptEndNodeClose then
         p1 := Points[FirstIndex]
        else
        if Index < LastIndex then
         p1 := Points[Index+1]
        else
         // Can't convert point
         Error := true;
        if not Error then begin
         // Calculate control points
         CtrlPointA.x := p0.x + (p1.x - p0.x) div 3;
         CtrlPointA.y := p0.y + (p1.y - p0.y) div 3;
         CtrlPointB.x := p1.x - (p1.x - p0.x) div 3;
         CtrlPointB.y := p1.y - (p1.y - p0.y) div 3;
         // Convert to curve point
         ChangeCount(Index+1, 2);
         Points[Index+1] := CtrlPointA;
         Types[Index+1] := ptControl;
         Points[Index+2] := CtrlPointB;
         Types[Index+2] := ptControl;
         inc(Index, 2);
         inc(LastIndex, 2);
         dec(DeltaCount, 2);
        end;
       end;
       inc(Index);
      end;
      FirstIndex := Index;
     end;
    end;
  pfToLine:
    begin
     Index := 0;
     DeltaCount := 0;
     while Index < Count do begin
      if Selected[Index+DeltaCount] and
        (Index < Count-1) and (Types[Index+1] = ptControl) then begin
       // Convert curve point to line point
       ChangeCount(Index+1, -2);
       inc(DeltaCount, 2);
      end;
      inc(Index);
     end;
    end;
 end;
end;

function  EditPath(var Points: TPointArray; var Types: TPointTypeArray;
  const Indexes: array of integer; Func: TPathEditFunc;
  Params: PPathEditParams = Nil): boolean; overload;
var Selected: TSelectedArray;
    i: integer;
begin
 SetLength(Selected, Length(Points));
 for i:=0 to Length(Selected)-1 do Selected[i] := false;
 for i:=0 to Length(Indexes)-1 do
  if Indexes[i] < Length(Selected) then Selected[Indexes[i]] := true;
 Result := EditPath(Points, Types, Selected, Func, Params);
end;

procedure GetPathInfo(const Points: TPointArray; const Types: TPointTypeArray;
  var Info: TPathInfo);
var i, Count, LastCount: integer;
    FigIndex, FigCount: integer;
    FirstNodeIndex: integer;
begin
 Info.IsCurve := false;
 Count := Length(Points);
 if (Count = 0) or (Count <> Length(Types)) then begin
  Info.Figures := Nil;
  exit;
 end;
 FigCount := Length(Info.Figures);
 FigIndex := -1;
 FirstNodeIndex := 0;
 with Info do begin
  PointCount := Count;
  for i:=0 to Count-1 do begin
   if i = FirstNodeIndex then begin
    // Start of figure
    inc(FigIndex);
    if FigIndex >= FigCount then begin
     FigCount := FigIndex+1;
     SetLength(Figures, FigCount);
    end;
    with Figures[FigIndex] do begin
     FirstNode := FirstNodeIndex;
     LastNode := -1;
     LastPoint := -1;
     IsClosed := false;
     IsCurve := false;
    end;
   end;
   case Types[i] of
    ptControl:
      // Curve point in figure
      Figures[FigIndex].IsCurve := true;
    ptEndNode,
    ptEndNodeClose:
      with Figures[FigIndex] do begin
       // End of figure
       LastNode := i;
       IsClosed := Types[i] = ptEndNodeClose;
       if (i < Count-2) and (Types[i+1] = ptControl) then begin
        LastCount := 3;
        IsCurve := true;
       end else
        LastCount := 1;
       FirstNodeIndex := i + LastCount;
       LastPoint := i + LastCount-1;
       Info.IsCurve := Info.IsCurve or IsCurve;
      end;
   end;
  end;
 end;
 if FigIndex < FigCount-1 then SetLength(Info.Figures, FigIndex+1);
end;

function GetFigureIndex(var Info: TPathInfo; PointIndex: integer): integer;
var i: integer;
begin
 Result := -1;
 for i:=0 to Length(Info.Figures)-1 do with Info.Figures[i] do
  if (PointIndex >= FirstNode) and (PointIndex <= LastPoint) then begin
   Result := i;
   break;
  end;
end;

function ChangePathCount(var Points: TPointArray; var Types: TPointTypeArray;
  Index, Delta: integer): boolean;
var Count: integer;
begin
 Count := Length(Points);
 Result := (Count = Length(Types)) and (Index >= 0) and (Index <= Count);
 if not Result then exit;
 if Delta > 0 then begin
  SetLength(Points, Count + Delta);
  SetLength(Types, Count + Delta);
 end else
  dec(Index, Delta);
 Move(Points[Index], Points[Index+Delta], (Count - Index) * SizeOf(Points[0]));
 Move(Types[Index], Types[Index+Delta], (Count - Index) * SizeOf(Types[0]));
 if Delta < 0 then begin
  SetLength(Points, Count + Delta);
  SetLength(Types, Count + Delta);
 end;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -