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