void KstRWLock::writeLock() const { #ifndef ONE_LOCK_TO_RULE_THEM_ALL QMutexLocker lock(&_mutex); #ifdef LOCKTRACE kstdDebug() << (void*)this << " KstRWLock::writeLock() by tid=" << (int)QThread::currentThread() << endl; // kstdDebug() << kstdBacktrace(6) << endl; #endif Qt::HANDLE me = QThread::currentThread(); if (_readCount > 0) { QMap<Qt::HANDLE, int>::Iterator it = _readLockers.find(me); if (it != _readLockers.end() && it.data() > 0) { // cannot acquire a write lock if I already have a read lock -- ERROR kstdFatal() << "Thread " << (int)QThread::currentThread() << " tried to write lock KstRWLock " << (void*)this << " while holding a read lock" << endl; return; } } while (_readCount > 0 || (_writeCount > 0 && _writeLocker != me)) { ++_waitingWriters; _writerWait.wait(&_mutex); --_waitingWriters; } _writeLocker = me; ++_writeCount; #ifdef LOCKTRACE kstdDebug() << (void*)this << " KstRWLock::writeLock() done by tid=" << (int)QThread::currentThread() << endl; #endif #else _mutex.lock(); #endif }
// Note: e can be null void KstViewWidget::paintEvent(QPaintEvent *e) { #ifdef BENCHMARK QTime t; t.start(); #endif if (e) { // Resize/expose/etc triggered by X11 QRegion r = e->region(); if (r.isEmpty()) { //kstdDebug() << "Paint event with NO region" << endl; _view->paint(KstPainter::P_PAINT); } else { //kstdDebug() << "Paint event with region " << e->region() << endl; _view->paint(KstPainter::P_PAINT, e->region()); } #ifdef BENCHMARK int x = t.elapsed(); kstdDebug() << "Paint event: X11 triggered - " << x << "ms" << endl; #endif } else { // explicitly forced paint in the code _view->paint(KstPainter::P_ZOOM); #ifdef BENCHMARK int x = t.elapsed(); kstdDebug() << "Paint event: Forced (zoom) - " << x << "ms" << endl; #endif } }
void KstRWLock::unlock() const { #ifndef ONE_LOCK_TO_RULE_THEM_ALL QMutexLocker lock(&_mutex); #ifdef LOCKTRACE kstdDebug() << (void*)this << " KstRWLock::unlock() by tid=" << (int)QThread::currentThread() << endl; #endif Qt::HANDLE me = QThread::currentThread(); if (_readCount > 0) { QMap<Qt::HANDLE, int>::Iterator it = _readLockers.find(me); if (it == _readLockers.end()) { // read locked but not by me -- ERROR kstdFatal() << "Thread " << (int)QThread::currentThread() << " tried to unlock KstRWLock " << (void*)this << " (read locked) without holding the lock" << endl; return; } else { --_readCount; if (it.data() == 1) { _readLockers.remove(it); } else { --(it.data()); } } } else if (_writeCount > 0) { if (_writeLocker != me) { // write locked but not by me -- ERROR kstdFatal() << "Thread " << (int)QThread::currentThread() << " tried to unlock KstRWLock " << (void*)this << " (write locked) without holding the lock" << endl; return; } else { --_writeCount; } } else if (_readCount == 0 && _writeCount == 0) { // not locked -- ERROR kstdFatal() << "Thread " << (int)QThread::currentThread() << " tried to unlock KstRWLock " << (void*)this << " (unlocked) without holding the lock" << endl; return; } if (_readCount == 0 && _writeCount == 0) { // no locks remaining if (_waitingWriters) { _writerWait.wakeOne(); } else if (_waitingReaders) { _readerWait.wakeAll(); } } #ifdef LOCKTRACE kstdDebug() << (void*)this << " KstRWLock::unlock() done by tid=" << (int)QThread::currentThread() << endl; #endif #else _mutex.unlock(); #endif }
int NADDirectSource::samplesPerFrame(const QString &field) { if (!_valid) { return 0; } if (field == "INDEX") { kstdDebug() << "NAD::samplesPerFrame(" << field << ") = 1\n"; return 1; } int spf = _conn->samplesPerFrame(field); kstdDebug() << "NAD::samplesPerFrame(" << field << ") = " << spf << endl; return spf; }
KstObject::UpdateType NADDirectSource::update(int u) { if (KstObject::checkUpdateCounter(u)) { return lastUpdateResult(); } if (_conn && _conn->updated()) { updateNumFramesScalar(); kstdDebug() << "NAD::update(" << QString::number(u) << ") = UPDATE\n"; return setLastUpdateResult(KstObject::UPDATE); } else { kstdDebug() << "NAD::update(" << QString::number(u) << ") = NO_CHANGE\n"; return setLastUpdateResult(KstObject::NO_CHANGE); } }
// if n > 0, read n FRAMES starting at frame s for field into buffer v // if n < 0, read 1 SAMPLE from frame s for field into buffer v int NADDirectSource::readField(double *v, const QString& field, int s, int n) { kstdDebug() << "NAD::readField(" << field << ", s=" + QString::number(s) + ", n=" + QString::number(n) + ")" << endl; if (field == "INDEX") { if (n < 0) { v[0] = double(s); return 1; } for (int i = 0; i < n; ++i) { v[i] = double(s + i); } return n > 0 ? n : 0; } if (!_valid || !_conn || !_conn->isValid()) { kstdDebug() << "tried to read from an invalid NAD source" << endl; kstdDebug() << "plugin is valid? " << _valid << endl; return -1; } QSize sz = _conn->range(field); long start = sz.width(), end = sz.height(); long count = end - start + 1; if (s + start > end) { kstdDebug() << "Nothing to read: (" << start << "," << end << ") " << s << endl; return 0; } if (n < 0) { // reading less than 0 -> read only one sample! int spf = _conn->samplesPerFrame(field); double *temp = new double[spf]; _conn->getData(field, temp, start + s, start + s); v[0] = temp[0]; delete[] temp; return 1; } else { if (s + n > count) { // trying to read past the end n = count - s; } // assert(n != 0); // kstdDebug() << "NAD: calling getData()" << endl; int ret = _conn->getData(field, v, start + s, start + s + n - 1); // kstdDebug() << "NAD::readField(" << field << ", s=" + QString::number(s) + ", n=" + QString::number(n) + ") = " << ret << endl; return ret; } }
QStringList provides_naddirect() { kstdDebug() << "in provides_naddirect" << endl; QStringList rc; rc += "Direct NAD Connection"; return rc; }
QStringList fieldList_naddirect(KConfig *cfg, const QString& filename, const QString& type, QString *typeSuggestion, bool *complete) { Q_UNUSED(cfg) kstdDebug() << "in fieldList_naddirect:" << filename << endl; if (!type.isEmpty() && !provides_naddirect().contains(type)) { return QStringList(); } NAD::NADConnection conn; conn.setUrl(filename); if (!conn.isValid()) { return QStringList(); } if (complete) { *complete = true; } if (typeSuggestion) { *typeSuggestion = "Direct NAD Connection"; } QStringList rc = conn.getFields(); if (!rc.empty()) { rc.prepend("INDEX"); } return rc; }
KstBaseCurvePtr KstCurveHint::makeCurve(const QString& tag, const QColor& color) const { KstVectorPtr x = xVector(); KstVectorPtr y = yVector(); if (!x || !y) { kstdDebug() << "Couldn't find either " << _xVectorName << " or " << _yVectorName << endl; return 0L; } return new KstVCurve(tag, x, y, 0L, 0L, 0L, 0L, color); }
int NADDirectSource::frameCount(const QString& field) const { if (!_valid) { return 0; } if (field.isEmpty() || _fieldList.contains(field)) { int maxLen = 0; for (QStringList::ConstIterator i = _fieldList.begin(); i != _fieldList.end(); ++i) { // assert(!(*i).isEmpty()); QSize sz = _conn->range(*i); maxLen = QMAX(sz.height() - sz.width() + 1, maxLen); } kstdDebug() << "NAD::frameCount(" << field << ") = maxLen = " << maxLen << endl; return maxLen; } QSize sz = _conn->range(field); kstdDebug() << "NAD::frameCount(" << field << ") = " << sz.height() - sz.width() + 1 << endl; return sz.height() - sz.width() + 1; }
bool NADDirectSource::init() { kstdDebug() << "NAD::init()\n"; if (_conn->isValid()) { _fieldList = _conn->getFields(); if (!_fieldList.empty()) { _fieldList.prepend("INDEX"); } } return update() == KstObject::UPDATE; }
NADDirectSource::NADDirectSource(KConfig *cfg, const QString& filename, const QString& type) : KstDataSource(cfg, filename, type) { kstdDebug() << "NAD: constructor (filename=" + filename + ")" << endl; _conn = new NAD::NADConnection(); _conn->setUrl(filename); if (init()) { _valid = true; } }
void KstTopLevelView::paint(KstPainter& p, const QRegion& bounds) { updateAlignment(p); #ifdef BENCHMARK QTime t; t.start(); #endif KstViewObject::paint(p, bounds); #ifdef BENCHMARK int x = t.elapsed(); kstdDebug() << " -> Parent class took " << x << "ms" << endl; #endif }
int understands_naddirect(KConfig *cfg, const QString& filename) { Q_UNUSED(cfg) kstdDebug() << "in understands_naddirect:" << filename << endl; KURL url(filename); if (url.protocol().lower() == "nad") { return 99; } else { return 0; } }
void KstRWLock::readLock() const { #ifndef ONE_LOCK_TO_RULE_THEM_ALL QMutexLocker lock(&_mutex); #ifdef LOCKTRACE kstdDebug() << (void*)this << " KstRWLock::readLock() by tid=" << (int)QThread::currentThread() << endl; // kstdDebug() << kstdBacktrace(6) << endl; #endif Qt::HANDLE me = QThread::currentThread(); if (_writeCount > 0 && _writeLocker == me) { // thread already has a write lock #ifdef LOCKTRACE kstdDebug() << "Thread " << (int)QThread::currentThread() << " has a write lock on KstRWLock " << (void*)this << ", getting a read lock" << endl; #endif } else { QMap<Qt::HANDLE, int>::Iterator it = _readLockers.find(me); if (it != _readLockers.end() && it.data() > 0) { // thread already has another read lock } else { while (_writeCount > 0 || _waitingWriters) { // writer priority otherwise ++_waitingReaders; _readerWait.wait(&_mutex); --_waitingReaders; } } } _readLockers[me] = _readLockers[me] + 1; ++_readCount; #ifdef LOCKTRACE kstdDebug() << (void*)this << " KstRWLock::readLock() done by tid=" << (int)QThread::currentThread() << endl; #endif #else _mutex.lock(); #endif }
bool NADDirectSource::isEmpty() const { kstdDebug() << "NAD::isEmpty()" << endl; if (!_valid) { return true; } for (QStringList::ConstIterator i = _fieldList.begin(); i != _fieldList.end(); ++i) { QSize sz = _conn->range(*i); if (sz.height() - sz.width() + 1 > 0) { return false; } } return true; }
void KstViewLabel::computeTextSize(Label::Parsed *lp) { if (lp && lp->chunk) { RenderContext rc(_fontName, _absFontSize, 0L); rc.setSubstituteScalars(_replace); rc.precision = _dataPrecision; #ifdef BENCHMARK QTime t; t.start(); #endif renderLabel(rc, lp->chunk, _vectorsUsed, _scalarsUsed, _stringsUsed); #ifdef BENCHMARK kstdDebug() << "compute (false render) took: " << t.elapsed() << endl; #endif _textWidth = rc.xMax; _ascent = rc.ascent; _textHeight = 1 + rc.ascent + rc.descent; } }
void renderLabel(RenderContext& rc, Label::Chunk *fi) { // FIXME: RTL support int oldSize = rc.size; int oldY = rc.y; int oldX = rc.x; while (fi) { if (fi->vOffset != Label::Chunk::None) { if (fi->vOffset == Label::Chunk::Up) { rc.y -= int(0.4 * rc.fontHeight()); } else { // Down rc.y += int(0.4 * rc.fontHeight()); } if (rc.size > 5) { rc.size = (rc.size*2)/3; } } QFont f = rc.font(); if (rc.fontSize() != rc.size) { f.setPointSize(rc.size); } f.setBold(fi->attributes.bold); f.setItalic(fi->attributes.italic); f.setUnderline(fi->attributes.underline); if (rc.p && fi->attributes.color.isValid()) { rc.p->setPen(fi->attributes.color); } else if (rc.p) { rc.p->setPen(rc.pen); } rc.setFont(f); if (fi->linebreak) { rc.x = oldX; rc.y += rc.fontAscent() + rc.fontDescent() + 1; fi = fi->next; continue; } if (!rc.substitute && (fi->scalar || fi->vector)) { QString txt = QString("[") + fi->text + "]"; if (rc.p) { rc.p->drawText(rc.x, rc.y, txt); } rc.x += rc.fontWidth(txt); } else if (fi->scalar) { // do scalar/string/fit substitution QString txt; if (!fi->text.isEmpty() && fi->text[0] == '=') { // Parse and evaluate as an equation bool ok = false; const double eqResult(Equation::interpret(fi->text.mid(1).latin1(), &ok)); txt = QString::number(eqResult, 'g', rc.precision); if (rc._cache) { rc._cache->append(DataRef(DataRef::DRExpression, fi->text, QString::null, 0.0, QVariant(eqResult))); } } else { KST::scalarList.lock().readLock(); KstScalarPtr scp = *KST::scalarList.findTag(fi->text); KST::scalarList.lock().unlock(); if (scp) { scp->readLock(); txt = QString::number(scp->value(), 'g', rc.precision); if (rc._cache) { rc._cache->append(DataRef(DataRef::DRScalar, fi->text, QString::null, 0.0, QVariant(scp->value()))); } scp->unlock(); } else { KST::stringList.lock().readLock(); KstStringPtr stp = *KST::stringList.findTag(fi->text); KST::stringList.lock().unlock(); if (stp) { stp->readLock(); txt = stp->value(); if (rc._cache) { rc._cache->append(DataRef(DataRef::DRString, fi->text, QString::null, 0.0, QVariant(stp->value()))); } stp->unlock(); } else { KST::dataObjectList.lock().readLock(); KstDataObjectList::Iterator oi = KST::dataObjectList.findTag(fi->text); KST::dataObjectList.lock().unlock(); if (oi != KST::dataObjectList.end()) { KstPluginPtr fit = kst_cast<KstPlugin>(*oi); if (fit) { fit->readLock(); const QString txtAll = fit->label(rc.precision); fit->unlock(); const QValueList<QString> strList = QStringList::split('\n', txtAll); QValueListConstIterator<QString> last = --(strList.end()); for (QValueListConstIterator<QString> iter = strList.begin(); iter != strList.end(); ++iter) { txt = (*iter); if (iter != last) { if (rc.p) { rc.p->drawText(rc.x, rc.y, txt); } else { rc.ascent = kMax(rc.ascent, -rc.y + rc.fontAscent()); if (-rc.y - rc.fontDescent() < 0) { rc.descent = kMax(rc.descent, rc.fontDescent() + rc.y); } } rc.x += rc.fontWidth(txt); rc.xMax = kMax(rc.xMax, rc.x); rc.x = oldX; rc.y += rc.fontAscent() + rc.fontDescent() + 1; } } if (rc._cache) { rc._cache->append(DataRef(DataRef::DRFit, fi->text, txtAll, rc.precision, QVariant(0.0))); } } } } } } if (rc.p) { rc.p->drawText(rc.x, rc.y, txt); } rc.x += rc.fontWidth(txt); } else if (fi->vector) { QString txt; KST::vectorList.lock().readLock(); KstVectorPtr vp = *KST::vectorList.findTag(fi->text); KST::vectorList.lock().unlock(); if (vp) { if (!fi->expression.isEmpty()) { // Parse and evaluate as an equation bool ok = false; // FIXME: make more efficient: cache the parsed equation const double idx = Equation::interpret(fi->expression.latin1(), &ok); if (ok) { vp->readLock(); const double vVal(vp->value()[int(idx)]); txt = QString::number(vVal, 'g', rc.precision); if (rc._cache) { rc._cache->append(DataRef(DataRef::DRVector, fi->text, fi->expression, idx, QVariant(vVal))); } vp->unlock(); } else { txt = "NAN"; } } } if (rc.p) { rc.p->drawText(rc.x, rc.y, txt); } rc.x += rc.fontWidth(txt); } else if (fi->tab) { const int tabWidth = rc.fontWidth("MMMMMMMM"); const int toSkip = tabWidth - (rc.x - rc.xStart) % tabWidth; if (rc.p && fi->attributes.underline) { const int spaceWidth = rc.fontWidth(" "); const int spacesToSkip = tabWidth / spaceWidth + (tabWidth % spaceWidth > 0 ? 1 : 0); rc.p->drawText(rc.x, rc.y, QString().fill(' ', spacesToSkip)); } rc.x += toSkip; } else { if (rc.p) { #ifdef BENCHMARK QTime t; t.start(); #endif rc.p->drawText(rc.x, rc.y, fi->text); #ifdef BENCHMARK kstdDebug() << "Renderer did draw, time: " << t.elapsed() << endl; #endif } rc.x += rc.fontWidth(fi->text); } if (!rc.p) { // No need to compute ascent and descent when really painting rc.ascent = kMax(rc.ascent, -rc.y + rc.fontAscent()); if (-rc.y - rc.fontDescent() < 0) { rc.descent = kMax(rc.descent, rc.fontDescent() + rc.y); } } int xNext = rc.x; if (fi->group) { renderLabel(rc, fi->group); xNext = rc.x; } if (fi->up) { int xPrev = rc.x; renderLabel(rc, fi->up); xNext = kMax(xNext, rc.x); rc.x = xPrev; } if (fi->down) { renderLabel(rc, fi->down); xNext = kMax(xNext, rc.x); } rc.x = xNext; rc.xMax = kMax(rc.xMax, rc.x); fi = fi->next; } rc.size = oldSize; rc.y = oldY; }
bool NADDirectSource::isValidField(const QString& field) const { bool valid = _fieldList.contains(field); kstdDebug() << "NAD::isValidField(" << field << ") = " << valid << endl; return valid; }
int CdfSource::readField(double *v, const QString& field, int s, int n) { int i; CDFstatus status; CDFid id; long dataType = 0, maxRec = 0, numDims = 0, dimSizes[CDF_MAX_DIMS]; long recCount = 0, indices[1] = {0}, counts[1] = {0}; char varName[CDF_VAR_NAME_LEN+1]; bool isZvar = true; /* Should be the case for recent cdf files */ // kstdDebug() << "Entering CdfSource::readField with params: " << field << ", from " << s << " for " << n << " values" << endl; // Handle the special case where we query INDEX if (field.lower() == "index") { if (n < 0) { v[0] = double(s); return 1; } for (int i = 0; i < n; ++i) { v[i] = double(s + i); } return n; } // If not INDEX, look into the CDF file... status = CDFopen(_filename.latin1(), &id); if (status < CDF_OK) { kstdDebug() << _filename << ": failed to open to read from field " << field << endl; return -1; } QString ftmp = field; ftmp.truncate(CDF_VAR_NAME_LEN); // Variable selection strcpy(varName, ftmp.latin1()); status = CDFlib(SELECT_, zVAR_NAME_, varName, GET_, zVAR_DATATYPE_, &dataType, NULL_); if (status < CDF_OK) { // if not zVar, try rVar // kstdDebug() << ftmp << ": " << " not a zVAR (" << status <<")" << endl; isZvar = false; status = CDFlib(SELECT_, rVAR_NAME_, varName, GET_, rVAR_DATATYPE_, &dataType, NULL_); } // I suppose the returned int is the number of values read, <0 when there is a problem if (status < CDF_OK) { kstdDebug() << ftmp << ": " << " not a rVAR either -> exiting" << endl; CDFclose(id); return -1; } // If n<0 set it to 1 as suggested by George Staikos // (needs to be documented better I guess !) // First check for the existence of more values for this field if (n < 0) { n = 1; } void *binary = 0L; void *pt = 0L; // Cast the iteration pointer to the right type and allocate the needed space for binary switch (dataType) { case CDF_INT2: binary = malloc(n*sizeof(Int16)); pt = (Int16 *)binary; break; case CDF_INT4: binary = malloc(n*sizeof(Int32)); pt = (Int32 *)binary; break; case CDF_UINT1: binary = malloc(n*sizeof(uChar)); pt = (uChar *)binary; break; case CDF_UINT2: binary = malloc(n*sizeof(uInt16)); pt = (uInt16 *)binary; break; case CDF_UINT4: binary = malloc(n*sizeof(uInt32)); pt = (uInt32 *)binary; break; case CDF_REAL4: case CDF_FLOAT: binary = malloc(n*sizeof(float)); pt = (float *)binary; break; case CDF_REAL8: case CDF_DOUBLE: binary = malloc(n*sizeof(double)); pt = (double *)binary; break; default : binary = malloc(n*sizeof(long double)); break; } // Get some useful values status = CDFlib (GET_, BOO(isZvar, zVAR_MAXREC_, rVAR_MAXREC_), &maxRec, BOO(isZvar, zVAR_NUMDIMS_, rVARs_NUMDIMS_), &numDims, BOO(isZvar, zVAR_DIMSIZES_, rVARs_DIMSIZES_), dimSizes, NULL_); maxRec += 1; if (numDims == 0 || (numDims == 1 && dimSizes[0] < 2)) { // Vars of dimension 0, or vectors of size 1 (pseudo scalars) with records > 1 status = CDFlib (SELECT_, BOO(isZvar, zVAR_RECNUMBER_, rVAR_SEQPOS_), (long) s, BOO(isZvar, zVAR_RECCOUNT_, rVARs_RECCOUNT_), (long) n, GET_, BOO(isZvar, zVAR_HYPERDATA_, rVAR_HYPERDATA_), binary, NULL_); } else { // Vectors of size [1: n>1] with only one sample/record a la Matlab indices[0] = s; counts[0] = n; recCount = 1; status = CDFlib (SELECT_, BOO(isZvar,zVAR_RECCOUNT_,rVARs_RECCOUNT_), recCount, BOO(isZvar,zVAR_DIMINDICES_,rVARs_DIMINDICES_), indices, BOO(isZvar,zVAR_DIMCOUNTS_,rVARs_DIMCOUNTS_), counts, GET_, BOO(isZvar,zVAR_HYPERDATA_,rVAR_HYPERDATA_), binary, NULL_); maxRec = dimSizes[0]; } for (i = 0; i < n && i < maxRec; i++) { switch (dataType) { case CDF_INT2: v[i] = (double) *((Int16 *)pt); pt = (Int16 *)pt + 1; break; case CDF_INT4: v[i] = (double) *((Int32 *)pt); pt = (Int32 *)pt + 1; break; case CDF_UINT1: v[i] = (double) *((uChar *)pt); pt = (uChar *)pt + 1; break; case CDF_UINT2: v[i] = (double) *((uInt16 *)pt); pt = (uInt16 *)pt + 1; break; case CDF_UINT4: v[i] = (double) *((uInt32 *)pt); pt = (uInt32 *)pt + 1; break; case CDF_REAL4: case CDF_FLOAT: v[i] = (double) *((float *)pt); pt = (float *)pt + 1; break; case CDF_REAL8: case CDF_DOUBLE: v[i] = (double) *((double *)pt); pt = (double *)pt + 1; break; } } free(binary); status = CDFclose(id); return i; }
bool CdfSource::initFile() { CDFid id; CDFstatus status = CDFopen(_filename.latin1(), &id); if (status < CDF_OK) { kstdDebug() << _filename << ": failed to open in initFile()" << endl; return false; } // Query field list and store it in _fieldList (plus "INDEX") _fieldList.clear(); //_fieldList += "INDEX"; commented out as it leads to problems in countFrames(): // which value should the method return when not all variables have the same length ? long numRvars = 0, numZvars = 0, varN = 0, numDims = 0, dimSizes[CDF_MAX_DIMS], maxRec = 0; char varName[CDF_VAR_NAME_LEN + 1]; status = CDFlib(SELECT_, CDF_READONLY_MODE_, READONLYon, GET_, CDF_NUMrVARS_, &numRvars, CDF_NUMzVARS_, &numZvars, NULL_); // We accept the following types of fields: // - scalars (numDims == 0) // - vectors (numDims == 1) of size 1 (dimSizes[0] == 1) // - vectors (numDims == 1) of any size, PROVIDED THAT THEY HAVE ONLY 1 RECORD // Note that the last case is required by Matlab-generated CDFs, where vectors are stored that way // Add 0-dimensional rVariables for (varN = 0; varN < numRvars; varN++) { status = CDFlib(SELECT_, rVAR_, varN, GET_, rVAR_NAME_, varName, rVARs_NUMDIMS_, &numDims, rVARs_DIMSIZES_, dimSizes, rVAR_MAXREC_, &maxRec, NULL_); // maxRec is not exactly the number of records :-) maxRec += 1; if (status == CDF_OK && numDims < 2) { if (numDims == 1 && dimSizes[0] > 1 && maxRec > 1) { // Ignore that, this is not really a vector kstdDebug() << "Variable " << varName << " can't be handled by kst: only CDF vectors with dimensionalities 0, 1[1] or 1[n] but only one record in the latter case are supported (try cdfexport on your CDF if you have problems)" << endl; continue; } _fieldList += varName; if (numDims == 1 && dimSizes[0] > 1) { _frameCounts[QString(varName)] = dimSizes[0]; if ((int) dimSizes[0] > _maxFrameCount) { _maxFrameCount = dimSizes[0]; } } else { _frameCounts[QString(varName)] = maxRec; if ((int) maxRec > _maxFrameCount) { _maxFrameCount = maxRec; } } } } // Add 0-dimensional zVariables for (varN = 0; varN < numZvars; varN++) { status = CDFlib(SELECT_, zVAR_, varN, GET_, zVAR_NAME_, varName, zVAR_NUMDIMS_, &numDims, zVAR_DIMSIZES_, dimSizes, zVAR_MAXREC_, &maxRec, NULL_); maxRec += 1; if (status == CDF_OK && numDims < 2) { if (numDims == 1 && dimSizes[0] > 1 && maxRec > 1) { // Ignore that, this is not really a vector kstdDebug() << "Variable " << varName << " can't be handled by kst: only CDF vectors with dimensionalities 0, 1[1] or 1[n] but only one record in the latter case are supported (try cdfexport on your CDF if you have problems)" << endl; continue; } _fieldList += varName; if (numDims == 1 && dimSizes[0] > 1) { _frameCounts[QString(varName)] = dimSizes[0]; if ((int) dimSizes[0] > _maxFrameCount) { _maxFrameCount = dimSizes[0]; } } else { _frameCounts[QString(varName)] = maxRec; if ((int) maxRec > _maxFrameCount) { _maxFrameCount = maxRec; } } } } // Close the file :-) status = CDFclose(id); return status >= CDF_OK; }
bool UpdateThread::doUpdates(bool force, bool *gotData) { KstObject::UpdateType U = KstObject::NO_CHANGE; _updatedCurves.clear(); // HACK if (gotData) { *gotData = false; } #if UPDATEDEBUG > 0 if (force) { kstdDebug() << "Forced update!" << endl; } #endif _updateCounter++; if (_updateCounter < 1) { _updateCounter = 1; // check for wrap around } #if UPDATEDEBUG > 2 kstdDebug() << "UPDATE: counter=" << _updateCounter << endl; #endif { // Must make a copy to avoid deadlock KstBaseCurveList cl; KstDataObjectList dol; kstObjectSplitList<KstDataObject, KstBaseCurve>(KST::dataObjectList, cl, dol); qHeapSort(cl); qHeapSort(dol); // Update all curves for (uint i = 0; i < cl.count(); ++i) { KstBaseCurvePtr bcp = cl[i]; bcp->writeLock(); assert(bcp.data()); #if UPDATEDEBUG > 1 kstdDebug() << "updating curve: " << (void*)bcp << " - " << bcp->tagName() << endl; #endif KstObject::UpdateType ut = bcp->update(_updateCounter); bcp->unlock(); if (ut == KstObject::UPDATE) { // HACK _updatedCurves.append(bcp); } if (U != KstObject::UPDATE) { U = ut; if (U == KstObject::UPDATE) { #if UPDATEDEBUG > 0 kstdDebug() << "Curve " << bcp->tagName() << " said UPDATE" << endl; #endif } } if (_done || (_paused && !force)) { #if UPDATEDEBUG > 1 kstdDebug() << "5 Returning from scan with U=" << (int)U << endl; #endif return U == KstObject::UPDATE; } } // Update all data objects for (uint i = 0; i < dol.count(); ++i) { KstDataObjectPtr dp = dol[i]; dp->writeLock(); assert(dp.data()); #if UPDATEDEBUG > 1 kstdDebug() << "updating data object: " << (void*)dp << " - " << dp->tagName() << endl; #endif dp->update(_updateCounter); dp->unlock(); if (_done || (_paused && !force)) { #if UPDATEDEBUG > 1 kstdDebug() << "5 Returning from scan with U=" << (int)U << endl; #endif return U == KstObject::UPDATE; } } } // Update the files if (!_paused) { // don't update even if paused && force KST::dataSourceList.lock().readLock(); unsigned cnt = KST::dataSourceList.count(); for (uint i = 0; i < cnt; ++i) { KstDataSourcePtr dsp = KST::dataSourceList[i]; dsp->writeLock(); dsp->update(_updateCounter); dsp->unlock(); if (_done) { KST::dataSourceList.lock().unlock(); return false; } } KST::dataSourceList.lock().unlock(); } if (KstScalar::scalarsDirty()) { KstScalar::clearScalarsDirty(); // Must do this first and take a risk of // falling slightly behind KST::scalarList.lock().readLock(); KstScalarList sl = QDeepCopy<KstScalarList>(KST::scalarList.list()); // avoid deadlock on exit KST::scalarList.lock().unlock(); for (KstScalarList::ConstIterator i = sl.begin(); i != sl.end(); ++i) { KstScalarPtr sp = *i; sp->writeLock(); KstObject::UpdateType ut = sp->update(_updateCounter); sp->unlock(); if (ut == KstObject::UPDATE) { U = KstObject::UPDATE; } if (_done) { return false; } } } if (U == KstObject::UPDATE) { kstdDebug() << "Update plots" << endl; if (gotData) { // FIXME: do we need to consider all the other exit points? *gotData = true; } } #if UPDATEDEBUG > 1 kstdDebug() << "6 Returning from scan with U=" << (int)U << endl; #endif return U == KstObject::UPDATE; }
NADDirectSource::~NADDirectSource() { kstdDebug() << "NAD: destructor\n"; if (_conn) { delete _conn; } }
void UpdateThread::run() { bool force; int updateTime; #if UPDATEDEBUG > 0 kstdDebug() << "Update thread running, tid=" << (int)QThread::currentThread() << endl; #if UPDATEDEBUG > 2 kstdDebug() << "dataObjectList lock is at " << (void*)(&KST::dataObjectList.lock()) << endl; kstdDebug() << "dataSourceList lock is at " << (void*)(&KST::dataSourceList.lock()) << endl; #endif #endif _done = false; while (!_done) { _statusMutex.lock(); updateTime = _updateTime; _statusMutex.unlock(); if (_waitCondition.wait(_updateTime)) { #if UPDATEDEBUG > 0 kstdDebug() << "Update timer " << _updateTime << endl; #endif if (!_force) { break; } } _statusMutex.lock(); if (_done) { _statusMutex.unlock(); break; } force = _force; _force = false; _statusMutex.unlock(); if (_paused && !force) { #if UPDATEDEBUG > 0 kstdDebug() << "Update thread paused..." << endl; #endif continue; } bool gotData = false; if (doUpdates(force, &gotData) && !_done) { #if UPDATEDEBUG > 1 kstdDebug() << "Update resulted in: TRUE!" << endl; #endif if (gotData) { kstdDebug() << "Posting UpdateDataDialogs" << endl; ThreadEvent *e = new ThreadEvent(ThreadEvent::UpdateDataDialogs); e->_curves = _updatedCurves; e->_counter = _updateCounter; QApplication::postEvent(_doc, e); // this event also triggers an implicit repaint } else { QApplication::postEvent(_doc, new ThreadEvent(ThreadEvent::Repaint)); } // Wait for UI thread to finish events. If we don't wait // 1: the UI thread could get flooded with events // 2: the update thread could change vectors during a paint, causing // inconsistent curves to be plotted ie, the X vector updated // and the Y vector not yet updated... // Race warning: Syncronization of updating() is not assured, // but updating() will always return a valid answer which was // true 'close' to when we asked. This will safely keep the // update thread from over filling the UI thread. The usleeps // will hopefully give the UI thread a chance to set itself... usleep(1000); // 1 ms on 2.6 kernel. 10ms on 2.4 kernel while (!_done && _doc->updating()) { // wait for the UI to finish old events usleep(1000); } usleep(1000); // check again... not strictly needed given implicit repaint below, // but it should just return false, so no harm done. while (!_done && _doc->updating()) { usleep(1000); } } else { QApplication::postEvent(_doc, new ThreadEvent(ThreadEvent::NoUpdate)); } } QApplication::postEvent(_doc, new ThreadEvent(ThreadEvent::Done)); }
// if n > 0, read 1 SAMPLE from each of n FRAMES starting at frame s skipping by 'skip' for field into buffer v // if n < 0, read 1 SAMPLE from frame s for field into buffer v int NADDirectSource::readField(double *v, const QString& field, int s, int n, int skip, int *lastFrameRead) { kstdDebug() << "NAD::readField(" << field << ", s=" + QString::number(s) + ", n=" + QString::number(n) + ", skip=" + QString::number(skip) + ")" << endl; if (lastFrameRead) *lastFrameRead = -1; if (field == "INDEX") { if (n < 0) { v[0] = double(s); if (lastFrameRead) *lastFrameRead = s; return 1; } for (int i = 0; i < n; ++i) { v[i] = double(s + i*skip); } if (lastFrameRead) *lastFrameRead = s + (n - 1) * skip; return n > 0 ? n : 0; } if (!_valid || !_conn || !_conn->isValid()) { kstdDebug() << "tried to read from an invalid NAD source" << endl; kstdDebug() << "plugin is valid? " << _valid << endl; return -1; } QSize sz = _conn->range(field); long start = sz.width(), end = sz.height(); long count = end - start + 1; int spf = _conn->samplesPerFrame(field); if (s + start > end) { kstdDebug() << "Nothing to read: (" << start << "," << end << ") " << s << endl; return 0; } if (n < 0) { // reading less than 0 -> read only one sample! double *temp = new double[spf]; _conn->getData(field, temp, start + s, start + s); v[0] = temp[0]; delete[] temp; if (lastFrameRead) *lastFrameRead = s; return 1; } else { if (s + (n-1)*skip >= count) { // trying to read past the end // n = ceil((count-s)/skip) if ((count - s) % skip == 0) { n = (count - s) / skip; } else { n = (count - s) / skip + 1; } n = count - s; } double *tmp = new double[n * spf]; // kstdDebug() << "NAD: calling getData()" << endl; int rc = _conn->getData(field, tmp, start + s, start + s + (n - 1) * skip, skip); // get skipped frames int framesRead = rc/spf; //kstdDebug() << "readObject rc=" << rc << " from=" << start+s << " to=" << start + s + (n - 1) * skip << endl; // extract first sample from each returned frame int i = 0; while (i < QMAX(n, framesRead)) { v[i] = tmp[i * spf]; ++i; } delete[] tmp; // kstdDebug() << "NAD::readField(" << field << ", s=" + QString::number(s) + ", n=" + QString::number(n) + ", skip=" + QString::number(skip) + ") = " << i << endl; if (i > 0 && lastFrameRead) { *lastFrameRead = s + (i - 1) * skip; } return i; } }
void KstViewLabel::drawToPainter(Label::Parsed *lp, QPainter& p) { int hJust = KST_JUSTIFY_H(_justify); if (QApplication::reverseLayout()) { if (hJust == KST_JUSTIFY_H_NONE) { hJust = KST_JUSTIFY_H_RIGHT; } } else { if (hJust == KST_JUSTIFY_H_NONE) { hJust = KST_JUSTIFY_H_LEFT; } } RenderContext rc(_fontName, _absFontSize, &p); rc.setSubstituteScalars(_replace); rc.precision = _dataPrecision; rc._cache = &_cache.data; _cache.valid = false; _cache.data.clear(); double rotationRadians = M_PI * (int(_rotation) % 360) / 180; double absin = fabs(sin(rotationRadians)); double abcos = fabs(cos(rotationRadians)); int tx = 0, ty = 0; // translation const QRect cr(contentsRect()); switch (hJust) { case KST_JUSTIFY_H_RIGHT: rc.x = -_textWidth / 2; tx = cr.width() - int(_textWidth * abcos + _textHeight * absin) / 2 - _labelMargin*_ascent/10; break; case KST_JUSTIFY_H_CENTER: rc.x = -_textWidth / 2; tx = cr.width() / 2; break; case KST_JUSTIFY_H_NONE: abort(); // should never be able to happen case KST_JUSTIFY_H_LEFT: default: rc.x = -_textWidth / 2; tx = int(_textWidth * abcos + _textHeight * absin) / 2 + _labelMargin*_ascent/10; break; } rc.y = _ascent - _textHeight / 2; ty = int(_textHeight * abcos + _textWidth * absin) / 2 + _labelMargin*_ascent/10; p.translate(tx, ty); p.rotate(_rotation); rc.pen = foregroundColor(); rc.xStart = rc.x; #ifdef BENCHMARK QTime t; t.start(); #endif if (lp && lp->chunk) { renderLabel(rc, lp->chunk, _vectorsUsed, _scalarsUsed, _stringsUsed); _cache.valid = true; } #ifdef BENCHMARK kstdDebug() << "render took: " << t.elapsed() << endl; t.start(); #endif QApplication::syncX(); #ifdef BENCHMARK kstdDebug() << "sync X took: " << t.elapsed() << endl; #endif }
KstDataSource *create_naddirect(KConfig *cfg, const QString& filename, const QString& type) { kstdDebug() << "in create_naddirect:" << filename << endl; return new NADDirectSource(cfg, filename, type); }
void doTests() { // the data file to use. // first determine the path used to call this program, // and then prepend that to the data file name. QString path = myName.section('/', 0, -3); QString datafile = path; datafile.append("/healpix_example_sm.fits"); // create a temporary config file to use QString cfgfile = "testhealpix.temp"; KConfig *cfg = new KConfig(cfgfile, false, false); cfg->setGroup("Healpix General"); cfg->setGroup(datafile); cfg->writeEntry("Matrix X Dimension", XDIM); cfg->writeEntry("Matrix Y Dimension", YDIM); cfg->writeEntry("Theta Autoscale", true); cfg->writeEntry("Theta Units", 0); cfg->writeEntry("Theta Min", 0.0); cfg->writeEntry("Theta Max", 1.0); cfg->writeEntry("Phi Autoscale", true); cfg->writeEntry("Phi Units", 0); cfg->writeEntry("Phi Min", 0.0); cfg->writeEntry("Phi Max", 1.0); cfg->writeEntry("Vector Theta", 1); cfg->writeEntry("Vector Phi", 2); cfg->writeEntry("Vector Degrade Factor", DEGRADE); cfg->writeEntry("Vector Magnitude Autoscale", true); cfg->writeEntry("Vector Max Magnitude", 1.0); cfg->writeEntry("Vector is QU", true); // use the C functions to test for healpix support int verstehen = understands_healpix(cfg, datafile); if (verstehen) { kstdDebug() << "Data file " << datafile << " is supported" << endl; QString suggestion; bool complete; QStringList matrices = matrixList_healpix(cfg, datafile, "HEALPIX", &suggestion, &complete); kstdDebug() << "Available matrices are:" << endl; for ( QStringList::Iterator it = matrices.begin(); it != matrices.end(); ++it ) { kstdDebug() << " " << *it << endl; } kstdDebug() << " suggestion = " << suggestion << endl; kstdDebug() << " complete = " << complete << endl; QStringList fields = fieldList_healpix(cfg, datafile, "HEALPIX", &suggestion, &complete); kstdDebug() << "Available fields are:" << endl; for ( QStringList::Iterator it = fields.begin(); it != fields.end(); ++it ) { kstdDebug() << " " << *it << endl; } kstdDebug() << " suggestion = " << suggestion << endl; kstdDebug() << " complete = " << complete << endl; // actually create HealpixSource HealpixSource *hpx = new HealpixSource(cfg, datafile, "HEALPIX"); // test that saveConfig produces the same as the // original input configuration QString cfgfile2 = "testhealpix.temp2"; KConfig *chk = new KConfig(cfgfile2, false, false); hpx->saveConfig(chk); StringMap cfgmap = cfg->entryMap(datafile); StringMap chkmap = chk->entryMap(datafile); /* kstdDebug() << cfgmap["Matrix X Dimension"] << " " << chkmap["Matrix X Dimension"] << endl; kstdDebug() << cfgmap["Matrix Y Dimension"] << " " << chkmap["Matrix Y Dimension"] << endl; kstdDebug() << cfgmap["Theta Autoscale"] << " " << chkmap["Theta Autoscale"] << endl; kstdDebug() << cfgmap["Theta Units"] << " " << chkmap["Theta Units"] << endl; kstdDebug() << cfgmap["Theta Min"] << " " << chkmap["Theta Min"] << endl; kstdDebug() << cfgmap["Theta Max"] << " " << chkmap["Theta Max"] << endl; kstdDebug() << cfgmap["Phi Autoscale"] << " " << chkmap["Phi Autoscale"] << endl; kstdDebug() << cfgmap["Phi Units"] << " " << chkmap["Phi Units"] << endl; kstdDebug() << cfgmap["Phi Min"] << " " << chkmap["Phi Min"] << endl; kstdDebug() << cfgmap["Phi Max"] << " " << chkmap["Phi Max"] << endl; kstdDebug() << cfgmap["Vector Theta"] << " " << chkmap["Vector Theta"] << endl; kstdDebug() << cfgmap["Vector Phi"] << " " << chkmap["Vector Phi"] << endl; kstdDebug() << cfgmap["Vector Degrade Factor"] << " " << chkmap["Vector Degrade Factor"] << endl; kstdDebug() << cfgmap["Vector Magnitude Autoscale"] << " " << chkmap["Vector Magnitude Autoscale"] << endl; kstdDebug() << cfgmap["Vector Max Magnitude"] << " " << chkmap["Vector Max Magnitude"] << endl; kstdDebug() << cfgmap["Vector is QU"] << " " << chkmap["Vector is QU"] << endl; */ if (cfgmap["Matrix X Dimension"] != chkmap["Matrix X Dimension"]) { QString msg = "Matrix X Dimension integrity"; testAssert(false, msg); } if (cfgmap["Matrix Y Dimension"] != chkmap["Matrix Y Dimension"]) { QString msg = "Matrix Y Dimension integrity"; testAssert(false, msg); } if (cfgmap["Theta Autoscale"] != chkmap["Theta Autoscale"]) { QString msg = "Theta Autoscale integrity"; testAssert(false, msg); } if (cfgmap["Theta Units"] != chkmap["Theta Units"]) { QString msg = "Theta Units integrity"; testAssert(false, msg); } if (cfgmap["Theta Min"] != chkmap["Theta Min"]) { QString msg = "Theta Min integrity"; testAssert(false, msg); } if (cfgmap["Theta Max"] != chkmap["Theta Max"]) { QString msg = "Theta Max integrity"; testAssert(false, msg); } if (cfgmap["Phi Autoscale"] != chkmap["Phi Autoscale"]) { QString msg = "Phi Autoscale integrity"; testAssert(false, msg); } if (cfgmap["Phi Units"] != chkmap["Phi Units"]) { QString msg = "Phi Units integrity"; testAssert(false, msg); } if (cfgmap["Phi Min"] != chkmap["Phi Min"]) { QString msg = "Phi Min integrity"; testAssert(false, msg); } if (cfgmap["Phi Max"] != chkmap["Phi Max"]) { QString msg = "Phi Max integrity"; testAssert(false, msg); } if (cfgmap["Vector Theta"] != chkmap["Vector Theta"]) { QString msg = "Vector Theta integrity"; testAssert(false, msg); } if (cfgmap["Vector Phi"] != chkmap["Vector Phi"]) { QString msg = "Vector Phi integrity"; testAssert(false, msg); } if (cfgmap["Vector Degrade Factor"] != chkmap["Vector Degrade Factor"]) { QString msg = "Vector Degrade Factor integrity"; testAssert(false, msg); } if (cfgmap["Vector Magnitude Autoscale"] != chkmap["Vector Magnitude Autoscale"]) { QString msg = "Vector Magnitude Autoscale integrity"; testAssert(false, msg); } if (cfgmap["Vector Max Magnitude"] != chkmap["Vector Max Magnitude"]) { QString msg = "Vector Max Magnitude integrity"; testAssert(false, msg); } if (cfgmap["Vector is QU"] != chkmap["Vector is QU"]) { QString msg = "Vector is QU integrity"; testAssert(false, msg); } kstdDebug() << "Save/Load config is consistent." << endl; // print _metaData and compute NSIDE and number // of samples in the vectors int nside = 0; int nvec; QString key; KstString *data; kstdDebug() << "Checking metaData:" << endl; QDict<KstString> metamap = hpx->metaData(); QDictIterator<KstString> it(metamap); for ( ; it.current(); ++it ) { key = it.currentKey(); data = it.current(); if (data) { kstdDebug() << " " << key.latin1() << " = " << data->value().latin1() << endl; if (key == "NSIDE") { nside = data->value().toInt(); } } } kstdDebug() << "Data file has nside = " << nside << endl; testAssert(nside != 0, "data file NSIDE"); for (int i = 0; i < DEGRADE; i++) { nside = (int)(nside/2); } nvec = 12*nside*nside; kstdDebug() << "Degraded vectorfield has nside = " << nside << " and " << nvec << " full-sphere pixels" << endl; // check that all returned fields are valid, and that // optionally field number names are valid. kstdDebug() << "Checking matrix validity:" << endl; int num = 1; int xdim, ydim, nframe, sampframe; for ( QStringList::Iterator it = matrices.begin(); it != matrices.end(); ++it ) { if (hpx->isValidMatrix(*it)) { kstdDebug() << " \"" << *it << "\" is VALID" << endl; hpx->matrixDimensions(*it, &xdim, &ydim); kstdDebug() << " and has dimensions " << xdim << "x" << ydim << endl; testAssert((xdim == XDIM)&&(ydim == YDIM), "dimension integrity"); } else { QString msg = (*it); msg.append(" validity"); testAssert(false, msg); } QString numfield = QString("%1").arg(num); if (hpx->isValidMatrix(numfield)) { kstdDebug() << " \"" << numfield << "\" is VALID" << endl; hpx->matrixDimensions(numfield, &xdim, &ydim); kstdDebug() << " and has dimensions " << xdim << "x" << ydim << endl; testAssert((xdim == XDIM)&&(ydim == YDIM), "dimension integrity"); } else { QString msg = numfield; msg.append(" validity"); testAssert(false, msg); } num++; } kstdDebug() << "Checking field validity:" << endl; num = 1; for ( QStringList::Iterator it = fields.begin(); it != fields.end(); ++it ) { if (hpx->isValidField(*it)) { kstdDebug() << " \"" << *it << "\" is VALID" << endl; nframe = hpx->frameCount(*it); sampframe = hpx->samplesPerFrame(*it); kstdDebug() << " and has " << nframe << " frames of " << sampframe << " sample(s) each" << endl; testAssert(sampframe == 1, "samples per frame"); testAssert(nframe == nvec, "number of frames"); } else { QString msg = (*it); msg.append(" validity"); testAssert(false, msg); } QString numfield = QString("%1").arg(num); if (hpx->isValidField(numfield)) { kstdDebug() << " \"" << numfield << "\" is VALID" << endl; nframe = hpx->frameCount(numfield); sampframe = hpx->samplesPerFrame(numfield); kstdDebug() << " and has " << nframe << " frames of " << sampframe << " sample(s) each" << endl; testAssert(sampframe == 1, "samples per frame"); testAssert(nframe == nvec, "number of frames"); } else { QString msg = numfield; msg.append(" validity"); testAssert(false, msg); } num++; } // check reset function if (hpx->reset()) { kstdDebug() << "Reset function is implemented." << endl; } else { testAssert(false, "reset"); } } else { testAssert(false, "understanding"); } }