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 }