comparison layer/Colour3DPlotLayer.cpp @ 997:296ccd36f626 tony-2.0-integration

Merge through to branch for Tony 2.0
author Chris Cannam
date Thu, 20 Aug 2015 14:54:21 +0100
parents bc23c2cfff65
children 7242fe160c19
comparison
equal deleted inserted replaced
943:788b7623bfca 997:296ccd36f626
52 m_binScale(LinearBinScale), 52 m_binScale(LinearBinScale),
53 m_normalizeColumns(false), 53 m_normalizeColumns(false),
54 m_normalizeVisibleArea(false), 54 m_normalizeVisibleArea(false),
55 m_normalizeHybrid(false), 55 m_normalizeHybrid(false),
56 m_invertVertical(false), 56 m_invertVertical(false),
57 m_rectified(false),
57 m_opaque(false), 58 m_opaque(false),
58 m_smooth(false), 59 m_smooth(false),
59 m_peakResolution(256), 60 m_peakResolution(256),
60 m_miny(0), 61 m_miny(0),
61 m_maxy(0) 62 m_maxy(0)
160 list.push_back("Normalize Columns"); 161 list.push_back("Normalize Columns");
161 list.push_back("Normalize Visible Area"); 162 list.push_back("Normalize Visible Area");
162 list.push_back("Gain"); 163 list.push_back("Gain");
163 list.push_back("Bin Scale"); 164 list.push_back("Bin Scale");
164 list.push_back("Invert Vertical Scale"); 165 list.push_back("Invert Vertical Scale");
166 list.push_back("Show Rectified");
165 list.push_back("Opaque"); 167 list.push_back("Opaque");
166 list.push_back("Smooth"); 168 list.push_back("Smooth");
167 return list; 169 return list;
168 } 170 }
169 171
173 if (name == "Colour") return tr("Colour"); 175 if (name == "Colour") return tr("Colour");
174 if (name == "Colour Scale") return tr("Scale"); 176 if (name == "Colour Scale") return tr("Scale");
175 if (name == "Normalize Columns") return tr("Normalize Columns"); 177 if (name == "Normalize Columns") return tr("Normalize Columns");
176 if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); 178 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
177 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale"); 179 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
180 if (name == "Show Rectified") return tr("Half-Wave Rectify");
178 if (name == "Gain") return tr("Gain"); 181 if (name == "Gain") return tr("Gain");
179 if (name == "Opaque") return tr("Always Opaque"); 182 if (name == "Opaque") return tr("Always Opaque");
180 if (name == "Smooth") return tr("Smooth"); 183 if (name == "Smooth") return tr("Smooth");
181 if (name == "Bin Scale") return tr("Bin Scale"); 184 if (name == "Bin Scale") return tr("Bin Scale");
182 return ""; 185 return "";
186 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const 189 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
187 { 190 {
188 if (name == "Normalize Columns") return "normalise-columns"; 191 if (name == "Normalize Columns") return "normalise-columns";
189 if (name == "Normalize Visible Area") return "normalise"; 192 if (name == "Normalize Visible Area") return "normalise";
190 if (name == "Invert Vertical Scale") return "invert-vertical"; 193 if (name == "Invert Vertical Scale") return "invert-vertical";
194 if (name == "Show Rectified") return "derivative";
191 if (name == "Opaque") return "opaque"; 195 if (name == "Opaque") return "opaque";
192 if (name == "Smooth") return "smooth"; 196 if (name == "Smooth") return "smooth";
193 return ""; 197 return "";
194 } 198 }
195 199
198 { 202 {
199 if (name == "Gain") return RangeProperty; 203 if (name == "Gain") return RangeProperty;
200 if (name == "Normalize Columns") return ToggleProperty; 204 if (name == "Normalize Columns") return ToggleProperty;
201 if (name == "Normalize Visible Area") return ToggleProperty; 205 if (name == "Normalize Visible Area") return ToggleProperty;
202 if (name == "Invert Vertical Scale") return ToggleProperty; 206 if (name == "Invert Vertical Scale") return ToggleProperty;
207 if (name == "Show Rectified") return ToggleProperty;
203 if (name == "Opaque") return ToggleProperty; 208 if (name == "Opaque") return ToggleProperty;
204 if (name == "Smooth") return ToggleProperty; 209 if (name == "Smooth") return ToggleProperty;
205 return ValueProperty; 210 return ValueProperty;
206 } 211 }
207 212
209 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const 214 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
210 { 215 {
211 if (name == "Normalize Columns" || 216 if (name == "Normalize Columns" ||
212 name == "Normalize Visible Area" || 217 name == "Normalize Visible Area" ||
213 name == "Colour Scale" || 218 name == "Colour Scale" ||
219 name == "Show Rectified" ||
214 name == "Gain") return tr("Scale"); 220 name == "Gain") return tr("Scale");
215 if (name == "Bin Scale" || 221 if (name == "Bin Scale" ||
216 name == "Invert Vertical Scale") return tr("Bins"); 222 name == "Invert Vertical Scale") return tr("Bins");
217 if (name == "Opaque" || 223 if (name == "Opaque" ||
218 name == "Smooth" || 224 name == "Smooth" ||
272 278
273 } else if (name == "Invert Vertical Scale") { 279 } else if (name == "Invert Vertical Scale") {
274 280
275 *deflt = 0; 281 *deflt = 0;
276 val = (m_invertVertical ? 1 : 0); 282 val = (m_invertVertical ? 1 : 0);
283
284 } else if (name == "Show Rectified") {
285
286 if (min) *min = 0;
287 if (max) *max = 0;
288 if (deflt) *deflt = 0;
289 val = (m_rectified ? 1.0 : 0.0);
277 290
278 } else if (name == "Bin Scale") { 291 } else if (name == "Bin Scale") {
279 292
280 *min = 0; 293 *min = 0;
281 *max = 1; 294 *max = 1;
353 setNormalizeColumns(value ? true : false); 366 setNormalizeColumns(value ? true : false);
354 } else if (name == "Normalize Visible Area") { 367 } else if (name == "Normalize Visible Area") {
355 setNormalizeVisibleArea(value ? true : false); 368 setNormalizeVisibleArea(value ? true : false);
356 } else if (name == "Invert Vertical Scale") { 369 } else if (name == "Invert Vertical Scale") {
357 setInvertVertical(value ? true : false); 370 setInvertVertical(value ? true : false);
371 } else if (name == "Show Rectified") {
372 setShowRectified(value > 0.5);
358 } else if (name == "Opaque") { 373 } else if (name == "Opaque") {
359 setOpaque(value ? true : false); 374 setOpaque(value ? true : false);
360 } else if (name == "Smooth") { 375 } else if (name == "Smooth") {
361 setSmooth(value ? true : false); 376 setSmooth(value ? true : false);
362 } else if (name == "Bin Scale") { 377 } else if (name == "Bin Scale") {
470 cacheInvalid(); 485 cacheInvalid();
471 emit layerParametersChanged(); 486 emit layerParametersChanged();
472 } 487 }
473 488
474 void 489 void
490 Colour3DPlotLayer::setShowRectified(bool show)
491 {
492 if (m_rectified == show) return;
493 m_rectified = show;
494 cacheInvalid();
495 emit layerParametersChanged();
496 }
497
498 void
475 Colour3DPlotLayer::setOpaque(bool n) 499 Colour3DPlotLayer::setOpaque(bool n)
476 { 500 {
477 if (m_opaque == n) return; 501 if (m_opaque == n) return;
478 m_opaque = n; 502 m_opaque = n;
479 emit layerParametersChanged(); 503 emit layerParametersChanged();
504 { 528 {
505 return m_smooth; 529 return m_smooth;
506 } 530 }
507 531
508 void 532 void
509 Colour3DPlotLayer::setLayerDormant(const View *v, bool dormant) 533 Colour3DPlotLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant)
510 { 534 {
511 if (dormant) { 535 if (dormant) {
512 536
513 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 537 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
514 cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")" 538 cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")"
528 Layer::setLayerDormant(v, false); 552 Layer::setLayerDormant(v, false);
529 } 553 }
530 } 554 }
531 555
532 bool 556 bool
533 Colour3DPlotLayer::isLayerScrollable(const View *v) const 557 Colour3DPlotLayer::isLayerScrollable(const LayerGeometryProvider *v) const
534 { 558 {
535 if (m_normalizeVisibleArea) { 559 if (m_normalizeVisibleArea) {
536 return false; 560 return false;
537 } 561 }
538 if (shouldPaintDenseIn(v)) { 562 if (shouldPaintDenseIn(v)) {
587 emit layerParametersChanged(); 611 emit layerParametersChanged();
588 return true; 612 return true;
589 } 613 }
590 614
591 bool 615 bool
592 Colour3DPlotLayer::getYScaleValue(const View *, int, 616 Colour3DPlotLayer::getYScaleValue(const LayerGeometryProvider *, int,
593 double &, QString &) const 617 double &, QString &) const
594 { 618 {
595 return false;//!!! 619 return false;//!!!
596 } 620 }
597 621
643 return new LinearRangeMapper(0, m_model->getHeight(), 667 return new LinearRangeMapper(0, m_model->getHeight(),
644 0, m_model->getHeight(), ""); 668 0, m_model->getHeight(), "");
645 } 669 }
646 670
647 double 671 double
648 Colour3DPlotLayer::getYForBin(View *v, double bin) const 672 Colour3DPlotLayer::getYForBin(LayerGeometryProvider *v, double bin) const
649 { 673 {
650 double y = bin; 674 double y = bin;
651 if (!m_model) return y; 675 if (!m_model) return y;
652 double mn = 0, mx = m_model->getHeight(); 676 double mn = 0, mx = m_model->getHeight();
653 getDisplayExtents(mn, mx); 677 getDisplayExtents(mn, mx);
654 double h = v->height(); 678 double h = v->getPaintHeight();
655 if (m_binScale == LinearBinScale) { 679 if (m_binScale == LinearBinScale) {
656 y = h - (((bin - mn) * h) / (mx - mn)); 680 y = h - (((bin - mn) * h) / (mx - mn));
657 } else { 681 } else {
658 double logmin = mn + 1, logmax = mx + 1; 682 double logmin = mn + 1, logmax = mx + 1;
659 LogRange::mapRange(logmin, logmax); 683 LogRange::mapRange(logmin, logmax);
661 } 685 }
662 return y; 686 return y;
663 } 687 }
664 688
665 int 689 int
666 Colour3DPlotLayer::getIYForBin(View *v, int bin) const 690 Colour3DPlotLayer::getIYForBin(LayerGeometryProvider *v, int bin) const
667 { 691 {
668 return int(round(getYForBin(v, bin))); 692 return int(round(getYForBin(v, bin)));
669 } 693 }
670 694
671 double 695 double
672 Colour3DPlotLayer::getBinForY(View *v, double y) const 696 Colour3DPlotLayer::getBinForY(LayerGeometryProvider *v, double y) const
673 { 697 {
674 double bin = y; 698 double bin = y;
675 if (!m_model) return bin; 699 if (!m_model) return bin;
676 double mn = 0, mx = m_model->getHeight(); 700 double mn = 0, mx = m_model->getHeight();
677 getDisplayExtents(mn, mx); 701 getDisplayExtents(mn, mx);
678 double h = v->height(); 702 double h = v->getPaintHeight();
679 if (m_binScale == LinearBinScale) { 703 if (m_binScale == LinearBinScale) {
680 bin = mn + ((h - y) * (mx - mn)) / h; 704 bin = mn + ((h - y) * (mx - mn)) / h;
681 } else { 705 } else {
682 double logmin = mn + 1, logmax = mx + 1; 706 double logmin = mn + 1, logmax = mx + 1;
683 LogRange::mapRange(logmin, logmax); 707 LogRange::mapRange(logmin, logmax);
685 } 709 }
686 return bin; 710 return bin;
687 } 711 }
688 712
689 int 713 int
690 Colour3DPlotLayer::getIBinForY(View *v, int y) const 714 Colour3DPlotLayer::getIBinForY(LayerGeometryProvider *v, int y) const
691 { 715 {
692 return int(floor(getBinForY(v, y))); 716 return int(floor(getBinForY(v, y)));
693 } 717 }
694 718
695 QString 719 QString
696 Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const 720 Colour3DPlotLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
697 { 721 {
698 if (!m_model) return ""; 722 if (!m_model) return "";
699 723
700 int x = pos.x(); 724 int x = pos.x();
701 int y = pos.y(); 725 int y = pos.y();
722 symax = sh; 746 symax = sh;
723 } 747 }
724 if (symin < 0) symin = 0; 748 if (symin < 0) symin = 0;
725 if (symax > sh) symax = sh; 749 if (symax > sh) symax = sh;
726 750
727 // double binHeight = double(v->height()) / (symax - symin); 751 // double binHeight = double(v->getPaintHeight()) / (symax - symin);
728 // int sy = int((v->height() - y) / binHeight) + symin; 752 // int sy = int((v->getPaintHeight() - y) / binHeight) + symin;
729 753
730 int sy = getIBinForY(v, y); 754 int sy = getIBinForY(v, y);
731 755
732 if (sy < 0 || sy >= m_model->getHeight()) { 756 if (sy < 0 || sy >= m_model->getHeight()) {
733 return ""; 757 return "";
753 777
754 return text; 778 return text;
755 } 779 }
756 780
757 int 781 int
758 Colour3DPlotLayer::getColourScaleWidth(QPainter &) const 782 Colour3DPlotLayer::getColourScaleWidth(QPainter &p) const
759 { 783 {
760 int cw = 20; 784 // Font is rotated
785 int cw = p.fontMetrics().height();
761 return cw; 786 return cw;
762 } 787 }
763 788
764 int 789 int
765 Colour3DPlotLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const 790 Colour3DPlotLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const
766 { 791 {
767 if (!m_model) return 0; 792 if (!m_model) return 0;
768 793
769 QString sampleText = QString("[%1]").arg(m_model->getHeight()); 794 QString sampleText = QString("[%1]").arg(m_model->getHeight());
770 int tw = paint.fontMetrics().width(sampleText); 795 int tw = paint.fontMetrics().width(sampleText);
782 807
783 return tw + 13 + getColourScaleWidth(paint); 808 return tw + 13 + getColourScaleWidth(paint);
784 } 809 }
785 810
786 void 811 void
787 Colour3DPlotLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const 812 Colour3DPlotLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const
788 { 813 {
789 if (!m_model) return; 814 if (!m_model) return;
790 815
791 int h = rect.height(), w = rect.width(); 816 int h = rect.height(), w = rect.width();
792 817
842 QString maxstr = QString("%1").arg(max); 867 QString maxstr = QString("%1").arg(max);
843 868
844 paint.save(); 869 paint.save();
845 870
846 QFont font = paint.font(); 871 QFont font = paint.font();
847 font.setPixelSize(10); 872 font.setPixelSize(int(font.pixelSize() * 0.65));
848 paint.setFont(font); 873 paint.setFont(font);
849 874
850 int msw = paint.fontMetrics().width(maxstr); 875 int msw = paint.fontMetrics().width(maxstr);
851 876
852 QMatrix m; 877 QMatrix m;
880 905
881 paint.save(); 906 paint.save();
882 907
883 int py = h; 908 int py = h;
884 909
910 int defaultFontHeight = paint.fontMetrics().height();
911
885 for (int i = symin; i <= symax; ++i) { 912 for (int i = symin; i <= symax; ++i) {
886 913
887 int y0; 914 int y0;
888 915
889 y0 = getIYForBin(v, i); 916 y0 = getIYForBin(v, i);
890 int h = py - y0; 917 int h = py - y0;
891 918
892 if (i > symin) { 919 if (i > symin) {
893 if (paint.fontMetrics().height() >= h) { 920 if (paint.fontMetrics().height() >= h) {
894 if (h >= 8) { 921 if (h >= defaultFontHeight * 0.8) {
895 QFont tf = paint.font(); 922 QFont tf = paint.font();
896 tf.setPixelSize(h-2); 923 tf.setPixelSize(int(h * 0.8));
897 paint.setFont(tf); 924 paint.setFont(tf);
898 } else { 925 } else {
899 continue; 926 continue;
900 } 927 }
901 } 928 }
928 DenseThreeDimensionalModel::Column 955 DenseThreeDimensionalModel::Column
929 Colour3DPlotLayer::getColumn(int col) const 956 Colour3DPlotLayer::getColumn(int col) const
930 { 957 {
931 Profiler profiler("Colour3DPlotLayer::getColumn"); 958 Profiler profiler("Colour3DPlotLayer::getColumn");
932 959
960 DenseThreeDimensionalModel::Column prev;
961 if (m_rectified && (col > m_model->getStartFrame())) {
962 prev = m_model->getColumn(col - 1);
963 }
964
933 DenseThreeDimensionalModel::Column values = m_model->getColumn(col); 965 DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
966
967 if (m_rectified && !prev.empty()) {
968 for (int y = 0; y < values.size(); ++y) {
969 if (values[y] < prev[y]) values[y] = 0;
970 else values[y] -= prev[y];
971 }
972 }
973
934 while (values.size() < m_model->getHeight()) values.push_back(0.f); 974 while (values.size() < m_model->getHeight()) values.push_back(0.f);
935 if (!m_normalizeColumns && !m_normalizeHybrid) return values; 975 if (!m_normalizeColumns && !m_normalizeHybrid) return values;
936 976
937 double colMax = 0.f, colMin = 0.f; 977 double colMax = 0.f, colMin = 0.f;
938 double min = 0.f, max = 0.f; 978 double min = 0.f, max = 0.f;
1244 1284
1245 delete[] peaks; 1285 delete[] peaks;
1246 } 1286 }
1247 1287
1248 bool 1288 bool
1249 Colour3DPlotLayer::shouldPaintDenseIn(const View *v) const 1289 Colour3DPlotLayer::shouldPaintDenseIn(const LayerGeometryProvider *v) const
1250 { 1290 {
1251 if (!m_model || !v || !(v->getViewManager())) { 1291 if (!m_model || !v || !(v->getViewManager())) {
1252 return false; 1292 return false;
1253 } 1293 }
1254 double srRatio = 1294 double srRatio =
1255 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate(); 1295 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate();
1256 if (m_opaque || 1296 if (m_opaque ||
1257 m_smooth || 1297 m_smooth ||
1258 m_model->getHeight() >= v->height() || 1298 m_model->getHeight() >= v->getPaintHeight() ||
1259 ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) { 1299 ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) {
1260 return true; 1300 return true;
1261 } 1301 }
1262 return false; 1302 return false;
1263 } 1303 }
1264 1304
1265 void 1305 void
1266 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const 1306 Colour3DPlotLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
1267 { 1307 {
1268 /* 1308 /*
1269 if (m_model) { 1309 if (m_model) {
1270 SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl; 1310 SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl;
1271 } 1311 }
1276 #endif 1316 #endif
1277 1317
1278 int completion = 0; 1318 int completion = 0;
1279 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) { 1319 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
1280 if (completion > 0) { 1320 if (completion > 0) {
1281 paint.fillRect(0, 10, v->width() * completion / 100, 1321 paint.fillRect(0, 10, v->getPaintWidth() * completion / 100,
1282 10, QColor(120, 120, 120)); 1322 10, QColor(120, 120, 120));
1283 } 1323 }
1284 return; 1324 return;
1285 } 1325 }
1286 1326
1287 if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect(); 1327 if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->getPaintRect();
1288 1328
1289 sv_frame_t modelStart = m_model->getStartFrame(); 1329 sv_frame_t modelStart = m_model->getStartFrame();
1290 sv_frame_t modelEnd = m_model->getEndFrame(); 1330 sv_frame_t modelEnd = m_model->getEndFrame();
1291 int modelResolution = m_model->getResolution(); 1331 int modelResolution = m_model->getResolution();
1292 1332
1300 // "small". This is "large"; see paintDense below for "small". 1340 // "small". This is "large"; see paintDense below for "small".
1301 1341
1302 int x0 = rect.left(); 1342 int x0 = rect.left();
1303 int x1 = rect.right() + 1; 1343 int x1 = rect.right() + 1;
1304 1344
1305 int h = v->height(); 1345 int h = v->getPaintHeight();
1306 1346
1307 double srRatio = 1347 double srRatio =
1308 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate(); 1348 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate();
1309 1349
1310 int sx0 = int((double(v->getFrameForX(x0)) / srRatio - double(modelStart)) 1350 int sx0 = int((double(v->getFrameForX(x0)) / srRatio - double(modelStart))
1422 } 1462 }
1423 } 1463 }
1424 } 1464 }
1425 1465
1426 void 1466 void
1427 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const 1467 Colour3DPlotLayer::paintDense(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
1428 { 1468 {
1429 Profiler profiler("Colour3DPlotLayer::paintDense", true); 1469 Profiler profiler("Colour3DPlotLayer::paintDense", true);
1430 if (!m_cache) return; 1470 if (!m_cache) return;
1431 1471
1432 double modelStart = double(m_model->getStartFrame()); 1472 double modelStart = double(m_model->getStartFrame());
1438 1478
1439 int x0 = rect.left(); 1479 int x0 = rect.left();
1440 int x1 = rect.right() + 1; 1480 int x1 = rect.right() + 1;
1441 1481
1442 const int w = x1 - x0; // const so it can be used as array size below 1482 const int w = x1 - x0; // const so it can be used as array size below
1443 int h = v->height(); // we always paint full height 1483 int h = v->getPaintHeight(); // we always paint full height
1444 int sh = m_model->getHeight(); 1484 int sh = m_model->getHeight();
1445 1485
1446 int symin = m_miny; 1486 int symin = m_miny;
1447 int symax = m_maxy; 1487 int symax = m_maxy;
1448 if (symax <= symin) { 1488 if (symax <= symin) {
1653 1693
1654 paint.drawImage(x0, 0, img); 1694 paint.drawImage(x0, 0, img);
1655 } 1695 }
1656 1696
1657 bool 1697 bool
1658 Colour3DPlotLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, 1698 Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
1659 int &resolution, 1699 int &resolution,
1660 SnapType snap) const 1700 SnapType snap) const
1661 { 1701 {
1662 if (!m_model) { 1702 if (!m_model) {
1663 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 1703 return Layer::snapToFeatureFrame(v, frame, resolution, snap);