In visuallization GUI, fix the surface saving issues with .ply and .stl
[mipav.git] / mipav / src / gov / nih / mipav / view / renderer / WildMagic / Interface / FileSurface_WM.java
1 package gov.nih.mipav.view.renderer.WildMagic.Interface;\r
2 \r
3 import gov.nih.mipav.util.MipavCoordinateSystems;\r
4 import gov.nih.mipav.model.file.FileBase;\r
5 import gov.nih.mipav.model.file.FileInfoSurfaceRefXML;\r
6 import gov.nih.mipav.model.file.FileSurfaceXML;\r
7 import gov.nih.mipav.model.structures.ModelImage;\r
8 import gov.nih.mipav.model.structures.TransMatrix;\r
9 import gov.nih.mipav.view.MipavUtil;\r
10 import gov.nih.mipav.view.Preferences;\r
11 import gov.nih.mipav.view.ViewImageFileFilter;\r
12 import gov.nih.mipav.view.ViewJProgressBar;\r
13 import gov.nih.mipav.view.ViewUserInterface;\r
14 import gov.nih.mipav.view.renderer.J3D.surfaceview.JPanelSurface;\r
15 import gov.nih.mipav.view.renderer.J3D.surfaceview.SurfaceAttributes;\r
16 import gov.nih.mipav.view.renderer.J3D.surfaceview.SurfaceRender;\r
17 \r
18 import java.io.BufferedInputStream;\r
19 import java.io.BufferedReader;\r
20 import java.io.DataInputStream;\r
21 import java.io.DataOutputStream;\r
22 import java.io.File;\r
23 import java.io.FileInputStream;\r
24 import java.io.FileNotFoundException;\r
25 import java.io.FileOutputStream;\r
26 import java.io.FileReader;\r
27 import java.io.FileWriter;\r
28 import java.io.IOException;\r
29 import java.io.InputStream;\r
30 import java.io.PrintWriter;\r
31 import java.io.RandomAccessFile;\r
32 import java.io.StreamTokenizer;\r
33 import java.util.ArrayList;\r
34 import java.util.HashMap;\r
35 import java.util.NoSuchElementException;\r
36 import java.util.StringTokenizer;\r
37 import java.util.Vector;\r
38 import java.util.regex.Matcher;\r
39 import java.util.regex.Pattern;\r
40 import java.nio.ByteOrder;\r
41 import java.nio.ByteBuffer;\r
42 \r
43 import javax.swing.JFileChooser;\r
44 \r
45 import WildMagic.LibFoundation.Mathematics.ColorRGBA;\r
46 import WildMagic.LibFoundation.Mathematics.Vector3f;\r
47 import WildMagic.LibGraphics.Detail.ClodMesh;\r
48 import WildMagic.LibGraphics.Detail.CollapseRecord;\r
49 import WildMagic.LibGraphics.Detail.CollapseRecordArray;\r
50 import WildMagic.LibGraphics.Rendering.GlobalState;\r
51 import WildMagic.LibGraphics.Rendering.MaterialState;\r
52 import WildMagic.LibGraphics.SceneGraph.Attributes;\r
53 import WildMagic.LibGraphics.SceneGraph.IndexBuffer;\r
54 import WildMagic.LibGraphics.SceneGraph.TriMesh;\r
55 import WildMagic.LibGraphics.SceneGraph.VertexBuffer;\r
56 import javax.vecmath.Point3f;\r
57 \r
58 /**\r
59  * FileSurface. Reads and writes surface files for the JPanelSurface class. When\r
60  * surface files are loaded by the user in the JPanelSurface.java class through\r
61  * the "Add" button, when surfaces are loaded as surfaces attached to .xml image\r
62  * files, or surfaces loaded through the FlyThruRender class. Any time a surface\r
63  * file is read from disk for display in the JPanelSurface (SurfaceRender) class\r
64  * the FileSurface.java class is used to provide the interface. Loaded surfaces\r
65  * are returned in an array of SurfaceAttributes[] which are then used to add\r
66  * the surfaces to the SurfaceRender scene graph.\r
67  *\r
68  * <p>\r
69  * This class also handles saving files from the JPanelSurface class. Surfaces\r
70  * are saved as surface files (.sur), single-level (.wrl), multi-level (.wrl) or\r
71  * XML surfaces (.xml).\r
72  * </p>\r
73  *\r
74  * @see JPanelSurface.java\r
75  * @see SurfaceRender.java\r
76  * @see SurfaceAttributes.java\r
77  * @see FileSurfaceXML.java\r
78  */\r
79 public class FileSurface_WM {\r
80 \r
81         /** flag indicates to flip y, z coordinate or not. */\r
82         private static boolean flip;\r
83 \r
84         /** flag indicates to read dicom matrix or not. */\r
85         private static boolean dicom;\r
86 \r
87         /** inverse dicom matrix array. */\r
88         private static double[][] inverseDicomArray;\r
89 \r
90         /** inverset dicom matrix. */\r
91         private static TransMatrix inverseDicomMatrix = new TransMatrix(4);\r
92 \r
93         /** image x, y, z orientation. */\r
94         private static int[] direction = new int[3];\r
95 \r
96         /** image start location. */\r
97         private static float[] startLocation = new float[3];\r
98 \r
99         /** image volume bounding box. */\r
100         private static float[] box = new float[3];\r
101 \r
102         /**\r
103          * coordinate used to transform data point from image coordinate to dicom\r
104          * coordinate.\r
105          */\r
106         private static float[] tCoord = new float[3];\r
107 \r
108         /**\r
109          * coordinate used to transform data point from image coordinate to dicom\r
110          * coordinate\r
111          */\r
112         private static float[] coord = new float[3];\r
113 \r
114         /** dicom matrix file. */\r
115         private static File dicomMatrixFile = null;\r
116 \r
117         // GeometryInfo needs Arrays\r
118         private Point3f[] coordArray = null;\r
119         private Vector3f[] normArray = null;\r
120 \r
121         // Needed because TRIANGLE_STRIP_ARRAY\r
122         // As the number of strips = the number of faces it's filled in\r
123         // objectToVectorArray\r
124         private int[] stripCounts = null;\r
125 \r
126         // ~ Methods\r
127         // --------------------------------------------------------------------------------------------------------\r
128 \r
129         /**\r
130          * Load the clod mesh from a binary file. The caller must have already opened\r
131          * the file and read the mesh type (0 = TriMesh, 1 = ModelClodMesh) and the\r
132          * number of meshes in the file. The caller then calls this function for each\r
133          * mesh. The format for a mesh is\r
134          *\r
135          * <pre>\r
136          int vCount;  // number of vertices\r
137          Point3f vertices[vCount];\r
138          Point3f normals[vCount];\r
139          int iCount;  // number of indices in the connectivity array\r
140          int indices[iCount];\r
141          int rCount;\r
142          ModelCollapseRecord collapses[rCount];\r
143          * </pre>\r
144          *\r
145          * with 4-byte quantities stored in Big Endian format.\r
146          *\r
147          * @param kIn\r
148          *            the file from which the triangle mesh is loaded\r
149          * @param pBar\r
150          *            DOCUMENT ME!\r
151          * @param added\r
152          *            DOCUMENT ME!\r
153          * @param piece\r
154          *            DOCUMENT ME!\r
155          *\r
156          * @return the loaded triangle mesh\r
157          *\r
158          * @exception IOException\r
159          *                if there is an error reading from the file\r
160          */\r
161         public static ClodMesh loadCMesh(RandomAccessFile kIn, ViewJProgressBar pBar, int added, int piece) {\r
162                 MaterialState kMaterial = new MaterialState();\r
163                 float[] startLocation = new float[3];\r
164                 float[] direction = new float[3];\r
165                 float[] box = new float[3];\r
166                 TriMesh kMesh = loadTMesh(kIn, pBar, added, piece, true, kMaterial, startLocation, direction, box);\r
167 \r
168                 try {\r
169                         int iRecordCount = kIn.readInt();\r
170                         CollapseRecord[] akRecord = new CollapseRecord[iRecordCount];\r
171                         int prog = iRecordCount * piece / 25;\r
172 \r
173                         for (int i = 0; i < iRecordCount; i++) {\r
174                                 akRecord[i] = load(kIn);\r
175 \r
176                                 if ((pBar != null) && (prog != 0) && ((i % prog) == 0)) {\r
177                                         pBar.updateValueImmed(Math.round(75 / piece) + added + (i / prog));\r
178                                         pBar.update(pBar.getGraphics());\r
179                                 }\r
180                         }\r
181 \r
182                         return new ClodMesh(kMesh.VBuffer, kMesh.IBuffer, new CollapseRecordArray(iRecordCount, akRecord));\r
183                 } catch (IOException e) {\r
184                         return null;\r
185                 }\r
186         }\r
187 \r
188         /**\r
189          * Load the TriMesh from a binary file. The caller must have already opened the\r
190          * file and read the mesh type (0 = TriMesh, 1 = ClodMesh) and the number of\r
191          * meshes in the file. The caller then calls this function for each mesh. The\r
192          * format for a mesh is\r
193          *\r
194          * <pre>\r
195          * int vCount; // number of vertices Point3f vertices[vCount]; Point3f\r
196          * normals[vCount]; int iCount; // number of indices in the connectivity array\r
197          * int indices[iCount];\r
198          * \r
199          * @param kIn\r
200          *            file containing TriMesh data\r
201          * @param progress\r
202          *            progress bar\r
203          * @param added\r
204          *            number of meshes added so far\r
205          * @param total\r
206          *            total number of meshes to add\r
207          * @param isVisible\r
208          *            sets the visibility of the progress bar\r
209          * @param kMaterial\r
210          *            MaterialState for the new mesh\r
211          * @param startLocation\r
212          *            3D location of the mesh\r
213          * @param direction\r
214          *            3D orientation of the mesh\r
215          * @param box\r
216          *            mesh bounding box\r
217          * @return new TriMesh\r
218          */\r
219         public static TriMesh loadTMesh(RandomAccessFile kIn, ViewJProgressBar progress, int added, int total,\r
220                         boolean isVisible, MaterialState kMaterial, float[] startLocation, float[] direction, float[] box) {\r
221 \r
222                 try {\r
223                         int i, index, tmpInt;\r
224                         int b1 = 0, b2 = 0, b3 = 0, b4 = 0;\r
225                         int actions;\r
226                         boolean flip;\r
227                         boolean dicom;\r
228                         long c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0, c7 = 0, c8 = 0;\r
229                         long tmpLong;\r
230                         int j;\r
231                         double[][] inverseDicomArray;\r
232                         TransMatrix inverseDicomMatrix = new TransMatrix(4);\r
233                         float[] tCoord = new float[3];\r
234                         float[] coord = new float[3];\r
235 \r
236                         actions = kIn.readInt();\r
237 \r
238                         if ((actions == 1) || (actions == 3)) {\r
239                                 flip = true;\r
240                         } else {\r
241                                 flip = false;\r
242                         }\r
243                         flip = !flip;\r
244                         if ((actions == 2) || (actions == 3)) {\r
245                                 dicom = true;\r
246                         } else {\r
247                                 dicom = false;\r
248                         }\r
249 \r
250                         direction[0] = kIn.readInt();\r
251                         direction[1] = kIn.readInt();\r
252                         direction[2] = kIn.readInt();\r
253 \r
254                         byte[] buffer = new byte[24];\r
255 \r
256                         kIn.read(buffer);\r
257                         index = 0;\r
258                         b1 = buffer[index++] & 0xff;\r
259                         b2 = buffer[index++] & 0xff;\r
260                         b3 = buffer[index++] & 0xff;\r
261                         b4 = buffer[index++] & 0xff;\r
262 \r
263                         tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
264 \r
265                         startLocation[0] = Float.intBitsToFloat(tmpInt);\r
266 \r
267                         b1 = buffer[index++] & 0xff;\r
268                         b2 = buffer[index++] & 0xff;\r
269                         b3 = buffer[index++] & 0xff;\r
270                         b4 = buffer[index++] & 0xff;\r
271 \r
272                         tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
273 \r
274                         startLocation[1] = Float.intBitsToFloat(tmpInt);\r
275 \r
276                         b1 = buffer[index++] & 0xff;\r
277                         b2 = buffer[index++] & 0xff;\r
278                         b3 = buffer[index++] & 0xff;\r
279                         b4 = buffer[index++] & 0xff;\r
280 \r
281                         tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
282 \r
283                         startLocation[2] = Float.intBitsToFloat(tmpInt);\r
284 \r
285                         b1 = buffer[index++] & 0xff;\r
286                         b2 = buffer[index++] & 0xff;\r
287                         b3 = buffer[index++] & 0xff;\r
288                         b4 = buffer[index++] & 0xff;\r
289 \r
290                         tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
291 \r
292                         box[0] = Float.intBitsToFloat(tmpInt);\r
293 \r
294                         b1 = buffer[index++] & 0xff;\r
295                         b2 = buffer[index++] & 0xff;\r
296                         b3 = buffer[index++] & 0xff;\r
297                         b4 = buffer[index++] & 0xff;\r
298 \r
299                         tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
300 \r
301                         box[1] = Float.intBitsToFloat(tmpInt);\r
302 \r
303                         b1 = buffer[index++] & 0xff;\r
304                         b2 = buffer[index++] & 0xff;\r
305                         b3 = buffer[index++] & 0xff;\r
306                         b4 = buffer[index++] & 0xff;\r
307 \r
308                         tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
309 \r
310                         box[2] = Float.intBitsToFloat(tmpInt);\r
311 \r
312                         if (dicom) {\r
313                                 buffer = new byte[128];\r
314                                 kIn.read(buffer);\r
315                                 index = 0;\r
316                                 inverseDicomArray = new double[4][4];\r
317 \r
318                                 for (i = 0; i <= 3; i++) {\r
319 \r
320                                         for (j = 0; j <= 3; j++) {\r
321                                                 c1 = buffer[index++] & 0xffL;\r
322                                                 c2 = buffer[index++] & 0xffL;\r
323                                                 c3 = buffer[index++] & 0xffL;\r
324                                                 c4 = buffer[index++] & 0xffL;\r
325                                                 c5 = buffer[index++] & 0xffL;\r
326                                                 c6 = buffer[index++] & 0xffL;\r
327                                                 c7 = buffer[index++] & 0xffL;\r
328                                                 c8 = buffer[index++] & 0xffL;\r
329                                                 tmpLong = ((c1 << 56) | (c2 << 48) | (c3 << 40) | (c4 << 32) | (c5 << 24) | (c6 << 16)\r
330                                                                 | (c7 << 8) | c8);\r
331                                                 inverseDicomArray[i][j] = Double.longBitsToDouble(tmpLong);\r
332                                         }\r
333                                 }\r
334 \r
335                                 inverseDicomMatrix.copyMatrix(inverseDicomArray);\r
336 \r
337                         } // if (dicom)\r
338 \r
339                         int iVertexCount = kIn.readInt();\r
340                         Vector3f[] akVertex = new Vector3f[iVertexCount];\r
341                         int bufferSize = 12 * iVertexCount;\r
342                         byte[] bufferVertex = new byte[bufferSize];\r
343                         byte[] bufferNormal = new byte[bufferSize];\r
344 \r
345                         progress.setLocation(200, 200);\r
346                         progress.setVisible(isVisible);\r
347 \r
348                         // read vertices\r
349                         kIn.read(bufferVertex);\r
350                         kIn.read(bufferNormal);\r
351 \r
352                         for (i = 0, index = 0; i < iVertexCount; i++) {\r
353                                 akVertex[i] = new Vector3f();\r
354 \r
355                                 b1 = bufferVertex[index++] & 0xff;\r
356                                 b2 = bufferVertex[index++] & 0xff;\r
357                                 b3 = bufferVertex[index++] & 0xff;\r
358                                 b4 = bufferVertex[index++] & 0xff;\r
359 \r
360                                 tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
361 \r
362                                 akVertex[i].X = Float.intBitsToFloat(tmpInt);\r
363 \r
364                                 b1 = bufferVertex[index++] & 0xff;\r
365                                 b2 = bufferVertex[index++] & 0xff;\r
366                                 b3 = bufferVertex[index++] & 0xff;\r
367                                 b4 = bufferVertex[index++] & 0xff;\r
368 \r
369                                 tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
370 \r
371                                 akVertex[i].Y = Float.intBitsToFloat(tmpInt);\r
372 \r
373                                 b1 = bufferVertex[index++] & 0xff;\r
374                                 b2 = bufferVertex[index++] & 0xff;\r
375                                 b3 = bufferVertex[index++] & 0xff;\r
376                                 b4 = bufferVertex[index++] & 0xff;\r
377 \r
378                                 tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
379 \r
380                                 akVertex[i].Z = Float.intBitsToFloat(tmpInt);\r
381 \r
382                                 if (dicom) {\r
383                                         tCoord[0] = akVertex[i].X - startLocation[0];\r
384                                         tCoord[1] = akVertex[i].Y - startLocation[1];\r
385                                         tCoord[2] = akVertex[i].Z - startLocation[2];\r
386                                         inverseDicomMatrix.transform(tCoord, coord);\r
387                                         akVertex[i].X = (coord[0] * direction[0]) + startLocation[0];\r
388                                         akVertex[i].Y = (coord[1] * direction[1]) + startLocation[1];\r
389                                         akVertex[i].Z = (coord[2] * direction[2]) + startLocation[2];\r
390                                 } // if (dicom)\r
391 \r
392                                 if (flip) {\r
393 \r
394                                         // Flip (kVertex.y - startLocation[1], but\r
395                                         // don't flip startLocation[1]\r
396                                         akVertex[i].Y = ((2 * startLocation[1]) + (box[1] * direction[1]) - akVertex[i].Y);\r
397                                         akVertex[i].Z = ((2 * startLocation[2]) + (box[2] * direction[2]) - akVertex[i].Z);\r
398                                 }\r
399 \r
400                         }\r
401 \r
402                         progress.updateValueImmed(added + (33 / total));\r
403 \r
404                         // read normals\r
405                         Vector3f[] akNormal = new Vector3f[iVertexCount];\r
406 \r
407                         for (i = 0, index = 0; i < iVertexCount; i++) {\r
408                                 akNormal[i] = new Vector3f();\r
409 \r
410                                 b1 = bufferNormal[index++] & 0xff;\r
411                                 b2 = bufferNormal[index++] & 0xff;\r
412                                 b3 = bufferNormal[index++] & 0xff;\r
413                                 b4 = bufferNormal[index++] & 0xff;\r
414 \r
415                                 tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
416 \r
417                                 akNormal[i].X = Float.intBitsToFloat(tmpInt);\r
418 \r
419                                 b1 = bufferNormal[index++] & 0xff;\r
420                                 b2 = bufferNormal[index++] & 0xff;\r
421                                 b3 = bufferNormal[index++] & 0xff;\r
422                                 b4 = bufferNormal[index++] & 0xff;\r
423 \r
424                                 tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
425 \r
426                                 akNormal[i].Y = Float.intBitsToFloat(tmpInt);\r
427 \r
428                                 b1 = bufferNormal[index++] & 0xff;\r
429                                 b2 = bufferNormal[index++] & 0xff;\r
430                                 b3 = bufferNormal[index++] & 0xff;\r
431                                 b4 = bufferNormal[index++] & 0xff;\r
432 \r
433                                 tmpInt = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
434 \r
435                                 akNormal[i].Z = Float.intBitsToFloat(tmpInt);\r
436                         }\r
437 \r
438                         progress.updateValueImmed(added + (66 / total));\r
439 \r
440                         // read connectivity\r
441                         int iIndexCount = kIn.readInt();\r
442 \r
443                         // System.out.println("connect count = " + iIndexCount);\r
444                         int[] aiConnect = new int[iIndexCount];\r
445                         byte[] bufferConnect = new byte[iIndexCount * 4];\r
446 \r
447                         kIn.read(bufferConnect);\r
448 \r
449                         for (i = 0, index = 0; i < iIndexCount; i++) {\r
450                                 b1 = bufferConnect[index++] & 0x000000ff;\r
451                                 b2 = bufferConnect[index++] & 0x000000ff;\r
452                                 b3 = bufferConnect[index++] & 0x000000ff;\r
453                                 b4 = bufferConnect[index++] & 0x000000ff;\r
454 \r
455                                 aiConnect[i] = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
456 \r
457                                 // System.out.println("connect[" + i + "]" + aiConnect[i]);\r
458                         }\r
459 \r
460                         // read per vertex color array\r
461                         int R, G, B, A;\r
462                         int isPerVertexColor = kIn.readInt();\r
463                         ColorRGBA[] perVertexColor = null;\r
464                         if (isPerVertexColor == 1) {\r
465                                 perVertexColor = new ColorRGBA[iVertexCount];\r
466                                 byte[] bufferPerVertexColor = new byte[iVertexCount * 4 * 4];\r
467                                 kIn.read(bufferPerVertexColor);\r
468                                 for (i = 0, index = 0; i < iVertexCount; i++) {\r
469                                         perVertexColor[i] = new ColorRGBA();\r
470 \r
471                                         b1 = bufferPerVertexColor[index++] & 0xff;\r
472                                         b2 = bufferPerVertexColor[index++] & 0xff;\r
473                                         b3 = bufferPerVertexColor[index++] & 0xff;\r
474                                         b4 = bufferPerVertexColor[index++] & 0xff;\r
475 \r
476                                         R = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
477 \r
478                                         perVertexColor[i].R = Float.intBitsToFloat(R);\r
479 \r
480                                         b1 = bufferPerVertexColor[index++] & 0xff;\r
481                                         b2 = bufferPerVertexColor[index++] & 0xff;\r
482                                         b3 = bufferPerVertexColor[index++] & 0xff;\r
483                                         b4 = bufferPerVertexColor[index++] & 0xff;\r
484 \r
485                                         G = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
486 \r
487                                         perVertexColor[i].G = Float.intBitsToFloat(G);\r
488 \r
489                                         b1 = bufferPerVertexColor[index++] & 0xff;\r
490                                         b2 = bufferPerVertexColor[index++] & 0xff;\r
491                                         b3 = bufferPerVertexColor[index++] & 0xff;\r
492                                         b4 = bufferPerVertexColor[index++] & 0xff;\r
493 \r
494                                         B = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
495 \r
496                                         perVertexColor[i].B = Float.intBitsToFloat(B);\r
497 \r
498                                         b1 = bufferPerVertexColor[index++] & 0xff;\r
499                                         b2 = bufferPerVertexColor[index++] & 0xff;\r
500                                         b3 = bufferPerVertexColor[index++] & 0xff;\r
501                                         b4 = bufferPerVertexColor[index++] & 0xff;\r
502 \r
503                                         A = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
504 \r
505                                         perVertexColor[i].A = Float.intBitsToFloat(A);\r
506 \r
507                                 }\r
508                         }\r
509 \r
510                         progress.updateValueImmed(added + (100 / total));\r
511 \r
512                         Attributes kAttr = new Attributes();\r
513                         kAttr.SetPChannels(3);\r
514                         kAttr.SetNChannels(3);\r
515                         kAttr.SetTChannels(0, 3);\r
516                         kAttr.SetCChannels(0, 4);\r
517                         /*\r
518                          * if ( perVertexColor != null ) { kAttr.SetCChannels(1,4); }\r
519                          */\r
520                         VertexBuffer pkVB = new VertexBuffer(kAttr, iVertexCount);\r
521                         for (i = 0; i < iVertexCount; i++) {\r
522                                 pkVB.SetPosition3(i, akVertex[i]);\r
523                                 pkVB.SetNormal3(i, akNormal[i]);\r
524 \r
525                                 if (perVertexColor != null) {\r
526                                         pkVB.SetColor4(0, i, perVertexColor[i].R, perVertexColor[i].G, perVertexColor[i].B,\r
527                                                         perVertexColor[i].A);\r
528                                 } else {\r
529                                         pkVB.SetColor4(0, i, 1f, 1f, 1f, 1f);\r
530                                 }\r
531 \r
532                         }\r
533                         IndexBuffer pkIB = new IndexBuffer(iIndexCount, aiConnect);\r
534                         TriMesh kMesh = new TriMesh(pkVB, pkIB);\r
535                         if (kMaterial != null) {\r
536                                 kMesh.AttachGlobalState(kMaterial);\r
537                         }\r
538                         return kMesh;\r
539                 } catch (IOException e) {\r
540                         return null;\r
541                 }\r
542         }\r
543 \r
544         /**\r
545          * Load the triangle mesh from a VRML file specifically written by MIPAV. The\r
546          * caller must have already opened the file.\r
547          * \r
548          * @param kIn\r
549          *            the file from which the triangle mesh is loaded\r
550          * @param progress\r
551          *            progress bar\r
552          * @param added\r
553          *            number of meshes added so far\r
554          * @param total\r
555          *            number of meshes to add\r
556          * @param flag\r
557          *            when true this is the first mesh, read header info.\r
558          * @param startLocation\r
559          *            3D location of mesh\r
560          * @param direction\r
561          *            3D orientation of mesh\r
562          * @param box\r
563          *            mesh bounding box\r
564          * @return new TriMesh\r
565          */\r
566         public static TriMesh loadVRMLMesh(RandomAccessFile kIn, ViewJProgressBar progress, int added, int total,\r
567                         boolean flag, float[] startLocation, float[] direction, float[] box) {\r
568 \r
569                 String str = null;\r
570                 String str2 = null;\r
571                 String str3 = null;\r
572                 StringTokenizer stoken = null;\r
573                 try {\r
574                         // read vertices\r
575                         if (flag) {\r
576 \r
577                                 if (kIn.getFilePointer() == 0) {\r
578                                         str = kIn.readLine().trim();\r
579                                         str2 = kIn.readLine().trim();\r
580                                         str3 = kIn.readLine().trim();\r
581 \r
582                                         if (!str.equals("#VRML V2.0 utf8") || !str2.equals("#MIPAV")\r
583                                                         || (str3.indexOf("#Number of shapes =") == -1)) {\r
584                                                 MipavUtil.displayWarning("File doesn't appear to be a VRML 2.0 file written by MIPAV");\r
585                                                 Preferences.debug(\r
586                                                                 "TriMesh.loadVRMLMesh: File doesn't appear to be a VRML 2.0 file written by MIPAV.\n");\r
587 \r
588                                                 // or throw error.\r
589                                                 return null;\r
590                                         }\r
591 \r
592                                         // read flip line\r
593                                         str = kIn.readLine().trim();\r
594                                         stoken = new StringTokenizer(str);\r
595 \r
596                                         if (stoken.nextToken().equals("#flip")) {\r
597                                                 stoken.nextToken();\r
598                                         }\r
599 \r
600                                         // read direction line\r
601                                         str = kIn.readLine().trim();\r
602                                         stoken = new StringTokenizer(str);\r
603 \r
604                                         if (stoken.nextToken().equals("#direction")) {\r
605                                                 stoken.nextToken();\r
606                                                 direction[0] = Integer.valueOf(stoken.nextToken()).intValue();\r
607                                                 direction[1] = Integer.valueOf(stoken.nextToken()).intValue();\r
608                                                 direction[2] = Integer.valueOf(stoken.nextToken()).intValue();\r
609                                         }\r
610 \r
611                                         // read start location line\r
612                                         str = kIn.readLine().trim();\r
613                                         stoken = new StringTokenizer(str);\r
614 \r
615                                         if (stoken.nextToken().equals("#startLocation")) {\r
616                                                 stoken.nextToken();\r
617                                                 startLocation[0] = Float.valueOf(stoken.nextToken()).floatValue();\r
618                                                 startLocation[1] = Float.valueOf(stoken.nextToken()).floatValue();\r
619                                                 startLocation[2] = Float.valueOf(stoken.nextToken()).floatValue();\r
620                                         }\r
621 \r
622                                         // read box line\r
623                                         str = kIn.readLine().trim();\r
624                                         stoken = new StringTokenizer(str);\r
625 \r
626                                         if (stoken.nextToken().equals("#box")) {\r
627                                                 stoken.nextToken();\r
628                                                 box[0] = Float.valueOf(stoken.nextToken()).floatValue();\r
629                                                 box[1] = Float.valueOf(stoken.nextToken()).floatValue();\r
630                                                 box[2] = Float.valueOf(stoken.nextToken()).floatValue();\r
631                                         }\r
632                                 }\r
633                         }\r
634 \r
635                         str = kIn.readLine().trim();\r
636 \r
637                         if (!str.equals("Shape")) {\r
638                                 return null;\r
639                         }\r
640 \r
641                         str = kIn.readLine();\r
642 \r
643                         str = kIn.readLine().trim();\r
644                         stoken = new StringTokenizer(str);\r
645 \r
646                         MaterialState kMaterial = null;\r
647                         float transparency = 0f;\r
648                         if (stoken.nextToken().equals("appearance")) {\r
649                                 kMaterial = new MaterialState();\r
650 \r
651                                 str = kIn.readLine(); // material Material {\r
652                                 str = kIn.readLine().trim(); // emissive Color\r
653                                 stoken = new StringTokenizer(str);\r
654                                 stoken.nextToken();\r
655                                 float red = Float.valueOf(stoken.nextToken()).floatValue();\r
656                                 float green = Float.valueOf(stoken.nextToken()).floatValue();\r
657                                 float blue = Float.valueOf(stoken.nextToken()).floatValue();\r
658                                 kMaterial.Emissive.R = red;\r
659                                 kMaterial.Emissive.G = green;\r
660                                 kMaterial.Emissive.B = blue;\r
661 \r
662                                 str = kIn.readLine().trim(); // diffuse color\r
663                                 stoken = new StringTokenizer(str);\r
664                                 stoken.nextToken();\r
665                                 red = Float.valueOf(stoken.nextToken()).floatValue();\r
666                                 green = Float.valueOf(stoken.nextToken()).floatValue();\r
667                                 blue = Float.valueOf(stoken.nextToken()).floatValue();\r
668                                 kMaterial.Diffuse.R = red;\r
669                                 kMaterial.Diffuse.G = green;\r
670                                 kMaterial.Diffuse.B = blue;\r
671 \r
672                                 str = kIn.readLine().trim(); // specular Color\r
673                                 stoken = new StringTokenizer(str);\r
674                                 stoken.nextToken();\r
675                                 red = Float.valueOf(stoken.nextToken()).floatValue();\r
676                                 green = Float.valueOf(stoken.nextToken()).floatValue();\r
677                                 blue = Float.valueOf(stoken.nextToken()).floatValue();\r
678                                 kMaterial.Specular.R = red;\r
679                                 kMaterial.Specular.G = green;\r
680                                 kMaterial.Specular.B = blue;\r
681 \r
682                                 str = kIn.readLine().trim(); // transparency\r
683                                 stoken = new StringTokenizer(str);\r
684                                 stoken.nextToken();\r
685                                 transparency = Float.valueOf(stoken.nextToken()).floatValue();\r
686 \r
687                                 str = kIn.readLine(); // }\r
688                                 str = kIn.readLine(); // }\r
689                         }\r
690 \r
691                         str = kIn.readLine().trim();\r
692 \r
693                         if (!str.equals("geometry IndexedFaceSet")) {\r
694                                 return null;\r
695                         }\r
696 \r
697                         str = kIn.readLine();\r
698 \r
699                         str = kIn.readLine().trim();\r
700 \r
701                         if (!str.equals("coord Coordinate")) {\r
702                                 return null;\r
703                         }\r
704 \r
705                         str = kIn.readLine();\r
706                         str = kIn.readLine().trim();\r
707 \r
708                         if (!str.equals("point [")) {\r
709                                 return null;\r
710                         }\r
711 \r
712                         ArrayList<Vector3f> vertexPts = new ArrayList<Vector3f>(1000);\r
713                         ArrayList<Integer> connArray = new ArrayList<Integer>(1000);\r
714 \r
715                         boolean readMore = true;\r
716                         Vector3f fPt;\r
717 \r
718                         while (readMore) {\r
719 \r
720                                 str = kIn.readLine().trim();\r
721 \r
722                                 if (str.equals("]")) {\r
723                                         break;\r
724                                 }\r
725 \r
726                                 stoken = new StringTokenizer(str);\r
727                                 fPt = new Vector3f();\r
728                                 fPt.set(Float.valueOf(stoken.nextToken()).floatValue(), Float.valueOf(stoken.nextToken()).floatValue(),\r
729                                                 Float.valueOf(stoken.nextToken()).floatValue());\r
730 \r
731                                 vertexPts.add(fPt);\r
732                         }\r
733 \r
734                         progress.updateValueImmed(added + (25 / total));\r
735 \r
736                         Attributes kAttr = new Attributes();\r
737                         kAttr.SetPChannels(3);\r
738                         kAttr.SetNChannels(3);\r
739                         kAttr.SetTChannels(0, 3);\r
740                         kAttr.SetCChannels(0, 4);\r
741                         VertexBuffer kVBuffer = new VertexBuffer(kAttr, vertexPts.size());\r
742                         for (int i = 0; i < vertexPts.size(); i++) {\r
743                                 Vector3f kVertex = vertexPts.get(i);\r
744 \r
745                                 kVBuffer.SetPosition3(i, kVertex);\r
746                                 kVBuffer.SetColor4(0, i, kMaterial.Diffuse.R, kMaterial.Diffuse.G, kMaterial.Diffuse.B,\r
747                                                 1.0f - transparency);\r
748                         }\r
749 \r
750                         vertexPts = null;\r
751                         System.gc();\r
752                         progress.updateValueImmed(added + (50 / total));\r
753 \r
754                         str = kIn.readLine().trim();\r
755                         str = kIn.readLine().trim();\r
756 \r
757                         if (!str.equals("coordIndex [")) {\r
758                                 return null;\r
759                         }\r
760 \r
761                         while (readMore) {\r
762 \r
763                                 str = kIn.readLine().trim();\r
764 \r
765                                 if (str.equals("]")) {\r
766                                         break;\r
767                                 }\r
768 \r
769                                 stoken = new StringTokenizer(str);\r
770 \r
771                                 Integer iConn;\r
772 \r
773                                 iConn = Integer.valueOf(stoken.nextToken());\r
774                                 connArray.add(iConn);\r
775 \r
776                                 iConn = Integer.valueOf(stoken.nextToken());\r
777                                 connArray.add(iConn);\r
778 \r
779                                 iConn = Integer.valueOf(stoken.nextToken());\r
780                                 connArray.add(iConn);\r
781                         }\r
782 \r
783                         progress.updateValueImmed(added + (75 / total));\r
784 \r
785                         long position = kIn.getFilePointer();\r
786 \r
787                         while ((str != null) && (str.indexOf("Shape") == -1)) {\r
788                                 position = kIn.getFilePointer();\r
789                                 str = kIn.readLine();\r
790                         }\r
791 \r
792                         kIn.seek(position);\r
793 \r
794                         int[] aiConnect = new int[connArray.size()];\r
795 \r
796                         for (int i = 0; i < connArray.size(); i++) {\r
797                                 aiConnect[i] = connArray.get(i).intValue();\r
798                         }\r
799 \r
800                         progress.updateValueImmed(added + (100 / total));\r
801 \r
802                         IndexBuffer kIBuffer = new IndexBuffer(aiConnect.length, aiConnect);\r
803                         TriMesh kMesh = new TriMesh(kVBuffer, kIBuffer);\r
804                         kMesh.AttachGlobalState(kMaterial);\r
805                         return kMesh;\r
806                 } catch (IOException e) {\r
807                         return null;\r
808                 }\r
809         }\r
810 \r
811         /**\r
812          * The action taken when the Add button is clicked in the JPanelSurface class. A\r
813          * file dialog is launched that allows the user to select new surfaces to load\r
814          * from disk.\r
815          * \r
816          * @param kImage\r
817          *            ModelImage for location/orientation and scale information.\r
818          * @return array of TriMesh objects.\r
819          */\r
820         public static TriMesh[] openSurfaces(ModelImage kImage) {\r
821                 return openSurfaces(kImage, false);\r
822         }\r
823 \r
824         /**\r
825          * The action taken when the Add button is clicked in the JPanelSurface class. A\r
826          * file dialog is launched that allows the user to select new surfaces to load\r
827          * from disk.\r
828          * \r
829          * @param kImage\r
830          *            ModelImage for location/orientation and scale information.\r
831          * @return array of TriMesh objects.\r
832          */\r
833         public static TriMesh[] openSurfaces(ModelImage kImage, boolean toFileCoords) {\r
834                 File[] akFiles = openFiles(true);\r
835 \r
836                 if (akFiles == null) {\r
837                         return null;\r
838                 }\r
839 \r
840                 TriMesh[] kSurface = new TriMesh[akFiles.length];\r
841                 for (int i = 0; i < akFiles.length; i++) {\r
842                         String kName = akFiles[i].getName();\r
843                         if ((kName.indexOf(".sur") != -1) || (kName.indexOf(".wrl") != -1) || (kName.indexOf(".vtk") != -1)\r
844                                         || (kName.indexOf(".vtp") != -1) || (kName.indexOf(".stl") != -1) || (kName.indexOf(".ply") != -1)\r
845                                         || (kName.indexOf(".txt") != -1) || (kName.indexOf(".gii") != -1)) {\r
846                                 kSurface[i] = readSurface(kImage, akFiles[i], null, toFileCoords);\r
847                         } else if (kName.indexOf(".xml") != -1) {\r
848                                 FileSurfaceRefXML_WM kSurfaceXML = new FileSurfaceRefXML_WM(kName, akFiles[i].getParent());\r
849                                 FileInfoSurfaceRefXML_WM kFileInfo = kSurfaceXML.readSurfaceXML(kName, akFiles[i].getParent());\r
850                                 akFiles[i] = new File(akFiles[i].getParent() + File.separatorChar + kFileInfo.getSurfaceFileName());\r
851                                 kSurface[i] = readSurface(kImage, akFiles[i], kFileInfo.getMaterial(), toFileCoords);\r
852                         }\r
853                 }\r
854 \r
855                 return kSurface;\r
856         }\r
857 \r
858         /**\r
859          * Parses the VRML to see how many surfaces there are.\r
860          * \r
861          * @param kIn\r
862          *            the file to parse\r
863          * @return int value for the number of surfaces in the file.\r
864          * @throws IOException\r
865          * @throws NoSuchElementException\r
866          */\r
867         public static int parseVRMLMesh(RandomAccessFile kIn) throws IOException, NoSuchElementException {\r
868                 String str = kIn.readLine();\r
869 \r
870                 str = kIn.readLine();\r
871                 str = kIn.readLine();\r
872 \r
873                 StringTokenizer token = new StringTokenizer(str);\r
874 \r
875                 token.nextToken();\r
876                 token.nextToken();\r
877                 token.nextToken();\r
878                 token.nextToken();\r
879 \r
880                 return Integer.valueOf(token.nextToken()).intValue();\r
881         }\r
882 \r
883         public static void save(String kName, TriMesh kMesh, ModelImage image, boolean transform) throws IOException {\r
884                 int iXDim = image.getExtents().length > 0 ? image.getExtents()[0] : 1;\r
885                 int iYDim = image.getExtents().length > 1 ? image.getExtents()[1] : 1;\r
886                 int iZDim = image.getExtents().length > 2 ? image.getExtents()[2] : 1;\r
887 \r
888                 float fXRes = image.getExtents().length > 0 ? image.getFileInfo()[0].getResolutions()[0] : 1;\r
889                 float fYRes = image.getExtents().length > 1 ? image.getFileInfo()[0].getResolutions()[1] : 1;\r
890                 float fZRes = image.getExtents().length > 2 ? image.getFileInfo()[0].getResolutions()[2] : 1;\r
891 \r
892                 float[] box = new float[] { (iXDim - 1) * fXRes, (iYDim - 1) * fYRes, (iZDim - 1) * fZRes };\r
893 \r
894                 /* Read the direction vector from the MipavCoordinateSystems class: */\r
895                 final int[] direction = MipavCoordinateSystems.getModelDirections(image);\r
896                 final float[] startLocation = image.getFileInfo(0).getOrigin();\r
897 \r
898                 TransMatrix dicomMatrix = null;\r
899                 TransMatrix inverseDicomMatrix = null;\r
900                 if (image.getMatrixHolder().containsType(TransMatrix.TRANSFORM_SCANNER_ANATOMICAL)) {\r
901 \r
902                         // Get the DICOM transform that describes the transformation from\r
903                         // axial to this image orientation\r
904                         dicomMatrix = new TransMatrix(image.getMatrix());\r
905                         inverseDicomMatrix = new TransMatrix(image.getMatrix());\r
906                         inverseDicomMatrix.Inverse();\r
907                 }\r
908 \r
909                 if (transform) {\r
910                         for (int i = 0; i < kMesh.VBuffer.GetVertexQuantity(); i++) {\r
911                                 Vector3f kV = kMesh.VBuffer.GetPosition3(i);\r
912 \r
913                                 if (dicomMatrix != null) {\r
914 \r
915                                         // Change the voxel coordinate into millimeters\r
916                                         coord[0] = kV.X * fXRes;\r
917                                         coord[1] = kV.Y * fYRes;\r
918                                         coord[2] = kV.Z * fZRes;\r
919 \r
920                                         // Convert the point to axial millimeter DICOM space\r
921                                         dicomMatrix.transform(coord, tCoord);\r
922 \r
923                                         // Add in the DICOM origin\r
924                                         tCoord[0] = tCoord[0] + startLocation[0];\r
925                                         tCoord[1] = tCoord[1] + startLocation[1];\r
926                                         tCoord[2] = tCoord[2] + startLocation[2];\r
927                                         kV = new Vector3f(tCoord[0], tCoord[1], tCoord[2]);\r
928                                 } else {\r
929                                         kV.X = (kV.X * fXRes * direction[0]) + startLocation[0];\r
930                                         kV.Y = (kV.Y * fYRes * direction[1]) + startLocation[1];\r
931                                         kV.Z = (kV.Z * fZRes * direction[2]) + startLocation[2];\r
932                                 }\r
933                                 kMesh.VBuffer.SetPosition3(i, kV);\r
934                         }\r
935                 }\r
936 \r
937                 save(kName, kMesh, 0, kMesh.VBuffer, true, direction, startLocation, box, inverseDicomMatrix);\r
938         }\r
939 \r
940         /**\r
941          * Save a TriMesh to disk\r
942          * \r
943          * @param kName\r
944          *            file name\r
945          * @param kMesh\r
946          *            TriMesh\r
947          * @param iType\r
948          *            type of mesh TriMesh or ClodMesh\r
949          * @param kVBuffer\r
950          *            VertexBuffer\r
951          * @param flip\r
952          *            invert y,z values\r
953          * @param direction\r
954          *            3D orientation of mesh\r
955          * @param startLocation\r
956          *            3D location of mesh\r
957          * @param box\r
958          *            3D bounding box\r
959          * @param inverseDicomMatrix\r
960          *            dicom matrix\r
961          * @throws IOException\r
962          *             file I/O exception\r
963          */\r
964         public static void save(String kName, TriMesh kMesh, int iType, VertexBuffer kVBuffer, boolean flip,\r
965                         int[] direction, float[] startLocation, float[] box, TransMatrix inverseDicomMatrix) throws IOException {\r
966                 if (kName == null) {\r
967                         return;\r
968                 }\r
969 \r
970                 int i = kName.lastIndexOf('.');\r
971                 String kExt = kName.substring(i);\r
972                 if (kExt.equals(".sur")) {\r
973                         saveSur(kName, kMesh, iType, kVBuffer, flip, direction, startLocation, box, inverseDicomMatrix);\r
974                 } else if (kExt.equals(".ply")) {\r
975                         saveSinglePlyMesh(kName, null, kMesh);\r
976                 } else if (kExt.equals(".stl")) {\r
977                         saveSingleSTLMesh(kName, null, kMesh);\r
978                 } else if (kExt.equals(".txt")) {\r
979                         saveAsTextFile(kName, kMesh);\r
980                 } else if (kExt.equals(".vtk")) {\r
981                         saveAsVTKLegacy(kName, kMesh);\r
982                 } else if (kExt.equals(".vtp")) {\r
983                         saveAsVTKXML(kName, kMesh);\r
984                 } else if (kExt.equals(".gii")) {\r
985                         saveAsGiftiXML(kName, kMesh);\r
986                 } else if (kExt.equals(".xml")) {\r
987                         try {\r
988                                 FileSurfaceRefXML_WM kSurfaceXML = new FileSurfaceRefXML_WM(null, null);\r
989                                 MaterialState kMaterial = (MaterialState) kMesh.GetGlobalState(GlobalState.StateType.MATERIAL);\r
990                                 if (kMaterial == null) {\r
991                                         kMaterial = new MaterialState();\r
992                                 }\r
993                                 float fOpacity = 0f;\r
994                                 if (kMesh.VBuffer.GetAttributes().GetCChannels(0) == 4) {\r
995                                         fOpacity = 1.0f - kMesh.VBuffer.GetColor4(0, 0).A;\r
996                                 }\r
997                                 int iLOD = 0;\r
998                                 kSurfaceXML.writeXMLsurface_WM(kName, kMaterial, fOpacity, iLOD);\r
999                                 String surfaceName = kName.substring(0, i) + ".sur";\r
1000                                 saveSur(surfaceName, kMesh, iType, kVBuffer, flip, direction, startLocation, box, inverseDicomMatrix);\r
1001                         } catch (IOException kError) {\r
1002                         }\r
1003                 } else if (kExt.equals(".wrl")) {\r
1004                         saveAsVRML(kName, kMesh, kVBuffer, flip, direction, startLocation, box);\r
1005                 }\r
1006         }\r
1007 \r
1008         /**\r
1009          * Save a TriMesh to disk\r
1010          * \r
1011          * @param kName\r
1012          *            file name\r
1013          * @param kMesh\r
1014          *            TriMesh\r
1015          * @param keyImage\r
1016          *            image\r
1017          * @throws IOException\r
1018          *             file I/O exception\r
1019          */\r
1020         public static void saveProstateSurface(String kName, TriMesh kMesh, ModelImage keyImage) throws IOException {\r
1021                 if (kName == null) {\r
1022                         return;\r
1023                 }\r
1024 \r
1025                 int i = kName.lastIndexOf('.');\r
1026                 String kExt = kName.substring(i);\r
1027                 if (kExt.equals(".ply")) {\r
1028                         // saveProstatePlyMesh(kName, keyImage, kMesh);\r
1029                         saveSinglePlyMesh(kName, keyImage, kMesh);\r
1030                 } else if (kExt.equals(".stl")) {\r
1031                     // saveProstateSTLMesh(kName, keyImage, kMesh);\r
1032                         saveSingleSTLMesh(kName, keyImage, kMesh);\r
1033                 }\r
1034         }\r
1035 \r
1036         /**\r
1037          * Save ClodMesh to disk\r
1038          * \r
1039          * @param kName\r
1040          *            file name\r
1041          * @param akComponent\r
1042          *            array of ClodMesh to save\r
1043          * @param flip\r
1044          *            invert y,z values\r
1045          * @param direction\r
1046          *            3D mesh orientation\r
1047          * @param startLocation\r
1048          *            3D mesh location\r
1049          * @param box\r
1050          *            mesh bounding box\r
1051          * @param inverseDicomMatrix\r
1052          *            dicom matrix\r
1053          */\r
1054         public static void saveClodMesh(String kName, ClodMesh[] akComponent, boolean flip, int[] direction,\r
1055                         float[] startLocation, float[] box, TransMatrix inverseDicomMatrix) {\r
1056                 if (akComponent.length == 0) {\r
1057                         return;\r
1058                 }\r
1059                 try {\r
1060                         for (int i = 0; i < akComponent.length; i++) {\r
1061                                 saveSur(kName, akComponent[i], 1, akComponent[i].VBuffer, flip, direction, startLocation, box,\r
1062                                                 inverseDicomMatrix);\r
1063                         }\r
1064                 } catch (IOException kIOError) {\r
1065                 }\r
1066         }\r
1067 \r
1068         /**\r
1069          * The action taken when the one of the save surface buttons is pressed in the\r
1070          * JPanelSurface class. A file dialog is launched that allows the user to select\r
1071          * where to save the surfaces.\r
1072          *\r
1073          * @param kImage\r
1074          *            the ModelImage displayed in the SurfaceRender class\r
1075          * @param akSurfaces\r
1076          *            an array of surfaces described by their SurfaceAttributes,\r
1077          *            containing information that is saved with the TriMesh\r
1078          * @param kCommand\r
1079          *            the type of save operation to perform\r
1080          */\r
1081         public static void saveSurfaces(ModelImage kImage, TriMesh[] akSurfaces, String kCommand) {\r
1082 \r
1083                 if (akSurfaces.length == 0) {\r
1084                         MipavUtil.displayError("Select a surface to save.");\r
1085 \r
1086                         return;\r
1087                 }\r
1088 \r
1089                 if (kCommand.equals("LevelS") || kCommand.equals("LevelV")) {\r
1090 \r
1091                         for (int i = 0; i < akSurfaces.length; i++) {\r
1092                                 saveSingleMesh(kImage, kCommand.equals("LevelS"), akSurfaces[i]);\r
1093                         }\r
1094                 }\r
1095                 // else if (kCommand.equals("LevelW")) {\r
1096                 // saveMultiMesh(kImage, akSurfaces);\r
1097                 // }\r
1098                 else if (kCommand.equals("LevelXML")) {\r
1099 \r
1100                         for (int i = 0; i < akSurfaces.length; i++) {\r
1101                                 writeTriangleMeshXML(null, kImage, akSurfaces[i]);\r
1102                         }\r
1103                 } else if (kCommand.equals("LevelSTL")) {\r
1104 \r
1105                         for (int i = 0; i < akSurfaces.length; i++) {\r
1106                                 saveSingleSTLMesh(null, kImage, akSurfaces[i]);\r
1107                         }\r
1108                 } else if (kCommand.equals("LevelPLY")) {\r
1109 \r
1110                         for (int i = 0; i < akSurfaces.length; i++) {\r
1111                                 saveSinglePlyMesh(null, kImage, akSurfaces[i]);\r
1112                         }\r
1113                 }\r
1114         }\r
1115 \r
1116         /**\r
1117          * Saves the triangle mesh in VRML97 (VRML 2.0) format. File name should end\r
1118          * with ".wrl"\r
1119          *\r
1120          * @param kOut\r
1121          *            the file to which the triangle mesh is saved\r
1122          * @param flip\r
1123          *            if the y and z axes should be flipped - true in extract and in\r
1124          *            save of JDialogSurface To have proper orientations in surface file\r
1125          *            if flip is true flip y and z on reading.\r
1126          * @param direction\r
1127          *            1 or -1 for each axis\r
1128          * @param startLocation\r
1129          *            DOCUMENT ME!\r
1130          * @param box\r
1131          *            (dimension-1)*resolution\r
1132          * @param color\r
1133          *            DOCUMENT ME!\r
1134          *\r
1135          * @exception IOException\r
1136          *                if there is an error writing to the file\r
1137          */\r
1138         protected static void saveAsVRML(PrintWriter kOut, TriMesh kMesh, VertexBuffer kVBuffer, boolean flip,\r
1139                         int[] direction, float[] startLocation, float[] box) {\r
1140                 kOut.print("#flip { ");\r
1141 \r
1142                 if (flip) {\r
1143                         kOut.print(1);\r
1144                 } else {\r
1145                         kOut.print(0);\r
1146                 }\r
1147 \r
1148                 kOut.print(" }\n");\r
1149 \r
1150                 kOut.print("#direction { ");\r
1151                 kOut.print(direction[0]);\r
1152                 kOut.print(' ');\r
1153                 kOut.print(direction[1]);\r
1154                 kOut.print(' ');\r
1155                 kOut.print(direction[2]);\r
1156                 kOut.print(" }\n");\r
1157 \r
1158                 kOut.print("#startLocation { ");\r
1159                 kOut.print(startLocation[0]);\r
1160                 kOut.print(' ');\r
1161                 kOut.print(startLocation[1]);\r
1162                 kOut.print(' ');\r
1163                 kOut.print(startLocation[2]);\r
1164                 kOut.print(" }\n");\r
1165 \r
1166                 kOut.print("#box { ");\r
1167                 kOut.print(box[0]);\r
1168                 kOut.print(' ');\r
1169                 kOut.print(box[1]);\r
1170                 kOut.print(' ');\r
1171                 kOut.print(box[2]);\r
1172                 kOut.print(" }\n");\r
1173 \r
1174                 MaterialState kMaterial = (MaterialState) kMesh.GetGlobalState(GlobalState.StateType.MATERIAL);\r
1175                 if (kMaterial == null) {\r
1176                         kMaterial = new MaterialState();\r
1177                 }\r
1178 \r
1179                 kOut.print("Shape\n{\n");\r
1180                 kOut.print("\tappearance Appearance {\n");\r
1181                 kOut.print("\t\tmaterial Material {\n");\r
1182                 kOut.print("\t\t\temissiveColor\t");\r
1183                 kOut.print(kMaterial.Emissive.R + " ");\r
1184                 kOut.print(kMaterial.Emissive.G + " ");\r
1185                 kOut.print(kMaterial.Emissive.B);\r
1186                 kOut.print("\n\t\t\tdiffuseColor\t");\r
1187                 kOut.print(kMaterial.Diffuse.R + " ");\r
1188                 kOut.print(kMaterial.Diffuse.G + " ");\r
1189                 kOut.print(kMaterial.Diffuse.B);\r
1190                 kOut.print("\n\t\t\tspecularColor\t");\r
1191                 kOut.print(kMaterial.Specular.R + " ");\r
1192                 kOut.print(kMaterial.Specular.G + " ");\r
1193                 kOut.print(kMaterial.Specular.B);\r
1194 \r
1195                 float fTransparency = 0f;\r
1196                 if (kVBuffer.GetAttributes().GetCChannels(0) == 4) {\r
1197                         fTransparency = 1.0f - kVBuffer.GetColor4(0, 0).A;\r
1198                 }\r
1199                 kOut.print("\n\t\t\ttransparency " + fTransparency + "\n");\r
1200                 kOut.print("\t\t}\n");\r
1201                 kOut.print("\t}\n");\r
1202 \r
1203                 kOut.print("\tgeometry IndexedFaceSet\n\t{\n");\r
1204 \r
1205                 kOut.print("\t\tcoord Coordinate\n");\r
1206                 kOut.print("\t\t{\n");\r
1207                 kOut.print("\t\t\tpoint [\n\t\t\t\t");\r
1208 \r
1209                 // write vertices\r
1210                 Vector3f kPos = new Vector3f();\r
1211                 int i;\r
1212                 for (i = 0; i < kVBuffer.GetVertexQuantity(); i++) {\r
1213                         kVBuffer.GetPosition3(i, kPos);\r
1214                         kOut.print(kPos.X);\r
1215                         kOut.print(' ');\r
1216 \r
1217                         kOut.print(kPos.Y);\r
1218                         kOut.print(' ');\r
1219 \r
1220                         kOut.print(kPos.Z);\r
1221 \r
1222                         if (i < (kVBuffer.GetVertexQuantity() - 1)) {\r
1223                                 kOut.print(" ,\n\t\t\t\t");\r
1224                         } else {\r
1225                                 kOut.print("\n\t\t\t\t]\n");\r
1226                         }\r
1227                 }\r
1228 \r
1229                 // write connectivity\r
1230                 kOut.print("\t\t\t}\n\t\t\tcoordIndex [\n\t\t\t\t");\r
1231                 int iTriangleCount = kMesh.IBuffer.GetIndexQuantity() / 3;\r
1232                 int[] aiIndex = kMesh.IBuffer.GetData();\r
1233                 for (i = 0; i < iTriangleCount; i++) {\r
1234                         kOut.print(aiIndex[3 * i]);\r
1235                         kOut.print(' ');\r
1236                         kOut.print(aiIndex[(3 * i) + 1]);\r
1237                         kOut.print(' ');\r
1238                         kOut.print(aiIndex[(3 * i) + 2]);\r
1239 \r
1240                         if (i < (iTriangleCount - 1)) {\r
1241                                 kOut.print(" -1\n\t\t\t\t");\r
1242                         } else {\r
1243                                 kOut.print("\n\t\t\t\t]\n");\r
1244                         }\r
1245                 }\r
1246 \r
1247                 kOut.print("\t\t\tconvex FALSE\n");\r
1248                 kOut.print("\t\t\tcreaseAngle 1.5\n");\r
1249                 kOut.print("\t}\n}\n");\r
1250         }\r
1251 \r
1252         /**\r
1253          * Calls a dialog to get a file name.\r
1254          * \r
1255          * @param bLoad\r
1256          *            if <code>true</code>, make it a load dialog.\r
1257          * @return File name.\r
1258          */\r
1259         private static String getFileName(boolean bLoad) {\r
1260                 File[] files = openFiles(bLoad);\r
1261 \r
1262                 if (files != null) {\r
1263                         return new String(files[0].getPath());\r
1264                 }\r
1265 \r
1266                 return null;\r
1267         }\r
1268 \r
1269         /**\r
1270          * Support for loading the collapse records from a binary file.\r
1271          * \r
1272          * @param kIn\r
1273          *            the file from which the records are loaded\r
1274          * @return CollapseRecord\r
1275          * @exception IOException\r
1276          *                if the there is an error reading from the file\r
1277          */\r
1278         private static CollapseRecord load(RandomAccessFile kIn) {\r
1279                 try {\r
1280                         int iVKeep = kIn.readInt();\r
1281                         int iVThrow = kIn.readInt();\r
1282                         int iVQuantity = kIn.readInt();\r
1283                         int iTQuantity = kIn.readInt();\r
1284                         CollapseRecord kRecord = new CollapseRecord(iVKeep, iVThrow, iVQuantity, iTQuantity);\r
1285                         kRecord.IQuantity = kIn.readInt();\r
1286                         if (kRecord.IQuantity > 0) {\r
1287                                 byte[] bufferByte = new byte[kRecord.IQuantity * 4];\r
1288                                 int b1 = 0, b2 = 0, b3 = 0, b4 = 0;\r
1289                                 kRecord.Index = new int[kRecord.IQuantity];\r
1290                                 kIn.read(bufferByte);\r
1291 \r
1292                                 for (int i = 0, index = 0; i < kRecord.IQuantity; i++) {\r
1293                                         b1 = bufferByte[index++] & 0x000000ff;\r
1294                                         b2 = bufferByte[index++] & 0x000000ff;\r
1295                                         b3 = bufferByte[index++] & 0x000000ff;\r
1296                                         b4 = bufferByte[index++] & 0x000000ff;\r
1297                                         kRecord.Index[i] = ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);\r
1298                                 }\r
1299                         }\r
1300                         return kRecord;\r
1301                 } catch (IOException kIOError) {\r
1302                 }\r
1303                 return null;\r
1304         }\r
1305 \r
1306         /**\r
1307          * Read a TriMesh from a Ply ascii file.\r
1308          * \r
1309          * @param file\r
1310          *            file storing the mesh\r
1311          * @return TriMesh\r
1312          */\r
1313         private static TriMesh loadPlyAsciiMesh(File file, ModelImage kImage) {\r
1314 \r
1315                 TriMesh mesh;\r
1316                 int i;\r
1317                 int iVertexCount = 0;\r
1318                 int iTriangleCount = 0;\r
1319                 boolean readHeader = true;\r
1320                 float x = 0f, y = 0f, z = 0f;\r
1321                 int idx1 = 0, idx2 = 0, idx3 = 0;\r
1322 \r
1323                 Vector<Vector3f> vertexArray = new Vector<Vector3f>();\r
1324                 Vector<Integer> connectivity = new Vector<Integer>();\r
1325                 VertexBuffer kVBuffer;\r
1326                 int[] aiConnect;\r
1327                 float _res[] = kImage.getFileInfo(0).getResolutions();\r
1328                 float[] _startLocation = kImage.getFileInfo()[0].getOrigin();\r
1329                 int[] _direction = MipavCoordinateSystems.getModelDirections(kImage);\r
1330 \r
1331                 Vector3f ptIn = new Vector3f();\r
1332                 Vector3f ptOut = new Vector3f();\r
1333 \r
1334                 try {\r
1335 \r
1336                         DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));\r
1337                         String s, token;\r
1338                         while ((s = readLine(in)).length() > 0) {\r
1339                                 StringTokenizer st = new StringTokenizer(s);\r
1340                                 while (st.hasMoreTokens() && readHeader) {\r
1341                                         // System.err.print(st.nextToken() + " ");\r
1342                                         token = st.nextToken();\r
1343                                         if (token.equals("vertex")) {\r
1344                                                 iVertexCount = Integer.valueOf(st.nextToken());\r
1345                                         } else if (token.equals("face")) {\r
1346                                                 iTriangleCount = Integer.valueOf(st.nextToken());\r
1347                                                 readLine(in);\r
1348                                                 readLine(in); // skip two lines follow the face count attribute in PLY file format.\r
1349                                                 readHeader = false;\r
1350                                                 break;\r
1351                                         }\r
1352                                 }\r
1353                                 if (readHeader == false)\r
1354                                         break;\r
1355                         }\r
1356 \r
1357                         // read Vertex\r
1358                         for (i = 0; i < iVertexCount; i++) {\r
1359                                 s = readLine(in);\r
1360                                 StringTokenizer st = new StringTokenizer(s);\r
1361                                 x = Float.valueOf(st.nextToken());\r
1362                                 y = Float.valueOf(st.nextToken());\r
1363                                 z = Float.valueOf(st.nextToken());\r
1364 \r
1365                                 ptIn.X = x;\r
1366                                 ptIn.Y = y;\r
1367                                 ptIn.Z = z;\r
1368 \r
1369                                 MipavCoordinateSystems.scannerToFile(ptIn, ptOut, kImage);\r
1370 \r
1371                                 x = (ptOut.X * _res[0] * _direction[0]) + _startLocation[0];\r
1372                                 y = (ptOut.Y * _res[1] * _direction[1]) + _startLocation[1];\r
1373                                 z = (ptOut.Z * _res[2] * _direction[2]) + _startLocation[2];\r
1374 \r
1375                                 vertexArray.add(new Vector3f(x, y, z));\r
1376                         }\r
1377 \r
1378                         // read connectivity\r
1379                         for (i = 0; i < iTriangleCount; i++) {\r
1380                                 s = readLine(in);\r
1381                                 StringTokenizer st = new StringTokenizer(s);\r
1382                                 st.nextToken(); // skip 3\r
1383                                 idx1 = Integer.valueOf(st.nextToken());\r
1384                                 connectivity.add(idx1);\r
1385                                 idx2 = Integer.valueOf(st.nextToken());\r
1386                                 connectivity.add(idx2);\r
1387                                 idx3 = Integer.valueOf(st.nextToken());\r
1388                                 connectivity.add(idx3);\r
1389                         }\r
1390 \r
1391                         int vertexCount = vertexArray.size();\r
1392                         Attributes kAttr = new Attributes();\r
1393                         kAttr.SetPChannels(3);\r
1394                         kAttr.SetNChannels(3);\r
1395                         kAttr.SetTChannels(0, 3);\r
1396                         kAttr.SetCChannels(0, 4);\r
1397                         kVBuffer = new VertexBuffer(kAttr, vertexCount);\r
1398 \r
1399                         int index = 0;\r
1400                         Vector3f pos;\r
1401                         for (i = 0; i < vertexCount; i++) {\r
1402                                 pos = vertexArray.elementAt(i);\r
1403                                 kVBuffer.SetPosition3(index, pos);\r
1404                                 kVBuffer.SetColor4(0, index, 1.0f, 1.0f, 1.0f, 1.0f);\r
1405                                 index++;\r
1406                         }\r
1407 \r
1408                         int indexCount = connectivity.size();\r
1409                         aiConnect = new int[indexCount];\r
1410                         for (i = 0; i < indexCount; i++) {\r
1411                                 aiConnect[i] = connectivity.get(i);\r
1412                         }\r
1413 \r
1414                         IndexBuffer kIBuffer = new IndexBuffer(aiConnect.length, aiConnect);\r
1415                         mesh = new TriMesh(kVBuffer, kIBuffer);\r
1416                         MaterialState kMaterial = new MaterialState();\r
1417                         mesh.AttachGlobalState(kMaterial);\r
1418                         return mesh;\r
1419                 } catch (FileNotFoundException e) {\r
1420                         System.err.println("ERROR: Can't find file " + file);\r
1421                         return null;\r
1422                 } catch (IOException e) {\r
1423                         return null;\r
1424                 }\r
1425         }\r
1426 \r
1427         /**\r
1428          * Load the STL ASCII file.\r
1429          * \r
1430          * @param file\r
1431          *            STL surface file reference\r
1432          * @param source\r
1433          *            image\r
1434          * @return TriMesh\r
1435          */\r
1436         private static TriMesh loadSTLAsciiMesh(File file, ModelImage kImage) {\r
1437 \r
1438                 TriMesh mesh;\r
1439                 try {\r
1440                         BufferedReader reader;\r
1441                         reader = new BufferedReader(new FileReader(file));\r
1442                         StreamTokenizer tokenizer = new StreamTokenizer(reader);\r
1443                         tokenizer.resetSyntax();\r
1444                         tokenizer.whitespaceChars(0, 0x20);\r
1445                         tokenizer.wordChars(0x21, 0xff);\r
1446                         mesh = readSTLAscii(tokenizer, kImage);\r
1447                         reader.close();\r
1448                         return mesh;\r
1449                 } catch (FileNotFoundException e) {\r
1450                         System.err.println("ERROR: Can't find file " + file);\r
1451                         return null;\r
1452                 } catch (IOException e) {\r
1453                         return null;\r
1454                 }\r
1455         }\r
1456 \r
1457         /**\r
1458          * Load legacy VTK mesh.\r
1459          * \r
1460          * @param kIn\r
1461          *            file containing mesh\r
1462          * @param progress\r
1463          *            progress bar\r
1464          * @param added\r
1465          *            number of meshes read from file so far\r
1466          * @param total\r
1467          *            total number of meshes in file\r
1468          * @param flag\r
1469          *            invert y,z values\r
1470          * @return TriMesh\r
1471          * @throws IOException\r
1472          */\r
1473         private static TriMesh loadVTKLegacyMesh(RandomAccessFile kIn, ViewJProgressBar progress, int added, int total,\r
1474                         String fileName) {\r
1475                 TriMesh kMesh;\r
1476 \r
1477                 System.out.println(fileName);\r
1478 \r
1479                 StringBuffer buff = new StringBuffer();\r
1480                 try {\r
1481                         // progress.setLocation(200, 200);\r
1482                         progress.setVisible(true);\r
1483                         String str;\r
1484                         // Read file as string\r
1485                         while ((str = kIn.readLine()) != null) {\r
1486                                 buff.append(str + "\n");\r
1487                         }\r
1488                 } catch (Exception e) {\r
1489                         System.err.println("Error occured while reading parameter file:\n" + e.getMessage());\r
1490                         e.printStackTrace();\r
1491                         return null;\r
1492                 }\r
1493                 Pattern header = Pattern.compile("POINTS\\s\\d+\\sfloat");\r
1494                 Matcher m = header.matcher(buff);\r
1495                 int vertexCount = 0;\r
1496                 int indexCount = 0;\r
1497 \r
1498                 Attributes kAttr = new Attributes();\r
1499                 kAttr.SetPChannels(3);\r
1500                 kAttr.SetNChannels(3);\r
1501                 kAttr.SetTChannels(0, 3);\r
1502                 kAttr.SetCChannels(0, 4);\r
1503                 // kAttr.SetCChannels(1,4);\r
1504 \r
1505                 VertexBuffer kVBuffer = null;\r
1506                 int[] indices;\r
1507                 if (m.find()) {\r
1508                         String head = buff.substring(m.start(), m.end());\r
1509                         String[] vals = head.split("\\D+");\r
1510                         if (vals.length > 0) {\r
1511                                 try {\r
1512                                         vertexCount = Integer.parseInt(vals[vals.length - 1]);\r
1513                                 } catch (NumberFormatException e) {\r
1514                                         System.err.println("CANNOT DETERMINE VERTEX COUNT");\r
1515                                         return null;\r
1516                                 }\r
1517                         }\r
1518 \r
1519                         kVBuffer = new VertexBuffer(kAttr, vertexCount);\r
1520 \r
1521                         System.out.println("vertex count is " + vertexCount);\r
1522                         progress.updateValueImmed(added + (25 / total));\r
1523                         System.out.println(m.end());\r
1524                         System.out.println(buff.length());\r
1525                         String[] strs = buff.substring(m.end(), buff.length()).split("\\s+", vertexCount * 3 + 2);\r
1526                         System.out.println(strs[0]);\r
1527                         System.out.println(strs[1]);\r
1528                         for (int i = 1; i < strs.length - 1; i += 3) {\r
1529                                 try {\r
1530                                         kVBuffer.SetPosition3((i - 1) / 3, Float.parseFloat(strs[i]), Float.parseFloat(strs[i + 1]),\r
1531                                                         Float.parseFloat(strs[i + 2]));\r
1532                                         kVBuffer.SetColor4(0, (i - 1) / 3, 1f, 1f, 1f, 1f);\r
1533                                         // System.out.println(i/3+")"+p);\r
1534                                 } catch (NumberFormatException e) {\r
1535                                         System.err.println("CANNOT FORMAT VERTS");\r
1536                                         return null;\r
1537                                 }\r
1538                         }\r
1539                 } else {\r
1540                         return null;\r
1541                 }\r
1542 \r
1543                 progress.updateValueImmed(added + (50 / total));\r
1544 \r
1545                 header = Pattern.compile("POLYGONS\\s+\\d+\\s+\\d+");\r
1546                 m = header.matcher(buff);\r
1547                 if (m.find()) {\r
1548                         String head = buff.substring(m.start(), m.end());\r
1549                         String[] vals = head.split("\\D+");\r
1550                         if (vals.length > 1) {\r
1551                                 try {\r
1552                                         indexCount = Integer.parseInt(vals[1]);\r
1553                                 } catch (NumberFormatException e) {\r
1554                                         System.err.println("CANNOT DETERMINE INDEX COUNT");\r
1555                                         return null;\r
1556                                 }\r
1557                         }\r
1558                         indices = new int[indexCount * 3];\r
1559                         System.out.println("INDICES " + indexCount);\r
1560                         String[] strs = buff.substring(m.end(), buff.length()).split("\\s+", indexCount * 4 + 2);\r
1561                         int count = 0;\r
1562                         System.out.println(strs[0]);\r
1563                         System.out.println(strs[1]);\r
1564                         for (int i = 1; i < strs.length - 1; i += 4) {\r
1565                                 try {\r
1566                                         if (Integer.parseInt(strs[i]) != 3) {\r
1567                                                 System.err.println("CANNOT FORMAT INDICES");\r
1568                                                 return null;\r
1569                                         }\r
1570                                         indices[count++] = Integer.parseInt(strs[i + 1]);\r
1571                                         indices[count++] = Integer.parseInt(strs[i + 2]);\r
1572                                         indices[count++] = Integer.parseInt(strs[i + 3]);\r
1573                                 } catch (NumberFormatException e) {\r
1574                                         System.err.println("CANNOT FORMAT INDICES");\r
1575                                         return null;\r
1576                                 }\r
1577                         }\r
1578                 } else {\r
1579                         return null;\r
1580                 }\r
1581 \r
1582                 header = Pattern.compile("POINT_DATA\\s+\\d+\\D+float\\s+\\d+\\nLOOKUP_TABLE\\s");\r
1583                 m = header.matcher(buff);\r
1584                 double[][] dat;\r
1585                 int count = 0;\r
1586                 int dim = 0;\r
1587                 if (m.find()) {\r
1588                         String head = buff.substring(m.start(), m.end());\r
1589                         String[] vals = head.split("\\D+");\r
1590                         if (vals.length > 0) {\r
1591                                 try {\r
1592                                         count = Integer.parseInt(vals[1]);\r
1593                                         dim = Integer.parseInt(vals[2]);\r
1594                                 } catch (NumberFormatException e) {\r
1595                                         System.err.println("CANNOT DETERMINE DATA POINTS");\r
1596                                         return null;\r
1597                                 }\r
1598                         }\r
1599                         dat = new double[count][dim];\r
1600                         System.out.println("DATA POINTS " + count + " by " + dim);\r
1601                         String[] strs = buff.substring(m.end(), buff.length()).split("\\s+", count * dim + 2);\r
1602                         int index = 0;\r
1603                         for (int i = 1; i < strs.length && index < count * dim; i++) {\r
1604                                 try {\r
1605                                         dat[index / dim][index % dim] = Double.parseDouble(strs[i]);\r
1606                                         index++;\r
1607                                 } catch (NumberFormatException e) {\r
1608                                         System.err.println("CANNOT FORMAT DATA [" + strs[i] + "]");\r
1609                                         // return null;\r
1610                                 }\r
1611                         }\r
1612                         // System.out.println(index+" "+count);\r
1613 \r
1614                         progress.updateValueImmed(added + (100 / total));\r
1615 \r
1616                 } else {\r
1617 \r
1618                 }\r
1619                 IndexBuffer kIBuffer = new IndexBuffer(indices.length, indices);\r
1620                 kMesh = new TriMesh(kVBuffer, kIBuffer);\r
1621                 return kMesh;\r
1622         }\r
1623 \r
1624         /**\r
1625          * Read VTK mesh from file.\r
1626          * \r
1627          * @param absPath\r
1628          *            file path\r
1629          * @param fileName\r
1630          *            file name\r
1631          * @param dir\r
1632          *            file directory\r
1633          * @return TriMesh\r
1634          */\r
1635         private static TriMesh loadVTKXMLMesh(String absPath, String fileName, String dir) {\r
1636                 TriMesh kMesh = null;\r
1637 \r
1638                 FileSurfaceVTKXML_WM surfaceVTKXML = new FileSurfaceVTKXML_WM(fileName, dir);\r
1639                 kMesh = surfaceVTKXML.readXMLSurface_WM(absPath);\r
1640 \r
1641                 return kMesh;\r
1642         }\r
1643 \r
1644         /**\r
1645          * Read Gifti mesh from file.\r
1646          * \r
1647          * @param absPath\r
1648          *            file path\r
1649          * @param fileName\r
1650          *            file name\r
1651          * @param dir\r
1652          *            file directory\r
1653          * @return TriMesh\r
1654          */\r
1655         private static TriMesh loadGiftiXMLMesh(String absPath, String fileName, String dir) {\r
1656                 TriMesh kMesh = null;\r
1657 \r
1658                 FileSurfaceGiftiXML_WM surfaceGiftiXML = new FileSurfaceGiftiXML_WM(fileName, dir);\r
1659                 kMesh = surfaceGiftiXML.readSurfaceXML(fileName, dir);\r
1660 \r
1661                 return kMesh;\r
1662         }\r
1663 \r
1664         /**\r
1665          * Returns an array of File objects, based on the user-selected files from the\r
1666          * FileChooser dialog.\r
1667          * \r
1668          * @param bLoad\r
1669          *            whether the files are opened for reading (bLoad = true) or writing\r
1670          *            (bLoad = false)\r
1671          * @return File[] array of opened files.\r
1672          */\r
1673         public static File[] openFiles(boolean bLoad) {\r
1674 \r
1675                 // file dialog to select surface mesh files (*.sur)\r
1676                 JFileChooser chooser = new JFileChooser();\r
1677                 chooser.setMultiSelectionEnabled(bLoad);\r
1678                 chooser.resetChoosableFileFilters();\r
1679                 chooser.addChoosableFileFilter(new ViewImageFileFilter(ViewImageFileFilter.SURFACE));\r
1680 \r
1681                 if (ViewUserInterface.getReference().getDefaultDirectory() != null) {\r
1682                         chooser.setCurrentDirectory(new File(ViewUserInterface.getReference().getDefaultDirectory()));\r
1683                 } else {\r
1684                         chooser.setCurrentDirectory(new File(System.getProperties().getProperty("user.dir")));\r
1685                 }\r
1686 \r
1687                 int returnVal;\r
1688 \r
1689                 if (bLoad) {\r
1690                         returnVal = chooser.showOpenDialog(null);\r
1691                 } else {\r
1692                         returnVal = chooser.showSaveDialog(null);\r
1693                 }\r
1694 \r
1695                 if (returnVal == JFileChooser.APPROVE_OPTION) {\r
1696                         ViewUserInterface.getReference()\r
1697                                         .setDefaultDirectory(String.valueOf(chooser.getCurrentDirectory()) + File.separatorChar);\r
1698 \r
1699                         if (bLoad) {\r
1700                                 File[] files = chooser.getSelectedFiles();\r
1701 \r
1702                                 return files;\r
1703                         }\r
1704                         File[] files = new File[1];\r
1705                         files[0] = chooser.getSelectedFile();\r
1706                         return files;\r
1707                 }\r
1708 \r
1709                 return null;\r
1710         }\r
1711 \r
1712         /**\r
1713          * Returns a dicomMatrix file objects, based on the user-selected filed from the\r
1714          * FileChooser dialog.\r
1715          * \r
1716          * @param bLoad\r
1717          *            whether the files are opened for reading (bLoad = true) or writing\r
1718          *            (bLoad = false)\r
1719          * @return File of opened file.\r
1720          */\r
1721         private static File openDicomMatrixFiles(boolean bLoad) {\r
1722 \r
1723                 // file dialog to select the dicom matrix info file\r
1724                 JFileChooser chooser = new JFileChooser();\r
1725                 chooser.setMultiSelectionEnabled(bLoad);\r
1726                 chooser.resetChoosableFileFilters();\r
1727                 chooser.addChoosableFileFilter(new ViewImageFileFilter(ViewImageFileFilter.DICOMMATRIX));\r
1728 \r
1729                 if (ViewUserInterface.getReference().getDefaultDirectory() != null) {\r
1730                         chooser.setCurrentDirectory(new File(ViewUserInterface.getReference().getDefaultDirectory()));\r
1731                 } else {\r
1732                         chooser.setCurrentDirectory(new File(System.getProperties().getProperty("user.dir")));\r
1733                 }\r
1734 \r
1735                 int returnVal;\r
1736 \r
1737                 if (bLoad) {\r
1738                         returnVal = chooser.showOpenDialog(null);\r
1739                 } else {\r
1740                         returnVal = chooser.showSaveDialog(null);\r
1741                 }\r
1742 \r
1743                 if (returnVal == JFileChooser.APPROVE_OPTION) {\r
1744                         ViewUserInterface.getReference()\r
1745                                         .setDefaultDirectory(String.valueOf(chooser.getCurrentDirectory()) + File.separatorChar);\r
1746 \r
1747                         if (bLoad) {\r
1748                                 File file = chooser.getSelectedFile();\r
1749 \r
1750                                 return file;\r
1751                         }\r
1752                         File[] file = new File[1];\r
1753                         file[0] = chooser.getSelectedFile();\r
1754                         return file[0];\r
1755                 }\r
1756 \r
1757                 return null;\r
1758         }\r
1759 \r
1760         /**\r
1761          * Print the contents of the TriMesh in ascii format.\r
1762          * \r
1763          * @param kOut\r
1764          *            output\r
1765          * @param kMesh\r
1766          *            TriMesh\r
1767          */\r
1768         private static void printAscii(PrintWriter kOut, TriMesh kMesh) {\r
1769                 Vector3f kVertex = new Vector3f();\r
1770                 Vector3f kNormal = new Vector3f();\r
1771 \r
1772                 // write vertices\r
1773                 kOut.println(kMesh.VBuffer.GetVertexQuantity());\r
1774                 kOut.println("Vertices");\r
1775 \r
1776                 int i;\r
1777 \r
1778                 for (i = 0; i < kMesh.VBuffer.GetVertexQuantity(); i++) {\r
1779                         kMesh.VBuffer.GetPosition3(i, kVertex);\r
1780                         kOut.print(kVertex.X);\r
1781                         kOut.print(' ');\r
1782                         kOut.print(kVertex.Y);\r
1783                         kOut.print(' ');\r
1784                         kOut.println(kVertex.Z);\r
1785                 }\r
1786 \r
1787                 kOut.println("Normals");\r
1788 \r
1789                 // write normals\r
1790                 for (i = 0; i < kMesh.VBuffer.GetVertexQuantity(); i++) {\r
1791                         kMesh.VBuffer.GetNormal3(i, kNormal);\r
1792                         kOut.print(kNormal.X);\r
1793                         kOut.print(' ');\r
1794                         kOut.print(kNormal.Y);\r
1795                         kOut.print(' ');\r
1796                         kOut.println(kNormal.Z);\r
1797                 }\r
1798 \r
1799                 kOut.println("Connectivity");\r
1800 \r
1801                 // write connectivity\r
1802                 int iTriangleCount = kMesh.GetTriangleQuantity();\r
1803                 int[] aiIndex = kMesh.IBuffer.GetData();\r
1804                 kOut.println(iTriangleCount);\r
1805 \r
1806                 for (i = 0; i < iTriangleCount; i++) {\r
1807                         kOut.print(aiIndex[(3 * i)]);\r
1808                         kOut.print(' ');\r
1809                         kOut.print(aiIndex[((3 * i) + 1)]);\r
1810                         kOut.print(' ');\r
1811                         kOut.println(aiIndex[((3 * i) + 2)]);\r
1812                 }\r
1813         }\r
1814 \r
1815         /**\r
1816          * Print the contents of the TriMesh in STL ascii format.\r
1817          * \r
1818          * @param kOut\r
1819          *            output\r
1820          * @param kMesh\r
1821          *            TriMesh\r
1822          */\r
1823         private static void printSTLAscii(PrintWriter kOut, ModelImage kImage, TriMesh kMesh) {\r
1824                 int i;\r
1825                 int index1, index2, index3;\r
1826                 VertexBuffer kVBuffer;\r
1827                 int iTriangleCount = kMesh.IBuffer.GetIndexQuantity() / 3;\r
1828                 int[] aiIndex = kMesh.IBuffer.GetData();\r
1829                 Vector3f kVertex = new Vector3f();\r
1830                 Vector3f kNormal = new Vector3f();\r
1831                 \r
1832                 Vector3f kVertex1 = new Vector3f();\r
1833                 Vector3f kVertex2 = new Vector3f();\r
1834                 Vector3f kVertex3 = new Vector3f();\r
1835                 \r
1836         float x1, y1, z1;\r
1837         float x2, y2, z2;\r
1838         float x3, y3, z3;\r
1839         float nx, ny, nz;\r
1840                 \r
1841                 if (kImage != null) {\r
1842                         kVBuffer = convertVertex(kImage, kMesh);\r
1843                 } else {\r
1844                         kVBuffer = kMesh.VBuffer;\r
1845                 }\r
1846 \r
1847                 kOut.println("solid");\r
1848 \r
1849                 for (i = 0; i < iTriangleCount; i++) {\r
1850                         \r
1851                         index1 = aiIndex[(3 * i)];\r
1852                         index2 = aiIndex[((3 * i) + 1)];\r
1853                         index3 = aiIndex[((3 * i) + 2)];\r
1854 \r
1855                         kVBuffer.GetPosition3(index1, kVertex1);\r
1856                         kVBuffer.GetPosition3(index2, kVertex2);\r
1857                         kVBuffer.GetPosition3(index3, kVertex3);\r
1858 \r
1859                         x1 = kVertex1.X; y1 = kVertex1.Y; z1 = kVertex1.Z;\r
1860                         x2 = kVertex2.X; y2 = kVertex2.Y; z2 = kVertex2.Z;\r
1861                         x3 = kVertex3.X; y3 = kVertex3.Y; z3 = kVertex3.Z;\r
1862                         \r
1863                         nx = (y2-y1)*(z3-z1) - (y3-y1)*(z2-z1);\r
1864                         ny = (z2-z1)*(x3-x1) - (x2-x1)*(z3-z1);\r
1865                         nz = (x2-x1)*(y3-y1) - (x3-x1)*(y2-y1);\r
1866                         \r
1867                         // Compute facet normal\r
1868                         kNormal.set(nx, ny, nz);\r
1869                         \r
1870                         kOut.print(" facet normal  ");\r
1871                         kOut.print(kNormal.X);\r
1872                         kOut.print(' ');\r
1873                         kOut.print(kNormal.Y);\r
1874                         kOut.print(' ');\r
1875                         kOut.println(kNormal.Z);\r
1876 \r
1877                         kOut.println("   outer loop");\r
1878                         // index 1\r
1879                         kVBuffer.GetPosition3(index1, kVertex);\r
1880                         kOut.print("     vertex ");\r
1881                         kOut.print(kVertex.X);\r
1882                         kOut.print(' ');\r
1883                         kOut.print(kVertex.Y);\r
1884                         kOut.print(' ');\r
1885                         kOut.println(kVertex.Z);\r
1886                         // index 2\r
1887                         kVBuffer.GetPosition3(index2, kVertex);\r
1888                         kOut.print("     vertex ");\r
1889                         kOut.print(kVertex.X);\r
1890                         kOut.print(' ');\r
1891                         kOut.print(kVertex.Y);\r
1892                         kOut.print(' ');\r
1893                         kOut.println(kVertex.Z);\r
1894                         // index 3\r
1895                         kVBuffer.GetPosition3(index3, kVertex);\r
1896                         kOut.print("     vertex ");\r
1897                         kOut.print(kVertex.X);\r
1898                         kOut.print(' ');\r
1899                         kOut.print(kVertex.Y);\r
1900                         kOut.print(' ');\r
1901                         kOut.println(kVertex.Z);\r
1902 \r
1903                         kOut.println("   endloop");\r
1904                         kOut.println(" endfacet");\r
1905                 }\r
1906                 kOut.println("endsolid");\r
1907         }\r
1908 \r
1909         /**\r
1910          * Print the contents of the TriMesh in STL ascii format.\r
1911          * \r
1912          * @param kOut\r
1913          *            output\r
1914          * @param kMesh\r
1915          *            TriMesh\r
1916          */\r
1917         private static void printProstateSTLAscii(PrintWriter kOut, ModelImage kImage, TriMesh kMesh) {\r
1918                 int i;\r
1919                 int index1, index2, index3;\r
1920                 VertexBuffer kVBuffer;\r
1921                 float res[] = kImage.getFileInfo(0).getResolutions();\r
1922                 int iTriangleCount = kMesh.IBuffer.GetIndexQuantity() / 3;\r
1923                 int[] aiIndex = kMesh.IBuffer.GetData();\r
1924 \r
1925                 Vector3f kNormal = new Vector3f();\r
1926                 Vector3f kNormal1 = new Vector3f();\r
1927                 Vector3f kNormal2 = new Vector3f();\r
1928                 Vector3f kNormal3 = new Vector3f();\r
1929 \r
1930                 Vector3f kVertex1 = new Vector3f();\r
1931                 Vector3f kVertex2 = new Vector3f();\r
1932                 Vector3f kVertex3 = new Vector3f();\r
1933 \r
1934                 kVBuffer = kMesh.VBuffer;\r
1935 \r
1936                 kOut.println("solid");\r
1937 \r
1938                 for (i = 0; i < iTriangleCount; i++) {\r
1939                         index1 = aiIndex[(3 * i)];\r
1940                         index2 = aiIndex[((3 * i) + 1)];\r
1941                         index3 = aiIndex[((3 * i) + 2)];\r
1942 \r
1943                         kVBuffer.GetPosition3(index1, kNormal1);\r
1944                         kVBuffer.GetPosition3(index2, kNormal2);\r
1945                         kVBuffer.GetPosition3(index3, kNormal3);\r
1946 \r
1947                         MipavCoordinateSystems.scannerToFile(kNormal1, kVertex1, kImage);\r
1948                         MipavCoordinateSystems.scannerToFile(kNormal2, kVertex2, kImage);\r
1949                         MipavCoordinateSystems.scannerToFile(kNormal3, kVertex3, kImage);\r
1950 \r
1951                         kVertex1.X *= res[0];\r
1952                         kVertex1.Y *= res[1];\r
1953                         kVertex1.Z *= res[2];\r
1954                         kVertex2.X *= res[0];\r
1955                         kVertex2.Y *= res[1];\r
1956                         kVertex2.Z *= res[2];\r
1957                         kVertex3.X *= res[0];\r
1958                         kVertex3.Y *= res[1];\r
1959                         kVertex3.Z *= res[2];\r
1960 \r
1961                         // Compute facet normal\r
1962                         kNormal.set(0f, 0f, 0f).add(kVertex1).add(kVertex2).add(kVertex3).scale(1f / 3f);\r
1963 \r
1964                         kOut.print(" facet normal  ");\r
1965                         kOut.print(kNormal.X);\r
1966                         kOut.print(' ');\r
1967                         kOut.print(kNormal.Y);\r
1968                         kOut.print(' ');\r
1969                         kOut.println(kNormal.Z);\r
1970 \r
1971                         kOut.println("   outer loop");\r
1972 \r
1973                         // index 1\r
1974                         kOut.print("     vertex ");\r
1975                         kOut.print(kVertex1.X);\r
1976                         kOut.print(' ');\r
1977                         kOut.print(kVertex1.Y);\r
1978                         kOut.print(' ');\r
1979                         kOut.println(kVertex1.Z);\r
1980                         // index 2\r
1981                         kOut.print("     vertex ");\r
1982                         kOut.print(kVertex2.X);\r
1983                         kOut.print(' ');\r
1984                         kOut.print(kVertex2.Y);\r
1985                         kOut.print(' ');\r
1986                         kOut.println(kVertex2.Z);\r
1987                         // index 3\r
1988                         kOut.print("     vertex ");\r
1989                         kOut.print(kVertex3.X);\r
1990                         kOut.print(' ');\r
1991                         kOut.print(kVertex3.Y);\r
1992                         kOut.print(' ');\r
1993                         kOut.println(kVertex3.Z);\r
1994 \r
1995                         kOut.println("   endloop");\r
1996                         kOut.println(" endfacet");\r
1997                 }\r
1998                 kOut.println("endsolid");\r
1999         }\r
2000 \r
2001         /**\r
2002          * Read a TriMesh from an ascii file.\r
2003          * \r
2004          * @param kFile\r
2005          *            file containing TriMesh\r
2006          * @return TriMesh\r
2007          * @throws IOException\r
2008          *             I/O exception\r
2009          */\r
2010         private static TriMesh readAscii(File kFile) throws IOException {\r
2011                 DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(kFile)));\r
2012                 String s, token;\r
2013                 s = readLine(in);\r
2014                 s = readLine(in);\r
2015                 s = readLine(in);\r
2016                 StringTokenizer st = new StringTokenizer(s);\r
2017                 int iNumVertices = 1;\r
2018                 if (st.hasMoreTokens()) {\r
2019                         token = st.nextToken();\r
2020                         iNumVertices = Integer.valueOf(token).intValue();\r
2021                 }\r
2022                 Attributes kAttr = new Attributes();\r
2023                 kAttr.SetPChannels(3);\r
2024                 kAttr.SetNChannels(3);\r
2025                 kAttr.SetTChannels(0, 3);\r
2026                 kAttr.SetCChannels(0, 4);\r
2027                 VertexBuffer kVBuffer = new VertexBuffer(kAttr, iNumVertices);\r
2028                 float fX, fY, fZ;\r
2029                 s = readLine(in);\r
2030                 for (int i = 0; i < iNumVertices; i++) {\r
2031                         s = readLine(in);\r
2032                         st = new StringTokenizer(s);\r
2033                         token = st.nextToken();\r
2034                         fX = Float.valueOf(token).floatValue();\r
2035                         token = st.nextToken();\r
2036                         fY = Float.valueOf(token).floatValue();\r
2037                         token = st.nextToken();\r
2038                         fZ = Float.valueOf(token).floatValue();\r
2039                         kVBuffer.SetPosition3(i, fX, fY, fZ);\r
2040                         kVBuffer.SetColor4(0, i, ColorRGBA.WHITE);\r
2041                 }\r
2042                 s = readLine(in);\r
2043                 for (int i = 0; i < iNumVertices; i++) {\r
2044                         s = readLine(in);\r
2045                         st = new StringTokenizer(s);\r
2046                         token = st.nextToken();\r
2047                         fX = Float.valueOf(token).floatValue();\r
2048                         token = st.nextToken();\r
2049                         fY = Float.valueOf(token).floatValue();\r
2050                         token = st.nextToken();\r
2051                         fZ = Float.valueOf(token).floatValue();\r
2052                         kVBuffer.SetNormal3(i, fX, fY, fZ);\r
2053                 }\r
2054 \r
2055                 int iTriangleCount = 0;\r
2056                 s = readLine(in);\r
2057                 s = readLine(in);\r
2058                 st = new StringTokenizer(s);\r
2059                 if (st.hasMoreTokens()) {\r
2060                         token = st.nextToken();\r
2061                         iTriangleCount = Integer.valueOf(token).intValue();\r
2062                 }\r
2063 \r
2064                 int[] aiIndex = new int[iTriangleCount * 3];\r
2065 \r
2066                 for (int i = 0; i < iTriangleCount; i++) {\r
2067                         s = readLine(in);\r
2068                         st = new StringTokenizer(s);\r
2069                         token = st.nextToken();\r
2070                         aiIndex[(3 * i)] = Integer.valueOf(token).intValue();\r
2071                         token = st.nextToken();\r
2072                         aiIndex[((3 * i) + 1)] = Integer.valueOf(token).intValue();\r
2073                         token = st.nextToken();\r
2074                         aiIndex[((3 * i) + 2)] = Integer.valueOf(token).intValue();\r
2075                 }\r
2076                 return new TriMesh(kVBuffer, new IndexBuffer(aiIndex));\r
2077         }\r
2078 \r
2079         /**\r
2080          * Read a line of ASCII text from the input stream.\r
2081          * \r
2082          * @param in\r
2083          *            InputStream\r
2084          * @return line of the ascii file as a String\r
2085          * @throws IOException\r
2086          *             I/O exception\r
2087          */\r
2088         private static String readLine(InputStream in) throws IOException {\r
2089                 StringBuffer buf = new StringBuffer();\r
2090                 int c;\r
2091                 while ((c = in.read()) > -1 && c != '\n') {\r
2092                         buf.append((char) c);\r
2093                 }\r
2094                 return buf.toString();\r
2095         }\r
2096 \r
2097         /**\r
2098          * Find the given label in the tokenizer stream and then return the next three\r
2099          * numbers as a point. Return null if end of stream\r
2100          * \r
2101          * @param tokenizer\r
2102          *            stream in\r
2103          * @param label\r
2104          *            string label (vertex, normal ) in the STL ASCII file.\r
2105          * @return Vector3f point coordinate.\r
2106          * @throws IOException\r
2107          */\r
2108         private static Vector3f readPoint(StreamTokenizer tokenizer, String label) throws IOException {\r
2109                 while (true) {\r
2110                         if (tokenizer.nextToken() == StreamTokenizer.TT_EOF)\r
2111                                 return null;\r
2112                         if (tokenizer.sval.equals(label))\r
2113                                 break;\r
2114                 }\r
2115 \r
2116                 if (tokenizer.nextToken() == StreamTokenizer.TT_EOF)\r
2117                         return null;\r
2118                 float x = Float.valueOf(tokenizer.sval).floatValue();\r
2119                 if (tokenizer.nextToken() == StreamTokenizer.TT_EOF)\r
2120                         return null;\r
2121                 float y = Float.valueOf(tokenizer.sval).floatValue();\r
2122                 if (tokenizer.nextToken() == StreamTokenizer.TT_EOF)\r
2123                         return null;\r
2124                 float z = Float.valueOf(tokenizer.sval).floatValue();\r
2125 \r
2126                 return new Vector3f(x, y, z);\r
2127         }\r
2128 \r
2129         /**\r
2130          * Read the STL ASCII file as a single stream tokenizer.\r
2131          * \r
2132          * @param tokenizer\r
2133          *            stream in\r
2134          * @return Triangle mesh\r
2135          * @throws IOException\r
2136          */\r
2137         private static TriMesh readSTLAscii(StreamTokenizer tokenizer, ModelImage kImage) throws IOException {\r
2138 \r
2139                 Vector3f temp = new Vector3f();\r
2140                 Vector3f normal = new Vector3f();\r
2141                 Vector3f side1 = new Vector3f();\r
2142                 Vector3f side2 = new Vector3f();\r
2143                 Vector3f surfaceNormal = new Vector3f();\r
2144                 Vector<Vector3f> vertexArray = new Vector<Vector3f>();\r
2145                 VertexBuffer kVBuffer;\r
2146                 int[] aiConnect;\r
2147 \r
2148                 TriMesh kMesh = null;\r
2149                 float x, y, z;\r
2150                 Vector3f vertex1, vertex2, vertex3;\r
2151                 int index = 0;\r
2152                 Integer searchIndex;\r
2153                 Vector<Integer> connectivity = new Vector<Integer>();\r
2154                 HashMap<String, Integer> vertexHashtable = new HashMap<String, Integer>();\r
2155 \r
2156                 float _res[] = kImage.getFileInfo(0).getResolutions();\r
2157                 float[] _startLocation = kImage.getFileInfo()[0].getOrigin();\r
2158                 int[] _direction = MipavCoordinateSystems.getModelDirections(kImage);\r
2159 \r
2160                 Vector3f ptIn = new Vector3f();\r
2161                 Vector3f ptOut = new Vector3f();\r
2162 \r
2163                 try {\r
2164 \r
2165                         while (true) {\r
2166                                 if ((temp = readPoint(tokenizer, "normal")) == null)\r
2167                                         break;\r
2168                                 normal = new Vector3f(temp);\r
2169 \r
2170                                 vertex1 = readPoint(tokenizer, "vertex");\r
2171                                 vertex2 = readPoint(tokenizer, "vertex");\r
2172                                 vertex3 = readPoint(tokenizer, "vertex");\r
2173 \r
2174                                 // Check that the normal is in the correct direction\r
2175                                 side1.copy(vertex2).sub(vertex1);\r
2176                                 side2.copy(vertex3).sub(vertex2);\r
2177 \r
2178                                 surfaceNormal.copy(side1).cross(side2);\r
2179                                 if (normal.dot(surfaceNormal) < 0) {\r
2180                                         // vertices were specified in the wrong order, so reverse\r
2181                                         // two of them\r
2182                                         temp.copy(vertex2);\r
2183                                         vertex2.copy(vertex3);\r
2184                                         vertex3.copy(temp);\r
2185                                 }\r
2186 \r
2187                                 // index 1;\r
2188                                 x = vertex1.X;\r
2189                                 y = vertex1.Y;\r
2190                                 z = vertex1.Z;\r
2191 \r
2192                                 ptIn.X = x;\r
2193                                 ptIn.Y = y;\r
2194                                 ptIn.Z = z;\r
2195 \r
2196                                 MipavCoordinateSystems.scannerToFile(ptIn, ptOut, kImage);\r
2197 \r
2198                                 x = (ptOut.X * _res[0] * _direction[0]) + _startLocation[0];\r
2199                                 y = (ptOut.Y * _res[1] * _direction[1]) + _startLocation[1];\r
2200                                 z = (ptOut.Z * _res[2] * _direction[2]) + _startLocation[2];\r
2201 \r
2202                                 searchIndex = vertexHashtable.get((x + " " + y + " " + z));\r
2203                                 if (searchIndex == null) { // not found\r
2204                                         vertexHashtable.put((x + " " + y + " " + z), new Integer(index));\r
2205                                         connectivity.add(new Integer(index));\r
2206                                         vertexArray.add(new Vector3f(x, y, z));\r
2207                                         index++;\r
2208                                 } else {\r
2209                                         connectivity.add(searchIndex);\r
2210                                 }\r
2211 \r
2212                                 // index 2;\r
2213                                 x = vertex2.X;\r
2214                                 y = vertex2.Y;\r
2215                                 z = vertex2.Z;\r
2216 \r
2217                                 ptIn.X = x;\r
2218                                 ptIn.Y = y;\r
2219                                 ptIn.Z = z;\r
2220 \r
2221                                 MipavCoordinateSystems.scannerToFile(ptIn, ptOut, kImage);\r
2222 \r
2223                                 x = (ptOut.X * _res[0] * _direction[0]) + _startLocation[0];\r
2224                                 y = (ptOut.Y * _res[1] * _direction[1]) + _startLocation[1];\r
2225                                 z = (ptOut.Z * _res[2] * _direction[2]) + _startLocation[2];\r
2226 \r
2227                                 searchIndex = vertexHashtable.get((x + " " + y + " " + z));\r
2228                                 if (searchIndex == null) { // not found\r
2229                                         vertexHashtable.put((x + " " + y + " " + z), new Integer(index));\r
2230                                         connectivity.add(new Integer(index));\r
2231                                         vertexArray.add(new Vector3f(x, y, z));\r
2232                                         index++;\r
2233                                 } else {\r
2234                                         connectivity.add(searchIndex);\r
2235                                 }\r
2236 \r
2237                                 // index 3;\r
2238                                 x = vertex3.X;\r
2239                                 y = vertex3.Y;\r
2240                                 z = vertex3.Z;\r
2241 \r
2242                                 ptIn.X = x;\r
2243                                 ptIn.Y = y;\r
2244                                 ptIn.Z = z;\r
2245 \r
2246                                 MipavCoordinateSystems.scannerToFile(ptIn, ptOut, kImage);\r
2247 \r
2248                                 x = (ptOut.X * _res[0] * _direction[0]) + _startLocation[0];\r
2249                                 y = (ptOut.Y * _res[1] * _direction[1]) + _startLocation[1];\r
2250                                 z = (ptOut.Z * _res[2] * _direction[2]) + _startLocation[2];\r
2251 \r
2252                                 searchIndex = vertexHashtable.get((x + " " + y + " " + z));\r
2253                                 if (searchIndex == null) { // not found\r
2254                                         vertexHashtable.put((x + " " + y + " " + z), new Integer(index));\r
2255                                         connectivity.add(new Integer(index));\r
2256                                         vertexArray.add(new Vector3f(x, y, z));\r
2257                                         index++;\r
2258                                 } else {\r
2259                                         connectivity.add(searchIndex);\r
2260                                 }\r
2261 \r
2262                         }\r
2263 \r
2264                         int vertexCount = vertexArray.size();\r
2265                         Attributes kAttr = new Attributes();\r
2266                         kAttr.SetPChannels(3);\r
2267                         kAttr.SetNChannels(3);\r
2268                         kAttr.SetTChannels(0, 3);\r
2269                         kAttr.SetCChannels(0, 4);\r
2270                         kVBuffer = new VertexBuffer(kAttr, vertexCount);\r
2271 \r
2272                         index = 0;\r
2273                         Vector3f pos;\r
2274                         for (int i = 0; i < vertexCount; i++) {\r
2275                                 pos = vertexArray.elementAt(i);\r
2276                                 kVBuffer.SetPosition3(index, pos);\r
2277                                 kVBuffer.SetColor4(0, index, 1.0f, 1.0f, 1.0f, 1.0f);\r
2278                                 index++;\r
2279                         }\r
2280 \r
2281                         int indexCount = connectivity.size();\r
2282                         aiConnect = new int[indexCount];\r
2283                         for (int i = 0; i < indexCount; i++) {\r
2284                                 aiConnect[i] = connectivity.get(i);\r
2285                         }\r
2286 \r
2287                 } catch (IOException e) {\r
2288                         throw e;\r
2289                 }\r
2290                 IndexBuffer kIBuffer = new IndexBuffer(aiConnect.length, aiConnect);\r
2291                 kMesh = new TriMesh(kVBuffer, kIBuffer);\r
2292                 MaterialState kMaterial = new MaterialState();\r
2293                 kMesh.AttachGlobalState(kMaterial);\r
2294                 return kMesh;\r
2295         }\r
2296 \r
2297         /**\r
2298          * Load the STL ASCII file.\r
2299          * \r
2300          * @param file\r
2301          *            STL surface file reference\r
2302          * @param source\r
2303          *            image\r
2304          * @return TriMesh\r
2305          */\r
2306         private static TriMesh loadSTLBinaryMesh(File file, ModelImage kImage) {\r
2307 \r
2308                 TriMesh mesh;\r
2309                 try {\r
2310                         FileInputStream data;\r
2311                         data = new FileInputStream(file);\r
2312                         mesh = readSTLBinary(data, kImage);\r
2313                         // reader.close();\r
2314                         return mesh;\r
2315                 } catch (FileNotFoundException e) {\r
2316                         System.err.println("ERROR: Can't find file " + file);\r
2317                         return null;\r
2318                 } catch (IOException e) {\r
2319                         return null;\r
2320                 }\r
2321         }\r
2322 \r
2323         /**\r
2324          * Method for reading binary files Execution is completly different It uses\r
2325          * ByteBuffer for reading data and ByteOrder for retrieving the machine's endian\r
2326          * (Needs JDK 1.4)\r
2327          *\r
2328          * TO-DO: 1.-Be able to read files over Internet 2.-If the amount of data\r
2329          * expected is bigger than what is on the file then the program will block\r
2330          * forever\r
2331          *\r
2332          * @param file\r
2333          *            The name of the file\r
2334          *\r
2335          * @throws IOException\r
2336          */\r
2337         private static TriMesh readSTLBinary(FileInputStream data, ModelImage kImage) throws IOException {\r
2338                 ByteBuffer dataBuffer; // For reading in the correct endian\r
2339                 byte[] Info = new byte[80]; // Header data\r
2340                 byte[] Array_number = new byte[4]; // Holds the number of faces\r
2341                 byte[] Temp_Info; // Intermediate array\r
2342 \r
2343                 Vector3f temp = new Vector3f();\r
2344                 Vector3f normal = new Vector3f();\r
2345                 Vector3f side1 = new Vector3f();\r
2346                 Vector3f side2 = new Vector3f();\r
2347                 Vector3f surfaceNormal = new Vector3f();\r
2348                 Vector<Vector3f> vertexArray = new Vector<Vector3f>();\r
2349                 VertexBuffer kVBuffer;\r
2350                 int[] aiConnect;\r
2351 \r
2352                 TriMesh kMesh = null;\r
2353                 float x, y, z;\r
2354                 Vector3f vertex1, vertex2, vertex3;\r
2355                 int index = 0;\r
2356                 Integer searchIndex;\r
2357                 Vector<Integer> connectivity = new Vector<Integer>();\r