2 <?xml version='1.0' standalone='yes' ?>
\r
5 <name>Export Gnu Triangulated Surface</name>
\r
6 <author>Enrique Perez</author>
\r
7 <version>1.0</version>
\r
8 <date>29-Apr-2008</date>
\r
10 This script exports triangle meshes to GNU Triangulated Surface (GTS) format files. The GTS Library homepage is at: http://gts.sourceforge.net/
\r
12 <licenseType>gpl</licenseType>
\r
15 //later once stable remove unused preferences, all the preferences will be kept in the unused Skeinforge, finish comments for this and import
\r
17 Get the info for all the selected curves and meshes.
\r
20 ObjectInfo[] getCurvesMeshesInfo()
\r
22 scene = window.getScene();
\r
23 selection = scene.getSelection();
\r
24 Vector objectInfoVector = new Vector();
\r
26 for ( int objectIndex = 0; objectIndex < selection.length; objectIndex++ ) {
\r
27 objectInfo = scene.getObject( selection[ objectIndex ] );
\r
29 if ( objectInfo.object instanceof TriangleMesh ) {
\r
30 objectInfoVector.add( objectInfo );
\r
34 if ( objectInfoVector.size() > 0 ) {
\r
35 return objectInfoVector.toArray( new ObjectInfo[ objectInfoVector.size() ] );
\r
38 for ( int objectIndex = 0; objectIndex < scene.getNumObjects(); objectIndex++ ) {
\r
39 objectInfo = scene.getObject( objectIndex );
\r
41 if ( objectInfo.object instanceof TriangleMesh ) {
\r
42 return new ObjectInfo[] { objectInfo };
\r
46 return new ObjectInfo[ 0 ];
\r
49 String getEdgeString( edges, edgeTriple, vertexIndexFirst, vertexIndexSecond )
\r
51 for ( int edgeTripleIndex = 0; edgeTripleIndex < edgeTriple.length; edgeTripleIndex++ ) {
\r
52 edgeIndex = edgeTriple[ edgeTripleIndex ];
\r
53 edge = edges[ edgeIndex ];
\r
55 if ( edge.v1 == vertexIndexFirst && edge.v2 == vertexIndexSecond ) {
\r
56 return getPlusOneToString( edgeIndex );
\r
59 if ( edge.v1 == vertexIndexSecond && edge.v2 == vertexIndexFirst ) {
\r
60 return getPlusOneToString( edgeIndex );
\r
64 print( "Inconsistent triangle mesh." );
\r
65 print( edgeTriple );
\r
66 print( vertexIndexFirst );
\r
67 print( vertexIndexSecond );
\r
70 String getPlusOneToString( int number )
\r
72 return ( number + 1 ).toString() ;
\r
76 Get Vec3 rotated around X axis from counterclockwise angle and vector.
\r
78 @param angle counterclockwise angle from 1, 0
\r
79 @param vector3 Vec3 whose rotation will be returned
\r
80 @return vector3 rotated around X axis
\r
83 Vec3 getRoundXAxis( double angle, Vec3 vector3 )
\r
85 x = Math.cos( angle );
\r
86 y = Math.sin( angle );
\r
88 return new Vec3( vector3.x, vector3.y * x - vector3.z * y, vector3.y * y + vector3.z * x );
\r
92 Get Vec3 rotated around Y axis from counterclockwise angle and vector.
\r
94 @param angle counterclockwise angle from 1, 0
\r
95 @param vector3 Vec3 whose rotation will be returned
\r
96 @return vector3 rotated around Y axis
\r
99 Vec3 getRoundYAxis( double angle, Vec3 vector3 )
\r
101 x = Math.cos( angle );
\r
102 y = Math.sin( angle );
\r
104 return new Vec3( vector3.x * x - vector3.z * y, vector3.y, vector3.x * y + vector3.z * x );
\r
108 Get Vec3 rotated around Z axis from counterclockwise angle and vector.
\r
110 @param angle counterclockwise angle from 1, 0
\r
111 @param vector3 Vec3 whose rotation will be returned
\r
112 @return vector3 rotated around Z axis
\r
115 Vec3 getRoundZAxis( double angle, Vec3 vector3 )
\r
117 x = Math.cos( angle );
\r
118 y = Math.sin( angle );
\r
120 return new Vec3( vector3.x * x - vector3.y * y, vector3.x * y + vector3.y * x, vector3.z );
\r
124 Output the curves and/or meshes.
\r
127 void outputCurvesMeshes( ObjectInfo[] objectInfoArray )
\r
129 if ( objectInfoArray.length < 1 ) {
\r
133 for ( int objectIndex = 0; objectIndex < objectInfoArray.length; objectIndex++ ) {
\r
134 objectInfo = objectInfoArray[ objectIndex ];
\r
136 if ( objectInfoArray.length > 1 && exportSelectionCheckbox.getState() ) {
\r
138 if ( bufferedWriter != null ) {
\r
139 //Close the output stream
\r
140 bufferedWriter.close();
\r
141 bufferedWriter = null;
\r
145 parentFile = new File( gnuSurfaceFilenameTextField.getText() ).getParentFile();
\r
147 if ( parentFile != null ) {
\r
148 file = new File( parentFile, objectInfo.name + ".gts" );
\r
151 if ( file != null ) {
\r
152 bufferedWriter = new BufferedWriter( new FileWriter( file ) );
\r
156 if ( file != null && bufferedWriter != null ) {
\r
157 print( objectInfo.name + " is being saved as the GNU Triangulated Surface file " + file.getAbsolutePath() );
\r
160 outputCurveMesh( objectInfo );
\r
162 if ( bufferedWriter != null ) {
\r
163 //Close the output stream
\r
164 bufferedWriter.close();
\r
165 bufferedWriter = null;
\r
171 Output the curve and/or mesh.
\r
172 Quoted from http://gts.sourceforge.net/reference/gts-surfaces.html#GTS-SURFACE-WRITE
\r
173 "All the lines beginning with GTS_COMMENTS (#!) are ignored. The first line contains three unsigned integers separated by spaces. The first integer is the number of vertices, nv, the second is the number of edges, ne and the third is the number of faces, nf.
\r
175 Follows nv lines containing the x, y and z coordinates of the vertices. Follows ne lines containing the two indices (starting from one) of the vertices of each edge. Follows nf lines containing the three ordered indices (also starting from one) of the edges of each face.
\r
177 The format described above is the least common denominator to all GTS files. Consistent with an object-oriented approach, the GTS file format is extensible. Each of the lines of the file can be extended with user-specific attributes accessible through the read() and write() virtual methods of each of the objects written (surface, vertices, edges or faces). When read with different object classes, these extra attributes are just ignored."
\r
180 void outputCurveMesh( ObjectInfo objectInfo )
\r
182 triangleMesh = objectInfo.object;
\r
183 edges = triangleMesh.getEdges();
\r
184 faces = triangleMesh.getFaces();
\r
185 vertexPositions = triangleMesh.getVertexPositions();
\r
186 origin = objectInfo.coords.getOrigin();
\r
187 orientation = objectInfo.coords.getRotationAngles();
\r
188 orientationXRadians = orientation[ 0 ] * Math.PI / 180.0;
\r
189 orientationYRadians = orientation[ 1 ] * Math.PI / 180.0;
\r
190 orientationZRadians = orientation[ 2 ] * Math.PI / 180.0;
\r
191 outputString( vertexPositions.length + " " + edges.length + " " + faces.length + " Number of Vertices, Number of Edges, Number of Faces" );
\r
193 for ( int vertexIndex = 0; vertexIndex < vertexPositions.length; vertexIndex++ ) {
\r
194 vertexPosition = vertexPositions[ vertexIndex ];
\r
195 vertexPosition = getRoundZAxis( - orientationZRadians, vertexPosition );
\r
196 vertexPosition = getRoundXAxis( - orientationXRadians, vertexPosition );
\r
197 vertexPosition = getRoundYAxis( orientationYRadians, vertexPosition );
\r
198 vertexPosition.add( origin );
\r
199 vertexLine = vertexPosition.x.toString() + " " + vertexPosition.y.toString() + " " + vertexPosition.z.toString();
\r
201 if ( vertexIndex == 0 ) {
\r
202 vertexLine += " Vertex Coordinates XYZ";
\r
205 outputString( vertexLine );
\r
208 for ( int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++ ) {
\r
209 edge = edges[ edgeIndex ];
\r
210 edgeLine = getPlusOneToString( edge.v1 ) + " " + getPlusOneToString( edge.v2 );
\r
212 if ( edgeIndex == 0 ) {
\r
213 edgeLine += " Edge Vertex Indices Starting from 1";
\r
216 outputString( edgeLine );
\r
219 for ( int faceIndex = 0; faceIndex < faces.length; faceIndex++ ) {
\r
220 face = faces[ faceIndex ];
\r
221 int[] edgeTriple = { face.e1, face.e2, face.e3 };
\r
223 faceLine = getEdgeString( edges, edgeTriple, face.v1, face.v2 ) + " " + getEdgeString( edges, edgeTriple, face.v2, face.v3 ) + " " + getEdgeString( edges, edgeTriple, face.v3, face.v1 );
\r
225 if ( faceIndex == 0 ) {
\r
226 faceLine += " Face Edge Indices Starting from 1";
\r
229 outputString( faceLine );
\r
234 Output comma separated strings followed by a linefeed.
\r
237 void outputString( string )
\r
239 if ( printSelectionCheckbox.getState() ) {
\r
243 if ( bufferedWriter != null ) {
\r
244 bufferedWriter.write( string.replace( ", ", "," ) + "\n" );
\r
249 Add radio button groups to the preference widgets.
\r
251 @param radioButtonGroups radio button groups which will be added to the memorable widgets
\r
252 @param widgetVector memorable widgets
\r
255 void preferencesAddRadioButtonGroups( RadioButtonGroup[] radioButtonGroups, Vector widgetVector )
\r
257 for ( int radioIndex = 0; radioIndex < radioButtonGroups.length; radioIndex++ ) {
\r
258 radioButtonGroup = radioButtonGroups[ radioIndex ];
\r
259 radioButtonGroupIterator = radioButtonGroup.getRadioButtons();
\r
261 while ( radioButtonGroupIterator.hasNext() ) {
\r
262 radioButton = radioButtonGroupIterator.next();
\r
263 preferencesAddWidgetWithString( radioButton, radioButton.getText(), widgetVector );
\r
269 Add widgets which have titles.
\r
271 @param widgets widgets which have titles
\r
272 @param widgetStrings widget titles
\r
273 @param widgetVector memorable widgets
\r
276 void preferencesAddWidgetsWithStrings( Widget[] widgets, String[] widgetStrings, Vector widgetVector )
\r
278 for ( int widgetIndex = 0; widgetIndex < widgets.length; widgetIndex++ ) {
\r
279 widget = widgets[ widgetIndex ];
\r
281 if ( widget instanceof BCheckBox || widget instanceof BOutline || widget instanceof BTextField || widget instanceof ValueField ) {
\r
282 preferencesAddWidgetWithString( widget, widgetStrings[ widgetIndex ], widgetVector );
\r
288 Give the widget a name and add it to the widget vector.
\r
290 @param widget widget which will be given a name
\r
291 @param widgetStrings widget name
\r
292 @param widgetVector memorable widgets
\r
295 void preferencesAddWidgetWithString( Widget widget, String widgetString, Vector widgetVector )
\r
297 widget.setName( widgetString );
\r
298 widgetVector.add( widget );
\r
302 Read widget settings from preferences file.
\r
304 @param preferencesFilename preferences filename
\r
305 @param widgetVector memorable widgets
\r
308 void preferencesRead( String preferencesFilename, Vector widgetVector )
\r
310 preferencesFile = new File( preferencesFilename );
\r
312 if ( !preferencesFile.canRead() ) {
\r
316 BufferedReader preferencesReader = new BufferedReader( new FileReader( preferencesFile ) );
\r
318 line = preferencesReader.readLine();
\r
320 while ( line != null ) {
\r
321 preferencesReadLine( line, widgetVector );
\r
322 line = preferencesReader.readLine();
\r
327 Read line of preferences and set widget to that line.
\r
329 @param line line of preferences
\r
330 @param widgetVector memorable widgets
\r
333 void preferencesReadLine( String line, Vector widgetVector )
\r
335 splitLine = line.split( "\t" );
\r
337 if ( splitLine.length < 2 ) {
\r
341 name = splitLine[ 0 ];
\r
343 for ( int widgetIndex = 0; widgetIndex < widgetVector.size(); widgetIndex++ ) {
\r
344 widget = widgetVector.elementAt( widgetIndex );
\r
346 if ( widget.getName().equals( name ) ) {
\r
347 preferencesReadWidget( splitLine[ 1 ], widget );
\r
355 Set widget to preferences value.
\r
357 @param value preferences value
\r
358 @param widget widget to be set to value
\r
361 void preferencesReadWidget( String value, Widget widget )
\r
363 if ( widget instanceof BCheckBox || widget instanceof BRadioButton ) {
\r
364 widget.setState( Boolean.valueOf( value ) );
\r
369 if ( widget instanceof BOutline ) { // it would be better to save the value instead of index because the list might change, but I'm lazy
\r
370 bList = widget.getContent().getContent();
\r
371 selectedIndex = Integer.valueOf( value );
\r
372 bList.setSelected( selectedIndex, true );
\r
373 bList.scrollToItem( selectedIndex );
\r
378 if ( widget instanceof BTextField ) {
\r
379 widget.setText( value );
\r
384 if ( widget instanceof ValueField ) {
\r
385 widget.setValue( Double.valueOf( value ) );
\r
390 Write widget settings to preferences file.
\r
392 @param preferencesFilename preferences filename
\r
393 @param widgetVector memorable widgets
\r
396 void preferencesWrite( String preferencesFilename, Vector widgetVector )
\r
398 preferencesFile = new File( preferencesFilename );
\r
400 if ( preferencesFile == null ) {
\r
401 print( "Can not write preferences to " + preferencesFilename );
\r
406 BufferedWriter preferencesWriter = new BufferedWriter( new FileWriter( preferencesFile ) );
\r
408 for ( int widgetIndex = 0; widgetIndex < widgetVector.size(); widgetIndex++ ) {
\r
409 widget = widgetVector.elementAt( widgetIndex );
\r
410 preferencesWriteWidget( preferencesWriter, widget );
\r
413 //Close the output stream
\r
414 preferencesWriter.close();
\r
418 Write widget settings to line of preferences.
\r
420 @param preferencesWriter buffered preferences file writer
\r
421 @param widget widget to be written
\r
424 void preferencesWriteWidget( BufferedWriter preferencesWriter, Widget widget )
\r
426 widgetString = widget.getName() + "\t";
\r
428 if ( widget instanceof BCheckBox || widget instanceof BRadioButton ) {
\r
429 preferencesWriter.write( widgetString + widget.getState().toString() + "\n" );
\r
434 if ( widget instanceof BOutline ) { // it would be better to save the value because the list might change, but I'm lazy
\r
435 BList bList = widget.getContent().getContent();
\r
436 bList = widget.getContent().getContent();
\r
437 preferencesWriter.write( widgetString + bList.getSelectedIndex().toString() + "\n" );
\r
442 if ( widget instanceof BTextField ) {
\r
443 preferencesWriter.write( widgetString + widget.getText() + "\n" );
\r
448 if ( widget instanceof ValueField ) {
\r
449 preferencesWriter.write( widgetString + widget.getValue().toString() + "\n" );
\r
453 // Set default parameters.
\r
454 bufferedWriter = null;
\r
455 exportSelectionCheckbox = new BCheckBox( "", false );
\r
457 gnuSurfaceFilenameTextField = new BTextField( "triangle_mesh.gts" );
\r
458 String preferencesFilename = "gnu_triangulated_surface_preferences.csv";
\r
459 printSelectionCheckbox = new BCheckBox( "", true );
\r
461 Widget[] widgets = new Widget[] { exportSelectionCheckbox,
\r
462 printSelectionCheckbox };
\r
464 String[] widgetStrings = new String[] { "Export Selection:",
\r
465 "Print Selection:" };
\r
467 // change the user interface parameters from default to preferences
\r
468 Vector widgetVector = new Vector();
\r
469 preferencesAddWidgetsWithStrings( widgets, widgetStrings, widgetVector );
\r
470 preferencesAddWidgetWithString( gnuSurfaceFilenameTextField, "GNU Triangulated Surface Filename:", widgetVector );
\r
471 preferencesRead( preferencesFilename, widgetVector );
\r
473 curvesMeshesInfo = getCurvesMeshesInfo();
\r
475 if ( curvesMeshesInfo.length < 1 ) {
\r
476 print( "There is no triangle mesh in the scene, so nothing will be done." );
\r
477 print( "It may be that there is a solid shape which is not a triangle mesh, in which case convert that shape to a triangle mesh." );
\r
482 dialog = new ComponentsDialog( window, "Export and/or Print Selection", widgets, widgetStrings );
\r
484 if ( !dialog.clickedOk() ) return;
\r
486 if ( exportSelectionCheckbox.getState() ) {
\r
487 fileDescriptor = new BFileChooser( BFileChooser.SAVE_FILE, "Select name for the GNU Triangulated Surface file.");
\r
488 fileDescriptor.setSelectedFile( new File( gnuSurfaceFilenameTextField.getText() ) );
\r
489 fileDescriptor.showDialog( window );
\r
490 file = fileDescriptor.getSelectedFile();
\r
492 if ( file != null ) {
\r
493 gnuSurfaceFilenameTextField.setText( file.getAbsolutePath() );
\r
494 bufferedWriter = new BufferedWriter( new FileWriter( file ) );
\r
498 preferencesWrite( preferencesFilename, widgetVector );
\r
499 outputCurvesMeshes( curvesMeshesInfo );
\r