comparison layer/Colour3DPlotLayer.cpp @ 535:78f9436195b1

* Add smoothing option to colour 3d plot
author Chris Cannam
date Fri, 22 May 2009 13:54:45 +0000
parents 7a560380b6e2
children aca01b3af29f
comparison
equal deleted inserted replaced
534:7a560380b6e2 535:78f9436195b1
47 m_binScale(LinearBinScale), 47 m_binScale(LinearBinScale),
48 m_normalizeColumns(false), 48 m_normalizeColumns(false),
49 m_normalizeVisibleArea(false), 49 m_normalizeVisibleArea(false),
50 m_invertVertical(false), 50 m_invertVertical(false),
51 m_opaque(false), 51 m_opaque(false),
52 m_smooth(false),
52 m_miny(0), 53 m_miny(0),
53 m_maxy(0) 54 m_maxy(0)
54 { 55 {
55 56
56 } 57 }
153 list.push_back("Normalize Visible Area"); 154 list.push_back("Normalize Visible Area");
154 list.push_back("Gain"); 155 list.push_back("Gain");
155 list.push_back("Bin Scale"); 156 list.push_back("Bin Scale");
156 list.push_back("Invert Vertical Scale"); 157 list.push_back("Invert Vertical Scale");
157 list.push_back("Opaque"); 158 list.push_back("Opaque");
159 list.push_back("Smooth");
158 return list; 160 return list;
159 } 161 }
160 162
161 QString 163 QString
162 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const 164 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
166 if (name == "Normalize Columns") return tr("Normalize Columns"); 168 if (name == "Normalize Columns") return tr("Normalize Columns");
167 if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); 169 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
168 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale"); 170 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
169 if (name == "Gain") return tr("Gain"); 171 if (name == "Gain") return tr("Gain");
170 if (name == "Opaque") return tr("Always Opaque"); 172 if (name == "Opaque") return tr("Always Opaque");
173 if (name == "Smooth") return tr("Smooth");
171 if (name == "Bin Scale") return tr("Bin Scale"); 174 if (name == "Bin Scale") return tr("Bin Scale");
172 return ""; 175 return "";
173 } 176 }
174 177
175 QString 178 QString
177 { 180 {
178 if (name == "Normalize Columns") return "normalise-columns"; 181 if (name == "Normalize Columns") return "normalise-columns";
179 if (name == "Normalize Visible Area") return "normalise"; 182 if (name == "Normalize Visible Area") return "normalise";
180 if (name == "Invert Vertical Scale") return "invert-vertical"; 183 if (name == "Invert Vertical Scale") return "invert-vertical";
181 if (name == "Opaque") return "opaque"; 184 if (name == "Opaque") return "opaque";
185 if (name == "Smooth") return "smooth";
182 return ""; 186 return "";
183 } 187 }
184 188
185 Layer::PropertyType 189 Layer::PropertyType
186 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const 190 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
188 if (name == "Gain") return RangeProperty; 192 if (name == "Gain") return RangeProperty;
189 if (name == "Normalize Columns") return ToggleProperty; 193 if (name == "Normalize Columns") return ToggleProperty;
190 if (name == "Normalize Visible Area") return ToggleProperty; 194 if (name == "Normalize Visible Area") return ToggleProperty;
191 if (name == "Invert Vertical Scale") return ToggleProperty; 195 if (name == "Invert Vertical Scale") return ToggleProperty;
192 if (name == "Opaque") return ToggleProperty; 196 if (name == "Opaque") return ToggleProperty;
197 if (name == "Smooth") return ToggleProperty;
193 return ValueProperty; 198 return ValueProperty;
194 } 199 }
195 200
196 QString 201 QString
197 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const 202 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
201 name == "Colour Scale" || 206 name == "Colour Scale" ||
202 name == "Gain") return tr("Scale"); 207 name == "Gain") return tr("Scale");
203 if (name == "Bin Scale" || 208 if (name == "Bin Scale" ||
204 name == "Invert Vertical Scale") return tr("Bins"); 209 name == "Invert Vertical Scale") return tr("Bins");
205 if (name == "Opaque" || 210 if (name == "Opaque" ||
211 name == "Smooth" ||
206 name == "Colour") return tr("Colour"); 212 name == "Colour") return tr("Colour");
207 return QString(); 213 return QString();
208 } 214 }
209 215
210 int 216 int
271 277
272 } else if (name == "Opaque") { 278 } else if (name == "Opaque") {
273 279
274 *deflt = 0; 280 *deflt = 0;
275 val = (m_opaque ? 1 : 0); 281 val = (m_opaque ? 1 : 0);
282
283 } else if (name == "Smooth") {
284
285 *deflt = 0;
286 val = (m_smooth ? 1 : 0);
276 287
277 } else { 288 } else {
278 val = Layer::getPropertyRangeAndValue(name, min, max, deflt); 289 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
279 } 290 }
280 291
337 setNormalizeVisibleArea(value ? true : false); 348 setNormalizeVisibleArea(value ? true : false);
338 } else if (name == "Invert Vertical Scale") { 349 } else if (name == "Invert Vertical Scale") {
339 setInvertVertical(value ? true : false); 350 setInvertVertical(value ? true : false);
340 } else if (name == "Opaque") { 351 } else if (name == "Opaque") {
341 setOpaque(value ? true : false); 352 setOpaque(value ? true : false);
353 } else if (name == "Smooth") {
354 setSmooth(value ? true : false);
342 } else if (name == "Bin Scale") { 355 } else if (name == "Bin Scale") {
343 switch (value) { 356 switch (value) {
344 default: 357 default:
345 case 0: setBinScale(LinearBinScale); break; 358 case 0: setBinScale(LinearBinScale); break;
346 case 1: setBinScale(LogBinScale); break; 359 case 1: setBinScale(LogBinScale); break;
442 if (m_opaque == n) return; 455 if (m_opaque == n) return;
443 m_opaque = n; 456 m_opaque = n;
444 emit layerParametersChanged(); 457 emit layerParametersChanged();
445 } 458 }
446 459
460 void
461 Colour3DPlotLayer::setSmooth(bool n)
462 {
463 if (m_smooth == n) return;
464 m_smooth = n;
465 emit layerParametersChanged();
466 }
467
447 bool 468 bool
448 Colour3DPlotLayer::getInvertVertical() const 469 Colour3DPlotLayer::getInvertVertical() const
449 { 470 {
450 return m_invertVertical; 471 return m_invertVertical;
451 } 472 }
452 473
453 bool 474 bool
454 Colour3DPlotLayer::getOpaque() const 475 Colour3DPlotLayer::getOpaque() const
455 { 476 {
456 return m_opaque; 477 return m_opaque;
478 }
479
480 bool
481 Colour3DPlotLayer::getSmooth() const
482 {
483 return m_smooth;
457 } 484 }
458 485
459 void 486 void
460 Colour3DPlotLayer::setLayerDormant(const View *v, bool dormant) 487 Colour3DPlotLayer::setLayerDormant(const View *v, bool dormant)
461 { 488 {
1184 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1211 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1185 std::cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << " (zoom level = " << v->getZoomLevel() << ", srRatio = " << srRatio << ")" << std::endl; 1212 std::cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << " (zoom level = " << v->getZoomLevel() << ", srRatio = " << srRatio << ")" << std::endl;
1186 #endif 1213 #endif
1187 1214
1188 if (m_opaque || 1215 if (m_opaque ||
1216 m_smooth ||
1189 int(m_model->getHeight()) >= v->height() || 1217 int(m_model->getHeight()) >= v->height() ||
1190 ((modelResolution * srRatio) / v->getZoomLevel()) < 2) { 1218 ((modelResolution * srRatio) / v->getZoomLevel()) < 2) {
1191 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1219 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1192 std::cerr << "calling paintDense" << std::endl; 1220 std::cerr << "calling paintDense" << std::endl;
1193 #endif 1221 #endif
1340 int sw = source->width(); 1368 int sw = source->width();
1341 1369
1342 long xf = -1; 1370 long xf = -1;
1343 long nxf = v->getFrameForX(x0); 1371 long nxf = v->getFrameForX(x0);
1344 1372
1345 int sxa[w * 2]; 1373 float epsilon = 0.000001;
1374
1375 float sxa[w * 2];
1346 for (int x = 0; x < w; ++x) { 1376 for (int x = 0; x < w; ++x) {
1347 1377
1348 xf = nxf; 1378 xf = nxf;
1349 nxf = xf + zoomLevel; 1379 nxf = xf + zoomLevel;
1350 1380
1351 float sx0 = (float(xf) / srRatio - modelStart) / modelResolution; 1381 float sx0 = (float(xf) / srRatio - modelStart) / modelResolution;
1352 float sx1 = (float(nxf) / srRatio - modelStart) / modelResolution; 1382 float sx1 = (float(nxf) / srRatio - modelStart) / modelResolution;
1353 1383
1354 int sx0i = int(sx0 + 0.001); 1384 sxa[x*2] = sx0;
1355 int sx1i = int(sx1); 1385 sxa[x*2 + 1] = sx1;
1356
1357 sxa[x*2] = sx0i;
1358 sxa[x*2 + 1] = sx1i;
1359 } 1386 }
1360 1387
1361 float logmin = symin+1, logmax = symax+1; 1388 float logmin = symin+1, logmax = symax+1;
1362 LogRange::mapRange(logmin, logmax); 1389 LogRange::mapRange(logmin, logmax);
1363 1390
1364 for (int y = 0; y < h; ++y) { 1391 if (m_smooth) {
1365
1366 float sy0, sy1;
1367
1368 sy0 = getBinForY(v, y + 1);
1369 sy1 = getBinForY(v, y);
1370 /*
1371 if (m_binScale == LinearBinScale) {
1372 sy0 = symin + (float(h - y - 1) * (symax - symin)) / h;
1373 sy1 = symin + (float(h - y) * (symax - symin)) / h;
1374 } else {
1375 // float logmin = LogRange::map(symin);
1376 // float logmax = LogRange::map(symax);
1377 sy0 = logmin + (float(h - y - 1) * (logmax - logmin)) / h;
1378 sy1 = logmin + (float(h - y) * (logmax - logmin)) / h;
1379 sy0 = LogRange::unmap(sy0)-1;
1380 sy1 = LogRange::unmap(sy1)-1;
1381 // sy0 = pow10f(sy0);
1382 // sy1 = pow10f(sy1);
1383 }
1384 */
1385 int sy0i = int(sy0 + 0.001);
1386 int sy1i = int(sy1);
1387
1388 uchar *targetLine = img.scanLine(y);
1389
1390 if (sy0i == sy1i && sy0i == psy1i) { // same scan line as just computed
1391 goto copy;
1392 }
1393
1394 for (int x = 0; x < w; ++x) {
1395 peaks[x] = 0;
1396 }
1397 1392
1398 for (int sy = sy0i; sy <= sy1i; ++sy) { 1393 for (int y = 0; y < h; ++y) {
1399 1394
1400 if (sy < 0 || sy >= source->height()) continue; 1395 float sy = getBinForY(v, y) - 0.5;
1401 1396 int syi = int(sy + epsilon);
1402 uchar *sourceLine = source->scanLine(sy); 1397 if (syi < 0 || syi >= source->height()) continue;
1398
1399 uchar *targetLine = img.scanLine(y);
1400 uchar *sourceLine = source->scanLine(syi);
1401 uchar *nextSource;
1402 if (syi + 1 < source->height()) {
1403 nextSource = source->scanLine(syi + 1);
1404 } else {
1405 nextSource = sourceLine;
1406 }
1407
1408 for (int x = 0; x < w; ++x) {
1409
1410 targetLine[x] = 0;
1411
1412 float sx0 = sxa[x*2];
1413 int sx0i = int(sx0 + epsilon);
1414 if (sx0i >= sw) break;
1415 if (sx0i < 0) continue;
1416
1417 float a, b, value;
1418
1419 float sx1 = sxa[x*2+1];
1420 if (sx1 > sx0 + 1.f) {
1421 int sx1i = int(sx1);
1422 bool have = false;
1423 for (int sx = sx0i; sx <= sx1i; ++sx) {
1424 if (sx < 0 || sx >= sw) continue;
1425 if (!have) {
1426 a = float(sourceLine[sx]);
1427 b = float(nextSource[sx]);
1428 have = true;
1429 } else {
1430 a = std::max(a, float(sourceLine[sx]));
1431 b = std::max(b, float(nextSource[sx]));
1432 }
1433 }
1434 float yprop = sy - syi;
1435 value = (a * (1.f - yprop) + b * yprop);
1436 } else {
1437 a = float(sourceLine[sx0i]);
1438 b = float(nextSource[sx0i]);
1439 float yprop = sy - syi;
1440 value = (a * (1.f - yprop) + b * yprop);
1441 int oi = sx0i + 1;
1442 float xprop = sx0 - sx0i;
1443 xprop -= 0.5;
1444 if (xprop < 0) {
1445 oi = sx0i - 1;
1446 xprop = -xprop;
1447 }
1448 if (oi < 0 || oi >= sw) oi = sx0i;
1449 a = float(sourceLine[oi]);
1450 b = float(nextSource[oi]);
1451 value = (value * (1.f - xprop) +
1452 (a * (1.f - yprop) + b * yprop) * xprop);
1453 }
1454
1455 int vi = lrintf(value);
1456 if (vi > 255) vi = 255;
1457 if (vi < 0) vi = 0;
1458 targetLine[x] = uchar(vi);
1459 }
1460 }
1461 } else {
1462
1463 for (int y = 0; y < h; ++y) {
1464
1465 float sy0, sy1;
1466
1467 sy0 = getBinForY(v, y + 1);
1468 sy1 = getBinForY(v, y);
1469
1470 int sy0i = int(sy0 + epsilon);
1471 int sy1i = int(sy1);
1472
1473 uchar *targetLine = img.scanLine(y);
1474
1475 if (sy0i == sy1i && sy0i == psy1i) { // same source scan line as just computed
1476 goto copy;
1477 }
1478
1479 for (int x = 0; x < w; ++x) {
1480 peaks[x] = 0;
1481 }
1482
1483 for (int sy = sy0i; sy <= sy1i; ++sy) {
1484
1485 if (sy < 0 || sy >= source->height()) continue;
1486
1487 uchar *sourceLine = source->scanLine(sy);
1403 1488
1489 for (int x = 0; x < w; ++x) {
1490
1491 int sx1i = int(sxa[x*2 + 1]);
1492 if (sx1i < 0) continue;
1493
1494 int sx0i = int(sxa[x*2] + epsilon);
1495 if (sx0i >= sw) break;
1496
1497 uchar peak = 0;
1498 for (int sx = sx0i; sx <= sx1i; ++sx) {
1499 if (sx < 0 || sx >= sw) continue;
1500 if (sourceLine[sx] > peak) peak = sourceLine[sx];
1501 }
1502 peaks[x] = peak;
1503 }
1504 }
1505
1506 copy:
1404 for (int x = 0; x < w; ++x) { 1507 for (int x = 0; x < w; ++x) {
1405 1508 targetLine[x] = peaks[x];
1406 int sx1i = sxa[x*2 + 1]; 1509 }
1407 if (sx1i < 0) continue;
1408
1409 int sx0i = sxa[x*2];
1410 if (sx0i >= sw) break;
1411
1412 uchar peak = 0;
1413 for (int sx = sx0i; sx <= sx1i; ++sx) {
1414 if (sx < 0 || sx >= sw) continue;
1415 if (sourceLine[sx] > peak) peak = sourceLine[sx];
1416 }
1417 peaks[x] = peak;
1418 }
1419 }
1420
1421 copy:
1422 for (int x = 0; x < w; ++x) {
1423 targetLine[x] = peaks[x];
1424 } 1510 }
1425 } 1511 }
1426 1512
1427 delete[] peaks; 1513 delete[] peaks;
1428 1514
1429 paint.drawImage(x0, 0, img);
1430 }
1431
1432 void
1433 Colour3DPlotLayer::paintSmooth(View *v, QPainter &paint, QRect rect) const
1434 {
1435 Profiler profiler("Colour3DPlotLayer:paintSmooth");
1436 if (!m_cache) return;
1437
1438 float modelStart = m_model->getStartFrame();
1439 float modelResolution = m_model->getResolution();
1440
1441 int mmsr = v->getViewManager()->getMainModelSampleRate();
1442 int msr = m_model->getSampleRate();
1443 float srRatio = float(mmsr) / float(msr);
1444
1445 int x0 = rect.left();
1446 int x1 = rect.right() + 1;
1447
1448 int h = v->height(); // we always paint full height
1449 int sh = m_model->getHeight();
1450
1451 int symin = m_miny;
1452 int symax = m_maxy;
1453 if (symax <= symin) {
1454 symin = 0;
1455 symax = sh;
1456 }
1457 if (symin < 0) symin = 0;
1458 if (symax > sh) symax = sh;
1459
1460 // QImage img(w, h, QImage::Format_Indexed8);
1461 // img.setColorTable(m_cache->colorTable());
1462
1463 int zoomLevel = v->getZoomLevel();
1464
1465 QImage *source = m_cache;
1466 if (m_peaksCache &&
1467 ((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) {
1468 std::cerr << "using peaks cache" << std::endl;
1469 source = m_peaksCache;
1470 modelResolution *= m_peakResolution;
1471 } else {
1472 std::cerr << "not using peaks cache" << std::endl;
1473 }
1474
1475 float sx0 = (float(v->getFrameForX(x0)) / srRatio - modelStart) / modelResolution;
1476 float sx1 = (float(v->getFrameForX(x1)) / srRatio - modelStart) / modelResolution;
1477 int sx0i = int(sx0 + 0.001);
1478 int sx1i = int(sx1);
1479
1480 if (sx0i < 0) sx0i = 0;
1481 if (sx0i > source->width()) sx0i = source->width();
1482
1483 int tx0 = v->getXForFrame(((sx0i * modelResolution) + modelStart) * srRatio + 0.001);
1484 int tx1 = v->getXForFrame(((sx1i * modelResolution) + modelStart) * srRatio);
1485
1486 std::cerr << "x0 " << x0 << ", x1 " << x1 << " -> sx0 " << sx0i << ", sx1 " << sx1i << " -> tx0 " << tx0 << ", tx1 " << tx1 << std::endl;
1487
1488 QImage img = source->copy(sx0i, 0, sx1i - sx0i, source->height())
1489 .scaled(QSize(tx1 - tx0, h),
1490 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1491 paint.drawImage(x0, 0, img); 1515 paint.drawImage(x0, 0, img);
1492 } 1516 }
1493 1517
1494 bool 1518 bool
1495 Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame, 1519 Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame,
1526 "normalizeColumns=\"%3\" " 1550 "normalizeColumns=\"%3\" "
1527 "normalizeVisibleArea=\"%4\" " 1551 "normalizeVisibleArea=\"%4\" "
1528 "minY=\"%5\" " 1552 "minY=\"%5\" "
1529 "maxY=\"%6\" " 1553 "maxY=\"%6\" "
1530 "invertVertical=\"%7\" " 1554 "invertVertical=\"%7\" "
1531 "opaque=\"%8\" " 1555 "opaque=\"%8\" %9")
1532 "binScale=\"%9\"")
1533 .arg((int)m_colourScale) 1556 .arg((int)m_colourScale)
1534 .arg(m_colourMap) 1557 .arg(m_colourMap)
1535 .arg(m_normalizeColumns ? "true" : "false") 1558 .arg(m_normalizeColumns ? "true" : "false")
1536 .arg(m_normalizeVisibleArea ? "true" : "false") 1559 .arg(m_normalizeVisibleArea ? "true" : "false")
1537 .arg(m_miny) 1560 .arg(m_miny)
1538 .arg(m_maxy) 1561 .arg(m_maxy)
1539 .arg(m_invertVertical ? "true" : "false") 1562 .arg(m_invertVertical ? "true" : "false")
1540 .arg(m_opaque ? "true" : "false") 1563 .arg(m_opaque ? "true" : "false")
1541 .arg((int)m_binScale); 1564 .arg(QString("binScale=\"%1\" smooth=\"%2\" ")
1542 1565 .arg((int)m_binScale)
1566 .arg(m_smooth ? "true" : "false"));
1567
1543 Layer::toXml(stream, indent, extraAttributes + " " + s); 1568 Layer::toXml(stream, indent, extraAttributes + " " + s);
1544 } 1569 }
1545 1570
1546 void 1571 void
1547 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes) 1572 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
1569 (attributes.value("invertVertical").trimmed() == "true"); 1594 (attributes.value("invertVertical").trimmed() == "true");
1570 setInvertVertical(invertVertical); 1595 setInvertVertical(invertVertical);
1571 1596
1572 bool opaque = 1597 bool opaque =
1573 (attributes.value("opaque").trimmed() == "true"); 1598 (attributes.value("opaque").trimmed() == "true");
1574 setNormalizeVisibleArea(opaque); 1599 setOpaque(opaque);
1600
1601 bool smooth =
1602 (attributes.value("smooth").trimmed() == "true");
1603 setSmooth(smooth);
1575 1604
1576 float min = attributes.value("minY").toFloat(&ok); 1605 float min = attributes.value("minY").toFloat(&ok);
1577 float max = attributes.value("maxY").toFloat(&alsoOk); 1606 float max = attributes.value("maxY").toFloat(&alsoOk);
1578 if (ok && alsoOk) setDisplayExtents(min, max); 1607 if (ok && alsoOk) setDisplayExtents(min, max);
1579 } 1608 }