View Javadoc
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   */
17  package org.apache.commons.geometry.core.partitioning.test;
18  
19  import org.apache.commons.geometry.core.Point;
20  import org.apache.commons.geometry.core.partitioning.Hyperplane;
21  import org.apache.commons.geometry.core.partitioning.bsp.AbstractBSPTree;
22  
23  /** Simple {@link org.apache.commons.geometry.core.partitioning.bsp.BSPTree} implementation allowing arbitrary values to be
24   * associated with each node.
25   * @param <P> Point implementation type
26   * @param <T> Tree node attribute type
27   */
28  public class AttributeBSPTree<P extends Point<P>, T>
29      extends AbstractBSPTree<P, AttributeBSPTree.AttributeNode<P, T>> {
30      /** The initial attribute value to use for newly created nodes. */
31      private final T initialNodeAttribute;
32  
33      /** Create a new tree instance. New nodes in the tree are given an attribute
34       * of null.
35       */
36      public AttributeBSPTree() {
37          this(null);
38      }
39  
40      /** Create a new tree instance. New nodes in the tree are assigned the given
41       * initial attribute value.
42       * @param initialNodeAttribute The attribute value to assign to newly created nodes.
43       */
44      public AttributeBSPTree(final T initialNodeAttribute) {
45          this.initialNodeAttribute = initialNodeAttribute;
46  
47          this.getRoot().setAttribute(initialNodeAttribute);
48      }
49  
50      /** {@inheritDoc} */
51      @Override
52      protected AttributeNode<P, T> createNode() {
53          return new AttributeNode<>(this);
54      }
55  
56      /** {@inheritDoc} */
57      @Override
58      protected void copyNodeProperties(final AttributeNode<P, T> src, final AttributeNode<P, T> dst) {
59          dst.setAttribute(src.getAttribute());
60      }
61  
62      /** {@link org.apache.commons.geometry.core.partitioning.bsp.BSPTree.Node} implementation for use with {@link AttributeBSPTree}s.
63       * @param <P> Point implementation type
64       * @param <T> Tree node attribute type
65       */
66      public static class AttributeNode<P extends Point<P>, T>
67          extends AbstractBSPTree.AbstractNode<P, AttributeNode<P, T>> {
68          /** The node attribute. */
69          private T attribute;
70  
71          /** Simple constructor.
72           * @param tree the owning tree; this must be an instance of {@link AttributeBSPTree}
73           */
74          protected AttributeNode(final AbstractBSPTree<P, AttributeNode<P, T>> tree) {
75              super(tree);
76          }
77  
78          /** {@inheritDoc} */
79          @Override
80          public AttributeBSPTree<P, T> getTree() {
81              // cast to our parent tree type
82              return (AttributeBSPTree<P, T>) super.getTree();
83          }
84  
85          /** Cut this node with the given hyperplane. If the hyperplane intersects the node's region,
86           * then the node becomes an internal node with two child leaf node. If the hyperplane does
87           * not intersect the node's region, then the node is made a leaf node. The same node is
88           * returned, regardless of the outcome of the cut operation.
89           * @param cutter hyperplane to cut the node with
90           * @return this node
91           */
92          public AttributeNode<P, T> cut(final Hyperplane<P> cutter) {
93              final AttributeBSPTree<P, T> tree = getTree();
94  
95              tree.cutNode(getSelf(), cutter, root -> {
96                  root.getMinus().setAttribute(tree.initialNodeAttribute);
97                  root.getPlus().setAttribute(tree.initialNodeAttribute);
98              });
99  
100             return this;
101         }
102 
103         /** Get the attribute associated with this node.
104          * @return the attribute associated with this node
105          */
106         public T getAttribute() {
107             return attribute;
108         }
109 
110         /** Set the attribute associated with this node.
111          * @param attribute the attribute to associate with this node
112          */
113         public void setAttribute(final T attribute) {
114             this.attribute = attribute;
115         }
116 
117         /** Set the attribute for this node. The node is returned.
118          * @param attributeValue attribute to set for the node
119          * @return the node instance
120          */
121         public AttributeNode<P, T> attr(final T attributeValue) {
122             setAttribute(attributeValue);
123 
124             return this;
125         }
126 
127         /** {@inheritDoc} */
128         @Override
129         public String toString() {
130             final StringBuilder sb = new StringBuilder();
131             sb.append(this.getClass().getSimpleName())
132                 .append("[cut= ")
133                 .append(getCut())
134                 .append(", attribute= ")
135                 .append(attribute)
136                 .append("]");
137 
138             return sb.toString();
139         }
140 
141         /** {@inheritDoc} */
142         @Override
143         protected AttributeNode<P, T> getSelf() {
144             return this;
145         }
146     }
147 }