checkpoint
[anneal.git] / src / edu / berkeley / qfat / StlFile.java
1 package edu.berkeley.qfat;
2 import com.sun.j3d.loaders.Loader;
3 import com.sun.j3d.loaders.Scene;
4 import com.sun.j3d.loaders.SceneBase;
5 import com.sun.j3d.loaders.IncorrectFormatException;
6 import com.sun.j3d.loaders.ParsingErrorException;
7 import com.sun.j3d.utils.geometry.GeometryInfo;
8
9 import java.net.URL;
10 import java.net.MalformedURLException;
11
12 import java.io.Reader;
13 import java.io.BufferedReader;
14 import java.io.FileReader;
15 import java.io.InputStreamReader;
16 import java.io.FileInputStream;
17 import java.io.FileNotFoundException;
18 import java.io.IOException;
19
20 import java.util.StringTokenizer;
21 import java.util.ArrayList;
22
23 import javax.vecmath.Point3f;
24 import javax.vecmath.Vector3f;
25
26 import javax.media.j3d.BranchGroup;
27 import javax.media.j3d.Shape3D;
28
29 // New from JDK 1.4 for endian related problems
30 import java.nio.ByteOrder;
31 import java.nio.ByteBuffer;
32
33
34
35 /**
36  * Title:         STL Loader
37  * Description:   STL files loader (Supports ASCII and binary files) for Java3D
38  *                Needs JDK 1.4 due to endian problems
39  * Company:       Universidad del Pais Vasco (UPV/EHU)
40  * @author:       Carlos Pedrinaci Godoy
41  * @version:      1.0
42  *
43  * Contact : xenicp@yahoo.es
44  *
45  *
46  * Things TO-DO:
47  *    1.-We can't read binary files over the net.
48  *    2.-For binary files if size is lower than expected (calculated with the number of faces)
49  *    the program will block.
50  *    3.-Improve the way for detecting the kind of stl file?
51  *    Can give us problems if the comment of the binary file begins by "solid"
52  */
53
54 public class StlFile implements Loader
55 {
56   private static final int DEBUG = 0;     // Sets mode to Debug: outputs every action done
57
58   // Maximum length (in chars) of basePath
59   private static final int MAX_PATH_LENGTH = 1024;
60
61   // Global variables
62   private int flag;                         // Needed cause implements Loader
63
64   private URL baseUrl = null;               // Reading files over Internet
65   private String basePath = null;           // For local files
66
67   private boolean fromUrl = false;          // Usefull for binary files
68   private boolean Ascii = true;             // File type Ascii -> true o binary -> false
69   private String fileName = null;
70
71   // Arrays with coordinates and normals
72   // Needed for reading ASCII files because its size is unknown until the end
73   private ArrayList coordList;          // Holds Point3f
74   private ArrayList normList;           // Holds Vector3f
75
76   // GeometryInfo needs Arrays
77     public Point3f[] coordArray = null;
78     public Vector3f[] normArray = null;
79
80   // Needed because TRIANGLE_STRIP_ARRAY
81   // As the number of strips = the number of faces it's filled in objectToVectorArray
82     public int[] stripCounts = null;
83
84   // Default = Not available
85   private String objectName=new String("Not available");
86
87   /**
88   *  Constructor
89   */
90   public StlFile()
91   {
92   }
93
94   /**
95    * Method that reads the EOL
96    * Needed for verifying that the file has a correct format
97    *
98    * @param parser The file parser. An instance of StlFileParser.
99    */
100   private void readEOL(StlFileParser parser)
101   {
102     try{
103     parser.nextToken();
104     }
105     catch (IOException e)
106     {
107       System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
108     }
109     if(parser.ttype != StlFileParser.TT_EOL)
110     {
111       System.err.println("Format Error:expecting End Of Line on line " + parser.lineno());
112     }
113   }
114
115   /**
116    * Method that reads the word "solid" and stores the object name.
117    * It also detects what kind of file it is
118    * TO-DO:
119    *    1.- Better way control of exceptions?
120    *    2.- Better way to decide between Ascii and Binary?
121    *
122    * @param parser The file parser. An instance of StlFileParser.
123    */
124   private void readSolid(StlFileParser parser)
125   {
126     if( !parser.sval.equals("solid"))
127     {
128       //System.out.println("Expecting solid on line " + parser.lineno());
129       // If the first word is not "solid" then we consider the file is binary
130       // Can give us problems if the comment of the binary file begins by "solid"
131       this.setAscii(false);
132     }
133     else  // It's an ASCII file
134     {
135       try{
136           parser.nextToken();
137           }
138       catch (IOException e)
139       {
140         System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
141       }
142       if( parser.ttype != StlFileParser.TT_WORD)
143       {
144         // Is the object name always provided???
145         System.err.println("Format Error:expecting the object name on line " + parser.lineno());
146       }
147       else
148       { // Store the object Name
149         this.setObjectName(new String(parser.sval));
150         if(DEBUG==1)
151         {
152           System.out.println("Object Name:" + this.getObjectName().toString());
153         }
154         this.readEOL(parser);
155       }
156     }
157   }//End of readSolid
158
159   /**
160    * Method that reads a normal
161    *
162    * @param parser The file parser. An instance of StlFileParser.
163    */
164   private void readNormal(StlFileParser parser)
165   {
166     Vector3f v = new Vector3f();
167
168     if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("normal")))
169     {
170       System.err.println("Format Error:expecting 'normal' on line " + parser.lineno());
171     }
172     else
173     {
174       if (parser.getNumber())
175       {
176         v.x=(float)parser.nval;
177
178         if(DEBUG==1)
179         {
180           System.out.println("Normal:");
181           System.out.print("X=" + v.x + " ");
182         }
183
184         if (parser.getNumber())
185         {
186           v.y=(float)parser.nval;
187           if(DEBUG==1)
188             System.out.print("Y=" + v.y + " ");
189
190           if (parser.getNumber())
191           {
192             v.z=(float)parser.nval;
193             if(DEBUG==1)
194               System.out.println("Z=" + v.z);
195
196             // We add that vector to the Normal's array
197             this.normList.add(v);
198             this.readEOL(parser);
199           }
200           else System.err.println("Format Error:expecting coordinate on line " + parser.lineno());
201         }
202         else System.err.println("Format Error:expecting coordinate on line " + parser.lineno());
203       }
204       else System.err.println("Format Error:expecting coordinate on line " + parser.lineno());
205     }
206   }// End of Read Normal
207
208   /**
209    * Method that reads the coordinates of a vector
210    *
211    * @param parser The file parser. An instance of StlFileParser.
212    */
213   private void readVertex(StlFileParser parser)
214   {
215     Point3f p = new Point3f();
216
217     if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("vertex")))
218     {
219       System.err.println("Format Error:expecting 'vertex' on line " + parser.lineno());
220     }
221     else
222     {
223       if (parser.getNumber())
224       {
225         p.x=(float)parser.nval;
226
227         if(DEBUG==1)
228         {
229           System.out.println("Vertex:");
230           System.out.print("X=" + p.x + " ");
231         }
232
233         if (parser.getNumber())
234         {
235           p.y=(float)parser.nval;
236           if(DEBUG==1)
237             System.out.print("Y=" + p.y + " ");
238
239           if (parser.getNumber())
240           {
241             p.z=(float)parser.nval;
242             if(DEBUG==1)
243               System.out.println("Z=" + p.z);
244
245             // We add that vertex to the array of vertex
246             coordList.add(p);
247             readEOL(parser);
248           }
249           else System.err.println("Format Error: expecting coordinate on line " + parser.lineno());
250         }
251         else System.err.println("Format Error: expecting coordinate on line " + parser.lineno());
252       }
253       else System.err.println("Format Error: expecting coordinate on line " + parser.lineno());
254     }
255   }//End of read vertex
256
257   /**
258    * Method that reads "outer loop" and then EOL
259    *
260    * @param parser The file parser. An instance of StlFileParser.
261    */
262   private void readLoop(StlFileParser parser)
263   {
264     if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("outer")))
265     {
266       System.err.println("Format Error:expecting 'outer' on line " + parser.lineno());
267     }
268     else
269     {
270       try{
271           parser.nextToken();
272           }
273       catch (IOException e)
274       {
275         System.err.println("IO error on line " + parser.lineno() + ": " + e.getMessage());
276       }
277       if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("loop")))
278       {
279         System.err.println("Format Error:expecting 'loop' on line " + parser.lineno());
280       }
281       else readEOL(parser);
282     }
283   }//End of readLoop
284
285   /**
286    * Method that reads "endloop" then EOL
287    *
288    * @param parser The file parser. An instance of StlFileParser.
289    */
290   private void readEndLoop(StlFileParser parser)
291   {
292     if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("endloop")))
293     {
294       System.err.println("Format Error:expecting 'endloop' on line " + parser.lineno());
295     }
296     else readEOL(parser);
297   }//End of readEndLoop
298
299   /**
300    * Method that reads "endfacet" then EOL
301    *
302    * @param parser The file parser. An instance of StlFileParser.
303    */
304   private void readEndFacet(StlFileParser parser)
305   {
306     if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("endfacet")))
307     {
308       System.err.println("Format Error:expecting 'endfacet' on line " + parser.lineno());
309     }
310     else readEOL(parser);
311   }//End of readEndFacet
312
313   /**
314    * Method that reads a face of the object
315    * (Cares about the format)
316    *
317    * @param parser The file parser. An instance of StlFileParser.
318    */
319   private void readFacet(StlFileParser parser)
320   {
321     if(!(parser.ttype==StlFileParser.TT_WORD && parser.sval.equals("facet")))
322     {
323       System.err.println("Format Error:expecting 'facet' on line " + parser.lineno());
324     }
325     else
326     {
327       try{
328           parser.nextToken();
329           readNormal(parser);
330
331           parser.nextToken();
332           readLoop(parser);
333
334           parser.nextToken();
335           readVertex(parser);
336
337           parser.nextToken();
338           readVertex(parser);
339
340           parser.nextToken();
341           readVertex(parser);
342
343           parser.nextToken();
344           readEndLoop(parser);
345
346           parser.nextToken();
347           readEndFacet(parser);
348       }
349       catch (IOException e)
350       {
351         System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
352       }
353     }
354   }// End of readFacet
355
356   /**
357    * Method that reads a face in binary files
358    * All binary versions of the methods end by 'B'
359    * As in binary files we can read the number of faces, we don't need
360    * to use coordArray and normArray (reading binary files should be faster)
361    *
362    * @param in The ByteBuffer with the data of the object.
363    * @param index The facet index
364    *
365    * @throws IOException
366    */
367   private void readFacetB(ByteBuffer in, int index) throws IOException
368   {
369     //File structure: Normal Vertex1 Vertex2 Vertex3
370     Vector3f normal = new Vector3f();
371     Point3f vertex = new Point3f();
372
373     if(DEBUG==1)
374       System.out.println("Reading face number " + index);
375
376     // Read the Normal
377     normArray[index]=new Vector3f();
378     normArray[index].x=in.getFloat();
379     normArray[index].y=in.getFloat();
380     normArray[index].z=in.getFloat();
381
382     if(DEBUG==1)
383       System.out.println("Normal: X=" + normArray[index].x + " Y=" + normArray[index].y + " Z=" + normArray[index].z);
384
385     // Read vertex1
386     coordArray[index*3] = new Point3f();
387     coordArray[index*3].x=in.getFloat();
388     coordArray[index*3].y=in.getFloat();
389     coordArray[index*3].z=in.getFloat();
390
391     if(DEBUG==1)
392       System.out.println("Vertex 1: X=" + coordArray[index*3].x + " Y=" + coordArray[index*3].y + " Z=" + coordArray[index*3].z);
393
394     // Read vertex2
395     coordArray[index*3+1] = new Point3f();
396     coordArray[index*3+1].x=in.getFloat();
397     coordArray[index*3+1].y=in.getFloat();
398     coordArray[index*3+1].z=in.getFloat();
399
400     if(DEBUG==1)
401       System.out.println("Vertex 2: X=" + coordArray[index*3+1].x + " Y=" + coordArray[index*3+1].y + " Z=" + coordArray[index*3+1].z);
402
403     // Read vertex3
404     coordArray[index*3+2] = new Point3f();
405     coordArray[index*3+2].x=in.getFloat();
406     coordArray[index*3+2].y=in.getFloat();
407     coordArray[index*3+2].z=in.getFloat();
408
409     if(DEBUG==1)
410       System.out.println("Vertex 3: X=" + coordArray[index*3+2].x + " Y=" + coordArray[index*3+2].y + " Z=" + coordArray[index*3+2].z);
411
412   }// End of readFacetB
413
414   /**
415    * Method for reading binary files
416    * Execution is completly different
417    * It uses ByteBuffer for reading data and ByteOrder for retrieving the machine's endian
418    * (Needs JDK 1.4)
419    *
420    * TO-DO:
421    *  1.-Be able to read files over Internet
422    *  2.-If the amount of data expected is bigger than what is on the file then
423    *  the program will block forever
424    *
425    * @param file The name of the file
426    *
427    * @throws IOException
428    */
429   private void readBinaryFile(String file) throws IOException
430   {
431     FileInputStream data;                 // For reading the file
432     ByteBuffer dataBuffer;                // For reading in the correct endian
433     byte[] Info=new byte[80];             // Header data
434     byte[] Array_number= new byte[4];     // Holds the number of faces
435     byte[] Temp_Info;                     // Intermediate array
436
437     int Number_faces; // First info (after the header) on the file
438
439     if(DEBUG==1)
440       System.out.println("Machine's endian: " + ByteOrder.nativeOrder());
441
442     // Get file's name
443     if(fromUrl)
444     {
445       // FileInputStream can only read local files!?
446       System.out.println("This version doesn't support reading binary files from internet");
447     }
448     else
449     { // It's a local file
450       data = new FileInputStream(file);
451
452       // First 80 bytes aren't important
453       if(80 != data.read(Info))
454       { // File is incorrect
455         //System.out.println("Format Error: 80 bytes expected");
456         throw new IncorrectFormatException();
457       }
458       else
459       { // We must first read the number of faces -> 4 bytes int
460         // It depends on the endian so..
461
462         data.read(Array_number);                      // We get the 4 bytes
463         dataBuffer = ByteBuffer.wrap(Array_number);   // ByteBuffer for reading correctly the int
464         dataBuffer.order(ByteOrder.nativeOrder());    // Set the right order
465         Number_faces = dataBuffer.getInt();
466
467         Temp_Info = new byte[50*Number_faces];        // Each face has 50 bytes of data
468
469         data.read(Temp_Info);                         // We get the rest of the file
470
471         dataBuffer = ByteBuffer.wrap(Temp_Info);      // Now we have all the data in this ByteBuffer
472         dataBuffer.order(ByteOrder.nativeOrder());
473
474         if(DEBUG==1)
475           System.out.println("Number of faces= " + Number_faces);
476
477         // We can create that array directly as we know how big it's going to be
478         coordArray = new Point3f[Number_faces*3]; // Each face has 3 vertex
479         normArray = new Vector3f[Number_faces];
480         stripCounts = new int[Number_faces];
481
482         for(int i=0;i<Number_faces;i++)
483         {
484           stripCounts[i]=3;
485           try
486           {
487             readFacetB(dataBuffer,i);
488             // After each facet there are 2 bytes without information
489             // In the last iteration we dont have to skip those bytes..
490             if(i != Number_faces - 1)
491             {
492               dataBuffer.get();
493               dataBuffer.get();
494             }
495           }
496           catch (IOException e)
497           {
498             // Quitar
499             System.out.println("Format Error: iteration number " + i);
500             throw new IncorrectFormatException();
501           }
502         }//End for
503       }// End file reading
504     }// End else
505   }// End of readBinaryFile
506
507   /**
508    * Method that reads ASCII files
509    * Uses StlFileParser for correct reading and format checking
510    * The beggining of that method is common to binary and ASCII files
511    * We try to detect what king of file it is
512    *
513    * TO-DO:
514    *  1.- Find a best way to decide what kind of file it is
515    *  2.- Is that return (first catch) the best thing to do?
516    *
517    * @param parser The file parser. An instance of StlFileParser.
518    */
519   private void readFile(StlFileParser parser)
520   {
521     int t;
522
523     try{
524         parser.nextToken();
525         }
526     catch (IOException e)
527     {
528       System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
529       System.err.println("File seems to be empty");
530       return;         // ????? Throw ?????
531     }
532
533     // Here we try to detect what kind of file it is (see readSolid)
534     readSolid(parser);
535
536     if(getAscii())
537     { // Ascii file
538       try
539       {
540           parser.nextToken();
541       }
542       catch (IOException e)
543       {
544        System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
545       }
546
547       // Read all the facets of the object
548       while (parser.ttype != StlFileParser.TT_EOF && !parser.sval.equals("endsolid"))
549       {
550         readFacet(parser);
551         try
552         {
553           parser.nextToken();
554         }
555         catch (IOException e)
556         {
557           System.err.println("IO Error on line " + parser.lineno() + ": " + e.getMessage());
558         }
559       }// End while
560
561       // Why are we out of the while?: EOF or endsolid
562       if(parser.ttype == StlFileParser.TT_EOF)
563        System.err.println("Format Error:expecting 'endsolid', line " + parser.lineno());
564       else
565       {
566         if(DEBUG==1)
567           System.out.println("File readed");
568       }
569     }//End of Ascii reading
570
571     else
572     { // Binary file
573       try{
574         readBinaryFile(getFileName());
575       }
576       catch(IOException e)
577       {
578         System.err.println("Format Error: reading the binary file");
579       }
580     }// End of binary file
581   }//End of readFile
582
583   /**
584    * The Stl File is loaded from the .stl file specified by
585    * the filename.
586    * To attach the model to your scene, call getSceneGroup() on
587    * the Scene object passed back, and attach the returned
588    * BranchGroup to your scene graph.  For an example, see
589    * $J3D/programs/examples/ObjLoad/ObjLoad.java.
590    *
591    * @param filename The name of the file with the object to load
592    *
593    * @return Scene The scene with the object loaded.
594    *
595    * @throws FileNotFoundException
596    * @throws IncorrectFormatException
597    * @throws ParsingErrorException
598    */
599   public Scene load(String filename) throws FileNotFoundException,
600                                             IncorrectFormatException,
601                                             ParsingErrorException
602   {
603     setBasePathFromFilename(filename);
604     setFileName(filename);     // For binary files
605
606     Reader reader = new BufferedReader(new FileReader(filename));
607     return load(reader);
608   } // End of load(String)
609
610    /**
611    * The Stl file is loaded off of the web.
612    * To attach the model to your scene, call getSceneGroup() on
613    * the Scene object passed back, and attach the returned
614    * BranchGroup to your scene graph.  For an example, see
615    * $J3D/programs/examples/ObjLoad/ObjLoad.java.
616    *
617    * @param url The url to load the onject from
618    *
619    * @return Scene The scene with the object loaded.
620    *
621    * @throws FileNotFoundException
622    * @throws IncorrectFormatException
623    * @throws ParsingErrorException
624    */
625   public Scene load(URL url) throws FileNotFoundException,
626                                     IncorrectFormatException,
627                                     ParsingErrorException
628   {
629     BufferedReader reader;
630
631     setBaseUrlFromUrl(url);
632
633     try {
634       reader = new BufferedReader(new InputStreamReader(url.openStream()));
635     }
636     catch (IOException e) {
637       throw new FileNotFoundException();
638     }
639     fromUrl = true;
640     return load(reader);
641   } // End of load(URL)
642
643   /**
644    * The Stl File is loaded from the already opened file.
645    * To attach the model to your scene, call getSceneGroup() on
646    * the Scene object passed back, and attach the returned
647    * BranchGroup to your scene graph.  For an example, see
648    * $J3D/programs/examples/ObjLoad/ObjLoad.java.
649    *
650    * @param reader The reader to read the object from
651    *
652    * @return Scene The scene with the object loaded.
653    *
654    * @throws FileNotFoundException
655    * @throws IncorrectFormatException
656    * @throws ParsingErrorException
657    */
658   public Scene load(Reader reader) throws FileNotFoundException,
659                                           IncorrectFormatException,
660                                           ParsingErrorException
661   {
662     // That method calls the method that loads the file for real..
663     // Even if the Stl format is not complicated I've decided to use
664     // a parser as in the Obj's loader included in Java3D
665
666     StlFileParser st=new StlFileParser(reader);
667
668     // Initialize data
669     coordList = new ArrayList();
670     normList = new ArrayList();
671     setAscii(true);      // Default ascii
672
673     readFile(st);
674     return makeScene();
675   }
676
677   /**
678    * Method that takes the info from an ArrayList of Point3f
679    * and returns a Point3f[].
680    * Needed for ASCII files as we don't know the number of facets until the end
681    *
682    * @param inList The list to transform into Point3f[]
683    *
684    * @return Point3f[] The result.
685    */
686   private Point3f[] objectToPoint3Array(ArrayList inList)
687   {
688     Point3f outList[] = new Point3f[inList.size()];
689
690     for (int i = 0 ; i < inList.size() ; i++) {
691       outList[i] = (Point3f)inList.get(i);
692     }
693     return outList;
694   } // End of objectToPoint3Array
695
696   /**
697    * Method that takes the info from an ArrayList of Vector3f
698    * and returns a Vector3f[].
699    * Needed for ASCII files as we don't know the number of facets until the end
700    *
701    * TO-DO:
702    *  1.- Here we fill stripCounts...
703    *      Find a better place to do it?
704    *
705    * @param inList The list to transform into Point3f[]
706    *
707    * @return Vector3f[] The result.
708    */
709   private Vector3f[] objectToVectorArray(ArrayList inList)
710   {
711     Vector3f outList[] = new Vector3f[inList.size()];
712
713     if(DEBUG==1)
714       System.out.println("Number of facets of the object=" + inList.size());
715
716     // To-do
717     stripCounts = new int[inList.size()];
718     for (int i = 0 ; i < inList.size() ; i++) {
719       outList[i] = (Vector3f)inList.get(i);
720       // To-do
721       stripCounts[i]=3;
722     }
723     return outList;
724   } // End of objectToVectorArray
725
726   /**
727    * Method that creates the SceneBase with the stl file info
728    *
729    * @return SceneBase The scene
730    */
731   private SceneBase makeScene()
732   {
733     // Create Scene to pass back
734     SceneBase scene = new SceneBase();
735     BranchGroup group = new BranchGroup();
736     scene.setSceneGroup(group);
737
738     // Store the scene info on a GeometryInfo
739     GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_STRIP_ARRAY);
740
741     // Convert ArrayLists to arrays: only needed if file was not binary
742     if(this.Ascii)
743     {
744       coordArray = objectToPoint3Array(coordList);
745       normArray = objectToVectorArray(normList);
746     }
747
748     gi.setCoordinates(coordArray);
749     gi.setNormals(normArray);
750     gi.setStripCounts(stripCounts);
751
752     // Put geometry into Shape3d
753     Shape3D shape = new Shape3D();
754     shape.setGeometry(gi.getGeometryArray());
755
756     group.addChild(shape);
757     scene.addNamedObject(objectName, shape);
758
759     return scene;
760   } // end of makeScene
761
762   /////////////////////// Accessors and Modifiers ///////////////////////////
763
764   public URL getBaseUrl()
765   {
766     return baseUrl;
767   }
768
769   /**
770    * Modifier for baseUrl, if accessing internet.
771    *
772    * @param url The new url
773    */
774   public void setBaseUrl(URL url)
775   {
776     baseUrl = url;
777   }
778
779   private void setBaseUrlFromUrl(URL url)
780   {
781     StringTokenizer stok =
782       new StringTokenizer(url.toString(), "/\\", true);
783     int tocount = stok.countTokens() - 1;
784     StringBuffer sb = new StringBuffer(MAX_PATH_LENGTH);
785     for(int i = 0; i < tocount ; i++) {
786         String a = stok.nextToken();
787         sb.append(a);
788 //      if((i == 0) && (!a.equals("file:"))) {
789 //          sb.append(a);
790 //          sb.append(java.io.File.separator);
791 //          sb.append(java.io.File.separator);
792 //      } else {
793 //          sb.append(a);
794 //          sb.append( java.io.File.separator );
795 //      }
796     }
797     try {
798       baseUrl = new URL(sb.toString());
799     }
800     catch (MalformedURLException e) {
801       System.err.println("Error setting base URL: " + e.getMessage());
802     }
803   } // End of setBaseUrlFromUrl
804
805
806   public String getBasePath()
807   {
808     return basePath;
809   }
810
811   /**
812    * Set the path where files associated with this .stl file are
813    * located.
814    * Only needs to be called to set it to a different directory
815    * from that containing the .stl file.
816    *
817    * @param pathName The new Path to the file
818    */
819   public void setBasePath(String pathName)
820   {
821     basePath = pathName;
822     if (basePath == null || basePath == "")
823         basePath = "." + java.io.File.separator;
824     basePath = basePath.replace('/', java.io.File.separatorChar);
825     basePath = basePath.replace('\\', java.io.File.separatorChar);
826     if (!basePath.endsWith(java.io.File.separator))
827         basePath = basePath + java.io.File.separator;
828   } // End of setBasePath
829
830   /*
831    * Takes a file name and sets the base path to the directory
832    * containing that file.
833    */
834   private void setBasePathFromFilename(String fileName)
835   {
836     // Get ready to parse the file name
837     StringTokenizer stok =
838       new StringTokenizer(fileName, java.io.File.separator);
839
840     //  Get memory in which to put the path
841     StringBuffer sb = new StringBuffer(MAX_PATH_LENGTH);
842
843     // Check for initial slash
844     if (fileName!= null && fileName.startsWith(java.io.File.separator))
845       sb.append(java.io.File.separator);
846
847     // Copy everything into path except the file name
848     for(int i = stok.countTokens() - 1 ; i > 0 ; i--) {
849       String a = stok.nextToken();
850       sb.append(a);
851       sb.append(java.io.File.separator);
852     }
853     setBasePath(sb.toString());
854   } // End of setBasePathFromFilename
855
856   public int getFlags()
857   {
858     return flag;
859   }
860
861   public void setFlags(int parm)
862   {
863     this.flag=parm;
864   }
865
866   public boolean getAscii()
867   {
868     return this.Ascii;
869   }
870
871   public void setAscii(boolean tipo)
872   {
873     this.Ascii = tipo;
874   }
875
876
877   public String getFileName()
878   {
879     return this.fileName;
880   }
881
882   public void setFileName(String filename)
883   {
884     this.fileName=new String(filename);
885   }
886
887
888   public String getObjectName()
889   {
890     return this.objectName;
891   }
892
893   public void setObjectName(String name)
894   {
895     this.objectName = name;
896   }
897
898 } // End of package stl_loader