1 package org.textensor.vis;
2
3 import java.awt.Color;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.Random;
7
8 import javax.media.j3d.Appearance;
9 import javax.media.j3d.BranchGroup;
10 import javax.media.j3d.GeometryArray;
11 import javax.media.j3d.Material;
12 import javax.media.j3d.Shape3D;
13 import javax.media.j3d.Transform3D;
14 import javax.media.j3d.TransformGroup;
15 import javax.media.j3d.TransparencyAttributes;
16 import javax.media.j3d.TriangleStripArray;
17 import javax.vecmath.Color3f;
18 import javax.vecmath.Vector3d;
19
20
21 public class SceneGraphBuilder {
22
23
24 BranchGroup baseGroup = null;
25
26 HashMap<Color, Appearance> appHM = new HashMap<Color, Appearance>();
27
28 Appearance defaultAppearance;
29
30 Appearance[] randomAppearances;
31
32 ArrayList<Shape3D> shapes;
33
34
35 public SceneGraphBuilder() {
36 defaultAppearance = makeDefaultAppearance();
37 randomAppearances = makeRandomAppearances(20);
38 }
39
40
41 private Appearance makeDefaultAppearance() {
42 Color3f aColor = new Color3f(0.3f, 0.3f, 0.3f);
43 Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f);
44 Color3f dColor = new Color3f(0.6f, 0.6f, 0.6f);
45 Color3f sColor = new Color3f(0.8f, 0.8f, 0.8f);
46
47 Material m = new Material(aColor, eColor, dColor, sColor, 70.0f);
48
49 Appearance a = new Appearance();
50 m.setLightingEnable(true);
51 a.setMaterial(m);
52 return a;
53 }
54
55 private Appearance[] makeRandomAppearances(int n) {
56 Random random = new Random();
57 ArrayList<Appearance> ala = new ArrayList<Appearance>();
58 for (int i = 0; i < n; i++) {
59 Color3f aColor = randomColor(random, 0.3);
60 Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f);
61 Color3f dColor = rescale(aColor, 0.6);
62 Color3f sColor = rescale(aColor, 0.8);
63
64 Material m = new Material(aColor, eColor, dColor, sColor, 70.0f);
65
66 Appearance a = new Appearance();
67 m.setLightingEnable(true);
68 a.setMaterial(m);
69
70
71
72
73
74
75 ala.add(a);
76 }
77 return ala.toArray(new Appearance[ala.size()]);
78 }
79
80
81 private Color3f rescale(Color3f c, double d) {
82 Color col = c.get();
83 double fr = col.getRed() / 256.;
84 double fg = col.getGreen() / 256.;
85 double fb = col.getBlue() / 256.;
86 double f = (fr + fg + fb) / 3;
87 Color3f ret = new Color3f(flimit(d * fr / f), flimit(d * fg / f), flimit(d * fb / f));
88 return ret;
89 }
90
91 private float flimit(double x) {
92 double y = x;
93 if (y < 0.) {
94 y = 0.;
95 }
96 if (y > 1.) {
97 y = 1;
98 }
99 return (float)y;
100 }
101
102 private Color3f randomColor(Random r, double d) {
103 double red = rcol(r, d);
104 double green = rcol(r, 1.5 * d);
105 double blue = rcol(r, d);
106
107 Color3f ret = new Color3f((float)red, (float)green, (float)blue);
108 return ret;
109 }
110
111
112 private double rcol(Random r, double d) {
113 double v = d + 0.15 * r.nextGaussian();
114 if (v > 1.0) {
115 v = 1.0;
116 }
117 if (v < 0.0) {
118 v = 0.0;
119 }
120 return v;
121 }
122
123
124
125 private Appearance getAppearance(Color c) {
126 Appearance ret = null;
127 if (appHM.containsKey(c)) {
128 ret = appHM.get(c);
129
130 } else {
131 Color3f aColor = new Color3f(c.darker());
132 Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f);
133 Color3f dColor = new Color3f(c);
134 Color3f sColor = new Color3f(c.brighter());
135
136 Material m = new Material(aColor, eColor, dColor, sColor, 70.0f);
137
138 ret = new Appearance();
139 m.setLightingEnable(true);
140 ret.setMaterial(m);
141 appHM.put(c, ret);
142 }
143
144 return ret;
145 }
146
147
148
149
150 public void buildTree(IcingPoint[] points, int res, double fac) {
151
152 buildFlatTree(points, res, fac);
153
154 }
155
156 private void buildFlatTree(IcingPoint[] points, int res, double fac) {
157 baseGroup = new BranchGroup();
158
159 for (IcingPoint p : points) {
160 double x = p.getX();
161 double y = p.getY();
162 double z = p.getZ();
163 double r = p.getR();
164
165 IcingPoint ppar = p.getParent();
166
167 if (ppar == null) {
168
169 if (p.isBall()) {
170 TransformGroup ctrans = new TransformGroup();
171 Transform3D cpos = new Transform3D();
172 cpos.setTranslation(new Vector3d(fac * x, fac * y, fac * z));
173 ctrans.setTransform(cpos);
174
175 Shape3D s = new Shape3D();
176 if (p.isColored3d()) {
177 s.setAppearance(getAppearance(p.getColor()));
178 } else {
179 s.setAppearance(defaultAppearance);
180 }
181 TriangleStripArray tsa = mkSphereTriangles(fac * r, 5);
182 s.setGeometry(tsa);
183
184 ctrans.addChild(s);
185
186 baseGroup.addChild(ctrans);
187
188 }
189
190
191 } else {
192 double dx = ppar.getX() - x;
193 double dy = ppar.getY() - y;
194 double dz = ppar.getZ() - z;
195 double lxy = Math.sqrt(dx * dx + dy * dy);
196
197 double d = Math.sqrt(dx*dx + dy*dy + dz*dz);
198
199 double ex = Math.atan2(dz, lxy);
200 double ey = 0.;
201 double ez = -Math.atan2(dx, dy);
202 Vector3d veuler = new Vector3d(ex, ey, ez);
203
204 TransformGroup ctrans = new TransformGroup();
205 Transform3D cpos = new Transform3D();
206 cpos.setEuler(veuler);
207 cpos.setTranslation(new Vector3d(fac * x, fac * y, fac * z));
208 ctrans.setTransform(cpos);
209
210 Shape3D s = new Shape3D();
211 if (p.isColored3d()) {
212 s.setAppearance(getAppearance(p.getColor()));
213 } else {
214 s.setAppearance(defaultAppearance);
215 }
216
217
218 double pr = ppar.getR();
219 if (p.isMinor() || p.uniform()) {
220 pr = p.getR();
221 }
222
223
224
225 if (res == Visualizer.LOW) {
226 TriangleStripArray tsa = mkCarrotoidTriangles(fac * r, fac * pr, fac * d, 8, 1, 1);
227 s.setGeometry(tsa);
228
229 } else if (res == Visualizer.MEDIUM) {
230 TriangleStripArray tsa = mkCarrotoidTriangles(fac * r, fac * pr, fac * d, 16,
231 (p.ball ? 3 : 1), (ppar.ball ? 3 : 1));
232 s.setGeometry(tsa);
233
234 } else if (res == Visualizer.HIGH) {
235 TriangleStripArray tsa = mkCarrotoidTriangles(fac * r, fac * pr, fac * d, 22,
236 (p.ball ? 5 : 1), (ppar.ball ? 5 : 1));
237 s.setGeometry(tsa);
238 }
239
240
241 ctrans.addChild(s);
242
243 baseGroup.addChild(ctrans);
244 }
245 }
246
247
248 }
249
250
251
252
253 private TriangleStripArray mkCarrotoidTriangles(double ra, double rb, double d,
254 int nside, int ncapa, int ncapb) {
255
256 int nstrip = 1 + ncapa + ncapb;
257 int nvert = 2 * nside * nstrip;
258
259 int[] svc = new int[nstrip];
260 for (int i = 0; i < nstrip; i++) {
261 svc[i] = 2 * nside;
262 }
263
264 float[] datv = new float[3 * nvert];
265 float[] datn = new float[3 * nvert];
266
267
268 double dtheta = 2. * Math.PI / (nside-1);
269 double[][] csas = new double[nside][2];
270 double[][] csbs = new double[nside][2];
271 for (int i = 0; i < nside; i++) {
272 double tha = i * dtheta;
273 double thb = (i + 0.5) * dtheta;
274 csas[i][0] = Math.cos(tha);
275 csas[i][1] = Math.sin(tha);
276
277 csbs[i][0] = Math.cos(thb);
278 csbs[i][1] = Math.sin(thb);
279 }
280
281 double dr = ra - rb;
282 double znorm = dr / Math.sqrt(dr*dr + d*d);
283 double zr = Math.sqrt(1. - znorm*znorm);
284 vnStrip(datv, datn, 0, nside, ra, rb, 0., d, znorm, zr, znorm, zr, csas, csbs);
285
286 int koff = 0;
287 koff += 6 * nside;
288
289 double frad = 1.;
290 if (ncapa == 1) {
291 frad = 0.;
292 }
293
294 for (int ic = 0; ic < ncapa; ic++) {
295 double[][] incs = (ic % 2 == 0 ? csbs : csas);
296 double[][] outcs = (ic % 2 == 0 ? csas : csbs);
297
298 double t0 = ic * (0.5 * Math.PI / (ncapa + 0.1));
299 double t1 = (ic + 1) * (0.5 * Math.PI / (ncapa + 0.1));
300 double s0 = Math.sin(t0);
301 double c0 = Math.cos(t0);
302 double s1 = Math.sin(t1);
303 double c1 = Math.cos(t1);
304 vnStrip(datv, datn, koff, nside, c1 * ra, c0 * ra, -frad * s1 * ra, -frad * s0 * ra, -s1, c1, -s0, c0, incs, outcs);
305 koff += 6 * nside;
306 }
307
308 frad = 1.;
309 if (ncapb == 1) {
310 frad = 0.;
311 }
312 for (int ic = 0; ic < ncapb; ic++) {
313 double[][] incs = (ic % 2 == 0 ? csbs : csas);
314 double[][] outcs = (ic % 2 == 0 ? csas : csbs);
315 double t0 = ic * (0.5 * Math.PI / (ncapb + 0.1));
316 double t1 = (ic + 1) * (0.5 * Math.PI / (ncapb + 0.1));
317 double s0 = Math.sin(t0);
318 double c0 = Math.cos(t0);
319 double s1 = Math.sin(t1);
320 double c1 = Math.cos(t1);
321 vnStrip(datv, datn, koff, nside, c0 * rb, c1 * rb, d + frad * s0 * rb, d + frad * s1 * rb, s0, c0, s1, c1, incs, outcs);
322 koff += 6 * nside;
323 }
324
325 TriangleStripArray ret = new TriangleStripArray(nvert,
326 GeometryArray.COORDINATES | GeometryArray.NORMALS, svc);
327 ret.setCoordinates(0, datv);
328 ret.setNormals(0, datn);
329 return ret;
330 }
331
332
333
334
335
336
337 private TriangleStripArray mkSphereTriangles(double ra, int ncap) {
338 int nside = 15;
339
340 int nstrip = 2 * ncap;
341 int nvert = 2 * nside * nstrip;
342
343 int[] svc = new int[nstrip];
344 for (int i = 0; i < nstrip; i++) {
345 svc[i] = 2 * nside;
346 }
347
348 float[] datv = new float[3 * nvert];
349 float[] datn = new float[3 * nvert];
350
351
352 double dtheta = 2. * Math.PI / (nside-1);
353 double[][] csas = new double[nside][2];
354 double[][] csbs = new double[nside][2];
355 for (int i = 0; i < nside; i++) {
356 double tha = i * dtheta;
357 double thb = (i + 0.5) * dtheta;
358 csas[i][0] = Math.cos(tha);
359 csas[i][1] = Math.sin(tha);
360
361 csbs[i][0] = Math.cos(thb);
362 csbs[i][1] = Math.sin(thb);
363 }
364
365 int koff = 0;
366
367 for (int ic = 0; ic < ncap; ic++) {
368 double[][] incs = (ic % 2 == 0 ? csbs : csas);
369 double[][] outcs = (ic % 2 == 0 ? csas : csbs);
370
371 double t0 = ic * (0.5 * Math.PI / (ncap + 0.1));
372 double t1 = (ic + 1) * (0.5 * Math.PI / (ncap + 0.1));
373 double s0 = Math.sin(t0);
374 double c0 = Math.cos(t0);
375 double s1 = Math.sin(t1);
376 double c1 = Math.cos(t1);
377 vnStrip(datv, datn, koff, nside, c1 * ra, c0 * ra, -1 * s1 * ra, -1 * s0 * ra, -s1, c1, -s0, c0, incs, outcs);
378 koff += 6 * nside;
379 }
380
381
382 for (int ic = 0; ic < ncap; ic++) {
383 double[][] incs = (ic % 2 == 0 ? csbs : csas);
384 double[][] outcs = (ic % 2 == 0 ? csas : csbs);
385 double t0 = ic * (0.5 * Math.PI / (ncap + 0.1));
386 double t1 = (ic + 1) * (0.5 * Math.PI / (ncap + 0.1));
387 double s0 = Math.sin(t0);
388 double c0 = Math.cos(t0);
389 double s1 = Math.sin(t1);
390 double c1 = Math.cos(t1);
391 vnStrip(datv, datn, koff, nside, c0 * ra, c1 * ra, s0 * ra, s1 * ra, s0, c0, s1, c1, incs, outcs);
392 koff += 6 * nside;
393 }
394
395 TriangleStripArray ret = new TriangleStripArray(nvert,
396 GeometryArray.COORDINATES | GeometryArray.NORMALS, svc);
397 ret.setCoordinates(0, datv);
398 ret.setNormals(0, datn);
399 return ret;
400 }
401
402
403
404
405 private void vnStrip(float[] datv, float[] datn, int koff, int nside, double ra, double rb, double da, double db, double s0, double c0, double s1, double c1, double[][] incs, double[][] outcs) {
406
407 for (int i = 0; i < nside; i++) {
408 int k = koff + 6 * i;
409 datv[k] = (float)(ra * incs[i][0]);
410 datv[k+1] = (float)da;
411 datv[k+2] = (float)(ra * incs[i][1]);
412 datv[k+3] = (float)(rb * outcs[i][0]);
413 datv[k+4] = (float)db;
414 datv[k+5] = (float)(rb * outcs[i][1]);
415
416 datn[k] = (float)(c0 * incs[i][0]);
417 datn[k+1] = (float)s0;
418 datn[k+2] = (float)(c0 * incs[i][1]);
419 datn[k+3] = (float)(c1 * outcs[i][0]);
420 datn[k+4] = (float)s1;
421 datn[k+5] = (float)(c1 * outcs[i][1]);
422 }
423 }
424
425
426 public BranchGroup getSceneGraph() {
427 return baseGroup;
428 }
429
430
431 public void loadElements(ArrayList<VolElt> elements) {
432 baseGroup = new BranchGroup();
433
434 shapes = new ArrayList<Shape3D>();
435
436 int iel = 0;
437 for (VolElt ve : elements) {
438
439 ve.centroidize();
440
441 TransformGroup ctrans = new TransformGroup();
442 Transform3D cpos = new Transform3D();
443 cpos.setTranslation(new Vector3d(ve.getCX(), ve.getCY(), ve.getCZ()));
444 ctrans.setTransform(cpos);
445
446 Shape3D s = new Shape3D();
447 shapes.add(s);
448
449 s.setAppearance(defaultAppearance);
450
451 int ira = (int)(Math.random() * (randomAppearances.length - 0.01));
452 Appearance app = randomAppearances[ira];
453 Appearance apc = (Appearance)(app.cloneNodeComponent(true));
454 apc.setCapability(Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE);
455 s.setAppearance(apc);
456
457
458 TriangleStripArray tsa = new TriangleStripArray(ve.getNvert(),
459 GeometryArray.COORDINATES | GeometryArray.NORMALS, ve.getLens());
460 tsa.setCoordinates(0, ve.getVerts());
461 tsa.setNormals(0, ve.getNorms());
462
463
464 s.setGeometry(tsa);
465
466 ctrans.addChild(s);
467
468 baseGroup.addChild(ctrans);
469
470 iel += 1;
471
472 }
473 }
474
475
476 public ArrayList<Shape3D> getShapes() {
477 return shapes;
478 }
479
480 }