r329: *** 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.25 2001/01/02 06:29:23 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>\r
30 #ifdef MSVC\r
31 typedef long off_t;\r
32 #endif
33
34
35 const kuint16 Array2dFile::m_signature = ('I'*256+'F');
36
37 ///////////////////////////////////////////////////////////////////////////
38 // CLASS IMPLEMENTATION
39 //
40 //     Name: Array2dFileLabel
41 //     Purpose: Labels for Array2dFiles
42 ///////////////////////////////////////////////////////////////////////////
43
44 void
45 Array2dFileLabel::init (void)
46 {
47   m_calcTime = 0;
48   m_labelType = L_EMPTY;
49   time_t t = time(0);
50   tm* lt = localtime(&t);
51   m_year = lt->tm_year;
52   m_month = lt->tm_mon;
53   m_day = lt->tm_mday;
54   m_hour = lt->tm_hour;
55   m_minute = lt->tm_min;
56   m_second = lt->tm_sec;
57 }
58
59 Array2dFileLabel::Array2dFileLabel() 
60 {
61   init();
62 }
63
64 Array2dFileLabel::Array2dFileLabel(const char* const str, double ctime)
65 : m_strLabel (str)
66 {
67   init();
68   
69   m_labelType = L_USER;
70   m_calcTime = ctime;
71 }
72
73 Array2dFileLabel::Array2dFileLabel(const int type, const char* const str, double ctime)
74 :  m_strLabel (str)
75 {
76   init();
77   
78   m_labelType = type;
79   m_calcTime = ctime;
80 }
81
82 Array2dFileLabel::~Array2dFileLabel()
83 {
84 }
85
86 void 
87 Array2dFileLabel::setDateTime (int year, int month, int day, int hour, int minute, int second)
88 {
89   m_year = year;
90   m_month = month;
91   m_day = day;
92   m_hour = hour;
93   m_minute = minute;
94   m_second = second;
95 }
96
97 void 
98 Array2dFileLabel::getDateTime (int& year, int& month, int& day, int& hour, int& minute, int& second) const
99 {
100   year = m_year;
101   month = m_month;
102   day = m_day;
103   hour = m_hour;
104   minute = m_minute;
105   second = m_second;
106 }
107
108 const std::string& 
109 Array2dFileLabel::getDateString (void) const
110 {
111   char szDate [128];\r
112   snprintf (szDate, sizeof(szDate), "%2d/%02d/%4d %02d:%02d:%02d",\r
113     m_month + 1, m_day, m_year + 1900, m_hour, m_minute, m_second);
114   m_strDate = szDate;
115   return m_strDate;
116 }
117
118
119 Array2dFileLabel::Array2dFileLabel (const Array2dFileLabel& rhs)
120 {
121   m_calcTime = rhs.m_calcTime;
122   m_labelType = rhs.m_labelType;
123   m_strLabel = rhs.m_strLabel;
124   m_year = rhs.m_year; m_month = rhs.m_month; m_day = rhs.m_day;
125   m_hour = rhs.m_hour; m_minute = rhs.m_minute; m_second = rhs.m_second;
126 }
127
128 Array2dFileLabel&
129 Array2dFileLabel::operator= (const Array2dFileLabel& rhs)
130 {
131   m_calcTime = rhs.m_calcTime;
132   m_labelType = rhs.m_labelType;
133   m_strLabel = rhs.m_strLabel;
134   m_year = rhs.m_year; m_month = rhs.m_month; m_day = rhs.m_day;
135   m_hour = rhs.m_hour; m_minute = rhs.m_minute; m_second = rhs.m_second;
136   
137   return (*this);
138 }
139
140 void\r
141 Array2dFileLabel::print (std::ostream& os) const\r
142 {\r
143   if (m_labelType == L_HISTORY) {\r
144     os << "History: " << std::endl;\r
145     os << "  " << m_strLabel << std::endl;\r
146     os << "  calc time = " << m_calcTime << " secs" << std::endl;\r
147     os << "  Timestamp = " << getDateString() << std::endl;\r
148   } else if (m_labelType == L_USER) {\r
149     os << "Note: " <<  m_strLabel << std::endl;\r
150     os << "  Timestamp = %s" << getDateString() << std::endl;\r
151   } else {\r
152     os << "Unknown (" << m_labelType << "): " <<  m_strLabel << std::endl;\r
153     os << "  Timestamp = %s" << getDateString() << std::endl;\r
154   }\r
155 }\r
156 \r
157 void\r
158 Array2dFileLabel::printBrief (std::ostream& os) const\r
159 {\r
160   if (m_labelType == L_HISTORY) {\r
161     os << "History (";\r
162     if (m_calcTime > 0)\r
163       os << m_calcTime << " secs, ";\r
164     os << getDateString() << "): " << m_strLabel << std::endl;\r
165   } else if (m_labelType == L_USER) {\r
166     os << "Note (" <<  getDateString() << "): " << m_strLabel << std::endl;\r
167   } else {\r
168     os << "Unknown (" << getDateString() << "): " << m_strLabel << std::endl;\r
169   }\r
170 }\r
171 \r
172
173 ///////////////////////////////////////////////////////////////////////////
174 // CLASS IMPLEMENTATION
175 //
176 //     Name: Array2dFile
177 //     Purpose: Array2dFiles
178 ///////////////////////////////////////////////////////////////////////////
179
180
181 Array2dFile::Array2dFile (int x, int y, int pixelSize, int pixelFormat, int dataType)
182 {
183   init();
184   setArraySize (x, y, pixelSize, pixelFormat, dataType);
185 }
186
187 Array2dFile::~Array2dFile (void)
188 {
189   freeArrays ();
190   for (labelIterator l = m_labels.begin(); l != m_labels.end(); l++)
191     delete *l;
192 }
193
194 Array2dFile::Array2dFile (void)
195 {
196   init();
197 }
198
199 void
200 Array2dFile::init (void)
201 {
202   m_pixelSize = 0;
203   m_pixelFormat = PIXEL_INVALID;
204   m_arrayData = NULL;\r
205   m_imaginaryArrayData = NULL;\r
206   m_dataType = DATA_TYPE_INVALID;
207   m_nx = 0;
208   m_ny = 0;
209   m_headersize = 0;
210   m_axisIncrementKnown = false;
211   m_axisIncrementX = m_axisIncrementY = 0;
212   m_axisExtentKnown = false;
213   m_minX = m_maxX = m_minY = m_maxY = 0;
214   m_offsetPV = 0;
215   m_scalePV = 1;
216 }
217
218
219 void
220 Array2dFile::setArraySize (int x, int y, int pixelSize, int pixelFormat, int dataType)
221 {
222   m_pixelSize = pixelSize;
223   m_pixelFormat = pixelFormat;\r
224   m_dataType = dataType;
225   setArraySize (x, y);
226 }
227
228 void
229 Array2dFile::setArraySize (int x, int y)
230 {
231   m_nx = x;
232   m_ny = y;
233   allocArrays ();
234 }\r
235 \r
236 bool\r
237 Array2dFile::reallocComplexToReal ()\r
238 {\r
239   if (m_dataType != DATA_TYPE_COMPLEX)\r
240     return false;\r
241 \r
242   freeArray (m_imaginaryArrayData);\r
243   m_dataType = DATA_TYPE_REAL;\r
244 \r
245   return true;\r
246 }\r
247 \r
248 \r
249 bool\r
250 Array2dFile::reallocRealToComplex ()\r
251 {\r
252   if (m_dataType != DATA_TYPE_REAL)\r
253     return false;\r
254 \r
255   allocArray (m_imaginaryArrayData);\r
256   m_dataType = DATA_TYPE_COMPLEX;\r
257 \r
258   return true;\r
259 }\r
260 \r
261
262
263 void 
264 Array2dFile::allocArrays ()
265 {
266   if (m_arrayData) \r
267     freeArray (m_arrayData);\r
268   if (m_imaginaryArrayData)\r
269     freeArray (m_imaginaryArrayData);\r
270 \r
271   allocArray (m_arrayData);\r
272   if (m_dataType == DATA_TYPE_COMPLEX)\r
273     allocArray (m_imaginaryArrayData);\r
274 }\r
275 \r
276 void\r
277 Array2dFile::allocArray (unsigned char**& rppData)\r
278 {\r
279   m_arraySize = m_nx * m_ny * m_pixelSize;
280   rppData = new unsigned char* [m_nx];\r
281   int columnBytes = m_ny * m_pixelSize;
282   for (unsigned int i = 0; i < m_nx; i++)
283     rppData[i] = new unsigned char [columnBytes];\r
284 }
285
286 void 
287 Array2dFile::freeArrays ()
288 {
289   if (m_arrayData) \r
290     freeArray (m_arrayData);\r
291   \r
292   if (m_imaginaryArrayData) \r
293     freeArray (m_imaginaryArrayData);\r
294   \r
295 }\r
296 \r
297 void\r
298 Array2dFile::freeArray (unsigned char**& rppData)\r
299 {\r
300    for (unsigned int i = 0; i < m_nx; i++)\r
301       delete rppData[i];\r
302     delete rppData;\r
303     rppData = NULL;\r
304 }\r
305 \r
306
307 bool
308 Array2dFile::fileWrite (const std::string& filename)
309 {
310   return fileWrite (filename.c_str());
311 }
312
313 bool
314 Array2dFile::fileWrite (const char* const filename)
315 {
316   m_filename = filename;
317   
318   frnetorderstream fs (m_filename.c_str(), std::ios::out | std::ios::in | std::ios::trunc | std::ios::binary);
319   if (fs.fail()) {
320     sys_error (ERR_WARNING, "Error opening file %s for writing [fileCreate]", m_filename.c_str());
321     return false;
322   }
323   if (! headerWrite(fs))
324     return false;
325   
326   if (! arrayDataWrite (fs))
327     return false;
328   
329   if (! labelsWrite (fs))
330     return false;
331   
332   return true;
333 }
334
335 bool
336 Array2dFile::fileRead (const std::string& filename)
337 {
338   return fileRead (filename.c_str());
339 }
340
341 bool
342 Array2dFile::fileRead (const char* const filename)
343 {
344   m_filename = filename;
345   
346 #ifdef MSVC\r
347   frnetorderstream fs (m_filename.c_str(), std::ios::out | std::ios::in | std::ios::binary);\r
348 #else\r
349   frnetorderstream fs (m_filename.c_str(), std::ios::out | std::ios::in | std::ios::binary | std::ios::nocreate);\r
350 #endif\r
351   if (fs.fail()) {
352     sys_error (ERR_WARNING, "Unable to open file %s [fileRead]", m_filename.c_str());
353     return false;
354   }
355   
356   if (! headerRead(fs))
357     return false;
358   
359   allocArrays ();
360   
361   if (! arrayDataRead(fs))
362     return false;;
363   
364   if (! labelsRead (fs))
365     return false;
366   
367   return true;
368 }
369
370 void
371 Array2dFile::setAxisIncrement (double incX, double incY)
372 {
373   m_axisIncrementKnown = true;
374   m_axisIncrementX = incX;
375   m_axisIncrementY = incY;
376 }
377
378 void 
379 Array2dFile::setAxisExtent (double minX, double maxX, double minY, double maxY)
380 {
381   m_axisExtentKnown = true;
382   m_minX = minX;
383   m_maxY = maxX;
384   m_minX = minX;
385   m_maxY = maxY;
386 }
387
388 bool
389 Array2dFile::headerRead (frnetorderstream& fs)
390 {
391   if (! fs) {
392     sys_error (ERR_WARNING, "Tried to read header with file closed [headerRead]");
393     return false;
394   }
395   
396   fs.seekg (0);
397   kuint16 file_signature;
398   
399   fs.readInt16 (m_headersize);
400   fs.readInt16 (file_signature);
401   fs.readInt16 (m_pixelFormat);
402   fs.readInt16 (m_pixelSize);
403   fs.readInt16 (m_numFileLabels);
404   fs.readInt32 (m_nx);
405   fs.readInt32 (m_ny);\r
406   fs.readInt16 (m_dataType);
407   fs.readInt16 (m_axisIncrementKnown);
408   fs.readFloat64 (m_axisIncrementX);
409   fs.readFloat64 (m_axisIncrementY);
410   fs.readInt16 (m_axisExtentKnown);
411   fs.readFloat64 (m_minX);
412   fs.readFloat64 (m_maxX);
413   fs.readFloat64 (m_minY);
414   fs.readFloat64 (m_maxY);
415   fs.readFloat64 (m_offsetPV);
416   fs.readFloat64 (m_scalePV);
417   
418   int read_m_headersize = fs.tellg();
419   if (read_m_headersize != m_headersize) {
420     sys_error (ERR_WARNING, "Read m_headersize %d != file m_headersize %d", read_m_headersize, m_headersize);
421     return false;
422   }
423   if (file_signature != m_signature) {
424     sys_error (ERR_WARNING, "File signature %d != true signature %d", file_signature, m_signature);
425     return false;
426   }
427   
428   return ! fs.fail();
429 }
430
431
432 bool
433 Array2dFile::headerWrite (frnetorderstream& fs)
434 {
435   if (! fs) {
436     sys_error (ERR_WARNING, "Tried to write header with ! fs");
437     return false;
438   }
439   
440   m_numFileLabels = m_labels.size();
441   
442   fs.seekp (0);
443   fs.writeInt16 (m_headersize);
444   fs.writeInt16 (m_signature);
445   fs.writeInt16 (m_pixelFormat);
446   fs.writeInt16 (m_pixelSize);
447   fs.writeInt16 (m_numFileLabels);
448   fs.writeInt32 (m_nx);
449   fs.writeInt32 (m_ny);\r
450   fs.writeInt16 (m_dataType);
451   fs.writeInt16 (m_axisIncrementKnown);
452   fs.writeFloat64 (m_axisIncrementX);
453   fs.writeFloat64 (m_axisIncrementY);
454   fs.writeInt16 (m_axisExtentKnown);
455   fs.writeFloat64 (m_minX);
456   fs.writeFloat64 (m_maxX);
457   fs.writeFloat64 (m_minY);
458   fs.writeFloat64 (m_maxY);
459   fs.writeFloat64 (m_offsetPV);
460   fs.writeFloat64 (m_scalePV);
461   
462   m_headersize = static_cast<kuint16>(fs.tellp());
463   fs.seekp (0);
464   fs.writeInt16 (m_headersize);
465   
466   return ! fs.fail();
467 }
468
469
470 bool
471 Array2dFile::arrayDataWrite (frnetorderstream& fs)
472 {
473   if (! fs) {
474     sys_error (ERR_WARNING, "Tried to arrayDataWrite with !fs");
475     return false;
476   }
477   
478   if (! m_arrayData) 
479     return false;
480   
481   fs.seekp (m_headersize);
482   int columnSize = m_ny * m_pixelSize;
483   for (unsigned int ix = 0; ix < m_nx; ix++) {\r
484     unsigned char* ptrColumn = m_arrayData[ix];\r
485     if (NativeBigEndian()) {\r
486       for (unsigned int iy = 0; iy < m_ny; iy++) {\r
487         ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);\r
488         fs.write (reinterpret_cast<const char*>(ptrColumn), m_pixelSize);\r
489         ptrColumn += m_pixelSize;\r
490       }\r
491     } else \r
492       fs.write (reinterpret_cast<const char*>(ptrColumn), columnSize);\r
493   }\r
494   if (m_dataType == DATA_TYPE_COMPLEX) {\r
495     for (unsigned int ix = 0; ix < m_nx; ix++) {\r
496       unsigned char* ptrColumn = m_imaginaryArrayData[ix];\r
497       if (NativeBigEndian()) {\r
498         for (unsigned int iy = 0; iy < m_ny; iy++) {\r
499           ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);\r
500           fs.write (reinterpret_cast<const char*>(ptrColumn), m_pixelSize);\r
501           ptrColumn += m_pixelSize;\r
502         }\r
503       } else \r
504         fs.write (reinterpret_cast<const char*>(ptrColumn), columnSize);\r
505     }\r
506   }\r
507   
508   return true;
509 }
510
511
512 bool
513 Array2dFile::arrayDataRead (frnetorderstream& fs)
514 {
515   if (! fs) {
516     sys_error (ERR_WARNING, "Tried to arrayDataRead with ! fs");
517     return false;
518   }
519   
520   if (! m_arrayData)
521     return false;
522   
523   fs.seekg (m_headersize);
524   int columnSize = m_ny * m_pixelSize;
525   for (unsigned int ix = 0; ix < m_nx; ix++) {\r
526     unsigned char* ptrColumn = m_arrayData[ix];\r
527     if (NativeBigEndian()) {\r
528       for (unsigned int iy = 0; iy < m_ny; iy++) {\r
529         fs.read (reinterpret_cast<char*>(ptrColumn), m_pixelSize);\r
530         ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);\r
531         ptrColumn += m_pixelSize;\r
532       } \r
533     } else\r
534       fs.read (reinterpret_cast<char*>(ptrColumn), columnSize);\r
535   }\r
536   if (m_dataType == DATA_TYPE_COMPLEX) {\r
537     for (unsigned int ix = 0; ix < m_nx; ix++) {\r
538       unsigned char* ptrColumn = m_imaginaryArrayData[ix];\r
539       if (NativeBigEndian()) {\r
540         for (unsigned int iy = 0; iy < m_ny; iy++) {\r
541           fs.read (reinterpret_cast<char*>(ptrColumn), m_pixelSize);\r
542           ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);\r
543           ptrColumn += m_pixelSize;\r
544         } \r
545       } else\r
546         fs.read (reinterpret_cast<char*>(ptrColumn), columnSize);\r
547     }\r
548   }\r
549   
550   return true;
551 }
552
553 bool
554 Array2dFile::labelsRead (frnetorderstream& fs)
555 {
556   off_t pos = m_headersize + m_arraySize;
557   fs.seekg (pos);
558   if (fs.fail())
559     return false;
560   
561   for (int i = 0; i < m_numFileLabels; i++) {
562     kuint16 labelType, year, month, day, hour, minute, second;
563     kfloat64 calcTime;
564     
565     fs.readInt16 (labelType);
566     fs.readInt16 (year);
567     fs.readInt16 (month);
568     fs.readInt16 (day);
569     fs.readInt16 (hour);
570     fs.readInt16 (minute);
571     fs.readInt16 (second);
572     fs.readFloat64 (calcTime);
573     
574     kuint16 strLength;
575     fs.readInt16 (strLength);
576     char* pszLabelStr = new char [strLength+1];
577     fs.read (pszLabelStr, strLength);
578     pszLabelStr[strLength] = 0;
579     
580     Array2dFileLabel* pLabel = new Array2dFileLabel (labelType, pszLabelStr, calcTime);
581     delete pszLabelStr;\r
582     \r
583     pLabel->setDateTime (year, month, day, hour, minute, second);
584     m_labels.push_back (pLabel);\r
585   }
586   
587   return true;
588 }
589
590 bool
591 Array2dFile::labelsWrite (frnetorderstream& fs)
592 {
593   off_t pos = m_headersize + m_arraySize;
594   fs.seekp (pos);
595   
596   for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
597     const Array2dFileLabel& label = **l;
598     kuint16 labelType = label.getLabelType();
599     kfloat64 calcTime = label.getCalcTime();
600     const char* const labelString = label.getLabelString().c_str();
601     int year, month, day, hour, minute, second;
602     kuint16 yearBuf, monthBuf, dayBuf, hourBuf, minuteBuf, secondBuf;
603     
604     label.getDateTime (year, month, day, hour, minute, second);
605     yearBuf = year; monthBuf = month; dayBuf = day;
606     hourBuf = hour; minuteBuf = minute; secondBuf = second;
607     
608     fs.writeInt16 (labelType);
609     fs.writeInt16 (yearBuf);
610     fs.writeInt16 (monthBuf);
611     fs.writeInt16 (dayBuf);
612     fs.writeInt16 (hourBuf);
613     fs.writeInt16 (minuteBuf);
614     fs.writeInt16 (secondBuf);
615     fs.writeFloat64 (calcTime);
616     kuint16 strlength = strlen (labelString);
617     fs.writeInt16 (strlength);
618     fs.write (labelString, strlength);
619   }
620   
621   return true;
622 }
623
624 void
625 Array2dFile::labelAdd (const char* const lstr, double calc_time)
626 {
627   labelAdd (Array2dFileLabel::L_HISTORY, lstr, calc_time);
628 }
629
630
631 void
632 Array2dFile::labelAdd (int type, const char* const lstr, double calc_time)
633 {
634   Array2dFileLabel label (type, lstr, calc_time);
635   
636   labelAdd (label);
637 }
638
639
640 void
641 Array2dFile::labelAdd (const Array2dFileLabel& label)
642 {
643   Array2dFileLabel* pLabel = new Array2dFileLabel(label);
644   
645   m_labels.push_back (pLabel);
646 }
647
648 void
649 Array2dFile::labelsCopy (const Array2dFile& copyFile, const char* const pszId)
650 {
651   std::string id;
652   if (pszId)
653     id = pszId;
654   for (unsigned int i = 0; i < copyFile.getNumLabels(); i++) {
655     Array2dFileLabel l (copyFile.labelGet (i));
656     std::string lstr = l.getLabelString();
657     lstr = id + lstr;
658     l.setLabelString (lstr);
659     labelAdd (l);
660   }
661 }
662
663 void 
664 Array2dFile::arrayDataClear (void)
665 {
666   if (m_arrayData) {\r
667     int columnSize = m_ny * m_pixelSize;\r
668     for (unsigned int ix = 0; ix < m_nx; ix++)\r
669       memset (m_arrayData[ix], 0, columnSize);\r
670   }\r
671   if (m_imaginaryArrayData) {\r
672     int columnSize = m_ny * m_pixelSize;\r
673     for (unsigned int ix = 0; ix < m_nx; ix++)\r
674       memset (m_arrayData[ix], 0, columnSize);\r
675   }\r
676 }
677
678 void\r
679 Array2dFile::printLabels (std::ostream& os) const\r
680 {\r
681   for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {\r
682     const Array2dFileLabel& label = **l;\r
683     \r
684     label.print (os);\r
685     os << std::endl;\r
686   }\r
687 }\r
688 \r
689 void\r
690 Array2dFile::printLabelsBrief (std::ostream& os) const\r
691 {\r
692   for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {\r
693     const Array2dFileLabel& label = **l;\r
694     \r
695     label.printBrief (os);\r
696   }\r
697 }\r
698 \r
699
700 const Array2dFileLabel&
701 Array2dFile::labelGet (int i) const
702 {
703   return *m_labels[i];
704 }