1
2
3
4
5
6
7
8 package org.sourceforge.jvb3d.Loader;
9
10 import java.util.LinkedList;
11 import java.util.List;
12 import java.util.Vector;
13
14 import javax.media.j3d.BoundingBox;
15 import javax.vecmath.Point2f;
16 import javax.vecmath.Point3d;
17 import javax.vecmath.TexCoord2f;
18 import javax.vecmath.Vector3d;
19
20 import com.sun.j3d.utils.geometry.GeometryInfo;
21 import com.sun.j3d.utils.geometry.NormalGenerator;
22
23 /***
24 * @author Łukasz Krzyżak
25 *
26 * klasa odpowiada za tworzenie subpowierzchni i różne operacje na jej geometrii
27 */
28 public class SubSurface {
29 protected class TextureCoordinates {
30 TexCoord2f[] textureCoords = new TexCoord2f[8];
31
32 int textureLevel = 0;
33
34 TextureCoordinates(int texNo) {
35 textureLevel = texNo;
36 }
37 }
38
39 protected Point3d[] vertices = new Point3d[4];
40
41 protected List<TextureCoordinates> textureCoords = new LinkedList<TextureCoordinates>();
42
43 BoundingBox surfaceBounds = null;
44
45 static final double wallDefaultWidth = 0.01;
46
47 static final double minSurfaceWidth = 0.01;
48
49 /***
50 * tworzy nową podpowierzchnię na podstawie tablicy 4 punktów
51 *
52 * @param vert
53 * tablica współrzędnych punktów
54 */
55 public SubSurface(Point3d[] vert) {
56 for (int i = 0; i < 4; i++) {
57 vertices[i] = vert[i];
58 }
59
60 Point3d[] corners = getBoundingCorners(vert);
61 surfaceBounds = new BoundingBox(corners[0], corners[1]);
62 }
63
64 private Point3d[] getBoundingCorners(Point3d[] vertex) {
65 Point3d[] coords = new Point3d[2];
66
67 double minX = vertex[0].x, minY = vertex[0].y, minZ = vertex[0].z, maxX = vertex[0].x, maxY = vertex[0].y, maxZ = vertex[0].z;
68
69 for (int i = 0; i < 4; i++) {
70 if (vertex[i].x < minX)
71 minX = vertex[i].x;
72 if (vertex[i].x > maxX)
73 maxX = vertex[i].x;
74 if (vertex[i].y < minY)
75 minY = vertex[i].y;
76 if (vertex[i].y > maxY)
77 maxY = vertex[i].y;
78 if (vertex[i].z < minZ)
79 minZ = vertex[i].z;
80 if (vertex[i].z > maxZ)
81 maxZ = vertex[i].z;
82 }
83
84 coords[0] = new Point3d(minX, minY, minZ);
85 coords[1] = new Point3d(maxX, maxY, maxZ);
86 return coords;
87 }
88
89 /***
90 * tworzy nową subpowierzchnię na podstawie podanych wierzchołków
91 *
92 * @param p0
93 * lewy górny
94 * @param p1
95 * prawy górny
96 * @param p2
97 * prawy dolny
98 * @param p3
99 * lewy dolny
100 */
101 public SubSurface(Point3d p0, Point3d p1, Point3d p2, Point3d p3) {
102 vertices[0] = p0;
103 vertices[1] = p1;
104 vertices[2] = p2;
105 vertices[3] = p3;
106
107 surfaceBounds = new BoundingBox(vertices[0], vertices[1]);
108 surfaceBounds.combine(vertices[2]);
109 surfaceBounds.combine(vertices[3]);
110 }
111
112 void setTextureCoordinate(int vertexNumber, Point2f texCoord,
113 int textureNumber) {
114
115 if (textureCoords.size() < textureNumber + 1
116 || textureCoords.get(textureNumber) == null) {
117 textureCoords.add(new TextureCoordinates(textureNumber));
118 }
119
120 for (TextureCoordinates coords : textureCoords)
121 if (coords.textureLevel == textureNumber)
122 coords.textureCoords[vertexNumber] = new TexCoord2f(texCoord.x,
123 texCoord.y);
124 }
125
126 Point3d getVertex(int vertexNumber) {
127 return vertices[vertexNumber];
128 }
129
130 /***
131 * testuje czy podany punkt znajduje sie na powierzchni
132 *
133 * @param point
134 * współrzędne punktu
135 * @return czy punktjest na powierzchni
136 */
137 boolean isInside(Point3d point) {
138 return surfaceBounds.intersect(point);
139 }
140
141 /***
142 * dzieli podpowierzchnię tak, aby powstał otwór
143 *
144 * @param vert
145 * współrzędne dziury
146 * @return tablica nowych podpowierzchni
147 */
148 SubSurface[] cutOpening(Point3d[] vert) {
149 Vector3d surfEdge = null, translation = null;
150 double transLength = 0;
151 Point3d[] splitPoints = new Point3d[4];
152 List<SubSurface> subsurfaces = new Vector<SubSurface>(4);
153
154 surfEdge = new Vector3d(vertices[1]);
155 surfEdge.sub(vertices[0]);
156 surfEdge.normalize();
157 translation = new Vector3d(selectClosest(vertices[0], vert));
158 translation.sub(vertices[0]);
159 transLength = translation.dot(surfEdge);
160 translation.scale(transLength, surfEdge);
161
162 splitPoints[0] = new Point3d(vertices[0]);
163 splitPoints[0].add(translation);
164
165 surfEdge = new Vector3d(vertices[0]);
166 surfEdge.sub(vertices[1]);
167 surfEdge.normalize();
168 translation = new Vector3d(selectClosest(vertices[1], vert));
169 translation.sub(vertices[1]);
170 transLength = translation.dot(surfEdge);
171 translation.scale(transLength, surfEdge);
172
173 splitPoints[1] = new Point3d(vertices[1]);
174 splitPoints[1].add(translation);
175
176 surfEdge = new Vector3d(vertices[3]);
177 surfEdge.sub(vertices[2]);
178 surfEdge.normalize();
179 translation = new Vector3d(selectClosest(vertices[2], vert));
180 translation.sub(vertices[2]);
181 transLength = translation.dot(surfEdge);
182 translation.scale(transLength, surfEdge);
183
184 splitPoints[2] = new Point3d(vertices[2]);
185 splitPoints[2].add(translation);
186
187 surfEdge = new Vector3d(vertices[2]);
188 surfEdge.sub(vertices[3]);
189 surfEdge.normalize();
190 translation = new Vector3d(selectClosest(vertices[3], vert));
191 translation.sub(vertices[3]);
192 transLength = translation.dot(surfEdge);
193 translation.scale(transLength, surfEdge);
194
195 splitPoints[3] = new Point3d(vertices[3]);
196 splitPoints[3].add(translation);
197
198 if (vertices[0].distance(splitPoints[0]) > minSurfaceWidth) {
199 subsurfaces.add(new SubSurface(vertices[0], splitPoints[0],
200 splitPoints[3], vertices[3]));
201 }
202
203 if (splitPoints[0].distance(vert[0]) > minSurfaceWidth
204 && splitPoints[0].distance(splitPoints[1]) > minSurfaceWidth) {
205 subsurfaces.add(new SubSurface(splitPoints[0], splitPoints[1],
206 selectClosest(vertices[1], vert), selectClosest(
207 vertices[0], vert)));
208 }
209
210 if (splitPoints[3].distance(vert[3]) > minSurfaceWidth
211 && splitPoints[3].distance(splitPoints[2]) > minSurfaceWidth) {
212 subsurfaces.add(new SubSurface(selectClosest(vertices[3], vert),
213 selectClosest(vertices[2], vert), splitPoints[2],
214 splitPoints[3]));
215 }
216
217 if (splitPoints[1].distance(vertices[1]) > minSurfaceWidth
218 && vertices[1].distance(vertices[2]) > minSurfaceWidth) {
219 subsurfaces.add(new SubSurface(splitPoints[1], vertices[1],
220 vertices[2], splitPoints[2]));
221 }
222
223 SubSurface[] result = new SubSurface[3];
224 result = subsurfaces.toArray(result);
225 return result;
226 }
227
228 private Point3d selectClosest(Point3d source, Point3d[] vertex) {
229 Point3d closest = vertex[0];
230 double dist = source.distanceSquared(vertex[0]);
231
232 for (int i = 1; i < 4; i++)
233 if (source.distanceSquared(vertex[i]) < dist) {
234 dist = source.distanceSquared(vertex[i]);
235 closest = vertex[i];
236 }
237
238 return closest;
239 }
240
241 /***
242 * przekształca płaską powierzchnię w trójwymiarowy obiekt
243 *
244 * @return tablica quadów opisujących obiekt
245 */
246 GeometryInfo[] createBox() {
247 GeometryInfo geometryArray[] = new GeometryInfo[6];
248
249 Point3d[] wallCoords = generateBoxCoords(vertices, wallDefaultWidth);
250
251 for (int i = 0; i < 6; i++)
252 geometryArray[i] = new GeometryInfo(GeometryInfo.QUAD_ARRAY);
253
254 geometryArray[0].setCoordinates(generateQuadCoords(new int[] { 0, 1, 2,
255 3 }, wallCoords));
256 geometryArray[1].setCoordinates(generateQuadCoords(new int[] { 7, 6, 5,
257 4 }, wallCoords));
258 geometryArray[2].setCoordinates(generateQuadCoords(new int[] { 0, 3, 7,
259 4 }, wallCoords));
260 geometryArray[3].setCoordinates(generateQuadCoords(new int[] { 5, 6, 2,
261 1 }, wallCoords));
262 geometryArray[4].setCoordinates(generateQuadCoords(new int[] { 0, 4, 5,
263 1 }, wallCoords));
264 geometryArray[5].setCoordinates(generateQuadCoords(new int[] { 2, 6, 7,
265 3 }, wallCoords));
266
267 if (textureCoords.size() > 0) {
268 geometryArray[0]
269 .setTextureCoordinateParams(textureCoords.size(), 2);
270 geometryArray[1]
271 .setTextureCoordinateParams(textureCoords.size(), 2);
272 for (TextureCoordinates coords : textureCoords) {
273 geometryArray[0].setTextureCoordinates(coords.textureLevel,
274 generateTexCoords(new int[] { 0, 1, 2, 3 },
275 coords.textureCoords));
276 geometryArray[1].setTextureCoordinates(coords.textureLevel,
277 generateTexCoords(new int[] { 7, 6, 5, 4 },
278 coords.textureCoords));
279 }
280 }
281
282 geometryArray[0].compact();
283 NormalGenerator ng = new NormalGenerator();
284 for (int i = 0; i < 6; i++)
285 ng.generateNormals(geometryArray[i]);
286 return geometryArray;
287 }
288
289 /***
290 * kopiuje dane o wsp tekstury z tablicy źródłowej w podanej kolejności
291 *
292 * @param source
293 * kolejność wartości w tablicy docelowej
294 * @param sourceArray
295 * tablica źródłowa
296 * @return tablica docelowa
297 */
298 private TexCoord2f[] generateTexCoords(int[] source,
299 TexCoord2f[] sourceArray) {
300 TexCoord2f[] coords = new TexCoord2f[4];
301
302 for (int i = 0; i < 4; i++)
303 coords[i] = new TexCoord2f(sourceArray[source[i]]);
304
305 return coords;
306 }
307
308 /***
309 * kopiuje dane o wsp wierzchołków z tablicy źródłowej w podanej kolejności
310 *
311 * @param source
312 * kolejność wartości w tablicy docelowej
313 * @param sourceArray
314 * tablica źródłowa
315 * @return tablica docelowa
316 */
317 private Point3d[] generateQuadCoords(int[] source, Point3d[] sourceArray) {
318 Point3d[] coords = new Point3d[4];
319
320 for (int i = 0; i < 4; i++)
321 coords[i] = new Point3d(sourceArray[source[i]]);
322
323 return coords;
324 }
325
326 /***
327 * na podstawie podanych wierzchołków oraz grubości tworzy koordynaty
328 * wierzchołków boxa o podanej grubości
329 *
330 * @param flatCoords
331 * koordynaty płaskiego obszaru
332 * @param depth
333 * grubość utworzonego pudełka
334 * @return koordynaty wierzchołków boxa
335 */
336 private Point3d[] generateBoxCoords(Point3d[] flatCoords, double depth) {
337
338 Point3d tempPoint = new Point3d(flatCoords[0]);
339 tempPoint.sub(vertices[1]);
340 Vector3d edge1 = new Vector3d(tempPoint);
341 tempPoint.set(vertices[0]);
342 tempPoint.sub(vertices[2]);
343 Vector3d edge2 = new Vector3d(tempPoint);
344
345 Vector3d normal = new Vector3d();
346 normal.cross(edge1, edge2);
347 normal.normalize();
348
349
350 Point3d[] wallCoords = new Point3d[8];
351
352 for (int i = 0; i < 4; i++) {
353 wallCoords[i] = new Point3d(flatCoords[i]);
354 wallCoords[i + 4] = new Point3d(flatCoords[i]);
355 }
356
357 Vector3d wallScale = new Vector3d(normal);
358 wallScale.scale(depth);
359
360 for (int i = 0; i < 4; i++) {
361 wallCoords[i].add(wallScale);
362 wallCoords[i + 4].sub(wallScale);
363 }
364
365 return wallCoords;
366
367 }
368 }