1    /* Copyright (C) 2002 Martin Green
2     *
3     * This program is free software; you can redistribute it and/or modify
4     * it under the terms of the GNU General Public License as published by
5     * the Free Software Foundation; either version 2 of the License, or
6     * (at your option) any later version.
7     *
8     * This program is distributed in the hope that it will be useful,
9     * but WITHOUT ANY WARRANTY; without even the implied warranty of
10    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    * GNU General Public License for more details.
12    *
13    * You should have received a copy of the GNU General Public License
14    * along with this program; if not, write to the Free Software
15    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16    */
17   
18   import java.io.*;
19   import java.util.Vector;
20   
21   public class Reader3d {
22   
23     public Input3d Reader3d(FileInputStream in) throws IOException {
24       int c;//used to read bytes from file
25       String surveytitle = new String();
26       String timestamp = new String();
27       String currentlabelbuffer = new String();
28       long[] coord= new long[3];
29       Vector stations = new Vector(20);
30       Vector legs = new Vector(20);
31       Vector names = new Vector(20);
32       SurvexSurvey survey = new SurvexSurvey(); 
33       Name previousname = new Name();
34       Reader3d reader3d = new Reader3d();
35   
36   
37       //Read in header
38       //Read in FileID
39       String fileidstring = new String();
40       while ((c = in.read()) != 10)
41         fileidstring =fileidstring +((char) c);
42       if(!fileidstring.equals("Survex 3D Image File"))
43         {
44           ErrorLog.log("File does not appear to be a Survex 3d file");
45         }
46       //check that the version number is 3
47       String fileverstring = new String();
48       while ((c = in.read()) != 10)
49         fileverstring =fileverstring +((char) c);
50       if(!fileverstring.equals("v3"))
51         {
52           ErrorLog.log("Survex version number should be 'v3' but is '"+fileverstring+"'");
53         }
54       //Read in survey title
55       while ((c = in.read()) != 10) surveytitle=surveytitle+((char) c);
56   //        	System.out.println("Survey Title = "+surveytitle);
57       //Read in time stamp
58       while ((c = in.read()) != 10) timestamp=timestamp+((char) c);
59   //        	System.out.println("Time Stamp = "+timestamp);
60       //Header finished
61       
62           	
63       //Read in Items
64       while (!(((c = in.read()) == 0)&&(currentlabelbuffer.equals(""))))
65         {
66           //System.out.println(c);
67           //0x00 : if the current label is empty, signifies the end of the data in the 3d file; 
68           //       if the current label isn't empty, make it empty. 
69           if (c==0) 
70             {
71               currentlabelbuffer="";
72               //System.out.println("0 - clear current label buffer");
73             }
74           
75           //0x01-0x0e : trim the last 17 characters of the current label, 
76           //then trim back N-1 (i.e. 0-13) dots ("."), removing "." and everything after it. 
77           //It's incorrect if the label ends up empty, or you attempt to trim more label than there is. 
78           else if (c<=0x0e) 
79             {
80               currentlabelbuffer=currentlabelbuffer.substring(0,(currentlabelbuffer.length()-17));
81               //System.out.println("Removed 17 chars " + currentlabelbuffer);
82               for(int i=0;i<c;i++)
83                 currentlabelbuffer=currentlabelbuffer.substring(0,currentlabelbuffer.lastIndexOf("."));
84               currentlabelbuffer=currentlabelbuffer+".";
85               //System.out.println(c+" - remove 17 chars + " + c +".s, leaving "+currentlabelbuffer);
86             }
87           //0x0f <x coord> <y coord> <z coord> : set current position to the coordinates given. 
88           //Coordinates are 4 bytes little-endian signed integers 
89           //representing values in centimetres (0.01 metres). 
90           else if (c==0x0f) 
91             {
92               //System.out.print("15 - set position to (");
93               for(int j=0;j<3;j++)
94                 {
95           	coord[j] = reader3d.read4byytelittleendian(in);
96           	//System.out.print(coord[j]+" ");
97           	previousname.coord[j]= coord[j];
98                 }
99               //System.out.println(")");
100            }
101          //0x10-0x1f : remove N-15 (i.e. 1-16) characters from the current label. 
102          //It's incorrect if the label ends up empty, or you attempt to trim more label than there is. 
103          else if (c<=0x1f)
104            {
105              currentlabelbuffer=currentlabelbuffer.substring(0,(currentlabelbuffer.length()-c+0x0f));
106              //System.out.println(c+" - remove "+ (c-15) +" charachters, leaving "+currentlabelbuffer);
107            }
108          //0x20-0x3f reserved
109          else if (c<=0x3f)
110            {
111              ErrorLog.log("Survex format error\nValue"+c+"is reserved");
112  //        			System.out.println(c+" - This values is reserved");
113            }
114          
115          /*0x40-0x5f <length> <label> <x coord> <y coord> <z coord> : station flags are (N & 0x1f): 
116            0x01 : Station is on an above ground leg 
117            0x02 : Station is on an underground leg (both may be true at an entrance) 
118            0x04 : Station is marked as an entrance (with *entrance) 
119            0x08 : Station is exported (i.e. may be used as a connection point to other surveys) 
120            0x10 : Station is a fixed point (control point) 
121            Append label to the current label buffer. 
122            Return station at the coordinates given, 
123            and update current position to coordinates given (FIXME: check this). 
124            The label gives the survey stations full name. 
125          */
126          else if (c<=0x5f)
127            {
128              //System.out.print(c+" - new station,");
129              int lengthbyte1=in.read();
130              //find length of text to be appended to currentlabelbuffer
131              long length;
132              
133              if(lengthbyte1<=0xfd)
134                length = (long) lengthbyte1;
135              else if (lengthbyte1==0xfe)
136                {
137          	length = reader3d.read2byytelittleendian(in);
138                }
139              else
140                {
141          	length = reader3d.read4byytelittleendian(in);
142                }
143              
144              //apend text to currentlabelbuffer
145              for(int i=0;i<length;i++)
146                currentlabelbuffer = currentlabelbuffer + ((char)in.read());
147              
148              Name newname= new Name();
149              
150              newname.name=(currentlabelbuffer);
151              //System.out.print(" add "+length+" chars survey name " + currentlabelbuffer);
152              if(c%2==0) 
153                newname.inanabovegroundleg = false;
154              else
155                {
156          	newname.inanabovegroundleg = true;
157          	c=c-1;
158                }
159              if (c%4==0) newname.inanundergroundleg = false;
160              else
161                {
162          	newname.inanundergroundleg = true;
163          	c=c-2;
164                }
165              if (c%8==0) newname.entrance = false;
166              else
167                {
168          	newname.entrance = true;
169          	c=c-4;
170                }
171              if (c%16==0) newname.exported = false;
172              else
173                {
174          	newname.exported = true;
175          	c=c-8;
176                }
177              if (c%32==0) newname.fixed = false;
178              else
179                {
180          	newname.fixed = true;
181          	c=c-16;
182                }
183              //System.out.print(" Position(");
184              for(int j=0;j<3;j++)
185                {
186          	newname.coord[j] = reader3d.read4byytelittleendian(in);
187          	//System.out.print(newstation.coord[j]+" ");
188          	previousname.coord[j]= newname.coord[j];
189                }
190              names.addElement(newname);
191              //System.out.println(")");
192            }
193          
194          //0x60-0x7f reserved
195          else if (c<=0x3f)
196            {
197              ErrorLog.log("Survex format error\nValue"+c+"is reserved");
198  //        			System.out.println(c+" - This value is reserved");
199            }
200          
201          /*0x80-0xaf <length> <label> <x coord> <y coord> <z coord> : leg flags are (N & 0x1f): 
202            0x01 : Leg is above ground
203            0x02 : Leg duplicates data in another leg (e.g. resurvey along a passage to tie into a known station) 
204            0x04 : Leg is a splay shot in a chamber (radial shots from a central point) 
205            0x08 : Reserved 
206            0x10 : Reserved 
207            Append label to the current label buffer. 
208            The length of label is given by length, which is encoded as follows:
209            0-253 - byte 0x00-0xfd 
210            254-65789 - byte 0xfe 2 byte little-endian unsigned integer len-254 0x0000-0xffff 
211            65790 and greater - byte 0xff 4 byte little-endian unsigned integer len 0x000100fd-0xffffffff 
212            Return leg from current position to coordinates given, 
213            and update current position to coordinates given. 
214            The label gives the survey that the leg is in. 
215          */
216          else if (c<=0xaf)
217            {
218              //System.out.print(c+" - new leg,");
219              int lengthbyte1=in.read();
220              //find length of text to be appended to currentlabelbuffer
221              long length;
222              if(lengthbyte1<=0xfd)
223                length = (long) lengthbyte1;
224              else if (lengthbyte1==0xfe)
225                {
226          	length = reader3d.read2byytelittleendian(in);
227                }
228              else
229                {
230          	length = reader3d.read4byytelittleendian(in);
231                }
232              //apend text to currentlabelbuffer
233              for(int i=0;i<length;i++)
234                currentlabelbuffer = currentlabelbuffer + ((char)in.read());
235              
236              Leg newleg = new Leg();
237              newleg.surveyname=currentlabelbuffer;
238              //System.out.print(" add "+length+" chars survey name " + currentlabelbuffer);
239              if(c%2==0) 
240                newleg.aboveground = false;
241              else
242                {
243          	newleg.aboveground = true;
244          	c=c-1;
245                }
246              if (c%4==0) newleg.duplicates = false;
247              else
248                {
249          	newleg.duplicates = true;
250          	c=c-2;
251                }
252              if (c%8==0) newleg.splayshot = false;
253              else
254                {
255          	newleg.splayshot = true;
256          	c=c-4;
257                }
258              newleg.coord[0] = (long[])previousname.coord.clone();
259              //System.out.print(" From(");
260              //for(int j=0;j<3;j++) System.out.print(newleg.coord[0][j]+" ");
261              //System.out.print(") To(");
262              for(int j=0;j<3;j++)
263                {
264          	newleg.coord[1][j] = reader3d.read4byytelittleendian(in);
265          	//System.out.print(newleg.coord[1][j]+" ");
266          	previousname.coord[j]= newleg.coord[1][j];
267                }
268              //System.out.println(")");
269              legs.addElement(newleg);
270              
271            }
272          //0xb0-oxff reserved
273          else
274            {
275              ErrorLog.log("Survex format error\nValue"+c+"is reserved");
276  //        			System.out.println(c+" - This values is reserved");
277            }			
278        }
279      //data all read in
280      in.close();
281      //Generate station vector, from name vector
282      
283      for(int i=0;i<names.size();i++)
284        {
285          boolean written = false;
286          for(int j=0;j<stations.size();j++)
287            {
288              if((((Name)names.elementAt(i)).coord[0]==((Station)stations.elementAt(j)).coord[0])
289                 &&(((Name)names.elementAt(i)).coord[1]==((Station)stations.elementAt(j)).coord[1])
290                 &&(((Name)names.elementAt(i)).coord[2]==((Station)stations.elementAt(j)).coord[2]))
291                {
292          	written=true;
293          	//System.out.print(((Name)names.elementAt(i)).name+"="+ ((Name)names.elementAt((int)(((Station)stations.elementAt(j)).names.elementAt(0)))).name);
294          	Integer w=new Integer(i);
295          	((Station)stations.elementAt(j)).namelist.addElement(w);
296          	if (((Name)names.elementAt(i)).entrance) ((Station)stations.elementAt(j)).entrance=true;
297          	if (((Name)names.elementAt(i)).exported) ((Station)stations.elementAt(j)).exported=true;
298          	if (((Name)names.elementAt(i)).fixed) ((Station)stations.elementAt(j)).fixed=true;
299          	if (((Name)names.elementAt(i)).inanabovegroundleg) ((Station)stations.elementAt(j)).inanabovegroundleg=true;
300          	if (((Name)names.elementAt(i)).inanundergroundleg) ((Station)stations.elementAt(j)).inanundergroundleg=true;
301          	((Name)names.elementAt(i)).station=j;
302                }
303            }
304          if (written==false)
305            {
306              Station newstation=new Station();
307              newstation.coord[0]=((Name)names.elementAt(i)).coord[0];
308              newstation.coord[1]=((Name)names.elementAt(i)).coord[1];
309              newstation.coord[2]=((Name)names.elementAt(i)).coord[2];
310              Integer w=new Integer(i);
311              newstation.namelist.addElement(w);
312              newstation.entrance=((Name)names.elementAt(i)).entrance;
313              newstation.exported=((Name)names.elementAt(i)).exported;
314              newstation.fixed=((Name)names.elementAt(i)).fixed;
315              newstation.inanabovegroundleg=((Name)names.elementAt(i)).inanabovegroundleg;
316              newstation.inanundergroundleg=((Name)names.elementAt(i)).inanundergroundleg;
317              stations.addElement(newstation);
318              ((Name)names.elementAt(i)).station=stations.size();
319            }
320        }
321      
322      //find the index of the surveys at each end of all the legs
323      for(int i=0;i<legs.size();i++)
324        {
325          for(int j=0;j<stations.size();j++)
326            {
327              //k=0 refers to first survey, k=1 refers to secound survey
328              for(int k=0;k<=1;k++)
329                {
330          	if((((Leg)legs.elementAt(i)).coord[k][0]==((Station)stations.elementAt(j)).coord[0])
331          	   &&(((Leg)legs.elementAt(i)).coord[k][1]==((Station)stations.elementAt(j)).coord[1])
332          	   &&(((Leg)legs.elementAt(i)).coord[k][2]==((Station)stations.elementAt(j)).coord[2]))
333          	  {
334          	    if (((Leg)legs.elementAt(i)).stations[k]==-1)
335          	      {
336          		((Leg)legs.elementAt(i)).stations[k]=j;
337          		Integer i2=new Integer(i);
338          		if (!((Station)stations.elementAt(j)).leglist.contains(i2))
339          		  ((Station)stations.elementAt(j)).leglist.addElement(i2);
340          	      }
341          	    else 
342          	      {
343          		ErrorLog.log("Survex format ambiguity\n"+
344          			     "Leg has two stations at an end!\n"+
345          			     "This means it is impossible to tell which is the right one\n"+
346          			     "Choosing the first one that was come across");
347  //        						System.out.println("Leg has two stations at an end!, this means it is impossible to tell which is the right one, choosing the first one that was come across");
348          	      }
349          	  }	
350                }
351            }
352          if((((Leg)legs.elementAt(i)).stations[0]==-1)
353             ||(((Leg)legs.elementAt(i)).stations[1]==-1))
354            {
355              ErrorLog.log("Survex Leg without station\n"+((Leg)legs.elementAt(i)).surveyname);
356  //        			System.out.println("Leg without station, "+((Leg)legs.elementAt(i)).surveyname);
357            }
358        }
359      //make survey tree
360      for(int i=0;i<names.size();i++)
361        {
362          survey.addname(((Name)names.elementAt(i)).name,(Name)names.elementAt(i));	
363        }
364      for(int i=0;i<legs.size();i++)
365        {
366          survey.addleg(((Leg)legs.elementAt(i)).surveyname,(Leg)legs.elementAt(i));	
367        }
368      for(int i=0;i<stations.size();i++)
369        {
370          for(int j=0;j<((Station)stations.elementAt(i)).namelist.size();j++)
371            {
372              int nameindex = ((Integer)((Station)stations.elementAt(i)).namelist.elementAt(j)).intValue();
373              survey.addstation(((Name)names.elementAt(nameindex)).name,(Station)stations.elementAt(i));	
374            }
375        }
376      //trim vectors
377      legs.trimToSize();
378      stations.trimToSize();
379      names.trimToSize();
380      //return read in file
381      Input3d input = new Input3d();
382      input.legs=legs;
383      input.stations=stations;
384      input.survey=survey;
385      input.names=names;
386      input.surveytitle=surveytitle;
387      input.timestamp=timestamp;
388  //        	System.out.println("Done");
389      return input;
390    }
391          
392    public long read4byytelittleendian(FileInputStream in)
393      {
394        int word = 0;
395        int a=0;
396        //change little endian to big endian
397        try
398          {		
399            for (int i = 0; i < 32; i += 8) 
400              {
401                if ((a=in.read())!=-1)
402          	{
403          	  a=a <<i;
404          	  word |= a;
405          	}
406              }
407          }
408        catch(IOException e)
409          {
410            ErrorLog.exception(e,"Survex error\nIn read4byytelittleendian");
411          }
412        return word;
413      }
414    
415    public long read2byytelittleendian(FileInputStream in)
416      {
417        int word = 0;
418        int a=0;
419        //change little endian to big endian
420        try
421          {		
422            for (int i = 0; i < 16; i += 8) 
423              {
424                if ((a=in.read())!=-1)
425          	{
426          	  a=a << i;
427          	  word |= a;
428          	}
429              }
430          }
431        catch(IOException e)
432          {
433            ErrorLog.exception(e,"Survex error\nIn read4bytelittleendian");
434          }
435        return word;
436      }
437    
438    
439  }
440