1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.geometry.partitioning;
23
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.hipparchus.geometry.Point;
28 import org.hipparchus.geometry.Space;
29 import org.hipparchus.geometry.partitioning.Region.Location;
30 import org.hipparchus.util.FastMath;
31
32
33
34
35
36 class BoundaryProjector<S extends Space, T extends Space> implements BSPTreeVisitor<S> {
37
38
39 private final Point<S> original;
40
41
42 private Point<S> projected;
43
44
45 private BSPTree<S> leaf;
46
47
48 private double offset;
49
50
51
52
53 BoundaryProjector(final Point<S> original) {
54 this.original = original;
55 this.projected = null;
56 this.leaf = null;
57 this.offset = Double.POSITIVE_INFINITY;
58 }
59
60
61 @Override
62 public Order visitOrder(final BSPTree<S> node) {
63
64
65 if (node.getCut().getHyperplane().getOffset(original) <= 0) {
66 return Order.MINUS_SUB_PLUS;
67 } else {
68 return Order.PLUS_SUB_MINUS;
69 }
70 }
71
72
73 @Override
74 public void visitInternalNode(final BSPTree<S> node) {
75
76
77 final Hyperplane<S> hyperplane = node.getCut().getHyperplane();
78 final double signedOffset = hyperplane.getOffset(original);
79 if (FastMath.abs(signedOffset) < offset) {
80
81
82 final Point<S> regular = hyperplane.project(original);
83
84
85 final List<Region<T>> boundaryParts = boundaryRegions(node);
86
87
88 boolean regularFound = false;
89 for (final Region<T> part : boundaryParts) {
90 if (!regularFound && belongsToPart(regular, hyperplane, part)) {
91
92 projected = regular;
93 offset = FastMath.abs(signedOffset);
94 regularFound = true;
95 }
96 }
97
98 if (!regularFound) {
99
100
101
102 for (final Region<T> part : boundaryParts) {
103 final Point<S> spI = singularProjection(regular, hyperplane, part);
104 if (spI != null) {
105 final double distance = original.distance(spI);
106 if (distance < offset) {
107 projected = spI;
108 offset = distance;
109 }
110 }
111 }
112
113 }
114
115 }
116
117 }
118
119
120 @Override
121 public void visitLeafNode(final BSPTree<S> node) {
122 if (leaf == null) {
123
124
125 leaf = node;
126 }
127 }
128
129
130
131
132 public BoundaryProjection<S> getProjection() {
133
134
135 offset = FastMath.copySign(offset, (Boolean) leaf.getAttribute() ? -1 : +1);
136
137 return new BoundaryProjection<S>(original, projected, offset);
138
139 }
140
141
142
143
144
145 private List<Region<T>> boundaryRegions(final BSPTree<S> node) {
146
147 final List<Region<T>> regions = new ArrayList<>(2);
148
149 @SuppressWarnings("unchecked")
150 final BoundaryAttribute<S> ba = (BoundaryAttribute<S>) node.getAttribute();
151 addRegion(ba.getPlusInside(), regions);
152 addRegion(ba.getPlusOutside(), regions);
153
154 return regions;
155
156 }
157
158
159
160
161
162 private void addRegion(final SubHyperplane<S> sub, final List<Region<T>> list) {
163 if (sub != null) {
164 @SuppressWarnings("unchecked")
165 final Region<T> region = ((AbstractSubHyperplane<S, T>) sub).getRemainingRegion();
166 if (region != null) {
167 list.add(region);
168 }
169 }
170 }
171
172
173
174
175
176
177
178 private boolean belongsToPart(final Point<S> point, final Hyperplane<S> hyperplane,
179 final Region<T> part) {
180
181
182 @SuppressWarnings("unchecked")
183 final Embedding<S, T> embedding = (Embedding<S, T>) hyperplane;
184 return part.checkPoint(embedding.toSubSpace(point)) != Location.OUTSIDE;
185
186 }
187
188
189
190
191
192
193
194 private Point<S> singularProjection(final Point<S> point, final Hyperplane<S> hyperplane,
195 final Region<T> part) {
196
197
198 @SuppressWarnings("unchecked")
199 final Embedding<S, T> embedding = (Embedding<S, T>) hyperplane;
200 final BoundaryProjection<T> bp = part.projectToBoundary(embedding.toSubSpace(point));
201
202
203 return (bp.getProjected() == null) ? null : embedding.toSpace(bp.getProjected());
204
205 }
206
207 }