Mercurial > hg > svgui
comparison layer/RegionLayer.cpp @ 1432:5b9692768beb single-point
Further snap fixes
author | Chris Cannam |
---|---|
date | Wed, 20 Mar 2019 15:46:17 +0000 |
parents | 8a7c82282fbc |
children | 696e569ff21b |
comparison
equal
deleted
inserted
replaced
1431:af824022bffd | 1432:5b9692768beb |
---|---|
443 { | 443 { |
444 if (!m_model) { | 444 if (!m_model) { |
445 return Layer::snapToFeatureFrame(v, frame, resolution, snap); | 445 return Layer::snapToFeatureFrame(v, frame, resolution, snap); |
446 } | 446 } |
447 | 447 |
448 // SnapLeft / SnapRight: return frame of nearest feature in that | |
449 // direction no matter how far away | |
450 // | |
451 // SnapNeighbouring: return frame of feature that would be used in | |
452 // an editing operation, i.e. closest feature in either direction | |
453 // but only if it is "close enough" | |
454 | |
448 resolution = m_model->getResolution(); | 455 resolution = m_model->getResolution(); |
449 EventVector points; | |
450 | 456 |
451 if (snap == SnapNeighbouring) { | 457 if (snap == SnapNeighbouring) { |
452 | 458 EventVector points = getLocalPoints(v, v->getXForFrame(frame)); |
453 points = getLocalPoints(v, v->getXForFrame(frame)); | |
454 if (points.empty()) return false; | 459 if (points.empty()) return false; |
455 frame = points.begin()->getFrame(); | 460 frame = points.begin()->getFrame(); |
456 return true; | 461 return true; |
457 } | 462 } |
458 | 463 |
459 //!!! I think this is not quite right - we want to be able to snap | 464 // Normally we snap to the start frame of whichever event we |
460 //!!! to events that are nearby but not covering the given frame, | 465 // find. However here, for SnapRight only, if the end frame of |
461 //!!! and I think that worked with the old code. Compare and | 466 // whichever event we would have snapped to had we been snapping |
462 //!!! revise. | 467 // left is closer than the start frame of the next event to the |
468 // right, then we snap to that frame instead. Clear? | |
463 | 469 |
464 points = m_model->getEventsCovering(frame); | 470 Event left; |
465 sv_frame_t snapped = frame; | 471 bool haveLeft = false; |
466 bool found = false; | 472 if (m_model->getNearestEventMatching |
467 | 473 (frame, [](Event) { return true; }, EventSeries::Backward, left)) { |
468 for (EventVector::const_iterator i = points.begin(); | 474 haveLeft = true; |
469 i != points.end(); ++i) { | 475 } |
470 | 476 |
471 if (snap == SnapRight) { | 477 if (snap == SnapLeft) { |
472 | 478 frame = left.getFrame(); |
473 // The best frame to snap to is the end frame of whichever | 479 return haveLeft; |
474 // feature we would have snapped to the start frame of if | 480 } |
475 // we had been snapping left. | 481 |
476 | 482 Event right; |
477 if (i->getFrame() <= frame) { | 483 bool haveRight = false; |
478 if (i->getFrame() + i->getDuration() > frame) { | 484 if (m_model->getNearestEventMatching |
479 snapped = i->getFrame() + i->getDuration(); | 485 (frame, [](Event) { return true; }, EventSeries::Forward, right)) { |
480 found = true; // don't break, as the next may be better | 486 haveRight = true; |
487 } | |
488 | |
489 if (haveLeft) { | |
490 sv_frame_t leftEnd = left.getFrame() + left.getDuration(); | |
491 if (leftEnd > frame) { | |
492 if (haveRight) { | |
493 if (leftEnd - frame < right.getFrame() - frame) { | |
494 frame = leftEnd; | |
495 } else { | |
496 frame = right.getFrame(); | |
481 } | 497 } |
482 } else { | 498 } else { |
483 if (!found) { | 499 frame = leftEnd; |
484 snapped = i->getFrame(); | |
485 found = true; | |
486 } | |
487 break; | |
488 } | 500 } |
489 | 501 return true; |
490 } else if (snap == SnapLeft) { | 502 } |
491 | 503 } |
492 if (i->getFrame() <= frame) { | 504 |
493 snapped = i->getFrame(); | 505 if (haveRight) { |
494 found = true; // don't break, as the next may be better | 506 frame = right.getFrame(); |
495 } else { | 507 return true; |
496 break; | 508 } |
497 } | 509 |
498 | 510 return false; |
499 } else { // nearest | |
500 | |
501 EventVector::const_iterator j = i; | |
502 ++j; | |
503 | |
504 if (j == points.end()) { | |
505 | |
506 snapped = i->getFrame(); | |
507 found = true; | |
508 break; | |
509 | |
510 } else if (j->getFrame() >= frame) { | |
511 | |
512 if (j->getFrame() - frame < frame - i->getFrame()) { | |
513 snapped = j->getFrame(); | |
514 } else { | |
515 snapped = i->getFrame(); | |
516 } | |
517 found = true; | |
518 break; | |
519 } | |
520 } | |
521 } | |
522 | |
523 frame = snapped; | |
524 return found; | |
525 } | 511 } |
526 | 512 |
527 bool | 513 bool |
528 RegionLayer::snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame, | 514 RegionLayer::snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame, |
529 int &resolution, | 515 int &resolution, |
531 { | 517 { |
532 if (!m_model) { | 518 if (!m_model) { |
533 return Layer::snapToSimilarFeature(v, frame, resolution, snap); | 519 return Layer::snapToSimilarFeature(v, frame, resolution, snap); |
534 } | 520 } |
535 | 521 |
522 // snap is only permitted to be SnapLeft or SnapRight here. We | |
523 // don't do the same trick as in snapToFeatureFrame, of snapping | |
524 // to the end of a feature sometimes. | |
525 | |
536 resolution = m_model->getResolution(); | 526 resolution = m_model->getResolution(); |
537 | 527 |
538 /*!!! todo: overhaul the logic of this function (and supporting | 528 Event ref; |
539 apis in EventSeries / RegionModel) | 529 Event e; |
540 | 530 float matchvalue; |
541 const EventVector &points = m_model->getPoints(); | 531 bool found; |
542 EventVector close = m_model->getPoints(frame, frame); | 532 |
543 */ | 533 found = m_model->getNearestEventMatching |
544 EventVector points = m_model->getAllEvents(); | 534 (frame, [](Event) { return true; }, EventSeries::Backward, ref); |
545 EventVector close = {}; | 535 |
536 if (!found) { | |
537 return false; | |
538 } | |
539 | |
540 matchvalue = ref.getValue(); | |
546 | 541 |
547 EventVector::const_iterator i; | 542 found = m_model->getNearestEventMatching |
548 | 543 (frame, |
549 sv_frame_t matchframe = frame; | 544 [matchvalue](Event e) { |
550 double matchvalue = 0.f; | 545 double epsilon = 0.0001; |
551 | 546 return fabs(e.getValue() - matchvalue) < epsilon; |
552 for (i = close.begin(); i != close.end(); ++i) { | 547 }, |
553 if (i->getFrame() > frame) break; | 548 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, |
554 matchvalue = i->getValue(); | 549 e); |
555 matchframe = i->getFrame(); | 550 |
556 } | 551 if (!found) { |
557 | 552 return false; |
558 sv_frame_t snapped = frame; | 553 } |
559 bool found = false; | 554 |
560 bool distant = false; | 555 frame = e.getFrame(); |
561 double epsilon = 0.0001; | 556 return true; |
562 | |
563 i = close.begin(); | |
564 | |
565 // Scan through the close points first, then the more distant ones | |
566 // if no suitable close one is found. So the while-termination | |
567 // condition here can only happen once i has passed through the | |
568 // whole of the close container and then the whole of the separate | |
569 // points container. The two iterators are totally distinct, but | |
570 // have the same type so we cheekily use the same variable and a | |
571 // single loop for both. | |
572 | |
573 while (i != points.end()) { | |
574 | |
575 if (!distant) { | |
576 if (i == close.end()) { | |
577 // switch from the close container to the points container | |
578 i = points.begin(); | |
579 distant = true; | |
580 } | |
581 } | |
582 | |
583 if (snap == SnapRight) { | |
584 | |
585 if (i->getFrame() > matchframe && | |
586 fabs(i->getValue() - matchvalue) < epsilon) { | |
587 snapped = i->getFrame(); | |
588 found = true; | |
589 break; | |
590 } | |
591 | |
592 } else if (snap == SnapLeft) { | |
593 | |
594 if (i->getFrame() < matchframe) { | |
595 if (fabs(i->getValue() - matchvalue) < epsilon) { | |
596 snapped = i->getFrame(); | |
597 found = true; // don't break, as the next may be better | |
598 } | |
599 } else if (found || distant) { | |
600 break; | |
601 } | |
602 | |
603 } else { | |
604 // no other snap types supported | |
605 } | |
606 | |
607 ++i; | |
608 } | |
609 | |
610 frame = snapped; | |
611 return found; | |
612 } | 557 } |
613 | 558 |
614 QString | 559 QString |
615 RegionLayer::getScaleUnits() const | 560 RegionLayer::getScaleUnits() const |
616 { | 561 { |