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

📄 ezrtree.pas

📁 很管用的GIS控件
💻 PAS
📖 第 1 页 / 共 4 页
字号:
Var
  i: integer;
  me: Longint;
  TmpDiskPage: TDiskPage;
Begin
  If rt.FCheckCancelSearch Then
  begin
    rt.CheckSearchCanceled;
    If rt.FSearchCanceled Then Exit;
  End;
  If Data.Leaf Then
    For i := 0 To Data.FullEntries - 1 Do
    Begin
      If Equals_rect( r, Data.Entries[i].R ) Then
        ol.Add( Data.Entries[i].Child );
    End
  Else
    For i := 0 To Data.FullEntries - 1 Do
      If Overlaps_rect( r, Data.Entries[i].R ) Then
      Begin
        me := oid;
        TmpDiskPage := Data;
        Read( Data.Entries[i].Child );
        equalitySearch( r, ol );
        //Read(me);                        // Refresh
        oid := me;
        Data := TmpDiskPage;
      End;

End;

// Add all objects containing r to ol, and return it.

Procedure TRTNode.existSearch( Const r: TRect_rt; ol: TSearchList );
Var
  i: Integer;
  me: Longint;
  TmpDiskPage: TDiskPage;
Begin
  rt.CheckSearchCanceled;
  If rt.FSearchCanceled Then Exit;
  If Data.Leaf Then
    For i := 0 To Data.FullEntries - 1 Do
    Begin
      If Contains_rect( Data.Entries[i].R, r ) Then
        ol.Add( Data.Entries[i].Child );
    End
  Else
    For i := 0 To Data.FullEntries - 1 Do
      If Overlaps_rect( r, Data.Entries[i].R ) Then
      Begin
        me := oid;
        TmpDiskPage := Data;
        Read( Data.Entries[i].Child );
        existSearch( r, ol );
        Data := TmpDiskPage;
        oid := me;
        //Read(me);                        // Refresh
      End;
End;

// Find the pair of entries in r which have the largest distance

Procedure PickSeed( Var r: Array Of TRTEntry; n: integer );
Var
  i, j, im, jm: integer;
  dmax, d: double;
Begin

  im := 0;
  jm := 1;
  dmax := Area_rect( Extent_rect( r[0].R, r[1].R ) );
  dmax := dmax - ( Area_rect( r[0].R ) + Area_rect( r[1].R ) );
  For i := 1 To n - 2 Do
    For j := i + 1 To n - 1 Do
    Begin
      d := Area_rect( Extent_rect( r[i].R, r[j].R ) ) - ( Area_rect( r[i].R ) + Area_rect( r[j].R ) );
      If d > dmax Then
      Begin
        im := i;
        jm := j;
        dmax := d;
      End;
    End;

  memswap( r[im], r[n - 2], SizeOf( TRTEntry ) );
  memswap( r[jm], r[n - 1], SizeOf( TRTEntry ) );

End;

Function PickNext( Var r: Array Of TRTEntry; n: integer; Const mbr0, mbr1: TRect_rt ): integer;
Var
  i, im, mm: integer;
  d0, d1, dmin: double;
Begin
  im := 0;

  d0 := Delta_rect( r[0].R, mbr0 );
  d1 := Delta_rect( r[0].R, mbr1 );

  If d0 < d1 Then
  Begin
    dmin := d0;
    mm := 0;
  End
  Else
  Begin
    dmin := d1;
    mm := 1;
  End;

  For i := 1 To n - 1 Do
  Begin
    d0 := Delta_rect( r[i].R, mbr0 );
    d1 := Delta_rect( r[i].R, mbr1 );
    If ezlib.dmin( d0, d1 ) < dmin Then
    Begin
      im := i;
      If d0 < d1 Then
      Begin
        dmin := d0;
        mm := 0;
      End
      Else
      Begin
        dmin := d1;
        mm := 1;
      End;
    End;
  End;
  memswap( r[n - 1], r[im], SizeOf( TRTEntry ) );
  result := mm;
End;

Procedure TRTNode.propagate( n: integer );
Var
  me: integer;
  MyOid, Par: Longint;
  r: TRect_rt;
  //oldData: TDiskPage;
Begin

  If isRoot Then
    exit;

  MyOid := oid;
  Par := Data.Parent;

  r := Data.Entries[n].R;

  Read( Par );

  me := Locate( MyOid );
  If me = NOTFOUND Then
    EzGISError( 'propagate' );

  //oldData := Data;

  Data.Entries[me].R := Extent_rect( Data.Entries[me].R, r );
  Write;
  //Data := oldData;

  propagate( me );
End;

// Insert r into this. Make all arrangements like splitting.
// Return ROOT_CHANGED if it changes.

Function TRTNode.Insert( Const r: TRect_rt; o: Longint; Var newo: Longint ): integer;
Var
  s1, s2, node, m, n, na, nb, me, ric, ret: integer;
  newNode, newRoot, parNode, childNode: TRTNode;
  temp: Array[0..BUCKETSIZE] Of TRTEntry;
  MBRa, MBRb: TRect_rt;
  MyOid, parNewo: Longint;
Begin
  ric := OK;
  na := 0;
  nb := 0;

  If Data.FullEntries < BUCKETSIZE Then // Trivial case.
  Begin
    Data.Entries[Data.FullEntries].R := r; // Put it at the end
    Data.Entries[Data.FullEntries].Child := o;
    Inc( Data.FullEntries );
    Write;

    If Not Data.Leaf Then
    Begin
      childNode := rt.CreateNewNode;
      childNode.Read( Data.Entries[Data.FullEntries - 1].Child );
      childNode.Data.Parent := oid;
      childNode.Write;
      childNode.free;
    End;

    MyOid := oid;
    propagate( Data.FullEntries - 1 );
    Read( MyOid );

    result := OK;
    exit;
  End;

  // This node is full. It needs to be splitted.

  If isRoot Then // If this is the root
  Begin
    newRoot := rt.CreateNewNode;
    newRoot.Data.Parent := -1; // invalidate the parent
    newRoot.Data.Leaf := False;
    newRoot.Data.FullEntries := 1; // One entry.

    // First son of the new root is the old root
    newRoot.Data.Entries[0].Child := oid;

    newRoot.AddNodeToFile;

    Data.Parent := newRoot.oid; // The same parent
    ric := ROOT_CHANGED; // Mark root is changed
    newRoot.free;
  End;

  newNode := rt.CreateNewNode;
  parNode := rt.CreateNewNode;
  Try

    newNode.Data.Leaf := Data.Leaf; // Initialize the new node
    newNode.Data.FullEntries := 0; // It's empty yet
    newNode.Data.Parent := Data.Parent; // The same parent
    newNode.AddNodeToFile; // Create it on disk
    newo := newNode.oid;

    parNode.Read( Data.Parent );

    me := parNode.Locate( oid ); // Which entry is pointing to me?
    If me = NOTFOUND Then
      EzGISError( 'Insert' );

    parNode.Data.Entries[me].R := NULL_RECT; // Replace the old mbr with
    // Nil rect
    parNode.Write;

    // Insert the new node into the parent

    parNewo := -1;
    ret := parNode.Insert( NULL_RECT, newNode.oid, parNewo );
    If ret = TREE_ERROR Then
    Begin
      result := TREE_ERROR;
      exit;
    End;
    If parNewo >= 0 Then
    Begin
      If parNode.Locate( oid ) = NOTFOUND Then
      Begin
        Data.Parent := parNewO;
        Write;
      End;
      If parNode.Locate( newNode.oid ) = NOTFOUND Then
      Begin
        newNode.Data.Parent := parNewO;
        newNode.Write;
      End;
    End;
    If ret = ROOT_CHANGED Then
      ric := ret;

    Move( Data.Entries[0], temp[0], SizeOf( TRTEntry ) * BUCKETSIZE );

    temp[BUCKETSIZE].R := r; // The entry to be inserted is placed
    temp[BUCKETSIZE].Child := o; // ...at the last position in the temp

    Data.FullEntries := 0; // Empty the node

    // Select the first pair of entries and move to the last 2 positions
    PickSeed( temp, BUCKETSIZE + 1 );

    s1 := BUCKETSIZE - 1;
    s2 := BUCKETSIZE; // Initialize the MBRs
    MBRa := temp[s1].R;
    MBRb := temp[s2].R; // of the nodes

    // Insert the first into this, and the second into the new node
       {parNewo := -1;} ret := Insert( MBRa, temp[s1].Child, parNewo );
    If ret = ROOT_CHANGED Then
      ric := ret;
    {parNewo := -1;} ret := newNode.Insert( MBRb, temp[s2].Child, parNewo );
    If ret = ROOT_CHANGED Then
      ric := ret;

    n := BUCKETSIZE - 1;
    m := HALF_BUCKET;

    While n <> 0 Do
    Begin
      If na = m Then
        node := 1 // node A is full, pick B
      Else If nb = m Then
        node := 0 // node B is full, pick A
      Else
        node := PickNext( temp, n, MBRa, MBRb ); // pick the next node

      If node <> 0 Then
      Begin
        {parNewo := -1;} ret := newNode.Insert( temp[n - 1].R, temp[n - 1].Child, parNewo );
        If ret = ROOT_CHANGED Then
          ric := ret;
        MBRb := Extent_rect( MBRb, temp[n - 1].R );
        inc( nb );
      End
      Else
      Begin
        {parNewo := -1;} ret := Insert( temp[n - 1].R, temp[n - 1].Child, parNewo );
        If ret = ROOT_CHANGED Then
          ric := ret;
        MBRa := Extent_rect( MBRa, temp[n - 1].R );
        Inc( na );
      End;
      Dec( n );
    End;

  Finally
    newNode.free;
    parNode.free;
  End;

  result := ric;

End;

Function TRTNode.IsRoot: boolean;
Begin
  result := ( Data.Parent = -1 );
End;

Procedure TRTNode.Compact;
Var
  r: TRect_rt;
  i, me: integer;
  MyOid, Par: Longint;
Begin

  If isRoot Then
    exit; // cannot compact root...

  MyOid := oid;
  Par := Data.Parent;

  r := Data.Entries[0].R;
  For i := 1 To Data.FullEntries - 1 Do
    r := Extent_rect( r, Data.Entries[i].R );

  Read( Par );

  me := Locate( MyOid );
  If me = NOTFOUND Then
    EzGISError( 'Compact' );

  Data.Entries[me].R := r;
  Write;

  Compact;
End;

// Delete r from this. Make all arrangements like condensing the tree
// Return Root if it changes.

Function TRTNode.Delete( o: Longint; l: integer; rl: TOList ): integer;
Var
  n, i: integer;
  child, parent: TRTNode;
  choid: Longint;
  retCode: integer;
Begin
  parent := rt.CreateNewNode;
  Try

    retcode := OK;

    n := Locate( o ); // Find the entry for this obj.

    If n = NOTFOUND Then
      EzGISError( 'Unrecoverable error! Aborting.' );

    If Not Data.Leaf Then
    Begin
      child := rt.CreateNewNode;
      child.Read( Data.Entries[n].Child );
      child.DeleteNodeFromFile; // Destroy the deleted node
      child.free;
    End;

    // Replace the entry with the last entry and decrement Full Entries
    Dec( Data.FullEntries );
    Data.Entries[n] := Data.Entries[Data.FullEntries];
    Write;

    If Data.FullEntries < LOWERBOUND Then // Condense
    Begin
      If isRoot Then // if this is the root
      Begin
        If Data.FullEntries <> 1 Then
        Begin
          result := OK;
          exit;
        End;
        If Not Data.Leaf Then
        Begin
          choid := Data.Entries[0].Child;
          child := rt.CreateNewNode;
          child.Read( choid );
          child.Data.Parent := -1;
          child.Write;
          child.free;
          result := ROOT_CHANGED;
          exit;
        End;
        result := OK;
        exit;
      End;

      For i := 0 To Data.FullEntries - 1 Do // copy rest of the entries into temp
        rl.Insertl( Data.Entries[i].Child, Data.Entries[i].R, l );

      parent.Read( Data.Parent );
      retCode := parent.Delete( oid, l + 1, rl ); // Delete this node from parent
    End
    Else
      Compact;

    result := retCode;
  Finally
    parent.free;
  End;
End;

// Return the index of the entry in this TRTNode which points to o.

Function TRTNode.Locate( o: Longint ): integer;
Var
  i: integer;
Begin
  result := NOTFOUND;
  For i := 0 To Data.FullEntries - 1 Do
    If Data.Entries[i].Child = o Then
    Begin
      result := i;
      exit;
    End;
End;

Function TRTNode.findLeaf( const r: TRect_rt; o: Longint ): integer;
Var
  i: integer;
  me: Longint;
Begin
  If Data.Leaf Then
  Begin
    If Locate( o ) = NOTFOUND Then
    Begin
      result := TREE_ERROR;
      exit;
    End
    Else
    Begin
      result := OK;
      exit;
    End; // it is here!
  End
  Else
    For i := 0 To Data.FullEntries - 1 Do
      If Contains_rect( Data.Entries[i].R, r ) Then
      Begin
        me := oid;
        Read( Data.Entries[i].Child );
        If findLeaf( r, o ) = OK Then
        Begin
          result := OK;
          exit;
        End;
        Read( me );
      End;

  result := TREE_ERROR;
End;

Function TRTNode.isLeaf: boolean;
Begin
  result := Data.Leaf;
End;

{$IFDEF FALSE}
// TRSTNode class implementation R*-tree

Function TRSTNode.fReinsert( Const r: TRect_rt; o: Longint; lev: integer; ril: TOList ): word;
Var
  sl: TSortList;
  reorg: TOlist; // reinsert & reorganize lists.
  ro: Longint;
  rr: TRect_rt;
  i, j, dist: integer;
  minx, maxx, miny, maxy, crx, cry, cx, cy: integer;
Begin

  reorg := TOlist.Create;
  sl := TSortList.Create( BUCKETSIZE + 1 );

  minx := r.x1;
  maxx := r.x2;
  miny := r.y1;
  maxy := r.y2;
  crx := ( minx + maxx ) Div 2;
  cry := ( miny + maxy ) Div 2;

  For i := 0 To BUCKETSIZE - 1 Do
  Begin
    If Data.Entries[i].R.x1 < minx Then
      minx := Data.Entries[i].R.x1;
    If Data.Entries[i].R.x2 > maxx Then
      maxx := Data.Entries[i].R.x2;
    If Data.Entries[i].R.y1 < miny Then
      miny := Data.Entries[i].R.y1;
    If Data.Entries[i].R.y2 > maxy Then
      maxy := Data.Entries[i].R.y2;
  End;

  cx := ( minx + maxx ) Div 2;
  cy := ( miny + maxy ) Div 2;

⌨️ 快捷键说明

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