1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.twod;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.commons.geometry.core.RegionLocation;
23 import org.apache.commons.geometry.core.Transform;
24 import org.apache.commons.geometry.core.internal.HyperplaneSubsets;
25 import org.apache.commons.geometry.core.partitioning.Hyperplane;
26 import org.apache.commons.geometry.core.partitioning.Split;
27 import org.apache.commons.geometry.core.partitioning.SplitLocation;
28 import org.apache.commons.geometry.euclidean.oned.Interval;
29 import org.apache.commons.geometry.euclidean.oned.OrientedPoint;
30 import org.apache.commons.geometry.euclidean.oned.OrientedPoints;
31 import org.apache.commons.geometry.euclidean.oned.RegionBSPTree1D;
32 import org.apache.commons.geometry.euclidean.oned.Vector1D;
33 import org.apache.commons.geometry.euclidean.twod.Line.SubspaceTransform;
34 import org.apache.commons.numbers.core.Precision;
35
36
37
38
39
40
41 public final class EmbeddedTreeLineSubset extends LineSubset {
42
43 private final RegionBSPTree1D region;
44
45
46
47
48 public EmbeddedTreeLineSubset(final Line line) {
49 this(line, false);
50 }
51
52
53
54
55
56
57
58
59 public EmbeddedTreeLineSubset(final Line line, final boolean full) {
60 this(line, new RegionBSPTree1D(full));
61 }
62
63
64
65
66
67
68 public EmbeddedTreeLineSubset(final Line line, final RegionBSPTree1D region) {
69 super(line);
70
71 this.region = region;
72 }
73
74
75 @Override
76 public boolean isFull() {
77 return region.isFull();
78 }
79
80
81 @Override
82 public boolean isEmpty() {
83 return region.isEmpty();
84 }
85
86
87 @Override
88 public double getSize() {
89 return region.getSize();
90 }
91
92
93 @Override
94 public Vector2D getCentroid() {
95 final Vector1D subspaceCentroid = region.getCentroid();
96 if (subspaceCentroid != null) {
97 return getLine().toSpace(subspaceCentroid);
98 }
99 return null;
100 }
101
102
103 @Override
104 public Bounds2D getBounds() {
105 final double min = region.getMin();
106 final double max = region.getMax();
107
108 if (Double.isFinite(min) && Double.isFinite(max)) {
109 final Line line = getLine();
110
111 return Bounds2D.builder()
112 .add(line.toSpace(min))
113 .add(line.toSpace(max))
114 .build();
115 }
116
117 return null;
118 }
119
120
121 @Override
122 public Vector2D closest(final Vector2D pt) {
123 return HyperplaneSubsets.closestToEmbeddedRegion(pt, getLine(), region);
124 }
125
126
127 @Override
128 public EmbeddedTreeLineSubset transform(final Transform<Vector2D> transform) {
129 final SubspaceTransform st = getLine().subspaceTransform(transform);
130
131 final RegionBSPTree1D tRegion = RegionBSPTree1D.empty();
132 tRegion.copy(region);
133 tRegion.transform(st.getTransform());
134
135 return new EmbeddedTreeLineSubset(st.getLine(), tRegion);
136 }
137
138
139 @Override
140 public List<LineConvexSubset> toConvex() {
141 final List<Interval> intervals = region.toIntervals();
142
143 final Line line = getLine();
144 final List<LineConvexSubset> convexSubsets = new ArrayList<>(intervals.size());
145
146 for (final Interval interval : intervals) {
147 convexSubsets.add(Lines.subsetFromInterval(line, interval));
148 }
149
150 return convexSubsets;
151 }
152
153
154 @Override
155 public RegionBSPTree1D getSubspaceRegion() {
156 return region;
157 }
158
159
160
161
162
163
164
165
166
167
168
169 @Override
170 public Split<EmbeddedTreeLineSubset> split(final Hyperplane<Vector2D> splitter) {
171 final Line thisLine = getLine();
172 final Line splitterLine = (Line) splitter;
173 final Precision.DoubleEquivalence precision = getPrecision();
174
175 final Vector2D intersection = splitterLine.intersection(thisLine);
176 if (intersection == null) {
177 return getNonIntersectingSplitResult(splitterLine, this);
178 }
179
180 final double abscissa = thisLine.abscissa(intersection);
181 final OrientedPoint subspaceSplitter = OrientedPoints.fromLocationAndDirection(
182 abscissa,
183 splitterPlusIsPositiveFacing(splitterLine),
184 precision);
185
186 final Split<RegionBSPTree1D> subspaceSplit = region.split(subspaceSplitter);
187 final SplitLocation subspaceSplitLoc = subspaceSplit.getLocation();
188
189 if (SplitLocation.MINUS == subspaceSplitLoc) {
190 return new Split<>(this, null);
191 } else if (SplitLocation.PLUS == subspaceSplitLoc) {
192 return new Split<>(null, this);
193 }
194
195 final EmbeddedTreeLineSubset minus = (subspaceSplit.getMinus() != null) ?
196 new EmbeddedTreeLineSubset(thisLine, subspaceSplit.getMinus()) :
197 null;
198 final EmbeddedTreeLineSubset plus = (subspaceSplit.getPlus() != null) ?
199 new EmbeddedTreeLineSubset(thisLine, subspaceSplit.getPlus()) :
200 null;
201
202 return new Split<>(minus, plus);
203 }
204
205
206
207
208
209
210 public void add(final LineConvexSubset subset) {
211 Lines.validateLinesEquivalent(getLine(), subset.getLine());
212
213 region.add(subset.getInterval());
214 }
215
216
217
218
219
220
221
222 public void add(final EmbeddedTreeLineSubset subset) {
223 Lines.validateLinesEquivalent(getLine(), subset.getLine());
224
225 region.union(subset.getSubspaceRegion());
226 }
227
228
229 @Override
230 public String toString() {
231 final Line line = getLine();
232
233 final StringBuilder sb = new StringBuilder();
234 sb.append(this.getClass().getSimpleName())
235 .append('[')
236 .append("lineOrigin= ")
237 .append(line.getOrigin())
238 .append(", lineDirection= ")
239 .append(line.getDirection())
240 .append(", region= ")
241 .append(region)
242 .append(']');
243
244 return sb.toString();
245 }
246
247
248 @Override
249 RegionLocation classifyAbscissa(final double abscissa) {
250 return region.classify(abscissa);
251 }
252 }