File indexing completed on 2024-12-22 04:17:04

0001 
0002 /***************************************************************************
0003                         dmcobj.cpp  -  Part of KST
0004                              -------------------
0005     begin                : Mon Oct 06 2003
0006     copyright            : (C) 2003 The University of Toronto
0007     email                :
0008  ***************************************************************************/
0009 
0010 /***************************************************************************
0011  *                                                                         *
0012  *   This program is free software; you can redistribute it and/or modify  *
0013  *   it under the terms of the GNU General Public License as published by  *
0014  *   the Free Software Foundation; either version 2 of the License, or     *
0015  *   (at your option) any later version.                                   *
0016  *                                                                         *
0017  ***************************************************************************/
0018 
0019 
0020 #include <assert.h>
0021 
0022 #include "debug.h"
0023 #include <math.h>
0024 
0025 //#define PIOLIBDEBUG
0026 #include "dmcobj.h"
0027 
0028 #include "HL2_PIOLIB/PIOErr.h"
0029 
0030 #ifdef NAN
0031 double NOPOINT = NAN;
0032 #else
0033 double NOPOINT = 0.0/0.0; // NaN
0034 #endif
0035 
0036 using namespace DMC;
0037 
0038 
0039 class DMC::ObjectGroup {
0040   friend class Object;
0041   public:
0042     ObjectGroup();
0043     ~ObjectGroup();
0044 
0045     bool open(const QString& groupURL);
0046     void close();
0047 
0048     bool updateObjectList();
0049 
0050     PIOSTRING *objTypes;
0051     PIOSTRING *objNames;
0052     PIOINT     objectListSize;
0053 
0054     PIOLONG *firstIndex;
0055     PIOLONG *lastIndex;
0056 
0057     PIOSTRING *TOItypes;
0058     PIOSTRING *Datatypes;
0059 
0060     PIOGroup *_group;
0061     bool _valid;
0062 };
0063 
0064 
0065 DMC::TimeType Object::typeOfTime() {
0066   PIOParseData MyData, MyDataFlag;
0067   PIOObject *obj = 0L;
0068   char range[128];
0069   DMC::ObjectGroup *g = findGroup(_group);
0070   assert(g);
0071 #ifdef PIOLONG_FMT
0072   snprintf(range, 127, "Begin=" PIOLONG_FMT "\nEnd=" PIOLONG_FMT, *g->firstIndex, *g->firstIndex);
0073 #else
0074   snprintf(range, 127, "Begin=%lld\nEnd=%lld", *g->firstIndex, *g->firstIndex);
0075 #endif
0076 
0077   long n = PIORead_1(const_cast<char*>("TIMES_OF_SAMPLES"), const_cast<char*>("Written"), const_cast<char*>("PIODOUBLE"), range, &g->_group, &obj, &MyData, &MyDataFlag);
0078 
0079   if (n != 1) {
0080     n = PIORead_1(const_cast<char*>("TIMESEC"), const_cast<char*>("Written"), const_cast<char*>("PIODOUBLE"), range, &g->_group, &obj, &MyData, &MyDataFlag);
0081     if (n != 1) {
0082       return DMC::Unknown;
0083     } else {
0084       return DMC::TimeSec;
0085     }
0086   }
0087   return DMC::TimesOfSamples;
0088 }
0089 
0090 
0091 double Object::fetchTimePoint(PIOLONG idx) {
0092   PIOParseData MyData, MyDataFlag;
0093   PIOObject *obj = 0L;
0094   char range[128];
0095   long n;
0096 #ifdef PIOLONG_FMT
0097   snprintf(range, 127, "Begin=" PIOLONG_FMT "\nEnd=" PIOLONG_FMT, idx, idx);
0098 #else
0099   snprintf(range, 127, "Begin=%lld\nEnd=%lld", idx, idx);
0100 #endif
0101   double buf[1];
0102   DMC::ObjectGroup *g = findGroup(_group);
0103   assert(g);
0104   static PIOFLAG Mask[1];
0105 
0106   switch (_tt) {
0107     case DMC::TimeSec:
0108       n = PIORead_1(const_cast<char*>("TIMESEC"), const_cast<char*>("Written"), const_cast<char*>("PIODOUBLE"), range, &g->_group, &obj, &MyData, &MyDataFlag);
0109       PIORead_2(buf, 0L, Mask, const_cast<char*>("TIMESEC"), const_cast<char*>("PIODOUBLE"), range, const_cast<char*>("Written"), g->_group, &obj, &MyData, &MyDataFlag, PIOLONG(n));
0110       break;
0111     case DMC::TimesOfSamples:
0112       n = PIORead_1(const_cast<char*>("TIMES_OF_SAMPLES"), const_cast<char*>("Written"), const_cast<char*>("PIODOUBLE"), range, &g->_group, &obj, &MyData, &MyDataFlag);
0113       PIORead_2(buf, 0L, Mask, const_cast<char*>("TIMES_OF_SAMPLES"), const_cast<char*>("PIODOUBLE"), range, const_cast<char*>("Written"), g->_group, &obj, &MyData, &MyDataFlag, PIOLONG(n));
0114       break;
0115     default:
0116       return NOPOINT;
0117   }
0118 
0119   return buf[0];
0120 }
0121 
0122 
0123 Object::Object() : Source() {
0124 #ifdef PIOLIBDEBUG
0125   kdDebug() << ">>>>>>>>>  Object created " << (void*)this << endl;
0126 #endif
0127   _tt = Undetermined;
0128 }
0129 
0130 
0131 Object::~Object() {
0132   reset();
0133 #ifdef PIOLIBDEBUG
0134   kdDebug() << "<<<<<<<<<  Object deleted " << (void*)this << endl;
0135 #endif
0136 }
0137 
0138 
0139 bool Object::updated() const {
0140   if (_isValid) {
0141     ObjectGroup *tg = findGroup(_group);
0142     if (tg) {
0143       bool rc = PIOUPDATE == PIOCheckUpdateGrp(tg->_group);
0144       if (rc) {
0145         tg->updateObjectList();
0146       }
0147       return rc;
0148     }
0149   }
0150   return false;
0151 }
0152 
0153 
0154 void Object::reset() {
0155 #ifdef PIOLIBDEBUG
0156   kdDebug() << ">>>>>>>>>  Object reset" << endl;
0157 #endif
0158   for (QMap<QString,ObjectGroup*>::Iterator i = _groupInfo.begin(); i != _groupInfo.end(); ++i) {
0159     delete (*i);
0160   }
0161   _groupInfo.clear();
0162   Source::reset();
0163 }
0164 
0165 
0166 bool Object::setGroup(const QString& group) {
0167 #ifdef PIOLIBDEBUG
0168   kdDebug() << ">>>>>>>>>  Object set group - " << group << endl;
0169 #endif
0170   // FIXME: verify the source
0171   if (group != _group) {
0172     reset();
0173     _group = group;
0174   }
0175   _isValid = true;
0176   return true;
0177 }
0178 
0179 
0180 QStringList Object::fields() const {
0181   QStringList rc;
0182   if (_isValid) {
0183     const ObjectGroup *tg = findGroup(_group);
0184     if (tg) {
0185       for (PIOINT i = 0; i < tg->objectListSize; ++i) {
0186         rc += tg->objNames[i];
0187       }
0188     }
0189   }
0190   return rc;
0191 }
0192 
0193 
0194 QSize Object::range(const QString& object) const {
0195   if (isValid()) {
0196     const ObjectGroup *g = findGroup(_group);
0197     if (!g) {
0198       return QSize(0, 0);
0199     }
0200 
0201     int i;
0202     for (i = 0; i < g->objectListSize; ++i) {
0203       if (object == g->objNames[i]) {
0204         break;
0205       }
0206     }
0207 
0208     if (i == g->objectListSize) {
0209 #ifdef PIOLIBDEBUG
0210       kdDebug() << "Error finding object " << object << endl;
0211 #endif
0212       return QSize(0, 0);
0213     }
0214 
0215     return QSize(g->firstIndex[i], g->lastIndex[i]);
0216   }
0217 return QSize(0, 0);
0218 }
0219 
0220 
0221 int Object::readObject(const QString& object, double *buf, long start, long end) {
0222 #ifdef PIOLIBDEBUG
0223   kdDebug() << ">>>>>>>>>  Object read object - " << _group << ":" << object << " from " << start << " to " << end << endl;
0224 #endif
0225   if (isValid()) {
0226     ObjectGroup *g = findGroup(_group);
0227     if (!g) {
0228       return 0;
0229     }
0230 
0231     int i;
0232     for (i = 0; i < g->objectListSize; ++i) {
0233       if (object == g->objNames[i]) {
0234         break;
0235       }
0236     }
0237 
0238     if (i == g->objectListSize) {
0239       return 0;
0240     }
0241 
0242 #ifdef PIOLIBDEBUG
0243     kdDebug() << "Found object " << object << " in group " << _group << " , type is " << g->objTypes[i] << ", data type is " << g->Datatypes[i] << endl;
0244 #endif
0245 
0246     QString range("");
0247 
0248     if (start < 0 || end < start) {
0249       // Leave blank
0250     } else {
0251       range = QString("Begin=%1\nEnd=%2").arg(start).arg(end);
0252     }
0253 
0254     PIOObject *MyObject = 0L;
0255     PIOParseData MyData;
0256      /* Specific data description needed to check that sample were written */
0257     PIOParseData MyDataFlag;
0258 
0259     PIOSTRING ObjName;
0260 //    sprintf(ObjName, "%s/%s", g->_group->HTMLName, g->objNames[i]);
0261     sprintf(ObjName, "%s/%s", g->_group->Name, g->objNames[i]);
0262 
0263     /* open the group only for reading this object */
0264     PIOGroup *MyGroup=NULL;
0265     long n=0;
0266 
0267     if (strncmp(g->Datatypes[i], "PIOFLAG", 7) == 0) {
0268       n = PIORead_1(ObjName, 
0269           const_cast<char*>("Written"),
0270           const_cast<char*>("PIOFLAG"),
0271           const_cast<char*>(range.toLatin1().constData()),
0272           &MyGroup, &MyObject, &MyData, &MyDataFlag);
0273 
0274 #ifdef PIOLIBDEBUG
0275       kdDebug() << "READ " << n << " flags." << endl;
0276 #endif
0277       if (n < 0) { // error
0278         // FIXME - might have to reset() here
0279         abort();
0280         n = 0;
0281         return n;
0282       }
0283 
0284       {
0285         /* table to store the sample validity */
0286         PIOFLAG *Mask = (PIOFLAG*)_PIOMALLOC(n);
0287 
0288         /* temporary buffer */
0289         PIOFLAG *flagbuf = (PIOFLAG*)_PIOMALLOC(n);
0290 
0291         PIORead_2(flagbuf, 0L, Mask,
0292             ObjName, 
0293             const_cast<char*>("PIOFLAG"),
0294             const_cast<char*>(range.toLatin1().constData()),
0295             const_cast<char*>("Written"), 
0296             MyGroup, 
0297             &MyObject, 
0298             &MyData, 
0299             &MyDataFlag,
0300             PIOLONG(n));
0301 
0302         for (i = 0; i < n; i++) {
0303           if (Mask[i] == 0) {
0304             buf[i] = NOPOINT;
0305           } else {
0306             // just cast flags to doubles
0307             buf[i] = (PIODOUBLE)flagbuf[i];
0308           }
0309         }
0310 
0311         _PIOFREE(flagbuf);
0312         _PIOFREE(Mask);
0313       }
0314     } else {
0315       n = PIORead_1(ObjName, 
0316           const_cast<char*>("Written"),
0317           const_cast<char*>("PIODOUBLE"),
0318           const_cast<char*>(range.toLatin1().constData()),
0319           &MyGroup, &MyObject, &MyData, &MyDataFlag);
0320 
0321 #ifdef PIOLIBDEBUG
0322     kdDebug() << "READ " << n << " doubles." << endl;
0323 #endif
0324       if (n < 0) { // error
0325         // FIXME - might have to reset() here
0326         abort();
0327         n = 0;
0328         return n;
0329       }
0330 
0331       {
0332         /* table to store the sample validity */
0333         PIOFLAG *Mask = (PIOFLAG*)_PIOMALLOC(n);
0334 
0335         PIORead_2(buf, 0L, Mask,
0336             ObjName, 
0337             const_cast<char*>("PIODOUBLE"),
0338             const_cast<char*>(range.toLatin1().constData()),
0339             const_cast<char*>("Written"), 
0340             MyGroup, 
0341             &MyObject, 
0342             &MyData, 
0343             &MyDataFlag,
0344             PIOLONG(n));
0345 
0346         /* the group is close no need to deletelink */
0347         //PIODeleteLink(buf, g->_group);
0348 
0349         for (i = 0; i < n; i++) {
0350           if (Mask[i] == 0) {
0351             buf[i] = NOPOINT;
0352           }
0353         }
0354 
0355         _PIOFREE(Mask);
0356       }
0357     }
0358 #ifdef PIOLIBDEBUG
0359     kdDebug() << "Read " << n << " samples of data.  Range = [" << range << "]" << endl;
0360     if (n > 0) {
0361       kdDebug() << "this = " << (void*)this << endl;
0362       kdDebug() << "buf = " << (void*)buf << endl;
0363     }
0364 #endif
0365     return int(n);
0366   }
0367   return 0;
0368 }
0369 
0370 
0371 ObjectGroup *Object::findGroup(const QString& group) const {
0372   if (_groupInfo.contains(group)) {
0373     return _groupInfo[group];
0374   }
0375 
0376   ObjectGroup *grp = new ObjectGroup;
0377   if (!grp->open(group)) {
0378     delete grp;
0379     grp = 0L;
0380   } else {
0381     _groupInfo.insert(group, grp);
0382   }
0383 
0384 #ifdef PIOLIBDEBUG
0385   if (!grp) {
0386     kdDebug() << "Error finding group " << group << endl;
0387   }
0388 #endif
0389   return grp;
0390 }
0391 
0392 
0393 double Object::timeForSample(int sample) {
0394   if (_tt == Undetermined) {
0395     _tt = typeOfTime();
0396   }
0397 
0398   return fetchTimePoint(sample);
0399 }
0400 
0401 
0402 int Object::sampleForTimeRelative(double ms, bool *ok) {
0403   if (_tt == Undetermined) {
0404     _tt = typeOfTime();
0405   }
0406 
0407   DMC::ObjectGroup *g = findGroup(_group);
0408   if (!g) {
0409     if (ok) {
0410       *ok = false;
0411     }
0412     return -1;
0413   }
0414   double left = fetchTimePoint(*g->firstIndex);
0415   if (left != left) {
0416     if (ok) {
0417       *ok = false;
0418     }
0419     return -1;
0420   }
0421   return sampleForTime(floor(left + 0.5) + ms / 1000, ok);
0422 }
0423 
0424 
0425 int Object::sampleForTime(double ms, bool *ok) {
0426   PIOLONG location = -1;
0427   bool found = false;
0428 
0429   if (_tt == Undetermined) {
0430     _tt = typeOfTime();
0431   }
0432 
0433   DMC::ObjectGroup *g = findGroup(_group);
0434   if (!g || _tt == Unknown) {
0435     if (ok) {
0436       *ok = false;
0437     }
0438     return -1;
0439   }
0440 
0441   PIOLONG FirstIndex = *g->firstIndex;
0442   PIOLONG LastIndex = *g->lastIndex;
0443   double left = fetchTimePoint(FirstIndex);
0444   double right = fetchTimePoint(LastIndex);
0445   double sch = ms;
0446 
0447   if (sch >= left && sch <= right) {
0448     if (sch == left) {
0449       found = true;
0450       location = FirstIndex;
0451     } else if (sch == right) {
0452       found = true;
0453       location = LastIndex;
0454     } else {
0455       while (FirstIndex < LastIndex) {
0456         PIOLONG point = (LastIndex - FirstIndex) / 2 + FirstIndex;
0457         if (LastIndex - FirstIndex < 3) {
0458           double left = fetchTimePoint(FirstIndex);
0459           double right = fetchTimePoint(LastIndex);
0460           double mid = fetchTimePoint(point);
0461           found = true;
0462           double ld = fabs(left - sch);
0463           double rd = fabs(right - sch);
0464           double md = fabs(mid - sch);
0465           if (ld <= rd && ld <= md) {
0466             location = FirstIndex;
0467           } else if (md <= ld && md <= rd) {
0468             location = point;
0469           } else if (rd <= ld && rd <= md) {
0470             location = LastIndex;
0471           } else {
0472             location = -1;
0473           }
0474           break;
0475         }
0476 
0477         double pt = fetchTimePoint(point);
0478         if (pt > sch) {
0479           LastIndex = point - 1;
0480         } else if (pt < sch) {
0481           FirstIndex = point + 1;
0482         } else if (pt == sch) {
0483           found = true;
0484           location = point;
0485           break;
0486         }
0487         if (LastIndex == FirstIndex) {
0488           found = true;
0489           location = FirstIndex;
0490         }
0491       }
0492     }
0493   }
0494 
0495   if (ok) {
0496     *ok = found;
0497   }
0498 
0499   return location;
0500 }
0501 
0502 
0503 /*
0504  *  We may want to consider storing with a Qt datatype instead so we can
0505  *  index these things and get far better performance.
0506  */
0507 
0508 ObjectGroup::ObjectGroup() {
0509   objNames = 0L;
0510   objTypes = 0L;
0511   firstIndex = 0L;
0512   lastIndex = 0L;
0513   objectListSize = 0;
0514   TOItypes = 0L;
0515   Datatypes = 0L;
0516 
0517   _group = 0L;
0518   _valid = false;
0519 }
0520 
0521 
0522 ObjectGroup::~ObjectGroup() {
0523   close();
0524 }
0525 
0526 
0527 void ObjectGroup::close() {
0528   //kdDebug() << "Close group" << endl;
0529   if (_valid) {
0530     _PIOFREE(objNames);
0531     objNames = 0L;
0532     _PIOFREE(objTypes);
0533     objTypes = 0L;
0534 
0535     delete[] TOItypes;
0536     TOItypes = 0L;
0537     delete[] Datatypes;
0538     Datatypes = 0L;
0539 
0540     objectListSize = 0;
0541     _valid = false;
0542   }
0543 
0544   delete[] firstIndex;
0545   firstIndex = 0L;
0546   delete[] lastIndex;
0547   lastIndex = 0L;
0548 
0549   if (_group) {
0550     PIOCloseVoidGrp(&_group);
0551     _group = 0L;
0552   }
0553 }
0554 
0555 
0556 bool ObjectGroup::updateObjectList() {
0557   if (objNames) {
0558     _PIOFREE(objNames);
0559     objNames = 0L;
0560     _PIOFREE(objTypes);
0561     objTypes = 0L;
0562   }
0563 
0564   _valid = false;
0565 
0566   PIOErr e = PIOGetObjectList(&objNames, &objTypes, _group);
0567   if (e > 0) {
0568     delete[] firstIndex;
0569     delete[] lastIndex;
0570     firstIndex = new PIOLONG[e];
0571     lastIndex = new PIOLONG[e];
0572     delete[] TOItypes;
0573     TOItypes = new PIOSTRING[e];
0574     delete[] Datatypes;
0575     Datatypes = new PIOSTRING[e];
0576     objectListSize = e;
0577     _valid = true;
0578 
0579 #ifdef PIOLIBDEBUG
0580     kdDebug() << "               -> info acquired." << endl;
0581     kdDebug() << "                  -> objects: " << e << endl;
0582 #endif  
0583     /* there are two solution:
0584        - get directly only the group maximal size,
0585        - get the object size (it depend how KST manage index after. */
0586     PIOLONG LastIdx, FirstIdx;
0587     
0588     PIOGetGrpSize(&FirstIdx, &LastIdx, _group);
0589 
0590     for (int i = 0; i < e; ++i) { 
0591       firstIndex[i] = FirstIdx;
0592       lastIndex[i] = LastIdx;
0593 
0594       PIOLONG beginIdx, endIdx;
0595       PIOSTRING author, date;
0596       PIOErr ret = PIOInfoObject(TOItypes[i], Datatypes[i], &beginIdx, &endIdx, author, date, objNames[i], _group);
0597 #ifdef PIOLIBDEBUG
0598       kdDebug() << "  PIOInfoObject(" << TOItypes[i] << "," << Datatypes[i] << "," << beginIdx << "," << endIdx << "," << author << "," << date << "," << objNames[i] << ") returned " << ret << endl;
0599 #endif  
0600       if (ret != 0) {
0601         _valid = false;
0602       }
0603     }
0604   }
0605   return _valid;
0606 }
0607 
0608 
0609 bool ObjectGroup::open(const QString& groupURL) {
0610 #ifdef PIOLIBDEBUG
0611   kdDebug() << ">>>>>>>>>  ObjectGroup open - " << groupURL << endl;
0612 #endif
0613 
0614   close();
0615 
0616   // API bug
0617   _group = PIOOpenVoidGrp(const_cast<char*>(groupURL.toLatin1().constData()), const_cast<char*>("r"));
0618 
0619   if (_group) {
0620 #ifdef PIOLIBDEBUG
0621     kdDebug() << "               -> opened." << endl;
0622 #endif
0623     if (!updateObjectList()) {
0624       PIOCloseVoidGrp(&_group);
0625       objectListSize = 0;
0626       _group = 0L;
0627     }
0628   }
0629 
0630   return _valid;
0631 }
0632