r164: *** empty log message ***
[ctsim.git] / libctsim / array2dfile.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:         array2dfile.cpp
5 **      Purpose:      2-dimension array file class
6 **      Programmer:   Kevin Rosenberg
7 **      Date Started: June 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2000 Kevin Rosenberg
11 **
12 **  $Id: array2dfile.cpp,v 1.8 2000/07/29 19:50:08 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "array2dfile.h"
29 #include <ctime>
30 #include <sstream>
31
32 using namespace std;
33
34
35 ///////////////////////////////////////////////////////////////////////////
36 // CLASS IMPLEMENTATION
37 //
38 //     Name: Array2dFileLabel
39 //     Purpose: Labels for Array2dFiles
40 ///////////////////////////////////////////////////////////////////////////
41
42 void
43 Array2dFileLabel::init (void)
44 {
45     m_calcTime = 0;
46     m_labelType = L_EMPTY;
47     time_t t = time(0);
48     tm* lt = localtime(&t);
49     m_year = lt->tm_year;
50     m_month = lt->tm_mon;
51     m_day = lt->tm_mday;
52     m_hour = lt->tm_hour;
53     m_minute = lt->tm_min;
54     m_second = lt->tm_sec;
55 }
56
57 Array2dFileLabel::Array2dFileLabel() 
58 {
59     init();
60 }
61
62 Array2dFileLabel::Array2dFileLabel(const char* const str, double ctime = 0.)
63     : m_strLabel (str)
64 {
65     init();
66
67     m_labelType = L_USER;
68     m_calcTime = ctime;
69 }
70
71 Array2dFileLabel::Array2dFileLabel(const int type, const char* const str, double ctime = 0.)
72   :  m_strLabel (str)
73 {
74     init();
75
76     m_labelType = type;
77     m_calcTime = ctime;
78 }
79
80 Array2dFileLabel::~Array2dFileLabel()
81 {
82 }
83
84 void 
85 Array2dFileLabel::setDateTime (int year, int month, int day, int hour, int minute, int second)
86 {
87   m_year = year;
88   m_month = month;
89   m_day = day;
90   m_hour = hour;
91   m_minute = minute;
92   m_second = second;
93 }
94
95 void 
96 Array2dFileLabel::getDateTime (int& year, int& month, int& day, int& hour, int& minute, int& second) const
97 {
98   year = m_year;
99   month = m_month;
100   day = m_day;
101   hour = m_hour;
102   minute = m_minute;
103   second = m_second;
104 }
105
106 const string& 
107 Array2dFileLabel::getDateString (void) const
108 {
109   ostringstream oss;
110   oss <<  static_cast<int>(m_month + 1) <<"/"<< static_cast<int>(m_day) <<"/"<< static_cast<int>(m_year + 1900) << " " << static_cast<int>(m_hour) <<":"<<  static_cast<int>(m_minute) <<":"<< static_cast<int>(m_second);
111   m_strDate = oss.str();
112   return m_strDate;
113 }
114
115
116 Array2dFileLabel::Array2dFileLabel (const Array2dFileLabel& rhs)
117 {
118     m_calcTime = rhs.m_calcTime;
119     m_labelType = rhs.m_labelType;
120     m_strLabel = rhs.m_strLabel;
121     m_year = rhs.m_year; m_month = rhs.m_month; m_day = rhs.m_day;
122     m_hour = rhs.m_hour; m_minute = rhs.m_minute; m_second = rhs.m_second;
123 }
124
125 Array2dFileLabel&
126 Array2dFileLabel::operator= (const Array2dFileLabel& rhs)
127 {
128     m_calcTime = rhs.m_calcTime;
129     m_labelType = rhs.m_labelType;
130     m_strLabel = rhs.m_strLabel;
131     m_year = rhs.m_year; m_month = rhs.m_month; m_day = rhs.m_day;
132     m_hour = rhs.m_hour; m_minute = rhs.m_minute; m_second = rhs.m_second;
133
134     return (*this);
135 }
136
137 void
138 Array2dFileLabel::print (ostream& os) const
139 {
140   if (m_labelType == L_HISTORY) {
141     os << "History: " << endl;
142     os << "  " << m_strLabel << endl;
143     os << "  calc time = " << m_calcTime << " secs" << endl;
144     os << "  Timestamp = " << getDateString() << endl;
145   } else if (m_labelType == L_USER) {
146     os << "Note: " <<  m_strLabel << endl;
147     os << "  Timestamp = %s" << getDateString() << endl;
148   } else {
149     os << "Unknown (" << m_labelType << "): " <<  m_strLabel << endl;
150     os << "  Timestamp = %s" << getDateString() << endl;
151   }
152 }
153
154
155 ///////////////////////////////////////////////////////////////////////////
156 // CLASS IMPLEMENTATION
157 //
158 //     Name: Array2dFile
159 //     Purpose: Array2dFiles
160 ///////////////////////////////////////////////////////////////////////////
161
162
163 Array2dFile::Array2dFile (int x, int y, int pixelSize, int pixelFormat)
164 {
165     init();
166     setArraySize (x, y, pixelSize, pixelFormat);
167 }
168
169 Array2dFile::~Array2dFile (void)
170 {
171     freeArray ();
172     for (labelIterator l = m_labels.begin(); l != m_labels.end(); l++)
173       delete *l;
174 }
175
176 Array2dFile::Array2dFile (void)
177 {
178     init();
179 }
180
181 void
182 Array2dFile::init (void)
183 {
184   m_pixelSize = 0;
185   m_pixelFormat = PIXEL_INVALID;
186   m_arrayData = NULL;
187   m_nx = 0;
188   m_ny = 0;
189   m_headersize = 0;
190   m_axisIncrementKnown = false;
191   m_axisIncrementX = m_axisIncrementY = 0;
192   m_axisExtentKnown = false;
193   m_minX = m_maxX = m_minY = m_maxY = 0;
194   m_offsetPV = 0;
195   m_scalePV = 1;
196 }
197
198
199 void
200 Array2dFile::setArraySize (int x, int y, int pixelSize, int pixelFormat)
201 {
202     m_pixelSize = pixelSize;
203     m_pixelFormat = pixelFormat;
204     setArraySize (x, y);
205 }
206
207 void
208 Array2dFile::setArraySize (int x, int y)
209 {
210     m_nx = x;
211     m_ny = y;
212     allocArray ();
213 }
214
215 void 
216 Array2dFile::allocArray (void)
217 {
218     if (m_arrayData)
219         freeArray();
220
221     m_arraySize = m_nx * m_ny * m_pixelSize;
222     m_arrayData = new unsigned char* [m_nx];
223     
224     int columnBytes = m_ny * m_pixelSize;
225     for (unsigned int i = 0; i < m_nx; i++)
226         m_arrayData[i] = new unsigned char [columnBytes];
227 }
228
229 void 
230 Array2dFile::freeArray (void)
231 {
232     if (m_arrayData) {
233         for (unsigned int i = 0; i < m_nx; i++)
234             delete m_arrayData[i];
235         delete m_arrayData;
236         m_arrayData = NULL;
237     }
238 }
239
240 bool
241 Array2dFile::fileWrite (const string& filename)
242 {
243   return fileWrite (filename.c_str());
244 }
245
246 bool
247 Array2dFile::fileWrite (const char* const filename)
248 {
249     m_filename = filename;
250
251     frnetorderstream fs (m_filename.c_str(), ios::out | ios::in | ios::trunc | ios::binary);
252     if (fs.fail()) {
253         sys_error (ERR_WARNING, "Error opening file %s for writing [fileCreate]", m_filename.c_str());
254       return false;
255     }
256     if (! headerWrite(fs))
257         return false;
258     
259     if (! arrayDataWrite (fs))
260         return false;
261     
262     if (! labelsWrite (fs))
263         return false;
264
265     return true;
266 }
267
268 bool
269 Array2dFile::fileRead (const string& filename)
270 {
271   return fileRead (filename.c_str());
272 }
273
274 bool
275 Array2dFile::fileRead (const char* const filename)
276 {
277     m_filename = filename;
278
279     frnetorderstream fs (m_filename.c_str(), ios::out | ios::in | ios::binary | ios::nocreate);
280     if (fs.fail()) {
281       sys_error (ERR_WARNING, "Unable to open file %s [fileRead]", m_filename.c_str());
282       return false;
283     }
284
285     if (! headerRead(fs))
286       return false;
287     
288     allocArray ();
289     
290     if (! arrayDataRead(fs))
291       return false;;
292
293     if (! labelsRead (fs))
294       return false;
295     
296     return true;
297 }
298
299 void
300 Array2dFile::setAxisIncrement (double incX, double incY)
301 {
302   m_axisIncrementKnown = true;
303   m_axisIncrementX = incX;
304   m_axisIncrementY = incY;
305 }
306
307 void 
308 Array2dFile::setAxisExtent (double minX, double maxX, double minY, double maxY)
309 {
310     m_axisExtentKnown = true;
311     m_minX = minX;
312     m_maxY = maxX;
313     m_minX = minX;
314     m_maxY = maxY;
315 }
316
317 bool
318 Array2dFile::headerRead (frnetorderstream& fs)
319 {
320   if (! fs) {
321     sys_error (ERR_WARNING, "Tried to read header with file closed [headerRead]");
322     return false;
323   }
324
325   fs.seekg (0);
326   kuint16 file_signature;
327
328   fs.readInt16 (m_headersize);
329   fs.readInt16 (file_signature);
330   fs.readInt16 (m_pixelFormat);
331   fs.readInt16 (m_pixelSize);
332   fs.readInt16 (m_numFileLabels);
333   fs.readInt32 (m_nx);
334   fs.readInt32 (m_ny);
335   fs.readInt16 (m_axisIncrementKnown);
336   fs.readFloat64 (m_axisIncrementX);
337   fs.readFloat64 (m_axisIncrementY);
338   fs.readInt16 (m_axisExtentKnown);
339   fs.readFloat64 (m_minX);
340   fs.readFloat64 (m_maxX);
341   fs.readFloat64 (m_minY);
342   fs.readFloat64 (m_maxY);
343   fs.readFloat64 (m_offsetPV);
344   fs.readFloat64 (m_scalePV);
345
346   int read_m_headersize = fs.tellg();
347   if (read_m_headersize != m_headersize) {
348     sys_error (ERR_WARNING, "Read m_headersize %d != file m_headersize %d", read_m_headersize, m_headersize);
349     return false;
350   }
351   if (file_signature != m_signature) {
352     sys_error (ERR_WARNING, "File signature %d != true signature %d", file_signature, m_signature);
353     return false;
354   }
355
356   return true;
357 }
358
359
360 bool
361 Array2dFile::headerWrite (frnetorderstream& fs)
362 {
363   if (! fs) {
364     sys_error (ERR_WARNING, "Tried to write header with ! fs");
365     return false;
366   }
367
368   m_numFileLabels = m_labels.size();
369
370   fs.seekp (0);
371   fs.writeInt16 (m_headersize);
372   fs.writeInt16 (m_signature);
373   fs.writeInt16 (m_pixelFormat);
374   fs.writeInt16 (m_pixelSize);
375   fs.writeInt16 (m_numFileLabels);
376   fs.writeInt32 (m_nx);
377   fs.writeInt32 (m_ny);
378   fs.writeInt16 (m_axisIncrementKnown);
379   fs.writeFloat64 (m_axisIncrementX);
380   fs.writeFloat64 (m_axisIncrementY);
381   fs.writeInt16 (m_axisExtentKnown);
382   fs.writeFloat64 (m_minX);
383   fs.writeFloat64 (m_maxX);
384   fs.writeFloat64 (m_minY);
385   fs.writeFloat64 (m_maxY);
386   fs.writeFloat64 (m_offsetPV);
387   fs.writeFloat64 (m_scalePV);
388
389   m_headersize = fs.tellp();
390   fs.seekp (0);
391   fs.writeInt16 (m_headersize);
392   
393   return true;
394 }
395
396
397 bool
398 Array2dFile::arrayDataWrite (frnetorderstream& fs)
399 {
400   if (! fs) {
401     sys_error (ERR_WARNING, "Tried to arrayDataWrite with !fs");
402     return false;
403   }
404
405   if (! m_arrayData) 
406       return false;
407
408   fs.seekp (m_headersize);
409   int columnSize = m_ny * m_pixelSize;
410   for (unsigned int ix = 0; ix < m_nx; ix++) {
411       unsigned char* ptrColumn = m_arrayData[ix];
412       if (NativeBigEndian()) {
413           for (unsigned int iy = 0; iy < m_ny; iy++) {
414               ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);
415               fs.write (ptrColumn, m_pixelSize);
416               ptrColumn += m_pixelSize;
417           }
418       } else 
419           fs.write (ptrColumn, columnSize);
420   }
421
422   return true;
423 }
424
425
426 bool
427 Array2dFile::arrayDataRead (frnetorderstream& fs)
428 {
429   if (! fs) {
430     sys_error (ERR_WARNING, "Tried to arrayDataRead with ! fs");
431     return false;
432   }
433
434   if (! m_arrayData)
435       return false;
436
437   fs.seekg (m_headersize);
438   int columnSize = m_ny * m_pixelSize;
439   for (unsigned int ix = 0; ix < m_nx; ix++) {
440       unsigned char* ptrColumn = m_arrayData[ix];
441       if (NativeBigEndian()) {
442           for (unsigned int iy = 0; iy < m_ny; iy++) {
443               fs.read (ptrColumn, m_pixelSize);
444               ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);
445               ptrColumn += m_pixelSize;
446           } 
447       } else
448           fs.read (ptrColumn, columnSize);
449   }
450
451   return true;
452 }
453
454 bool
455 Array2dFile::labelsRead (frnetorderstream& fs)
456 {
457     off_t pos = m_headersize + m_arraySize;
458     fs.seekg (pos);
459     if (fs.fail())
460         return false;
461
462     for (int i = 0; i < m_numFileLabels; i++) {
463         kuint16 labelType, year, month, day, hour, minute, second;
464         kfloat64 calcTime;
465
466         fs.readInt16 (labelType);
467         fs.readInt16 (year);
468         fs.readInt16 (month);
469         fs.readInt16 (day);
470         fs.readInt16 (hour);
471         fs.readInt16 (minute);
472         fs.readInt16 (second);
473         fs.readFloat64 (calcTime);
474         
475         kuint16 strLength;
476         fs.readInt16 (strLength);
477         char labelStr [strLength+1];
478         fs.read (labelStr, strLength);
479         labelStr[strLength] = 0;
480
481         Array2dFileLabel* pLabel = new Array2dFileLabel(labelType, labelStr, calcTime);
482         pLabel->setDateTime (year, month, day, hour, minute, second);
483         m_labels.push_back (pLabel);
484     }
485
486     return true;
487 }
488
489 bool
490 Array2dFile::labelsWrite (frnetorderstream& fs)
491 {
492     off_t pos = m_headersize + m_arraySize;
493     fs.seekp (pos);
494
495     for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
496         const Array2dFileLabel& label = **l;
497         kuint16 labelType = label.getLabelType();
498         kfloat64 calcTime = label.getCalcTime();
499         const char* const labelString = label.getLabelString().c_str();
500         int year, month, day, hour, minute, second;
501         kuint16 yearBuf, monthBuf, dayBuf, hourBuf, minuteBuf, secondBuf;
502
503         label.getDateTime (year, month, day, hour, minute, second);
504         yearBuf = year; monthBuf = month; dayBuf = day;
505         hourBuf = hour; minuteBuf = minute; secondBuf = second;
506
507         fs.writeInt16 (labelType);
508         fs.writeInt16 (yearBuf);
509         fs.writeInt16 (monthBuf);
510         fs.writeInt16 (dayBuf);
511         fs.writeInt16 (hourBuf);
512         fs.writeInt16 (minuteBuf);
513         fs.writeInt16 (secondBuf);
514         fs.writeFloat64 (calcTime);
515         kuint16 strlength = strlen (labelString);
516         fs.writeInt16 (strlength);
517         fs.write (labelString, strlength);
518     }
519
520     return true;
521 }
522
523 void
524 Array2dFile::labelAdd (const char* const lstr, double calc_time=0.)
525 {
526   labelAdd (Array2dFileLabel::L_HISTORY, lstr, calc_time);
527 }
528
529
530 void
531 Array2dFile::labelAdd (int type, const char* const lstr, double calc_time=0.)
532 {
533   Array2dFileLabel label (type, lstr, calc_time);
534
535   labelAdd (label);
536 }
537
538
539 void
540 Array2dFile::labelAdd (const Array2dFileLabel& label)
541 {
542     Array2dFileLabel* pLabel = new Array2dFileLabel(label);
543
544     m_labels.push_back (pLabel);
545 }
546
547 void
548 Array2dFile::labelsCopy (Array2dFile& copyFile, const char* const idStr)
549 {
550     string id = idStr;
551     for (unsigned int i = 0; i < copyFile.getNumLabels(); i++) {
552       Array2dFileLabel l (copyFile.labelGet (i));
553       string lstr = l.getLabelString();
554       lstr = idStr + lstr;
555       l.setLabelString (lstr);
556       labelAdd (l);
557     }
558 }
559
560 void 
561 Array2dFile::arrayDataClear (void)
562 {
563     if (m_arrayData) {
564         int columnSize = m_ny * m_pixelSize;
565         for (unsigned int ix = 0; ix < m_nx; ix++)
566             memset (m_arrayData[ix], 0, columnSize);
567     }
568 }
569
570 void
571 Array2dFile::printLabels (ostream& os) const
572 {
573     for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
574       const Array2dFileLabel& label = **l;
575
576       label.print (os);
577       os << endl;
578     }
579 }
580
581
582 const Array2dFileLabel&
583 Array2dFile::labelGet (int i) const
584 {
585   return *m_labels[i];
586 }