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