2 |
26 Feb 07 |
jari |
1 |
/* |
2 |
26 Feb 07 |
jari |
Copyright @ 1999-2003, The Institute for Genomic Research (TIGR). |
2 |
26 Feb 07 |
jari |
All rights reserved. |
2 |
26 Feb 07 |
jari |
4 |
*/ |
2 |
26 Feb 07 |
jari |
5 |
/* |
2 |
26 Feb 07 |
jari |
* $RCSfile: Landscape.java,v $ |
2 |
26 Feb 07 |
jari |
* $Revision: 1.3 $ |
2 |
26 Feb 07 |
jari |
* $Date: 2005/03/10 20:33:21 $ |
2 |
26 Feb 07 |
jari |
* $Author: braistedj $ |
2 |
26 Feb 07 |
jari |
* $State: Exp $ |
2 |
26 Feb 07 |
jari |
11 |
*/ |
2 |
26 Feb 07 |
jari |
12 |
package org.tigr.microarray.mev.cluster.gui.impl.terrain; |
2 |
26 Feb 07 |
jari |
13 |
|
2 |
26 Feb 07 |
jari |
14 |
import java.awt.image.BufferedImage; |
2 |
26 Feb 07 |
jari |
15 |
import java.util.Arrays; |
2 |
26 Feb 07 |
jari |
16 |
|
2 |
26 Feb 07 |
jari |
17 |
import javax.media.j3d.Appearance; |
2 |
26 Feb 07 |
jari |
18 |
import javax.media.j3d.Geometry; |
2 |
26 Feb 07 |
jari |
19 |
import javax.media.j3d.GeometryArray; |
2 |
26 Feb 07 |
jari |
20 |
import javax.media.j3d.GeometryUpdater; |
2 |
26 Feb 07 |
jari |
21 |
import javax.media.j3d.Material; |
2 |
26 Feb 07 |
jari |
22 |
import javax.media.j3d.PolygonAttributes; |
2 |
26 Feb 07 |
jari |
23 |
import javax.media.j3d.Shape3D; |
2 |
26 Feb 07 |
jari |
24 |
import javax.media.j3d.TriangleStripArray; |
2 |
26 Feb 07 |
jari |
25 |
import javax.vecmath.Vector3f; |
2 |
26 Feb 07 |
jari |
26 |
|
2 |
26 Feb 07 |
jari |
27 |
public class Landscape extends Shape3D implements GeometryUpdater { |
2 |
26 Feb 07 |
jari |
28 |
|
2 |
26 Feb 07 |
jari |
29 |
private float[][] heights; |
2 |
26 Feb 07 |
jari |
30 |
private float[] coords; // reference to this shape geometry coordinaties |
2 |
26 Feb 07 |
jari |
31 |
private float[] colors; // reference to this shape vertices colors |
2 |
26 Feb 07 |
jari |
32 |
private float[] normals; // reference to this shape vertices normals |
2 |
26 Feb 07 |
jari |
33 |
|
2 |
26 Feb 07 |
jari |
34 |
public Landscape(float[][] heights) { |
2 |
26 Feb 07 |
jari |
35 |
this.heights = heights; |
2 |
26 Feb 07 |
jari |
36 |
setCapability(ALLOW_GEOMETRY_READ); |
2 |
26 Feb 07 |
jari |
37 |
setCapability(ALLOW_GEOMETRY_WRITE); |
2 |
26 Feb 07 |
jari |
38 |
setCapability(ALLOW_APPEARANCE_READ); |
2 |
26 Feb 07 |
jari |
39 |
setCapability(ENABLE_PICK_REPORTING); |
2 |
26 Feb 07 |
jari |
40 |
initBuffers(heights.length); |
2 |
26 Feb 07 |
jari |
// create the shape geometry coords |
2 |
26 Feb 07 |
jari |
42 |
updateCoords(this.coords, this.heights); |
2 |
26 Feb 07 |
jari |
43 |
updateColors(this.colors, this.heights); |
2 |
26 Feb 07 |
jari |
44 |
updateNormals(this.normals, this.heights); |
2 |
26 Feb 07 |
jari |
// set geometry and appearance |
2 |
26 Feb 07 |
jari |
46 |
setGeometry(createGeometry(heights.length, this.coords, this.colors, this.normals)); |
2 |
26 Feb 07 |
jari |
47 |
setAppearance(createAppearance()); |
2 |
26 Feb 07 |
jari |
48 |
} |
2 |
26 Feb 07 |
jari |
49 |
|
2 |
26 Feb 07 |
jari |
50 |
private void initBuffers(int size) { |
2 |
26 Feb 07 |
jari |
51 |
this.coords = new float[(size-1)*size*2*3]; |
2 |
26 Feb 07 |
jari |
52 |
this.colors = new float[(size-1)*size*2*3]; |
2 |
26 Feb 07 |
jari |
53 |
this.normals = new float[(size-1)*size*2*3]; |
2 |
26 Feb 07 |
jari |
54 |
} |
2 |
26 Feb 07 |
jari |
55 |
|
2 |
26 Feb 07 |
jari |
56 |
public void setHeights(float[][] heights) { |
2 |
26 Feb 07 |
jari |
57 |
if (this.heights.length != heights.length) { |
2 |
26 Feb 07 |
jari |
58 |
initBuffers(heights.length); |
2 |
26 Feb 07 |
jari |
59 |
setGeometry(createGeometry(heights.length, this.coords, this.colors, this.normals)); |
2 |
26 Feb 07 |
jari |
60 |
} |
2 |
26 Feb 07 |
jari |
61 |
this.heights = heights; |
2 |
26 Feb 07 |
jari |
62 |
((GeometryArray)getGeometry()).updateData(this); |
2 |
26 Feb 07 |
jari |
63 |
} |
2 |
26 Feb 07 |
jari |
64 |
|
2 |
26 Feb 07 |
jari |
65 |
public void setPoligonMode(int mode) { |
2 |
26 Feb 07 |
jari |
66 |
Appearance appearance = getAppearance(); |
2 |
26 Feb 07 |
jari |
67 |
PolygonAttributes pa = appearance.getPolygonAttributes(); |
2 |
26 Feb 07 |
jari |
68 |
pa.setPolygonMode(mode); |
2 |
26 Feb 07 |
jari |
69 |
} |
2 |
26 Feb 07 |
jari |
70 |
|
2 |
26 Feb 07 |
jari |
71 |
private Geometry createGeometry(int size, float[] coords, float[] colors, float[] normals) { |
2 |
26 Feb 07 |
jari |
72 |
int[] stripVertexCounts = new int[size-1]; |
2 |
26 Feb 07 |
jari |
73 |
Arrays.fill(stripVertexCounts, size*2); |
2 |
26 Feb 07 |
jari |
74 |
|
2 |
26 Feb 07 |
jari |
75 |
GeometryArray geometry = new TriangleStripArray(coords.length/3, |
2 |
26 Feb 07 |
jari |
76 |
GeometryArray.COORDINATES | |
2 |
26 Feb 07 |
jari |
77 |
GeometryArray.COLOR_3 | |
2 |
26 Feb 07 |
jari |
78 |
GeometryArray.NORMALS | |
2 |
26 Feb 07 |
jari |
79 |
GeometryArray.BY_REFERENCE, |
2 |
26 Feb 07 |
jari |
80 |
stripVertexCounts |
2 |
26 Feb 07 |
jari |
81 |
); |
2 |
26 Feb 07 |
jari |
82 |
geometry.setCapability(GeometryArray.ALLOW_COUNT_READ); |
2 |
26 Feb 07 |
jari |
83 |
geometry.setCapability(GeometryArray.ALLOW_FORMAT_READ); |
2 |
26 Feb 07 |
jari |
84 |
geometry.setCapability(GeometryArray.ALLOW_REF_DATA_READ); |
2 |
26 Feb 07 |
jari |
85 |
geometry.setCapability(GeometryArray.ALLOW_REF_DATA_WRITE); |
2 |
26 Feb 07 |
jari |
86 |
geometry.setCoordRefFloat(coords); |
2 |
26 Feb 07 |
jari |
87 |
geometry.setColorRefFloat(colors); |
2 |
26 Feb 07 |
jari |
88 |
geometry.setNormalRefFloat(normals); |
2 |
26 Feb 07 |
jari |
89 |
return geometry; |
2 |
26 Feb 07 |
jari |
90 |
} |
2 |
26 Feb 07 |
jari |
91 |
|
2 |
26 Feb 07 |
jari |
92 |
private Appearance createAppearance() { |
2 |
26 Feb 07 |
jari |
93 |
PolygonAttributes pa = new PolygonAttributes(); |
2 |
26 Feb 07 |
jari |
94 |
pa.setCapability(PolygonAttributes.ALLOW_MODE_WRITE); |
2 |
26 Feb 07 |
jari |
95 |
pa.setCullFace(PolygonAttributes.CULL_NONE); |
2 |
26 Feb 07 |
jari |
96 |
|
2 |
26 Feb 07 |
jari |
97 |
Appearance appearance = new Appearance(); |
2 |
26 Feb 07 |
jari |
98 |
appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_READ); |
2 |
26 Feb 07 |
jari |
99 |
appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_WRITE); |
2 |
26 Feb 07 |
jari |
100 |
appearance.setPolygonAttributes(pa); |
2 |
26 Feb 07 |
jari |
101 |
appearance.setMaterial(new Material()); |
2 |
26 Feb 07 |
jari |
102 |
return appearance; |
2 |
26 Feb 07 |
jari |
103 |
} |
2 |
26 Feb 07 |
jari |
104 |
|
2 |
26 Feb 07 |
jari |
105 |
public void updateData(Geometry geometry) { |
2 |
26 Feb 07 |
jari |
106 |
updateCoords(this.coords, this.heights); |
2 |
26 Feb 07 |
jari |
107 |
updateColors(this.colors, this.heights); |
2 |
26 Feb 07 |
jari |
108 |
updateNormals(this.normals, this.heights); |
2 |
26 Feb 07 |
jari |
109 |
} |
2 |
26 Feb 07 |
jari |
110 |
|
2 |
26 Feb 07 |
jari |
111 |
/** |
2 |
26 Feb 07 |
jari |
* Creates a triangulated surface from the two dimensional array of heights. |
2 |
26 Feb 07 |
jari |
113 |
*/ |
2 |
26 Feb 07 |
jari |
114 |
public static void updateCoords(float[] coords, float[][] heights) { |
2 |
26 Feb 07 |
jari |
115 |
final int size = heights.length; |
2 |
26 Feb 07 |
jari |
116 |
final int stride = 2*3; |
2 |
26 Feb 07 |
jari |
117 |
float step = 1f/size; |
2 |
26 Feb 07 |
jari |
118 |
float x = step/2; |
2 |
26 Feb 07 |
jari |
119 |
float y = step/2; |
2 |
26 Feb 07 |
jari |
120 |
for (int i=0; i<size-1; i++) { |
2 |
26 Feb 07 |
jari |
121 |
for (int j=0; j<size; j++) { |
2 |
26 Feb 07 |
jari |
122 |
int pos = (i*size+j)*stride; |
2 |
26 Feb 07 |
jari |
//0 |
2 |
26 Feb 07 |
jari |
124 |
coords[pos++] = x; |
2 |
26 Feb 07 |
jari |
125 |
coords[pos++] = heights[i][j]; |
2 |
26 Feb 07 |
jari |
126 |
coords[pos++] = y; |
2 |
26 Feb 07 |
jari |
//1 |
2 |
26 Feb 07 |
jari |
128 |
coords[pos++] = x; |
2 |
26 Feb 07 |
jari |
129 |
coords[pos++] = heights[i+1][j]; |
2 |
26 Feb 07 |
jari |
130 |
coords[pos++] = y+step; |
2 |
26 Feb 07 |
jari |
131 |
|
2 |
26 Feb 07 |
jari |
132 |
x += step; |
2 |
26 Feb 07 |
jari |
133 |
} |
2 |
26 Feb 07 |
jari |
134 |
x = step/2; |
2 |
26 Feb 07 |
jari |
135 |
y += step; |
2 |
26 Feb 07 |
jari |
136 |
} |
2 |
26 Feb 07 |
jari |
137 |
} |
2 |
26 Feb 07 |
jari |
138 |
|
2 |
26 Feb 07 |
jari |
139 |
public static void updateColors(float[] colors, float[][] heights) { |
2 |
26 Feb 07 |
jari |
140 |
final int size = heights.length; |
2 |
26 Feb 07 |
jari |
141 |
final int stride = 2*3; |
2 |
26 Feb 07 |
jari |
142 |
float step = 1f/size; |
2 |
26 Feb 07 |
jari |
143 |
float x = step/2; |
2 |
26 Feb 07 |
jari |
144 |
float y = step/2; |
2 |
26 Feb 07 |
jari |
145 |
float scale = (float)(size-1)/getMaxValue(heights); |
2 |
26 Feb 07 |
jari |
// create gradient image |
2 |
26 Feb 07 |
jari |
147 |
BufferedImage gradient = DomainUtil.createGradientImage(size); |
2 |
26 Feb 07 |
jari |
148 |
int rgb1, rgb2; |
2 |
26 Feb 07 |
jari |
149 |
for (int i=0; i<size-1; i++) { |
2 |
26 Feb 07 |
jari |
150 |
for (int j=0; j<size; j++) { |
2 |
26 Feb 07 |
jari |
151 |
int pos = (i*size+j)*stride; |
2 |
26 Feb 07 |
jari |
152 |
|
2 |
26 Feb 07 |
jari |
153 |
rgb1 = gradient.getRGB((int)(heights[i ][j]*scale), 0); |
2 |
26 Feb 07 |
jari |
154 |
rgb2 = gradient.getRGB((int)(heights[i+1][j]*scale), 0); |
2 |
26 Feb 07 |
jari |
155 |
|
2 |
26 Feb 07 |
jari |
156 |
colors[pos++] = (float)((rgb1 >> 16) & 0xFF)/255f; |
2 |
26 Feb 07 |
jari |
157 |
colors[pos++] = (float)((rgb1 >> 8) & 0xFF)/255f; |
2 |
26 Feb 07 |
jari |
158 |
colors[pos++] = (float)((rgb1 >> 0) & 0xFF)/255f; |
2 |
26 Feb 07 |
jari |
159 |
|
2 |
26 Feb 07 |
jari |
160 |
colors[pos++] = (float)((rgb2 >> 16) & 0xFF)/255f; |
2 |
26 Feb 07 |
jari |
161 |
colors[pos++] = (float)((rgb2 >> 8) & 0xFF)/255f; |
2 |
26 Feb 07 |
jari |
162 |
colors[pos++] = (float)((rgb2 >> 0) & 0xFF)/255f; |
2 |
26 Feb 07 |
jari |
163 |
|
2 |
26 Feb 07 |
jari |
164 |
x += step; |
2 |
26 Feb 07 |
jari |
165 |
} |
2 |
26 Feb 07 |
jari |
166 |
x = step/2; |
2 |
26 Feb 07 |
jari |
167 |
y += step; |
2 |
26 Feb 07 |
jari |
168 |
} |
2 |
26 Feb 07 |
jari |
169 |
} |
2 |
26 Feb 07 |
jari |
170 |
|
2 |
26 Feb 07 |
jari |
171 |
protected static void updateNormals(float[] normals, float[][] heights) { |
2 |
26 Feb 07 |
jari |
172 |
final int size = heights.length; |
2 |
26 Feb 07 |
jari |
173 |
float[][][] buff = new float[size][size][3]; // vertices normals; |
2 |
26 Feb 07 |
jari |
174 |
float step = 1f/size; |
2 |
26 Feb 07 |
jari |
175 |
Vector3f v0 = new Vector3f(); |
2 |
26 Feb 07 |
jari |
176 |
Vector3f south = new Vector3f(); |
2 |
26 Feb 07 |
jari |
177 |
Vector3f east = new Vector3f(); |
2 |
26 Feb 07 |
jari |
178 |
Vector3f normal = new Vector3f(); |
2 |
26 Feb 07 |
jari |
179 |
for (int i=0; i<size; i++) { |
2 |
26 Feb 07 |
jari |
180 |
for (int j=0; j<size; j++) { |
2 |
26 Feb 07 |
jari |
181 |
if (i == size-1) { // last row |
2 |
26 Feb 07 |
jari |
182 |
south.set(0f, 0f, step); |
2 |
26 Feb 07 |
jari |
183 |
} else { |
2 |
26 Feb 07 |
jari |
184 |
south.set(0f, heights[i+1][j], step); |
2 |
26 Feb 07 |
jari |
185 |
} |
2 |
26 Feb 07 |
jari |
186 |
if (j == size-1) { // last column |
2 |
26 Feb 07 |
jari |
187 |
east.set(step, 0f, 0f); |
2 |
26 Feb 07 |
jari |
188 |
} else { |
2 |
26 Feb 07 |
jari |
189 |
east.set(step, heights[i][j+1], 0f); |
2 |
26 Feb 07 |
jari |
190 |
} |
2 |
26 Feb 07 |
jari |
191 |
v0.set(0, heights[i][j], 0); |
2 |
26 Feb 07 |
jari |
192 |
south.sub(v0); |
2 |
26 Feb 07 |
jari |
193 |
east.sub(v0); |
2 |
26 Feb 07 |
jari |
194 |
normal.cross(south, east); |
2 |
26 Feb 07 |
jari |
195 |
normal.normalize(); |
2 |
26 Feb 07 |
jari |
196 |
buff[i][j][0] = normal.x; |
2 |
26 Feb 07 |
jari |
197 |
buff[i][j][1] = normal.y; |
2 |
26 Feb 07 |
jari |
198 |
buff[i][j][2] = normal.z; |
2 |
26 Feb 07 |
jari |
199 |
} |
2 |
26 Feb 07 |
jari |
200 |
} |
2 |
26 Feb 07 |
jari |
// copying data |
2 |
26 Feb 07 |
jari |
202 |
for (int i=0; i<size-1; i++) { |
2 |
26 Feb 07 |
jari |
203 |
for (int j=0; j<size; j++) { |
2 |
26 Feb 07 |
jari |
204 |
int pos = (i*size+j)*6; |
2 |
26 Feb 07 |
jari |
205 |
normals[pos++] = buff[i][j][0]; |
2 |
26 Feb 07 |
jari |
206 |
normals[pos++] = buff[i][j][1]; |
2 |
26 Feb 07 |
jari |
207 |
normals[pos++] = buff[i][j][2]; |
2 |
26 Feb 07 |
jari |
208 |
normals[pos++] = buff[i+1][j][0]; |
2 |
26 Feb 07 |
jari |
209 |
normals[pos++] = buff[i+1][j][1]; |
2 |
26 Feb 07 |
jari |
210 |
normals[pos++] = buff[i+1][j][2]; |
2 |
26 Feb 07 |
jari |
211 |
} |
2 |
26 Feb 07 |
jari |
212 |
} |
2 |
26 Feb 07 |
jari |
213 |
} |
2 |
26 Feb 07 |
jari |
214 |
|
2 |
26 Feb 07 |
jari |
215 |
private static float getMaxValue(float[][] heights) { |
2 |
26 Feb 07 |
jari |
216 |
final int size = heights.length; |
2 |
26 Feb 07 |
jari |
217 |
float max = -Float.MAX_VALUE; |
2 |
26 Feb 07 |
jari |
218 |
for (int i=0; i<size; i++) |
2 |
26 Feb 07 |
jari |
219 |
for (int j=0; j<size; j++) |
2 |
26 Feb 07 |
jari |
220 |
max = Math.max(max, heights[i][j]); |
2 |
26 Feb 07 |
jari |
221 |
return max; |
2 |
26 Feb 07 |
jari |
222 |
} |
2 |
26 Feb 07 |
jari |
223 |
} |
2 |
26 Feb 07 |
jari |
224 |
|
2 |
26 Feb 07 |
jari |
225 |
|