The QCPColorMap can already be used to create nice-looking spectrograms, but it requires some tedious work like shifting all existing data before inserting next line/row. Perhaps a lineOffset field could be added to QCPColorMapData and updateMapImage() modified from
for (int line=0; line<lineCount; ++line) { QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-line)); mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic); }to
for (int line=mMapData->lineOffset; line<lineCount; ++line) { QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-(line-mMapData->lineOffset))); mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic); } for (int line=0; line<mMapData->lineOffset; ++line) { QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-(line +lineCount-mMapData->lineOffset))); mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic); }
and data/cell getters/setters changed to
double QCPColorMapData::data(double key, double value) { int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5; int valueCell = (1.0-(value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower))*(mValueSize-1)+0.5; valueCell = (valueCell + lineOffset)%valueSize(); if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize) return mData[valueCell*mKeySize + keyCell]; else return 0; }
double QCPColorMapData::cell(int keyIndex, int valueIndex) { if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize) { valueIndex = (valueIndex + lineOffset)%valueSize(); return mData[valueIndex*mKeySize + keyIndex]; } else return 0; }
void QCPColorMapData::setData(double key, double value, double z) { int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5; int valueCell = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5; valueCell = (valueCell + lineOffset)%valueSize(); if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize) { mData[valueCell*mKeySize + keyCell] = z; if (z < mDataBounds.lower) mDataBounds.lower = z; if (z > mDataBounds.upper) mDataBounds.upper = z; mDataModified = true; } }
void QCPColorMapData::setCell(int keyIndex, int valueIndex, double z) { if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize) { valueIndex = (valueIndex + lineOffset)%valueSize(); mData[valueIndex*mKeySize + keyIndex] = z; if (z < mDataBounds.lower) mDataBounds.lower = z; if (z > mDataBounds.upper) mDataBounds.upper = z; mDataModified = true; } }
Some helper functions like
void QCPColorMapData::shift(bool down) { if(down) lineOffset = ++lineOffset%valueSize(); else lineOffset = (--lineOffset +valueSize())%valueSize(); mDataModified = true; }
and
void QCPColorMapData::insertValues(QVector<double> values, bool top) { shift(top); for(int i = 0; i < values.size(); ++i) setCell(i, top?mValueSize-1:0, values[i]); }
could then easily be introduced.