📄 ezlib.pas
字号:
visible := true;
End;
End;
{ if Canvas and Grapher are not nil then draw line from p1 to p2 }
If visible Then
Begin
If ( Canvas <> Nil ) And ( Grapher <> Nil ) Then
Begin
dp1 := Grapher.RealToPoint( TransformPoint2D( p1, Matrix ) );
dp2 := Grapher.RealToPoint( TransformPoint2D( p2, Matrix ) );
Canvas.MoveTo( dp1.x, dp1.y );
Canvas.LineTo( dp2.x, dp2.y );
End;
If ResultVector <> Nil Then
Begin
ResultVector.Parts.Add( ResultVector.Count );
ResultVector.Add( p1 );
ResultVector.Add( p2 );
End;
End;
End;
Begin
n := 0;
If FParts.Count < 2 Then
Begin
Idx1 := 0;
Idx2 := FCount - 1;
End
Else
Begin
Idx1 := FParts[n];
Idx2 := FParts[n + 1] - 1;
End;
Repeat
For i := Idx1 + 1 To Idx2 Do
clipLine( FPoints^[i - 1], FPoints^[i] );
If FParts.Count < 2 Then
Break;
Inc( n );
If n >= FParts.Count Then
Break;
Idx1 := FParts[n];
If n < FParts.Count - 1 Then
Idx2 := FParts[n + 1] - 1
Else
Idx2 := FCount - 1;
Until false;
{if not EqualPoint2D(FPoints^[FCount - 1], FPoints^[0]) then
clipLine( FPoints^[FCount - 1], FPoints^[0]); }
End;
Function TEzVector.CrossFrame( Const Frm: TEzRect; Const M: TEzMatrix ): Boolean;
Var
cnt, n, Idx1, Idx2: Integer;
TmpPt1, TmpPt2: TEzPoint;
ClipRes: TEzClipCodes;
Begin
Result := false;
If FCount = 0 Then
Exit;
If IsBoxFullInBox2D( Self.Extension, Frm ) Then
Result := true
Else
Begin
n := 0;
If FParts.Count < 2 Then
Begin
Idx1 := 0;
Idx2 := FCount - 1;
End
Else
Begin
Idx1 := FParts[n];
Idx2 := FParts[n + 1] - 1;
End;
Repeat
For cnt := Idx1 + 1 To Idx2 Do
Begin
TmpPt1 := TransformPoint2D( FPoints^[cnt - 1], M );
TmpPt2 := TransformPoint2D( FPoints^[cnt], M );
ClipRes := ClipLine2D( Frm, TmpPt1.X, TmpPt1.Y, TmpPt2.X, TmpPt2.Y );
If Not ( ccNotVisible In ClipRes ) Or ( ccSecond In ClipRes ) Then
Begin
Result := true;
Exit;
End;
End;
If FParts.Count < 2 Then
Break;
Inc( n );
If n >= FParts.Count Then
Break;
Idx1 := FParts[n];
If n < FParts.Count - 1 Then
Idx2 := FParts[n + 1] - 1
Else
Idx2 := FCount - 1;
Until false;
End;
End;
(* If point P is on a line of Vector.Points a distance <= Aperture return:
PICKED_NONE if point P is not on the line
PICKED_POINT if point P is on the line
Dist is the distance found and must be <= Aperture
Taken from Graphics programming book*)
Function TEzVector.PointOnPolyLine2D( Idx1: Integer; Const P: TEzPoint; Var
Dist: Double; Const Aperture: Double; Const T: TEzMatrix; Const MustClose: Boolean ): Integer;
Var
TmpDist: Double;
TmpPt1, TmpPt2: TEzPoint;
I, Max: Integer;
Begin
Result := PICKED_NONE;
Ez_Preferences.GNumPoint := PICKED_NONE;
TmpPt1 := TransformPoint2D( FPoints^[0], T );
Dist := Aperture { * 2};
If MustClose Then
Max := FCount
Else
Max := FCount - 1;
For I := 1 To Max Do
Begin
If I = FCount Then
TmpPt2 := TransformPoint2D( FPoints^[0], T )
Else
TmpPt2 := TransformPoint2D( FPoints^[I], T );
If PointLineDistance2D( P, TmpPt1, TmpPt2, TmpDist ) And ( TmpDist <= Dist ) Then
Begin
Result := PICKED_POINT;
Dist := TmpDist;
Ez_Preferences.GNumPoint := Idx1 + Pred( I );
End;
TmpPt1 := TmpPt2;
End;
End;
{$IFDEF FALSE}
Function ccw( p0, p1, p2: TEzPoint ): INTEGER;
Var
dx1, dx2, dy1, dy2: Double;
Begin
dx1 := p1.x - p0.x;
dy1 := p1.y - p0.y;
dx2 := p2.x - p0.x;
dy2 := p2.y - p0.y;
If dx1 * dy2 > dy1 * dx2 Then
Result := 1;
If dx1 * dy2 < dy1 * dx2 Then
Result := -1;
If dx1 * dy2 = dy1 * dx2 Then
Begin
If ( dx1 * dx2 < 0 ) Or ( dy1 * dy2 < 0 ) Then
Result := -1
Else If ( dx1 * dx1 + dy1 * dy1 ) >= ( dx2 * dx2 + dy2 * dy2 ) Then
Result := 0
Else
Result := 1;
End
End;
Type
TLineType = Record
p1, p2: TEzPoint;
End;
Function intersect( l1, l2: TLinetype ): BOOLEAN;
Var
ccw11, ccw12, ccw21, ccw22: INTEGER;
Begin
ccw11 := ccw( l1.p1, l1.p2, l2.p1 );
ccw12 := ccw( l1.p1, l1.p2, l2.p2 );
ccw21 := ccw( l2.p1, l2.p2, l1.p1 );
ccw22 := ccw( l2.p1, l2.p2, l1.p2 );
Result := ( ( ccw11 * ccw12 < 0 ) And ( ccw21 * ccw22 < 0 ) ) Or
( ccw11 * ccw12 * ccw21 * ccw22 = 0 );
End;
{$ENDIF}
Function TEzVector.PointInPolygon2D( Const P: TEzPoint; Var Dist: Double;
Const Aperture: Double; Const T: TEzMatrix ): Integer;
Var
I, J, Idx1, Idx2, n, np: Integer;
p1_i, p1_j: TEzPoint;
IsInside: Boolean;
Begin
Result := PICKED_NONE;
Dist := Aperture * 2;
np := FParts.Count;
n := 0;
If np < 2 Then
Begin
Idx1 := 0;
Idx2 := FCount - 1;
End
Else
Begin
Idx1 := FParts[n];
Idx2 := FParts[n + 1] - 1;
End;
Repeat
IsInside := false;
J := Idx2;
For I := Idx1 To Idx2 Do
Begin
p1_i := TransformPoint2D( FPoints^[I], T );
p1_j := TransformPoint2D( FPoints^[J], T );
If ( ( ( ( p1_i.y <= p.y ) And ( p.y < p1_j.y ) ) Or
( ( p1_j.y <= p.y ) And ( p.y < p1_i.y ) ) ) And
( p.x < ( p1_j.x - p1_i.x ) * ( p.y - p1_i.y ) /
( p1_j.y - p1_i.y ) + p1_i.x ) ) Then
IsInside := Not IsInside;
J := I;
End;
{ is this part inside ?}
If ( np < 2 ) Or IsInside Then Break;
Inc( n );
If n >= np Then Break;
Idx1 := FParts[n];
If n < np - 1 Then
Idx2 := FParts[n + 1] - 1
Else
Idx2 := FCount - 1;
Until false;
If IsInside Then
Begin
Dist := Aperture;
Result := PICKED_INTERIOR;
End;
End;
Procedure TEzVector.RevertDirection;
Var
K: Integer;
TmpParts: PIntegerArray;
TmpPts: PEzPointArray;
PartSize, TmpSize: Integer;
Begin
TmpSize := ( FCount + 4 ) * sizeof( TEzPoint );
PartSize := ( FParts.Count + 2 ) * sizeof( Integer );
GetMem( TmpPts, TmpSize );
Getmem( TmpParts, PartSize );
Try
For K := 0 To FCount - 1 Do
TmpPts^[K] := FPoints^[K];
For K := 0 To FCount - 1 Do
FPoints^[K] := TmpPts^[FCount - K - 1];
If FParts.Count > 1 Then
Begin
For K := 0 To FParts.Count - 1 Do
TmpParts[K] := FParts[K];
For K := 1 To FParts.Count - 1 Do
FParts[K] := ( FCount - 1 ) - TmpParts[FParts.Count - K];
End;
Finally
FreeMem( TmpPts, TmpSize );
Freemem( TmpParts, PartSize );
End;
End;
Function TEzVector.IsEqualTo( Vector: TEzVector ): Boolean;
Var
I: Integer;
Begin
Result := False;
If FParts.Count <> Vector.Parts.Count Then Exit;
For I := 0 To FParts.Count - 1 Do
If FParts[I] <> Vector.FParts[I] Then Exit;
If FCount <> Vector.Count Then Exit;
For I := 0 To FCount - 1 Do
If Not EqualPoint2D( FPoints^[I], Vector.FPoints^[I] ) Then Exit;
Result := True;
End;
{ This method takes a vector as a parameter and split it in n parts
every parts is the same distance, then populate this vector with the calculus
- It is specially for splines.
- Only works for single-part vector (not multi-part)
- It is supposed only for not closed vector
- if IndexList <> Nil then in IndexList place the index in the list of the point found
}
procedure TEzVector.SplitEquidistant(const Source: TEzVector; NumSegs: Integer;
IndexList: TIntegerList; WidthList: TEzDoubleList);
Var
Traveled, ThisSegmentLen: Double;
p, p1, p2: TEzPoint;
Ang: Double;
PivotIndex, WListIndex: Integer;
PivotDistance, PartLen, TotalLen: Double;
begin
TotalLen:= ezsystem.Perimeter( Source, false );
if (TotalLen = 0) or (NumSegs = 0) or (Source.Count < 2) or
(Source.Parts.Count > 1) or ( (WidthList <> Nil) and (WidthList.Count = 0) ) then Exit;
if WidthList = Nil then
PartLen := TotalLen / NumSegs
else
PartLen := WidthList[0];
if PartLen = 0 then Exit;
Clear;
if IndexList <> Nil then
IndexList.Clear;
Self.Add( Source.Points[0]);
if IndexList <> Nil then
IndexList.Add( 0 );
PivotDistance := PartLen;
PivotIndex := 0;
Traveled := 0;
WListIndex:= 0;
ThisSegmentLen := Dist2D( Source.FPoints^[PivotIndex], Source.FPoints^[PivotIndex+1] );
repeat
If Traveled + ThisSegmentLen < PivotDistance Then
begin
Repeat
Traveled := Traveled + ThisSegmentLen;
Inc( PivotIndex );
if PivotIndex >= Source.Count - 1 then Break;
ThisSegmentLen := Dist2D( Source.FPoints^[PivotIndex], Source.FPoints^[PivotIndex + 1] );
if not EqualPoint2d( Source.Points[PivotIndex], FPoints^[FCount-1]) then
Self.Add( Source.Points[PivotIndex]);
Until Traveled + ThisSegmentLen >= PivotDistance;
end;
if PivotIndex >= Source.Count - 1 then Break;
p1 := Source.FPoints^[PivotIndex];
p2 := Source.FPoints^[PivotIndex+1];
P := p1;
If p1.X = p2.X Then
Begin
// es una linea vertical
If p1.Y < p2.Y Then
P.Y := P.Y + ( PivotDistance - Traveled )
Else
P.Y := P.Y - ( PivotDistance - Traveled );
End
Else If p1.Y = p2.Y Then
Begin
// es una linea horizontal
If p1.X < p2.X Then
P.X := P.X + ( PivotDistance - Traveled )
Else
P.X := P.X - ( PivotDistance - Traveled );
End
Else
Begin
Ang := Angle2D( P1, P2 );
P.X := P.X + ( PivotDistance - Traveled ) * Cos( Ang );
P.Y := P.Y + ( PivotDistance - Traveled ) * Sin( Ang );
End;
Self.Add( P );
if IndexList <> Nil then
IndexList.Add(Self.FCount-1);
if WidthList <> Nil then
begin
Inc(WListIndex);
if WListIndex > WidthList.Count-1 then Break;
PartLen:= WidthList[WListIndex];
end;
PivotDistance := PivotDistance + PartLen;
until PivotDistance >= TotalLen;
if not EqualPoint2D( FPoints^[FCount-1], Source.FPoints^[Source.FCount-1]) then
Self.Add( Source.FPoints^[Source.FCount-1] );
end;
{ Determines the points that is apart a given Distance from startpoint
until the given distance is reached.
returns in P the point where the distance was found
and in Index1, Index2 the segment where indices in points array the distance
was found.
It is supposed that StartPoint<>FPoints^[FCount-1] }
Function TEzVector.TravelDistance( Const Distance: Double;
Var p: TEzPoint;
Var Index1, Index2: Integer ): Boolean;
Var
Traveled, D: Double;
K: Integer;
p1, p2: TEzPoint;
Ang: Double;
Idx1, Idx2, n, np: Integer;
Begin
{ Supports multi-part points }
Result := FALSE;
If FCount < 2 Then Exit;
np := FParts.Count;
n := 0;
If np < 2 Then
Begin
Idx1 := 0;
Idx2 := FCount - 1;
End
Else
Begin
Idx1 := FParts[n];
Idx2 := FParts[n + 1] - 1;
End;
Index1 := Idx1;
In
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -