📄 flexpath.pas
字号:
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 + -