1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.threed;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.commons.geometry.core.Transform;
23 import org.apache.commons.geometry.core.partitioning.Hyperplane;
24 import org.apache.commons.geometry.core.partitioning.Split;
25 import org.apache.commons.geometry.euclidean.twod.ConvexArea;
26 import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
27 import org.apache.commons.geometry.euclidean.twod.Vector2D;
28 import org.apache.commons.geometry.euclidean.twod.rotation.Rotation2D;
29 import org.apache.commons.numbers.core.Precision;
30
31
32
33
34
35
36 public final class EmbeddedTreePlaneSubset extends AbstractEmbeddedRegionPlaneSubset {
37
38
39 private final RegionBSPTree2D region;
40
41
42
43
44 public EmbeddedTreePlaneSubset(final EmbeddingPlane plane) {
45 this(plane, false);
46 }
47
48
49
50
51
52
53
54
55 public EmbeddedTreePlaneSubset(final EmbeddingPlane plane, final boolean full) {
56 this(plane, new RegionBSPTree2D(full));
57 }
58
59
60
61
62
63 public EmbeddedTreePlaneSubset(final EmbeddingPlane plane, final RegionBSPTree2D region) {
64 super(plane);
65
66 this.region = region;
67 }
68
69
70 @Override
71 public PlaneSubset.Embedded getEmbedded() {
72 return this;
73 }
74
75
76 @Override
77 public RegionBSPTree2D getSubspaceRegion() {
78 return region;
79 }
80
81
82 @Override
83 public List<PlaneConvexSubset> toConvex() {
84 final List<ConvexArea> areas = region.toConvex();
85
86 final List<PlaneConvexSubset> facets = new ArrayList<>(areas.size());
87
88 for (final ConvexArea area : areas) {
89 facets.add(Planes.subsetFromConvexArea(getPlane(), area));
90 }
91
92 return facets;
93 }
94
95
96 @Override
97 public List<Triangle3D> toTriangles() {
98 final EmbeddingPlane plane = getPlane();
99 final List<Triangle3D> triangles = new ArrayList<>();
100
101 List<Vector3D> vertices;
102 for (final ConvexArea area : region.toConvex()) {
103 if (area.isInfinite()) {
104 throw new IllegalStateException("Cannot convert infinite plane subset to triangles: " + this);
105 }
106
107 vertices = plane.toSpace(area.getVertices());
108
109 triangles.addAll(Planes.convexPolygonToTriangleFan(plane, vertices));
110 }
111
112 return triangles;
113 }
114
115
116 @Override
117 public Bounds3D getBounds() {
118 return getBoundsFromSubspace(region);
119 }
120
121
122
123
124
125
126
127
128
129
130
131 @Override
132 public Split<EmbeddedTreePlaneSubset> split(final Hyperplane<Vector3D> splitter) {
133 return Planes.subspaceSplit((Plane) splitter, this,
134 (p, r) -> new EmbeddedTreePlaneSubset(p, (RegionBSPTree2D) r));
135 }
136
137
138 @Override
139 public EmbeddedTreePlaneSubset transform(final Transform<Vector3D> transform) {
140 final EmbeddingPlane.SubspaceTransform subTransform =
141 getPlane().getEmbedding().subspaceTransform(transform);
142
143 final RegionBSPTree2D tRegion = RegionBSPTree2D.empty();
144 tRegion.copy(region);
145 tRegion.transform(subTransform.getTransform());
146
147 return new EmbeddedTreePlaneSubset(subTransform.getPlane(), tRegion);
148 }
149
150
151
152
153
154
155 public void add(final PlaneConvexSubset subset) {
156 Planes.validatePlanesEquivalent(getPlane(), subset.getPlane());
157
158 final PlaneConvexSubset.Embedded embedded = subset.getEmbedded();
159 final Rotation2D rot = getEmbeddedRegionRotation(embedded);
160
161 final ConvexArea subspaceArea = embedded.getSubspaceRegion();
162
163 final ConvexArea toAdd = rot != null ?
164 subspaceArea.transform(rot) :
165 subspaceArea;
166
167 region.add(toAdd);
168 }
169
170
171
172
173
174
175 public void add(final EmbeddedTreePlaneSubset subset) {
176 Planes.validatePlanesEquivalent(getPlane(), subset.getPlane());
177
178 final RegionBSPTree2D otherTree = subset.getSubspaceRegion();
179 final Rotation2D rot = getEmbeddedRegionRotation(subset);
180
181 final RegionBSPTree2D regionToAdd;
182 if (rot != null) {
183
184 regionToAdd = otherTree.copy();
185 regionToAdd.transform(rot);
186 } else {
187 regionToAdd = otherTree;
188 }
189
190 region.union(regionToAdd);
191 }
192
193
194
195
196
197
198
199
200
201 private Rotation2D getEmbeddedRegionRotation(final PlaneSubset.Embedded embedded) {
202
203 final EmbeddingPlane thisPlane = getPlane();
204 final EmbeddingPlane otherPlane = embedded.getPlane();
205
206 final Precision.DoubleEquivalence precision = thisPlane.getPrecision();
207
208 final double uDot = thisPlane.getU().dot(otherPlane.getU());
209 if (!precision.eq(uDot, 1.0)) {
210 final Vector2D otherPlaneU = thisPlane.toSubspace(otherPlane.getOrigin().add(otherPlane.getU()));
211 final double angle = Math.atan2(otherPlaneU.getY(), otherPlaneU.getX());
212
213 return Rotation2D.of(angle);
214 }
215
216 return null;
217 }
218 }