Mercurial > hg > svgui
comparison view/View.cpp @ 1507:996e971df9e7
Fix, I think, #1914 Mounting rounding error when dragging aligned view left/right - and therefore the associated #1874 Pointer position becomes increasingly erroneous when rewinding with alignment active
author | Chris Cannam |
---|---|
date | Fri, 13 Sep 2019 17:40:59 +0100 |
parents | 60fe0d20df5d |
children | 395ef06beab1 |
comparison
equal
deleted
inserted
replaced
1506:60fe0d20df5d | 1507:996e971df9e7 |
---|---|
395 // In FramesPerPixel mode, the pixel should be the one "covering" | 395 // In FramesPerPixel mode, the pixel should be the one "covering" |
396 // the given frame, i.e. to the "left" of it - not necessarily the | 396 // the given frame, i.e. to the "left" of it - not necessarily the |
397 // nearest boundary. | 397 // nearest boundary. |
398 | 398 |
399 sv_frame_t level = m_zoomLevel.level; | 399 sv_frame_t level = m_zoomLevel.level; |
400 sv_frame_t fdiff = frame - getCentreFrame(); | 400 sv_frame_t fdiff = frame - m_centreFrame; |
401 int result = 0; | 401 int result = 0; |
402 | 402 |
403 bool inRange = false; | 403 bool inRange = false; |
404 if (m_zoomLevel.zone == ZoomLevel::FramesPerPixel) { | 404 if (m_zoomLevel.zone == ZoomLevel::FramesPerPixel) { |
405 inRange = ((fdiff / level) < sv_frame_t(INT_MAX) && | 405 inRange = ((fdiff / level) < sv_frame_t(INT_MAX) && |
412 if (inRange) { | 412 if (inRange) { |
413 | 413 |
414 sv_frame_t adjusted; | 414 sv_frame_t adjusted; |
415 | 415 |
416 if (m_zoomLevel.zone == ZoomLevel::FramesPerPixel) { | 416 if (m_zoomLevel.zone == ZoomLevel::FramesPerPixel) { |
417 sv_frame_t roundedCentreFrame = (m_centreFrame / level) * level; | |
418 fdiff = frame - roundedCentreFrame; | |
417 adjusted = fdiff / level; | 419 adjusted = fdiff / level; |
418 if ((fdiff < 0) && ((fdiff % level) != 0)) { | 420 if ((fdiff < 0) && ((fdiff % level) != 0)) { |
419 --adjusted; // round to the left | 421 --adjusted; // round to the left |
420 } | 422 } |
421 } else { | 423 } else { |
440 << "called for locations unadjacent to the current view" | 442 << "called for locations unadjacent to the current view" |
441 << endl; | 443 << endl; |
442 return 0; | 444 return 0; |
443 } | 445 } |
444 | 446 |
447 #ifdef DEBUG_VIEW | |
448 if (m_zoomLevel.zone == ZoomLevel::PixelsPerFrame) { | |
449 sv_frame_t reversed = getFrameForX(result); | |
450 if (reversed != frame) { | |
451 SVCERR << "View[" << getId() << "]::getXForFrame: WARNING: Converted frame " << frame << " to x " << result << " in PixelsPerFrame zone, but the reverse conversion gives frame " << reversed << " (error = " << reversed - frame << ")" << endl; | |
452 SVCERR << "(centre frame = " << getCentreFrame() << ", fdiff = " | |
453 << fdiff << ", level = " << level << ", centre % level = " | |
454 << (getCentreFrame() % level) << ", fdiff % level = " | |
455 << (fdiff % level) << ", frame % level = " | |
456 << (frame % level) << ", reversed % level = " | |
457 << (reversed % level) << ")" << endl; | |
458 } | |
459 } | |
460 #endif | |
461 | |
445 return result; | 462 return result; |
446 } | 463 } |
447 | 464 |
448 sv_frame_t | 465 sv_frame_t |
449 View::getFrameForX(int x) const | 466 View::getFrameForX(int x) const |
450 { | 467 { |
451 // Note, this must always return a value that is on a zoom-level | 468 // Note, this must always return a value that is on a zoom-level |
452 // boundary - regardless of whether the nominal centre frame is on | 469 // boundary - regardless of whether the nominal centre frame is on |
453 // such a boundary or not. | 470 // such a boundary or not. (It is legitimate for the centre frame |
454 | 471 // not to be on a zoom-level boundary, because the centre frame |
455 // In PixelsPerFrame mode, the frame should be the one immediately | 472 // may be shared with other views having different zoom levels.) |
456 // left of the given pixel, not necessarily the nearest. | 473 |
474 // In FramesPerPixel mode, the frame returned for a given x should | |
475 // be the first for which getXForFrame(frame) == x; a corollary is | |
476 // that if the centre frame is not on a zoom-level boundary, then | |
477 // getFrameForX(x) should not return the centre frame for any x. | |
478 | |
479 // In PixelsPerFrame mode, the frame returned should be the one | |
480 // immediately left of the given pixel, not necessarily the | |
481 // nearest. | |
457 | 482 |
458 int diff = x - (width()/2); | 483 int diff = x - (width()/2); |
459 sv_frame_t level = m_zoomLevel.level; | 484 sv_frame_t level = m_zoomLevel.level; |
460 sv_frame_t fdiff, result; | 485 sv_frame_t fdiff, result; |
461 | 486 |
462 if (m_zoomLevel.zone == ZoomLevel::FramesPerPixel) { | 487 if (m_zoomLevel.zone == ZoomLevel::FramesPerPixel) { |
488 sv_frame_t roundedCentreFrame = (m_centreFrame / level) * level; | |
463 fdiff = diff * level; | 489 fdiff = diff * level; |
464 result = ((fdiff + m_centreFrame) / level) * level; | 490 result = fdiff + roundedCentreFrame; |
465 } else { | 491 } else { |
466 fdiff = diff / level; | 492 fdiff = diff / level; |
467 if ((diff < 0) && ((diff % level) != 0)) { | 493 if ((diff < 0) && ((diff % level) != 0)) { |
468 --fdiff; // round to the left | 494 --fdiff; // round to the left |
469 } | 495 } |
470 result = fdiff + m_centreFrame; | 496 result = fdiff + m_centreFrame; |
471 } | 497 } |
472 | 498 |
473 #ifdef DEBUG_VIEW_WIDGET_PAINT | 499 #ifdef DEBUG_VIEW_WIDGET_PAINT |
500 /* | |
474 if (x == 0) { | 501 if (x == 0) { |
475 SVCERR << "getFrameForX(" << x << "): diff = " << diff << ", fdiff = " | 502 SVCERR << "getFrameForX(" << x << "): diff = " << diff << ", fdiff = " |
476 << fdiff << ", m_centreFrame = " << m_centreFrame | 503 << fdiff << ", m_centreFrame = " << m_centreFrame |
477 << ", level = " << m_zoomLevel.level | 504 << ", level = " << m_zoomLevel.level |
478 << ", diff % level = " << (diff % m_zoomLevel.level) | 505 << ", diff % level = " << (diff % m_zoomLevel.level) |
479 << ", nominal " << fdiff + m_centreFrame | 506 << ", nominal " << fdiff + m_centreFrame |
480 << ", will return " << result | 507 << ", will return " << result |
481 << endl; | 508 << endl; |
509 } | |
510 */ | |
511 #endif | |
512 | |
513 #ifdef DEBUG_VIEW | |
514 if (m_zoomLevel.zone == ZoomLevel::FramesPerPixel) { | |
515 int reversed = getXForFrame(result); | |
516 if (reversed != x) { | |
517 SVCERR << "View[" << getId() << "]::getFrameForX: WARNING: Converted pixel " << x << " to frame " << result << " in FramesPerPixel zone, but the reverse conversion gives pixel " << reversed << " (error = " << reversed - x << ")" << endl; | |
518 SVCERR << "(centre frame = " << getCentreFrame() | |
519 << ", width/2 = " << width()/2 << ", diff = " << diff | |
520 << ", fdiff = " << fdiff << ", level = " << level | |
521 << ", centre % level = " << (getCentreFrame() % level) | |
522 << ", fdiff % level = " << (fdiff % level) | |
523 << ", frame % level = " << (result % level) << ")" << endl; | |
524 } | |
482 } | 525 } |
483 #endif | 526 #endif |
484 | 527 |
485 return result; | 528 return result; |
486 } | 529 } |