source: src/main/java/agents/anac/y2019/harddealer/math3/geometry/partitioning/BSPTree.java

Last change on this file was 204, checked in by Katsuhide Fujita, 5 years ago

Fixed errors of ANAC2019 agents

  • Property svn:executable set to *
File size: 33.2 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package agents.anac.y2019.harddealer.math3.geometry.partitioning;
18
19import java.util.ArrayList;
20import java.util.List;
21
22import agents.anac.y2019.harddealer.math3.exception.MathIllegalStateException;
23import agents.anac.y2019.harddealer.math3.exception.MathInternalError;
24import agents.anac.y2019.harddealer.math3.exception.util.LocalizedFormats;
25import agents.anac.y2019.harddealer.math3.geometry.Point;
26import agents.anac.y2019.harddealer.math3.geometry.Space;
27import agents.anac.y2019.harddealer.math3.geometry.Vector;
28import agents.anac.y2019.harddealer.math3.util.FastMath;
29
30/** This class represent a Binary Space Partition tree.
31
32 * <p>BSP trees are an efficient way to represent space partitions and
33 * to associate attributes with each cell. Each node in a BSP tree
34 * represents a convex region which is partitioned in two convex
35 * sub-regions at each side of a cut hyperplane. The root tree
36 * contains the complete space.</p>
37
38 * <p>The main use of such partitions is to use a boolean attribute to
39 * define an inside/outside property, hence representing arbitrary
40 * polytopes (line segments in 1D, polygons in 2D and polyhedrons in
41 * 3D) and to operate on them.</p>
42
43 * <p>Another example would be to represent Voronoi tesselations, the
44 * attribute of each cell holding the defining point of the cell.</p>
45
46 * <p>The application-defined attributes are shared among copied
47 * instances and propagated to split parts. These attributes are not
48 * used by the BSP-tree algorithms themselves, so the application can
49 * use them for any purpose. Since the tree visiting method holds
50 * internal and leaf nodes differently, it is possible to use
51 * different classes for internal nodes attributes and leaf nodes
52 * attributes. This should be used with care, though, because if the
53 * tree is modified in any way after attributes have been set, some
54 * internal nodes may become leaf nodes and some leaf nodes may become
55 * internal nodes.</p>
56
57 * <p>One of the main sources for the development of this package was
58 * Bruce Naylor, John Amanatides and William Thibault paper <a
59 * href="http://www.cs.yorku.ca/~amana/research/bsptSetOp.pdf">Merging
60 * BSP Trees Yields Polyhedral Set Operations</a> Proc. Siggraph '90,
61 * Computer Graphics 24(4), August 1990, pp 115-124, published by the
62 * Association for Computing Machinery (ACM).</p>
63
64 * @param <S> Type of the space.
65
66 * @since 3.0
67 */
68public class BSPTree<S extends Space> {
69
70 /** Cut sub-hyperplane. */
71 private SubHyperplane<S> cut;
72
73 /** Tree at the plus side of the cut hyperplane. */
74 private BSPTree<S> plus;
75
76 /** Tree at the minus side of the cut hyperplane. */
77 private BSPTree<S> minus;
78
79 /** Parent tree. */
80 private BSPTree<S> parent;
81
82 /** Application-defined attribute. */
83 private Object attribute;
84
85 /** Build a tree having only one root cell representing the whole space.
86 */
87 public BSPTree() {
88 cut = null;
89 plus = null;
90 minus = null;
91 parent = null;
92 attribute = null;
93 }
94
95 /** Build a tree having only one root cell representing the whole space.
96 * @param attribute attribute of the tree (may be null)
97 */
98 public BSPTree(final Object attribute) {
99 cut = null;
100 plus = null;
101 minus = null;
102 parent = null;
103 this.attribute = attribute;
104 }
105
106 /** Build a BSPTree from its underlying elements.
107 * <p>This method does <em>not</em> perform any verification on
108 * consistency of its arguments, it should therefore be used only
109 * when then caller knows what it is doing.</p>
110 * <p>This method is mainly useful to build trees
111 * bottom-up. Building trees top-down is realized with the help of
112 * method {@link #insertCut insertCut}.</p>
113 * @param cut cut sub-hyperplane for the tree
114 * @param plus plus side sub-tree
115 * @param minus minus side sub-tree
116 * @param attribute attribute associated with the node (may be null)
117 * @see #insertCut
118 */
119 public BSPTree(final SubHyperplane<S> cut, final BSPTree<S> plus, final BSPTree<S> minus,
120 final Object attribute) {
121 this.cut = cut;
122 this.plus = plus;
123 this.minus = minus;
124 this.parent = null;
125 this.attribute = attribute;
126 plus.parent = this;
127 minus.parent = this;
128 }
129
130 /** Insert a cut sub-hyperplane in a node.
131 * <p>The sub-tree starting at this node will be completely
132 * overwritten. The new cut sub-hyperplane will be built from the
133 * intersection of the provided hyperplane with the cell. If the
134 * hyperplane does intersect the cell, the cell will have two
135 * children cells with {@code null} attributes on each side of
136 * the inserted cut sub-hyperplane. If the hyperplane does not
137 * intersect the cell then <em>no</em> cut hyperplane will be
138 * inserted and the cell will be changed to a leaf cell. The
139 * attribute of the node is never changed.</p>
140 * <p>This method is mainly useful when called on leaf nodes
141 * (i.e. nodes for which {@link #getCut getCut} returns
142 * {@code null}), in this case it provides a way to build a
143 * tree top-down (whereas the {@link #BSPTree(SubHyperplane,
144 * BSPTree, BSPTree, Object) 4 arguments constructor} is devoted to
145 * build trees bottom-up).</p>
146 * @param hyperplane hyperplane to insert, it will be chopped in
147 * order to fit in the cell defined by the parent nodes of the
148 * instance
149 * @return true if a cut sub-hyperplane has been inserted (i.e. if
150 * the cell now has two leaf child nodes)
151 * @see #BSPTree(SubHyperplane, BSPTree, BSPTree, Object)
152 */
153 public boolean insertCut(final Hyperplane<S> hyperplane) {
154
155 if (cut != null) {
156 plus.parent = null;
157 minus.parent = null;
158 }
159
160 final SubHyperplane<S> chopped = fitToCell(hyperplane.wholeHyperplane());
161 if (chopped == null || chopped.isEmpty()) {
162 cut = null;
163 plus = null;
164 minus = null;
165 return false;
166 }
167
168 cut = chopped;
169 plus = new BSPTree<S>();
170 plus.parent = this;
171 minus = new BSPTree<S>();
172 minus.parent = this;
173 return true;
174
175 }
176
177 /** Copy the instance.
178 * <p>The instance created is completely independent of the original
179 * one. A deep copy is used, none of the underlying objects are
180 * shared (except for the nodes attributes and immutable
181 * objects).</p>
182 * @return a new tree, copy of the instance
183 */
184 public BSPTree<S> copySelf() {
185
186 if (cut == null) {
187 return new BSPTree<S>(attribute);
188 }
189
190 return new BSPTree<S>(cut.copySelf(), plus.copySelf(), minus.copySelf(),
191 attribute);
192
193 }
194
195 /** Get the cut sub-hyperplane.
196 * @return cut sub-hyperplane, null if this is a leaf tree
197 */
198 public SubHyperplane<S> getCut() {
199 return cut;
200 }
201
202 /** Get the tree on the plus side of the cut hyperplane.
203 * @return tree on the plus side of the cut hyperplane, null if this
204 * is a leaf tree
205 */
206 public BSPTree<S> getPlus() {
207 return plus;
208 }
209
210 /** Get the tree on the minus side of the cut hyperplane.
211 * @return tree on the minus side of the cut hyperplane, null if this
212 * is a leaf tree
213 */
214 public BSPTree<S> getMinus() {
215 return minus;
216 }
217
218 /** Get the parent node.
219 * @return parent node, null if the node has no parents
220 */
221 public BSPTree<S> getParent() {
222 return parent;
223 }
224
225 /** Associate an attribute with the instance.
226 * @param attribute attribute to associate with the node
227 * @see #getAttribute
228 */
229 public void setAttribute(final Object attribute) {
230 this.attribute = attribute;
231 }
232
233 /** Get the attribute associated with the instance.
234 * @return attribute associated with the node or null if no
235 * attribute has been explicitly set using the {@link #setAttribute
236 * setAttribute} method
237 * @see #setAttribute
238 */
239 public Object getAttribute() {
240 return attribute;
241 }
242
243 /** Visit the BSP tree nodes.
244 * @param visitor object visiting the tree nodes
245 */
246 public void visit(final BSPTreeVisitor<S> visitor) {
247 if (cut == null) {
248 visitor.visitLeafNode(this);
249 } else {
250 switch (visitor.visitOrder(this)) {
251 case PLUS_MINUS_SUB:
252 plus.visit(visitor);
253 minus.visit(visitor);
254 visitor.visitInternalNode(this);
255 break;
256 case PLUS_SUB_MINUS:
257 plus.visit(visitor);
258 visitor.visitInternalNode(this);
259 minus.visit(visitor);
260 break;
261 case MINUS_PLUS_SUB:
262 minus.visit(visitor);
263 plus.visit(visitor);
264 visitor.visitInternalNode(this);
265 break;
266 case MINUS_SUB_PLUS:
267 minus.visit(visitor);
268 visitor.visitInternalNode(this);
269 plus.visit(visitor);
270 break;
271 case SUB_PLUS_MINUS:
272 visitor.visitInternalNode(this);
273 plus.visit(visitor);
274 minus.visit(visitor);
275 break;
276 case SUB_MINUS_PLUS:
277 visitor.visitInternalNode(this);
278 minus.visit(visitor);
279 plus.visit(visitor);
280 break;
281 default:
282 throw new MathInternalError();
283 }
284
285 }
286 }
287
288 /** Fit a sub-hyperplane inside the cell defined by the instance.
289 * <p>Fitting is done by chopping off the parts of the
290 * sub-hyperplane that lie outside of the cell using the
291 * cut-hyperplanes of the parent nodes of the instance.</p>
292 * @param sub sub-hyperplane to fit
293 * @return a new sub-hyperplane, guaranteed to have no part outside
294 * of the instance cell
295 */
296 private SubHyperplane<S> fitToCell(final SubHyperplane<S> sub) {
297 SubHyperplane<S> s = sub;
298 for (BSPTree<S> tree = this; tree.parent != null && s != null; tree = tree.parent) {
299 if (tree == tree.parent.plus) {
300 s = s.split(tree.parent.cut.getHyperplane()).getPlus();
301 } else {
302 s = s.split(tree.parent.cut.getHyperplane()).getMinus();
303 }
304 }
305 return s;
306 }
307
308 /** Get the cell to which a point belongs.
309 * <p>If the returned cell is a leaf node the points belongs to the
310 * interior of the node, if the cell is an internal node the points
311 * belongs to the node cut sub-hyperplane.</p>
312 * @param point point to check
313 * @return the tree cell to which the point belongs
314 * @deprecated as of 3.3, replaced with {@link #getCell(Point, double)}
315 */
316 @Deprecated
317 public BSPTree<S> getCell(final Vector<S> point) {
318 return getCell((Point<S>) point, 1.0e-10);
319 }
320
321 /** Get the cell to which a point belongs.
322 * <p>If the returned cell is a leaf node the points belongs to the
323 * interior of the node, if the cell is an internal node the points
324 * belongs to the node cut sub-hyperplane.</p>
325 * @param point point to check
326 * @param tolerance tolerance below which points close to a cut hyperplane
327 * are considered to belong to the hyperplane itself
328 * @return the tree cell to which the point belongs
329 */
330 public BSPTree<S> getCell(final Point<S> point, final double tolerance) {
331
332 if (cut == null) {
333 return this;
334 }
335
336 // position of the point with respect to the cut hyperplane
337 final double offset = cut.getHyperplane().getOffset(point);
338
339 if (FastMath.abs(offset) < tolerance) {
340 return this;
341 } else if (offset <= 0) {
342 // point is on the minus side of the cut hyperplane
343 return minus.getCell(point, tolerance);
344 } else {
345 // point is on the plus side of the cut hyperplane
346 return plus.getCell(point, tolerance);
347 }
348
349 }
350
351 /** Get the cells whose cut sub-hyperplanes are close to the point.
352 * @param point point to check
353 * @param maxOffset offset below which a cut sub-hyperplane is considered
354 * close to the point (in absolute value)
355 * @return close cells (may be empty if all cut sub-hyperplanes are farther
356 * than maxOffset from the point)
357 */
358 public List<BSPTree<S>> getCloseCuts(final Point<S> point, final double maxOffset) {
359 final List<BSPTree<S>> close = new ArrayList<BSPTree<S>>();
360 recurseCloseCuts(point, maxOffset, close);
361 return close;
362 }
363
364 /** Get the cells whose cut sub-hyperplanes are close to the point.
365 * @param point point to check
366 * @param maxOffset offset below which a cut sub-hyperplane is considered
367 * close to the point (in absolute value)
368 * @param close list to fill
369 */
370 private void recurseCloseCuts(final Point<S> point, final double maxOffset,
371 final List<BSPTree<S>> close) {
372 if (cut != null) {
373
374 // position of the point with respect to the cut hyperplane
375 final double offset = cut.getHyperplane().getOffset(point);
376
377 if (offset < -maxOffset) {
378 // point is on the minus side of the cut hyperplane
379 minus.recurseCloseCuts(point, maxOffset, close);
380 } else if (offset > maxOffset) {
381 // point is on the plus side of the cut hyperplane
382 plus.recurseCloseCuts(point, maxOffset, close);
383 } else {
384 // point is close to the cut hyperplane
385 close.add(this);
386 minus.recurseCloseCuts(point, maxOffset, close);
387 plus.recurseCloseCuts(point, maxOffset, close);
388 }
389
390 }
391 }
392
393 /** Perform condensation on a tree.
394 * <p>The condensation operation is not recursive, it must be called
395 * explicitly from leaves to root.</p>
396 */
397 private void condense() {
398 if ((cut != null) && (plus.cut == null) && (minus.cut == null) &&
399 (((plus.attribute == null) && (minus.attribute == null)) ||
400 ((plus.attribute != null) && plus.attribute.equals(minus.attribute)))) {
401 attribute = (plus.attribute == null) ? minus.attribute : plus.attribute;
402 cut = null;
403 plus = null;
404 minus = null;
405 }
406 }
407
408 /** Merge a BSP tree with the instance.
409 * <p>All trees are modified (parts of them are reused in the new
410 * tree), it is the responsibility of the caller to ensure a copy
411 * has been done before if any of the former tree should be
412 * preserved, <em>no</em> such copy is done here!</p>
413 * <p>The algorithm used here is directly derived from the one
414 * described in the Naylor, Amanatides and Thibault paper (section
415 * III, Binary Partitioning of a BSP Tree).</p>
416 * @param tree other tree to merge with the instance (will be
417 * <em>unusable</em> after the operation, as well as the
418 * instance itself)
419 * @param leafMerger object implementing the final merging phase
420 * (this is where the semantic of the operation occurs, generally
421 * depending on the attribute of the leaf node)
422 * @return a new tree, result of <code>instance &lt;op&gt;
423 * tree</code>, this value can be ignored if parentTree is not null
424 * since all connections have already been established
425 */
426 public BSPTree<S> merge(final BSPTree<S> tree, final LeafMerger<S> leafMerger) {
427 return merge(tree, leafMerger, null, false);
428 }
429
430 /** Merge a BSP tree with the instance.
431 * @param tree other tree to merge with the instance (will be
432 * <em>unusable</em> after the operation, as well as the
433 * instance itself)
434 * @param leafMerger object implementing the final merging phase
435 * (this is where the semantic of the operation occurs, generally
436 * depending on the attribute of the leaf node)
437 * @param parentTree parent tree to connect to (may be null)
438 * @param isPlusChild if true and if parentTree is not null, the
439 * resulting tree should be the plus child of its parent, ignored if
440 * parentTree is null
441 * @return a new tree, result of <code>instance &lt;op&gt;
442 * tree</code>, this value can be ignored if parentTree is not null
443 * since all connections have already been established
444 */
445 private BSPTree<S> merge(final BSPTree<S> tree, final LeafMerger<S> leafMerger,
446 final BSPTree<S> parentTree, final boolean isPlusChild) {
447 if (cut == null) {
448 // cell/tree operation
449 return leafMerger.merge(this, tree, parentTree, isPlusChild, true);
450 } else if (tree.cut == null) {
451 // tree/cell operation
452 return leafMerger.merge(tree, this, parentTree, isPlusChild, false);
453 } else {
454 // tree/tree operation
455 final BSPTree<S> merged = tree.split(cut);
456 if (parentTree != null) {
457 merged.parent = parentTree;
458 if (isPlusChild) {
459 parentTree.plus = merged;
460 } else {
461 parentTree.minus = merged;
462 }
463 }
464
465 // merging phase
466 plus.merge(merged.plus, leafMerger, merged, true);
467 minus.merge(merged.minus, leafMerger, merged, false);
468 merged.condense();
469 if (merged.cut != null) {
470 merged.cut = merged.fitToCell(merged.cut.getHyperplane().wholeHyperplane());
471 }
472
473 return merged;
474
475 }
476 }
477
478 /** This interface gather the merging operations between a BSP tree
479 * leaf and another BSP tree.
480 * <p>As explained in Bruce Naylor, John Amanatides and William
481 * Thibault paper <a
482 * href="http://www.cs.yorku.ca/~amana/research/bsptSetOp.pdf">Merging
483 * BSP Trees Yields Polyhedral Set Operations</a>,
484 * the operations on {@link BSPTree BSP trees} can be expressed as a
485 * generic recursive merging operation where only the final part,
486 * when one of the operand is a leaf, is specific to the real
487 * operation semantics. For example, a tree representing a region
488 * using a boolean attribute to identify inside cells and outside
489 * cells would use four different objects to implement the final
490 * merging phase of the four set operations union, intersection,
491 * difference and symmetric difference (exclusive or).</p>
492 * @param <S> Type of the space.
493 */
494 public interface LeafMerger<S extends Space> {
495
496 /** Merge a leaf node and a tree node.
497 * <p>This method is called at the end of a recursive merging
498 * resulting from a {@code tree1.merge(tree2, leafMerger)}
499 * call, when one of the sub-trees involved is a leaf (i.e. when
500 * its cut-hyperplane is null). This is the only place where the
501 * precise semantics of the operation are required. For all upper
502 * level nodes in the tree, the merging operation is only a
503 * generic partitioning algorithm.</p>
504 * <p>Since the final operation may be non-commutative, it is
505 * important to know if the leaf node comes from the instance tree
506 * ({@code tree1}) or the argument tree
507 * ({@code tree2}). The third argument of the method is
508 * devoted to this. It can be ignored for commutative
509 * operations.</p>
510 * <p>The {@link BSPTree#insertInTree BSPTree.insertInTree} method
511 * may be useful to implement this method.</p>
512 * @param leaf leaf node (its cut hyperplane is guaranteed to be
513 * null)
514 * @param tree tree node (its cut hyperplane may be null or not)
515 * @param parentTree parent tree to connect to (may be null)
516 * @param isPlusChild if true and if parentTree is not null, the
517 * resulting tree should be the plus child of its parent, ignored if
518 * parentTree is null
519 * @param leafFromInstance if true, the leaf node comes from the
520 * instance tree ({@code tree1}) and the tree node comes from
521 * the argument tree ({@code tree2})
522 * @return the BSP tree resulting from the merging (may be one of
523 * the arguments)
524 */
525 BSPTree<S> merge(BSPTree<S> leaf, BSPTree<S> tree, BSPTree<S> parentTree,
526 boolean isPlusChild, boolean leafFromInstance);
527
528 }
529
530 /** This interface handles the corner cases when an internal node cut sub-hyperplane vanishes.
531 * <p>
532 * Such cases happens for example when a cut sub-hyperplane is inserted into
533 * another tree (during a merge operation), and is split in several parts,
534 * some of which becomes smaller than the tolerance. The corresponding node
535 * as then no cut sub-hyperplane anymore, but does have children. This interface
536 * specifies how to handle this situation.
537 * setting
538 * </p>
539 * @param <S> Type of the space.
540 * @since 3.4
541 */
542 public interface VanishingCutHandler<S extends Space> {
543
544 /** Fix a node with both vanished cut and children.
545 * @param node node to fix
546 * @return fixed node
547 */
548 BSPTree<S> fixNode(BSPTree<S> node);
549
550 }
551
552 /** Split a BSP tree by an external sub-hyperplane.
553 * <p>Split a tree in two halves, on each side of the
554 * sub-hyperplane. The instance is not modified.</p>
555 * <p>The tree returned is not upward-consistent: despite all of its
556 * sub-trees cut sub-hyperplanes (including its own cut
557 * sub-hyperplane) are bounded to the current cell, it is <em>not</em>
558 * attached to any parent tree yet. This tree is intended to be
559 * later inserted into an higher level tree.</p>
560 * <p>The algorithm used here is the one given in Naylor, Amanatides
561 * and Thibault paper (section III, Binary Partitioning of a BSP
562 * Tree).</p>
563 * @param sub partitioning sub-hyperplane, must be already clipped
564 * to the convex region represented by the instance, will be used as
565 * the cut sub-hyperplane of the returned tree
566 * @return a tree having the specified sub-hyperplane as its cut
567 * sub-hyperplane, the two parts of the split instance as its two
568 * sub-trees and a null parent
569 */
570 public BSPTree<S> split(final SubHyperplane<S> sub) {
571
572 if (cut == null) {
573 return new BSPTree<S>(sub, copySelf(), new BSPTree<S>(attribute), null);
574 }
575
576 final Hyperplane<S> cHyperplane = cut.getHyperplane();
577 final Hyperplane<S> sHyperplane = sub.getHyperplane();
578 final SubHyperplane.SplitSubHyperplane<S> subParts = sub.split(cHyperplane);
579 switch (subParts.getSide()) {
580 case PLUS :
581 { // the partitioning sub-hyperplane is entirely in the plus sub-tree
582 final BSPTree<S> split = plus.split(sub);
583 if (cut.split(sHyperplane).getSide() == Side.PLUS) {
584 split.plus =
585 new BSPTree<S>(cut.copySelf(), split.plus, minus.copySelf(), attribute);
586 split.plus.condense();
587 split.plus.parent = split;
588 } else {
589 split.minus =
590 new BSPTree<S>(cut.copySelf(), split.minus, minus.copySelf(), attribute);
591 split.minus.condense();
592 split.minus.parent = split;
593 }
594 return split;
595 }
596 case MINUS :
597 { // the partitioning sub-hyperplane is entirely in the minus sub-tree
598 final BSPTree<S> split = minus.split(sub);
599 if (cut.split(sHyperplane).getSide() == Side.PLUS) {
600 split.plus =
601 new BSPTree<S>(cut.copySelf(), plus.copySelf(), split.plus, attribute);
602 split.plus.condense();
603 split.plus.parent = split;
604 } else {
605 split.minus =
606 new BSPTree<S>(cut.copySelf(), plus.copySelf(), split.minus, attribute);
607 split.minus.condense();
608 split.minus.parent = split;
609 }
610 return split;
611 }
612 case BOTH :
613 {
614 final SubHyperplane.SplitSubHyperplane<S> cutParts = cut.split(sHyperplane);
615 final BSPTree<S> split =
616 new BSPTree<S>(sub, plus.split(subParts.getPlus()), minus.split(subParts.getMinus()),
617 null);
618 split.plus.cut = cutParts.getPlus();
619 split.minus.cut = cutParts.getMinus();
620 final BSPTree<S> tmp = split.plus.minus;
621 split.plus.minus = split.minus.plus;
622 split.plus.minus.parent = split.plus;
623 split.minus.plus = tmp;
624 split.minus.plus.parent = split.minus;
625 split.plus.condense();
626 split.minus.condense();
627 return split;
628 }
629 default :
630 return cHyperplane.sameOrientationAs(sHyperplane) ?
631 new BSPTree<S>(sub, plus.copySelf(), minus.copySelf(), attribute) :
632 new BSPTree<S>(sub, minus.copySelf(), plus.copySelf(), attribute);
633 }
634
635 }
636
637 /** Insert the instance into another tree.
638 * <p>The instance itself is modified so its former parent should
639 * not be used anymore.</p>
640 * @param parentTree parent tree to connect to (may be null)
641 * @param isPlusChild if true and if parentTree is not null, the
642 * resulting tree should be the plus child of its parent, ignored if
643 * parentTree is null
644 * @see LeafMerger
645 * @deprecated as of 3.4, replaced with {@link #insertInTree(BSPTree, boolean, VanishingCutHandler)}
646 */
647 @Deprecated
648 public void insertInTree(final BSPTree<S> parentTree, final boolean isPlusChild) {
649 insertInTree(parentTree, isPlusChild, new VanishingCutHandler<S>() {
650 /** {@inheritDoc} */
651 public BSPTree<S> fixNode(BSPTree<S> node) {
652 // the cut should not be null
653 throw new MathIllegalStateException(LocalizedFormats.NULL_NOT_ALLOWED);
654 }
655 });
656 }
657
658 /** Insert the instance into another tree.
659 * <p>The instance itself is modified so its former parent should
660 * not be used anymore.</p>
661 * @param parentTree parent tree to connect to (may be null)
662 * @param isPlusChild if true and if parentTree is not null, the
663 * resulting tree should be the plus child of its parent, ignored if
664 * parentTree is null
665 * @param vanishingHandler handler to use for handling very rare corner
666 * cases of vanishing cut sub-hyperplanes in internal nodes during merging
667 * @see LeafMerger
668 * @since 3.4
669 */
670 public void insertInTree(final BSPTree<S> parentTree, final boolean isPlusChild,
671 final VanishingCutHandler<S> vanishingHandler) {
672
673 // set up parent/child links
674 parent = parentTree;
675 if (parentTree != null) {
676 if (isPlusChild) {
677 parentTree.plus = this;
678 } else {
679 parentTree.minus = this;
680 }
681 }
682
683 // make sure the inserted tree lies in the cell defined by its parent nodes
684 if (cut != null) {
685
686 // explore the parent nodes from here towards tree root
687 for (BSPTree<S> tree = this; tree.parent != null; tree = tree.parent) {
688
689 // this is an hyperplane of some parent node
690 final Hyperplane<S> hyperplane = tree.parent.cut.getHyperplane();
691
692 // chop off the parts of the inserted tree that extend
693 // on the wrong side of this parent hyperplane
694 if (tree == tree.parent.plus) {
695 cut = cut.split(hyperplane).getPlus();
696 plus.chopOffMinus(hyperplane, vanishingHandler);
697 minus.chopOffMinus(hyperplane, vanishingHandler);
698 } else {
699 cut = cut.split(hyperplane).getMinus();
700 plus.chopOffPlus(hyperplane, vanishingHandler);
701 minus.chopOffPlus(hyperplane, vanishingHandler);
702 }
703
704 if (cut == null) {
705 // the cut sub-hyperplane has vanished
706 final BSPTree<S> fixed = vanishingHandler.fixNode(this);
707 cut = fixed.cut;
708 plus = fixed.plus;
709 minus = fixed.minus;
710 attribute = fixed.attribute;
711 if (cut == null) {
712 break;
713 }
714 }
715
716 }
717
718 // since we may have drop some parts of the inserted tree,
719 // perform a condensation pass to keep the tree structure simple
720 condense();
721
722 }
723
724 }
725
726 /** Prune a tree around a cell.
727 * <p>
728 * This method can be used to extract a convex cell from a tree.
729 * The original cell may either be a leaf node or an internal node.
730 * If it is an internal node, it's subtree will be ignored (i.e. the
731 * extracted cell will be a leaf node in all cases). The original
732 * tree to which the original cell belongs is not touched at all,
733 * a new independent tree will be built.
734 * </p>
735 * @param cellAttribute attribute to set for the leaf node
736 * corresponding to the initial instance cell
737 * @param otherLeafsAttributes attribute to set for the other leaf
738 * nodes
739 * @param internalAttributes attribute to set for the internal nodes
740 * @return a new tree (the original tree is left untouched) containing
741 * a single branch with the cell as a leaf node, and other leaf nodes
742 * as the remnants of the pruned branches
743 * @since 3.3
744 */
745 public BSPTree<S> pruneAroundConvexCell(final Object cellAttribute,
746 final Object otherLeafsAttributes,
747 final Object internalAttributes) {
748
749 // build the current cell leaf
750 BSPTree<S> tree = new BSPTree<S>(cellAttribute);
751
752 // build the pruned tree bottom-up
753 for (BSPTree<S> current = this; current.parent != null; current = current.parent) {
754 final SubHyperplane<S> parentCut = current.parent.cut.copySelf();
755 final BSPTree<S> sibling = new BSPTree<S>(otherLeafsAttributes);
756 if (current == current.parent.plus) {
757 tree = new BSPTree<S>(parentCut, tree, sibling, internalAttributes);
758 } else {
759 tree = new BSPTree<S>(parentCut, sibling, tree, internalAttributes);
760 }
761 }
762
763 return tree;
764
765 }
766
767 /** Chop off parts of the tree.
768 * <p>The instance is modified in place, all the parts that are on
769 * the minus side of the chopping hyperplane are discarded, only the
770 * parts on the plus side remain.</p>
771 * @param hyperplane chopping hyperplane
772 * @param vanishingHandler handler to use for handling very rare corner
773 * cases of vanishing cut sub-hyperplanes in internal nodes during merging
774 */
775 private void chopOffMinus(final Hyperplane<S> hyperplane, final VanishingCutHandler<S> vanishingHandler) {
776 if (cut != null) {
777
778 cut = cut.split(hyperplane).getPlus();
779 plus.chopOffMinus(hyperplane, vanishingHandler);
780 minus.chopOffMinus(hyperplane, vanishingHandler);
781
782 if (cut == null) {
783 // the cut sub-hyperplane has vanished
784 final BSPTree<S> fixed = vanishingHandler.fixNode(this);
785 cut = fixed.cut;
786 plus = fixed.plus;
787 minus = fixed.minus;
788 attribute = fixed.attribute;
789 }
790
791 }
792 }
793
794 /** Chop off parts of the tree.
795 * <p>The instance is modified in place, all the parts that are on
796 * the plus side of the chopping hyperplane are discarded, only the
797 * parts on the minus side remain.</p>
798 * @param hyperplane chopping hyperplane
799 * @param vanishingHandler handler to use for handling very rare corner
800 * cases of vanishing cut sub-hyperplanes in internal nodes during merging
801 */
802 private void chopOffPlus(final Hyperplane<S> hyperplane, final VanishingCutHandler<S> vanishingHandler) {
803 if (cut != null) {
804
805 cut = cut.split(hyperplane).getMinus();
806 plus.chopOffPlus(hyperplane, vanishingHandler);
807 minus.chopOffPlus(hyperplane, vanishingHandler);
808
809 if (cut == null) {
810 // the cut sub-hyperplane has vanished
811 final BSPTree<S> fixed = vanishingHandler.fixNode(this);
812 cut = fixed.cut;
813 plus = fixed.plus;
814 minus = fixed.minus;
815 attribute = fixed.attribute;
816 }
817
818 }
819 }
820
821}
Note: See TracBrowser for help on using the repository browser.