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 agents.anac.y2019.harddealer.math3.geometry.partitioning;
|
---|
18 |
|
---|
19 | import java.util.HashMap;
|
---|
20 | import java.util.Map;
|
---|
21 |
|
---|
22 | import agents.anac.y2019.harddealer.math3.geometry.Space;
|
---|
23 |
|
---|
24 | /** This class implements the dimension-independent parts of {@link SubHyperplane}.
|
---|
25 |
|
---|
26 | * <p>sub-hyperplanes are obtained when parts of an {@link
|
---|
27 | * Hyperplane hyperplane} are chopped off by other hyperplanes that
|
---|
28 | * intersect it. The remaining part is a convex region. Such objects
|
---|
29 | * appear in {@link BSPTree BSP trees} as the intersection of a cut
|
---|
30 | * hyperplane with the convex region which it splits, the chopping
|
---|
31 | * hyperplanes are the cut hyperplanes closer to the tree root.</p>
|
---|
32 |
|
---|
33 | * @param <S> Type of the embedding space.
|
---|
34 | * @param <T> Type of the embedded sub-space.
|
---|
35 |
|
---|
36 | * @since 3.0
|
---|
37 | */
|
---|
38 | public abstract class AbstractSubHyperplane<S extends Space, T extends Space>
|
---|
39 | implements SubHyperplane<S> {
|
---|
40 |
|
---|
41 | /** Underlying hyperplane. */
|
---|
42 | private final Hyperplane<S> hyperplane;
|
---|
43 |
|
---|
44 | /** Remaining region of the hyperplane. */
|
---|
45 | private final Region<T> remainingRegion;
|
---|
46 |
|
---|
47 | /** Build a sub-hyperplane from an hyperplane and a region.
|
---|
48 | * @param hyperplane underlying hyperplane
|
---|
49 | * @param remainingRegion remaining region of the hyperplane
|
---|
50 | */
|
---|
51 | protected AbstractSubHyperplane(final Hyperplane<S> hyperplane,
|
---|
52 | final Region<T> remainingRegion) {
|
---|
53 | this.hyperplane = hyperplane;
|
---|
54 | this.remainingRegion = remainingRegion;
|
---|
55 | }
|
---|
56 |
|
---|
57 | /** Build a sub-hyperplane from an hyperplane and a region.
|
---|
58 | * @param hyper underlying hyperplane
|
---|
59 | * @param remaining remaining region of the hyperplane
|
---|
60 | * @return a new sub-hyperplane
|
---|
61 | */
|
---|
62 | protected abstract AbstractSubHyperplane<S, T> buildNew(final Hyperplane<S> hyper,
|
---|
63 | final Region<T> remaining);
|
---|
64 |
|
---|
65 | /** {@inheritDoc} */
|
---|
66 | public AbstractSubHyperplane<S, T> copySelf() {
|
---|
67 | return buildNew(hyperplane.copySelf(), remainingRegion);
|
---|
68 | }
|
---|
69 |
|
---|
70 | /** Get the underlying hyperplane.
|
---|
71 | * @return underlying hyperplane
|
---|
72 | */
|
---|
73 | public Hyperplane<S> getHyperplane() {
|
---|
74 | return hyperplane;
|
---|
75 | }
|
---|
76 |
|
---|
77 | /** Get the remaining region of the hyperplane.
|
---|
78 | * <p>The returned region is expressed in the canonical hyperplane
|
---|
79 | * frame and has the hyperplane dimension. For example a chopped
|
---|
80 | * hyperplane in the 3D euclidean is a 2D plane and the
|
---|
81 | * corresponding region is a convex 2D polygon.</p>
|
---|
82 | * @return remaining region of the hyperplane
|
---|
83 | */
|
---|
84 | public Region<T> getRemainingRegion() {
|
---|
85 | return remainingRegion;
|
---|
86 | }
|
---|
87 |
|
---|
88 | /** {@inheritDoc} */
|
---|
89 | public double getSize() {
|
---|
90 | return remainingRegion.getSize();
|
---|
91 | }
|
---|
92 |
|
---|
93 | /** {@inheritDoc} */
|
---|
94 | public AbstractSubHyperplane<S, T> reunite(final SubHyperplane<S> other) {
|
---|
95 | @SuppressWarnings("unchecked")
|
---|
96 | AbstractSubHyperplane<S, T> o = (AbstractSubHyperplane<S, T>) other;
|
---|
97 | return buildNew(hyperplane,
|
---|
98 | new RegionFactory<T>().union(remainingRegion, o.remainingRegion));
|
---|
99 | }
|
---|
100 |
|
---|
101 | /** Apply a transform to the instance.
|
---|
102 | * <p>The instance must be a (D-1)-dimension sub-hyperplane with
|
---|
103 | * respect to the transform <em>not</em> a (D-2)-dimension
|
---|
104 | * sub-hyperplane the transform knows how to transform by
|
---|
105 | * itself. The transform will consist in transforming first the
|
---|
106 | * hyperplane and then the all region using the various methods
|
---|
107 | * provided by the transform.</p>
|
---|
108 | * @param transform D-dimension transform to apply
|
---|
109 | * @return the transformed instance
|
---|
110 | */
|
---|
111 | public AbstractSubHyperplane<S, T> applyTransform(final Transform<S, T> transform) {
|
---|
112 | final Hyperplane<S> tHyperplane = transform.apply(hyperplane);
|
---|
113 |
|
---|
114 | // transform the tree, except for boundary attribute splitters
|
---|
115 | final Map<BSPTree<T>, BSPTree<T>> map = new HashMap<BSPTree<T>, BSPTree<T>>();
|
---|
116 | final BSPTree<T> tTree =
|
---|
117 | recurseTransform(remainingRegion.getTree(false), tHyperplane, transform, map);
|
---|
118 |
|
---|
119 | // set up the boundary attributes splitters
|
---|
120 | for (final Map.Entry<BSPTree<T>, BSPTree<T>> entry : map.entrySet()) {
|
---|
121 | if (entry.getKey().getCut() != null) {
|
---|
122 | @SuppressWarnings("unchecked")
|
---|
123 | BoundaryAttribute<T> original = (BoundaryAttribute<T>) entry.getKey().getAttribute();
|
---|
124 | if (original != null) {
|
---|
125 | @SuppressWarnings("unchecked")
|
---|
126 | BoundaryAttribute<T> transformed = (BoundaryAttribute<T>) entry.getValue().getAttribute();
|
---|
127 | for (final BSPTree<T> splitter : original.getSplitters()) {
|
---|
128 | transformed.getSplitters().add(map.get(splitter));
|
---|
129 | }
|
---|
130 | }
|
---|
131 | }
|
---|
132 | }
|
---|
133 |
|
---|
134 | return buildNew(tHyperplane, remainingRegion.buildNew(tTree));
|
---|
135 |
|
---|
136 | }
|
---|
137 |
|
---|
138 | /** Recursively transform a BSP-tree from a sub-hyperplane.
|
---|
139 | * @param node current BSP tree node
|
---|
140 | * @param transformed image of the instance hyperplane by the transform
|
---|
141 | * @param transform transform to apply
|
---|
142 | * @param map transformed nodes map
|
---|
143 | * @return a new tree
|
---|
144 | */
|
---|
145 | private BSPTree<T> recurseTransform(final BSPTree<T> node,
|
---|
146 | final Hyperplane<S> transformed,
|
---|
147 | final Transform<S, T> transform,
|
---|
148 | final Map<BSPTree<T>, BSPTree<T>> map) {
|
---|
149 |
|
---|
150 | final BSPTree<T> transformedNode;
|
---|
151 | if (node.getCut() == null) {
|
---|
152 | transformedNode = new BSPTree<T>(node.getAttribute());
|
---|
153 | } else {
|
---|
154 |
|
---|
155 | @SuppressWarnings("unchecked")
|
---|
156 | BoundaryAttribute<T> attribute = (BoundaryAttribute<T>) node.getAttribute();
|
---|
157 | if (attribute != null) {
|
---|
158 | final SubHyperplane<T> tPO = (attribute.getPlusOutside() == null) ?
|
---|
159 | null : transform.apply(attribute.getPlusOutside(), hyperplane, transformed);
|
---|
160 | final SubHyperplane<T> tPI = (attribute.getPlusInside() == null) ?
|
---|
161 | null : transform.apply(attribute.getPlusInside(), hyperplane, transformed);
|
---|
162 | // we start with an empty list of splitters, it will be filled in out of recursion
|
---|
163 | attribute = new BoundaryAttribute<T>(tPO, tPI, new NodesSet<T>());
|
---|
164 | }
|
---|
165 |
|
---|
166 | transformedNode = new BSPTree<T>(transform.apply(node.getCut(), hyperplane, transformed),
|
---|
167 | recurseTransform(node.getPlus(), transformed, transform, map),
|
---|
168 | recurseTransform(node.getMinus(), transformed, transform, map),
|
---|
169 | attribute);
|
---|
170 | }
|
---|
171 |
|
---|
172 | map.put(node, transformedNode);
|
---|
173 | return transformedNode;
|
---|
174 |
|
---|
175 | }
|
---|
176 |
|
---|
177 | /** {@inheritDoc} */
|
---|
178 | @Deprecated
|
---|
179 | public Side side(Hyperplane<S> hyper) {
|
---|
180 | return split(hyper).getSide();
|
---|
181 | }
|
---|
182 |
|
---|
183 | /** {@inheritDoc} */
|
---|
184 | public abstract SplitSubHyperplane<S> split(Hyperplane<S> hyper);
|
---|
185 |
|
---|
186 | /** {@inheritDoc} */
|
---|
187 | public boolean isEmpty() {
|
---|
188 | return remainingRegion.isEmpty();
|
---|
189 | }
|
---|
190 |
|
---|
191 | }
|
---|