Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

252
LINES

< > BotCompany Repo | #1032244 // PtTree - tree structure for quick finding of points in any rectangle [backup with the cool co_iterate]

JavaX fragment (include)

1  
// TODO: find splitPoint faster (just access the median element!)
2  
// TODO: really slow making the initial tree (5s for ~250 points)
3  
sclass PtTree extends AbstractSet<Pt> {
4  
  int size;
5  
  Node root = new Leaf(null);
6  
  
7  
  // config
8  
  
9  
  int maxPointsPerNode = 4;
10  
    
11  
  abstract class Node {
12  
    Node parent;
13  
    
14  
    abstract bool add(Pt p);
15  
    abstract void collectPointsIn(Rect r, L<Pt> out);
16  
    
17  
    abstract void replaceChild(Node from, Node to);
18  
    
19  
    void addAll(Iterable<Pt> l) {
20  
      fOr (Pt p : l) add(p);
21  
    }
22  
  }
23  
  
24  
  class Leaf extends Node {
25  
    Cl<Pt> points;
26  
    
27  
    *(Node *parent) {}
28  
    
29  
    bool add(Pt p) {
30  
      if (main contains(points, p)) false;
31  
      if (points == null) points = new L;
32  
      points.add(p);
33  
      ++size;
34  
      possiblySplit();
35  
      true;
36  
    }
37  
    
38  
    void possiblySplit {
39  
      if (l(points) > maxPointsPerNode)
40  
        split();
41  
    }
42  
    
43  
    void collectPointsIn(Rect r, L<Pt> out) {
44  
      fOr (p : points)
45  
        if (containsPt(r, p))
46  
          out.add(p);
47  
    }
48  
    
49  
    record noeq ProposedSplit(int dimension, int splitPoint, int count) {
50  
      int error() { ret abs(count-half(l(points))); }
51  
    }
52  
    
53  
    Split split() {
54  
      int n = l(points), half = n/2;
55  
      
56  
      ProposedSplit xSplit = checkSplit(0);
57  
      ProposedSplit ySplit = checkSplit(1);
58  
      
59  
      var best = xSplit.error() < ySplit.error() ? xSplit : ySplit;
60  
61  
      new Split split;
62  
      split.dimension = (byte) best.dimension;
63  
      split.splitPoint = best.splitPoint;
64  
      Leaf a = new Leaf(split);
65  
      IPred<Pt> pred = p -> ptCoord(split.dimension, p) >= split.splitPoint;
66  
      a.addAll(antiFilter(pred, points));
67  
      split.a = a;
68  
      Leaf b = new Leaf(split);
69  
      b.addAll(filter(pred, points));
70  
      split.b = b;
71  
      
72  
      a.possiblySplit();
73  
      b.possiblySplit();
74  
      
75  
      ret replaceMeWith(split);
76  
    }
77  
    
78  
    <A extends Node> A replaceMeWith(A node) {
79  
      node.parent = parent;
80  
      if (parent != null) parent.replaceChild(this, node);
81  
      else if (root == this) root = node;
82  
      ret node;
83  
    }
84  
85  
    ProposedSplit checkSplit(int dimension) {
86  
      L<Pt> lx = sortedBy(points, p -> ptCoord(dimension, p));
87  
      new ProposedSplit ps;
88  
      ps.dimension = dimension;
89  
      
90  
      int n = l(points), half = n/2;
91  
      int i = 0;
92  
      int splitPoint = Int.MIN_VALUE;
93  
      while true {
94  
        int lastSplitPoint = splitPoint;
95  
        splitPoint = ptCoord(lx.get(i++), dimension)+1;
96  
        int lastI = i;
97  
        while (i < n && ptCoord(lx.get(i), dimension) < splitPoint) ++i;
98  
        if (i >= half) {
99  
          if (abs(lastI-half) < abs(i-half)) {
100  
            ps.splitPoint = lastSplitPoint;
101  
            ps.count = lastI;
102  
          } else {
103  
            ps.splitPoint = splitPoint;
104  
            ps.count = i;
105  
          }
106  
          ret ps;
107  
        }
108  
      }
109  
    }
110  
    
111  
    void replaceChild(Node from, Node to) { unimplemented(); } // doesn't need
112  
  }
113  
  
114  
  static final int minInf = Int.MIN_VALUE/4;
115  
  static final int inf = Int.MAX_VALUE/4;
116  
  
117  
  class Split extends Node {
118  
    byte dimension; // 0 for X, 1 for Y
119  
    int splitPoint;
120  
    Node a, b;
121  
    
122  
    bool add(Pt p) {
123  
      ret (ptCoord(p, dimension) >= splitPoint ? b : a).add(p);
124  
    }
125  
    
126  
    Rect aRect() {
127  
      ret rectFromPoints(minInf, minInf,
128  
        dimension == 0 ? splitPoint : inf,
129  
        dimension == 1 ? splitPoint : inf);
130  
    }
131  
    
132  
    Rect bRect() {
133  
      ret rectFromPoints(
134  
        dimension == 0 ? splitPoint : minInf,
135  
        dimension == 1 ? splitPoint : minInf,
136  
        inf, inf);
137  
    }
138  
    
139  
    void collectPointsIn(Rect r, L<Pt> out) {
140  
      Rect rA = intersectRect(r, aRect());
141  
      if (nempty(rA))
142  
        a.collectPointsIn(rA, out);
143  
        
144  
      Rect rB = intersectRect(r, bRect());
145  
      if (nempty(rB))
146  
        b.collectPointsIn(rB, out);
147  
    }
148  
    
149  
    void replaceChild(Node from, Node to) {
150  
      if (a == from) a = to;
151  
      if (b == from) b = to;
152  
    } 
153  
  }
154  
  
155  
  public bool add(Pt p) {
156  
    ret root.add(p);
157  
  }
158  
  
159  
  L<Pt> pointsIn aka pointsInRect(Rect r) {
160  
    new L<Pt> out;
161  
    root.collectPointsIn(r, out);
162  
    ret out;
163  
  }
164  
  
165  
  public bool contains(O p) {
166  
    ret p instanceof Pt && contains(p/Pt);
167  
  }
168  
  
169  
  bool contains(Pt p) {
170  
    ret nempty(pointsIn(rect(p.x, p.y, 1, 1)));
171  
  }
172  
  
173  
  // use this to make a PtTree!
174  
  // It's actually makes a balanced tree.
175  
  // It is assumed that points contains no duplicates
176  
  static PtTree fromPointSet(Iterable<Pt> points) {
177  
    new PtTree tree;
178  
    Leaf root = cast tree.root;
179  
    root.points = cloneList(points);
180  
    tree.size = l(root.points);
181  
    root.possiblySplit();
182  
    ret tree;
183  
  }
184  
  
185  
  public int size() { ret size; }
186  
  
187  
  public Iterator<Pt> iterator() {
188  
    /* What we actually want is a coroutine yielding the values.
189  
    // Like this, if we had this syntax:
190  
    
191  
    ret coroutine {
192  
      void iterate(Node node) {
193  
        if (node cast Leaf)
194  
          returnAll(node.points);
195  
        else {
196  
          cast node to Split;
197  
          iterate(node.a);
198  
          iterate(node.b);
199  
        }
200  
        
201  
        run { iterate(root); }
202  
      }
203  
    };
204  
    
205  
    // So how do we turn this into an iterator?
206  
    // Maybe through VStack.Computable.
207  
    */
208  
    
209  
    new Var<Iterator<Pt>> out;
210  
    new VStack stack;
211  
    stack.push(new co_iterate(root, out));
212  
    
213  
    ret iff_endOnNull(new IF0<Pt> {
214  
      bool done;
215  
      
216  
      public Pt get() {
217  
        while ping (true) {
218  
          // something in the pipe? return it
219  
          if (out.has())
220  
            if (out->hasNext())
221  
              ret out->next();
222  
            else
223  
              out.clear(); // and clean the pipe afterwards, boy!
224  
              
225  
          if (done) null; // end of the line
226  
          // nothing in the pipe, gotta walk the tree some more
227  
          if (!step(stack))
228  
            set done; // prepare to get off the train
229  
        }
230  
      }
231  
    });
232  
  }
233  
  
234  
  record noeq co_iterate(Node node, Var<Iterator<Pt>> out) extends VStackComputableWithStep {
235  
    void step(VStack stack) {
236  
      if (step == 0) {
237  
        if (node cast Leaf) {
238  
          out.set(main iterator(node.points));
239  
          stack.return();
240  
        } else {
241  
          cast node to Split;
242  
          stack.call(new co_iterate(node.a, out));
243  
          ret with step = 1;
244  
        }
245  
      } else {
246  
        cast node to Split;
247  
        stack.replace(new co_iterate(node.b, out));
248  
      }
249  
    }
250  
  }
251  
252  
}

Author comment

Began life as a copy of #1032229

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx

No comments. add comment

Snippet ID: #1032244
Snippet name: PtTree - tree structure for quick finding of points in any rectangle [backup with the cool co_iterate]
Eternal ID of this version: #1032244/2
Text MD5: 48d18dfe58ade11919813153c81f7455
Author: stefan
Category: javax / 2d space
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-08-22 19:06:59
Source code size: 6595 bytes / 252 lines
Pitched / IR pitched: No / No
Views / Downloads: 91 / 119
Version history: 1 change(s)
Referenced in: [show references]