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

📄 ezlib.pas

📁 很管用的GIS控件
💻 PAS
📖 第 1 页 / 共 5 页
字号:
            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 + -