Krita Source Code Documentation
Loading...
Searching...
No Matches
KisMeshTransformStrategy Class Reference

#include <kis_mesh_transform_strategy.h>

+ Inheritance diagram for KisMeshTransformStrategy:

Classes

struct  Private
 

Signals

void requestCanvasUpdate ()
 
void requestImageRecalculation ()
 

Public Member Functions

bool acceptsClicks () const override
 
bool beginPrimaryAction (const QPointF &pt) override
 
virtual bool beginPrimaryAction (const QPointF &pt)=0
 
bool beginPrimaryAction (KoPointerEvent *event) override
 
void continuePrimaryAction (const QPointF &pt, bool shiftModifierActive, bool altModifierActive) override
 
virtual void continuePrimaryAction (const QPointF &pt, bool shiftModifierActive, bool altModifierActive)=0
 
void continuePrimaryAction (KoPointerEvent *event) override
 
bool endPrimaryAction () override
 
virtual bool endPrimaryAction ()=0
 
bool endPrimaryAction (KoPointerEvent *event) override
 
void externalConfigChanged () override
 
QCursor getCurrentCursor () const override
 
QPointF handleSnapPoint (const QPointF &imagePos) override
 
 KisMeshTransformStrategy (const KisCoordinatesConverter *converter, KoSnapGuide *snapGuide, ToolTransformArgs &currentArgs, TransformTransactionProperties &transaction)
 
void paint (QPainter &gc, const KoColorDisplayRendererInterface *displayRendererInterface) override
 
void setTransformFunction (const QPointF &mousePos, bool perspectiveModifierActive, bool shiftModifierActive, bool altModifierActive) override
 
bool shiftModifierIsUsed () const override
 
 ~KisMeshTransformStrategy () override
 
- Public Member Functions inherited from KisSimplifiedActionPolicyStrategy
void activateAlternateAction (KisTool::AlternateAction action) override
 
void activatePrimaryAction () override
 
bool beginAlternateAction (KoPointerEvent *event, KisTool::AlternateAction action) override
 
bool beginPrimaryAction (KoPointerEvent *event) override
 
void continueAlternateAction (KoPointerEvent *event, KisTool::AlternateAction action) override
 
void continuePrimaryAction (KoPointerEvent *event) override
 
void deactivateAlternateAction (KisTool::AlternateAction action) override
 
bool endAlternateAction (KoPointerEvent *event, KisTool::AlternateAction action) override
 
bool endPrimaryAction (KoPointerEvent *event) override
 
void hoverActionCommon (KoPointerEvent *event) override
 
 KisSimplifiedActionPolicyStrategy (const KisCoordinatesConverter *_converter, KoSnapGuide *snapGuide=0)
 
 ~KisSimplifiedActionPolicyStrategy () override
 
- Public Member Functions inherited from KisTransformStrategyBase
virtual void deactivatePrimaryAction ()
 
virtual int decorationThickness () const
 
virtual void decreaseBrushSize (KoCanvasBase *canvas)
 
virtual QPainterPath getCursorOutline () const
 
virtual void increaseBrushSize (KoCanvasBase *canvas)
 
 KisTransformStrategyBase ()
 
QImage originalImage () const
 
virtual void setDecorationThickness (int thickness)
 
void setThumbnailImage (const QImage &image, QTransform thumbToImageTransform)
 
QTransform thumbToImageTransform () const
 
 ~KisTransformStrategyBase () override
 

Private Member Functions

 Q_PRIVATE_SLOT (m_d, void recalculateTransformations())
 
bool shouldDeleteNode (qreal distance, qreal param)
 
bool splitHoveredSegment (const QPointF &pt)
 
void verifyExpectedMeshSize ()
 

Private Attributes

const QScopedPointer< Privatem_d
 

Additional Inherited Members

- Protected Member Functions inherited from KisSimplifiedActionPolicyStrategy
virtual void hoverActionCommon (const QPointF &pt)
 

Detailed Description

Definition at line 23 of file kis_mesh_transform_strategy.h.

Constructor & Destructor Documentation

◆ KisMeshTransformStrategy()

KisMeshTransformStrategy::KisMeshTransformStrategy ( const KisCoordinatesConverter * converter,
KoSnapGuide * snapGuide,
ToolTransformArgs & currentArgs,
TransformTransactionProperties & transaction )

Definition at line 95 of file kis_mesh_transform_strategy.cpp.

99 : KisSimplifiedActionPolicyStrategy(converter, snapGuide),
100 m_d(new Private(this, converter, currentArgs, transaction))
101{
102
103 connect(&m_d->recalculateSignalCompressor, SIGNAL(timeout()),
104 SLOT(recalculateTransformations()));
105
106 m_d->selectedNodes << KisBezierTransformMesh::NodeIndex(1, 1);
109}
std::pair< NodeIndex, int > SegmentIndex
const QScopedPointer< Private > m_d
KisSimplifiedActionPolicyStrategy(const KisCoordinatesConverter *_converter, KoSnapGuide *snapGuide=0)

References m_d.

◆ ~KisMeshTransformStrategy()

KisMeshTransformStrategy::~KisMeshTransformStrategy ( )
override

Definition at line 111 of file kis_mesh_transform_strategy.cpp.

112{
113}

Member Function Documentation

◆ acceptsClicks()

bool KisMeshTransformStrategy::acceptsClicks ( ) const
overridevirtual

◆ beginPrimaryAction() [1/3]

bool KisMeshTransformStrategy::beginPrimaryAction ( const QPointF & pt)
overridevirtual

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 480 of file kis_mesh_transform_strategy.cpp.

481{
482 // retval shows if the stroke may have a continuation
483 bool retval = false;
484
485 m_d->mouseClickPos = pt;
486
487 QRectF selectionBounds;
488
489 if (m_d->selectedNodes.size() > 1) {
490 for (auto it = m_d->selectedNodes.begin(); it != m_d->selectedNodes.end(); ++it) {
492 m_d->currentArgs.meshTransform()->node(*it).node, &selectionBounds);
493 }
494 } else {
495 selectionBounds = m_d->currentArgs.meshTransform()->dstBoundingRect();
496 }
497
498 m_d->initialRotationCenter = selectionBounds.center();
499 m_d->initialSelectionMaxDimension = KisAlgebra2D::maxDimension(selectionBounds);
500 m_d->initialMeshState = *m_d->currentArgs.meshTransform();
501
502 m_d->pointWasDragged = false;
503
504 if (m_d->mode == Private::OVER_NODE ||
505 m_d->mode == Private::OVER_POINT ||
507 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->hoveredControl, false);
508
509 if (m_d->selectedNodes.size() <= 1 ||
510 !m_d->selectedNodes.contains(m_d->hoveredControl->nodeIndex)) {
511
512 m_d->selectedNodes.clear();
513 m_d->selectedNodes << m_d->hoveredControl->nodeIndex;
514 }
515
516 retval = true;
517 } else if (m_d->mode == Private::OVER_NODE_WHOLE_LINE) {
518 m_d->selectedNodes.clear();
519 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredControl);
520 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(it != m_d->currentArgs.meshTransform()->endControlPoints(), false);
521
522 if (it.isTopBorder() || it.isBottomBorder()) {
523 for (int i = 0; i < m_d->currentArgs.meshTransform()->size().height(); i++) {
524 m_d->selectedNodes << KisBezierTransformMesh::NodeIndex(m_d->hoveredControl->nodeIndex.x(), i);
525 }
526 } else {
527 for (int i = 0; i < m_d->currentArgs.meshTransform()->size().width(); i++) {
528 m_d->selectedNodes << KisBezierTransformMesh::NodeIndex(i, m_d->hoveredControl->nodeIndex.y());
529 }
530 }
531 retval = true;
532 } else if (m_d->mode == Private::OVER_SEGMENT || m_d->mode == Private::OVER_SEGMENT_SYMMETRIC) {
533 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->hoveredSegment, false);
534
535 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredSegment);
536 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(it != m_d->currentArgs.meshTransform()->endSegments(), false);
537
538 retval = true;
539
540 } else if (m_d->mode == Private::OVER_PATCH || m_d->mode == Private::OVER_PATCH_LOCKED) {
541 retval = true;
542
543 } else if (m_d->mode == Private::SPLIT_SEGMENT) {
544 retval = splitHoveredSegment(pt);
545
546 } else if (m_d->mode == Private::MULTIPLE_POINT_SELECTION) {
547 if (m_d->hoveredControl) {
548 if (!m_d->selectedNodes.contains(m_d->hoveredControl->nodeIndex)) {
549 m_d->selectedNodes.insert(m_d->hoveredControl->nodeIndex);
550 } else {
551 m_d->selectedNodes.remove(m_d->hoveredControl->nodeIndex);
552 }
553 } else if (m_d->hoveredSegment) {
554 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredSegment);
555 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(it != m_d->currentArgs.meshTransform()->endSegments(), false);
556
557 if (!m_d->selectedNodes.contains(it.firstNodeIndex()) ||
558 !m_d->selectedNodes.contains(it.secondNodeIndex())) {
559
560 m_d->selectedNodes.insert(it.firstNodeIndex());
561 m_d->selectedNodes.insert(it.secondNodeIndex());
562 } else {
563 m_d->selectedNodes.remove(it.firstNodeIndex());
564 m_d->selectedNodes.remove(it.secondNodeIndex());
565 }
566 }
567 retval = false;
568 } else if (m_d->mode == Private::MOVE_MODE ||
569 m_d->mode == Private::SCALE_MODE ||
570 m_d->mode == Private::ROTATE_MODE) {
571
572 retval = true;
573 }
574
575 m_d->lastMousePos = pt;
576 return retval;
577}
bool splitHoveredSegment(const QPointF &pt)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
auto maxDimension(Size size) -> decltype(size.width())
void accumulateBounds(const Point &pt, Rect *bounds)
int size(const Forest< T > &forest)
Definition KisForest.h:1232

References KisAlgebra2D::accumulateBounds(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, KisAlgebra2D::maxDimension(), KisMeshTransformStrategy::Private::MOVE_MODE, KisMeshTransformStrategy::Private::MULTIPLE_POINT_SELECTION, KisMeshTransformStrategy::Private::OVER_NODE, KisMeshTransformStrategy::Private::OVER_NODE_WHOLE_LINE, KisMeshTransformStrategy::Private::OVER_PATCH, KisMeshTransformStrategy::Private::OVER_PATCH_LOCKED, KisMeshTransformStrategy::Private::OVER_POINT, KisMeshTransformStrategy::Private::OVER_POINT_SYMMETRIC, KisMeshTransformStrategy::Private::OVER_SEGMENT, KisMeshTransformStrategy::Private::OVER_SEGMENT_SYMMETRIC, KisMeshTransformStrategy::Private::ROTATE_MODE, KisMeshTransformStrategy::Private::SCALE_MODE, KisMeshTransformStrategy::Private::SPLIT_SEGMENT, and splitHoveredSegment().

◆ beginPrimaryAction() [2/3]

virtual bool KisSimplifiedActionPolicyStrategy::beginPrimaryAction ( const QPointF & pt)
virtual

◆ beginPrimaryAction() [3/3]

bool KisSimplifiedActionPolicyStrategy::beginPrimaryAction ( KoPointerEvent * event)
overridevirtual

Note: Snapping with Offset is not yet used in the transform strategies. When the user starts an action, we just move the handle to the mouse position, even if it was positioned with an offset. That is not what we do in Crop Tool.

Implements KisTransformStrategyBase.

Definition at line 27 of file kis_simplified_action_policy_strategy.cpp.

66{
67 const QPointF rawImagePoint = m_d->converter->documentToImage(event->point);
68 const QPointF snappedImagePoint = handleSnapPoint(rawImagePoint);
69
77 if (m_d->snapGuide && rawImagePoint != snappedImagePoint) {
78 QPointF imageOffset = snappedImagePoint - rawImagePoint;
79 m_d->dragOffset = m_d->converter->imageToDocument(imageOffset);
80 }
81
82 const QPointF pos = snapDocPoint(event->point, event->modifiers());
83
84 QPointF imagePos = m_d->converter->documentToImage(pos);
85 m_d->lastImagePos = imagePos;
86
87 return beginPrimaryAction(imagePos);
88}
bool beginPrimaryAction(const QPointF &pt) override
QPointF handleSnapPoint(const QPointF &imagePos) override
QPointF snapDocPoint(const QPointF &point, Qt::KeyboardModifiers modifiers) const
Qt::KeyboardModifiers modifiers() const
QPointF point
The point in document coordinates.

◆ continuePrimaryAction() [1/3]

void KisMeshTransformStrategy::continuePrimaryAction ( const QPointF & pt,
bool shiftModifierActive,
bool altModifierActive )
overridevirtual

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 579 of file kis_mesh_transform_strategy.cpp.

580{
581 Q_UNUSED(shiftModifierActive);
582 Q_UNUSED(altModifierActive);
583
584 if (m_d->mode == Private::OVER_POINT ||
586 m_d->mode == Private::OVER_NODE) {
587
588 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->hoveredControl);
589
592 KisSmartMoveMeshControlMode::MoveSymmetricLock :
593 KisSmartMoveMeshControlMode::MoveFree;
594
595 smartMoveControl(*m_d->currentArgs.meshTransform(),
596 *m_d->hoveredControl,
597 pt - m_d->lastMousePos,
598 mode,
599 m_d->currentArgs.meshScaleHandles());
600
601 } else if (m_d->mode == Private::OVER_SEGMENT || m_d->mode == Private::OVER_SEGMENT_SYMMETRIC) {
602 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->hoveredSegment);
603
604 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredSegment);
605
606 // TODO: recover special case for degree-2 curves. There is a special
607 // function for that in KisBezierUtils::interpolateQuadric(), but
608 // it seems like not working properly.
609
610 const QPointF offset = pt - m_d->lastMousePos;
611
612 QPointF offsetP1;
613 QPointF offsetP2;
614
615 std::tie(offsetP1, offsetP2) =
616 KisBezierUtils::offsetSegment(m_d->localSegmentPosition, offset);
617
618
621 KisSmartMoveMeshControlMode::MoveSymmetricLock :
622 KisSmartMoveMeshControlMode::MoveFree;
623
624 smartMoveControl(*m_d->currentArgs.meshTransform(), it.itP1().controlIndex(), offsetP1, mode, m_d->currentArgs.meshScaleHandles());
625 smartMoveControl(*m_d->currentArgs.meshTransform(), it.itP2().controlIndex(), offsetP2, mode, m_d->currentArgs.meshScaleHandles());
626
627 } else if (m_d->mode == Private::OVER_PATCH || m_d->mode == Private::OVER_PATCH_LOCKED) {
628 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->hoveredPatch);
629
631
632 KisBezierTransformMesh &mesh = *m_d->currentArgs.meshTransform();
633 mesh = m_d->initialMeshState;
634
635 auto patchIt = m_d->currentArgs.meshTransform()->find(*m_d->hoveredPatch);
636
637 QPointF offset = pt - m_d->mouseClickPos;
638
639 auto offsetSegment =
641 qreal t,
642 const QPointF &offset) {
643
644 QPointF offsetP1;
645 QPointF offsetP2;
646
647 std::tie(offsetP1, offsetP2) =
649
650
651 smartMoveControl(*m_d->currentArgs.meshTransform(), it.itP1().controlIndex(), offsetP1, KisSmartMoveMeshControlMode::MoveSymmetricLock, m_d->currentArgs.meshScaleHandles());
652 smartMoveControl(*m_d->currentArgs.meshTransform(), it.itP2().controlIndex(), offsetP2, KisSmartMoveMeshControlMode::MoveSymmetricLock, m_d->currentArgs.meshScaleHandles());
653 };
654
655
656 const QPointF center = patchIt->localToGlobal(QPointF(0.5, 0.5));
657 const qreal centerDistance = kisDistance(m_d->mouseClickPos, center);
658
660 qreal nearestSegmentSignificance = 0;
661 qreal nearestSegmentDistance = std::numeric_limits<qreal>::max();
662 qreal nearestSegmentDistanceSignificance = 0.0;
663 qreal nearestSegmentParam = 0.5;
664
665 auto testSegment =
666 [&nearestSegment,
667 &nearestSegmentSignificance,
668 &nearestSegmentDistance,
669 &nearestSegmentDistanceSignificance,
670 &nearestSegmentParam,
671 centerDistance,
672 this] (KisBezierTransformMesh::segment_iterator it, qreal param) {
673
674 const QPointF movedPoint = KisBezierUtils::bezierCurve(it.p0(), it.p1(), it.p2(), it.p3(), param);
675 const qreal distance = kisDistance(m_d->mouseClickPos, movedPoint);
676
677 if (distance < nearestSegmentDistance) {
678 const qreal proportion = KisBezierUtils::curveProportionByParam(it.p0(), it.p1(), it.p2(), it.p3(), param, 0.1);
679
680 qreal distanceSignificance =
681 centerDistance / (centerDistance + distance);
682
683 if (distanceSignificance > 0.6) {
684 distanceSignificance = std::min(1.0, linearReshapeFunc(distanceSignificance, 0.6, 0.75, 0.6, 1.0));
685 }
686
687 const qreal directionSignificance =
688 1.0 - std::min(1.0, std::abs(proportion - 0.5) / 0.4);
689
690 nearestSegmentDistance = distance;
691 nearestSegment = it;
692 nearestSegmentParam = param;
693 nearestSegmentSignificance = m_d->mode != Private::OVER_PATCH_LOCKED ? distanceSignificance * directionSignificance : 0;
694 nearestSegmentDistanceSignificance = distanceSignificance;
695 }
696 };
697
698 testSegment(patchIt.segmentP(), m_d->localPatchPosition.x());
699 testSegment(patchIt.segmentQ(), m_d->localPatchPosition.x());
700 testSegment(patchIt.segmentR(), m_d->localPatchPosition.y());
701 testSegment(patchIt.segmentS(), m_d->localPatchPosition.y());
702
703 KIS_SAFE_ASSERT_RECOVER_RETURN(nearestSegment != mesh.endSegments());
704
705 const qreal translationOffsetCoeff =
706 qBound(0.0,
707 linearReshapeFunc(1.0 - nearestSegmentDistanceSignificance,
708 0.95, 0.75, 1.0, 0.0),
709 1.0);
710 const QPointF translationOffset = translationOffsetCoeff * offset;
711 offset -= translationOffset;
712
713 QPointF segmentOffset;
714
715 if (nearestSegmentSignificance > 0) {
716 segmentOffset = nearestSegmentSignificance * offset;
717 offset -= segmentOffset;
718 }
719
720 const qreal alpha =
721 1.0 - KisBezierUtils::curveProportionByParam(nearestSegment.p0(),
722 nearestSegment.p1(),
723 nearestSegment.p2(),
724 nearestSegment.p3(),
725 nearestSegmentParam, 0.1);
726
727 const qreal coeffN1 =
728 alpha > 0.5 ? std::max(0.0, linearReshapeFunc(alpha, 0.6, 0.75, 1.0, 0.0)) : 1.0;
729 const qreal coeffN0 =
730 alpha < 0.5 ? std::max(0.0, linearReshapeFunc(alpha, 0.25, 0.4, 0.0, 1.0)) : 1.0;
731
732 smartMoveControl(*m_d->currentArgs.meshTransform(), nearestSegment.itP0().controlIndex(), offset * coeffN0, KisSmartMoveMeshControlMode::MoveSymmetricLock, m_d->currentArgs.meshScaleHandles());
733 smartMoveControl(*m_d->currentArgs.meshTransform(), nearestSegment.itP3().controlIndex(), offset * coeffN1, KisSmartMoveMeshControlMode::MoveSymmetricLock, m_d->currentArgs.meshScaleHandles());
734
735 smartMoveControl(*m_d->currentArgs.meshTransform(), patchIt.nodeTopLeft().controlIndex(), translationOffset, KisSmartMoveMeshControlMode::MoveSymmetricLock, m_d->currentArgs.meshScaleHandles());
736 smartMoveControl(*m_d->currentArgs.meshTransform(), patchIt.nodeTopRight().controlIndex(), translationOffset, KisSmartMoveMeshControlMode::MoveSymmetricLock, m_d->currentArgs.meshScaleHandles());
737 smartMoveControl(*m_d->currentArgs.meshTransform(), patchIt.nodeBottomLeft().controlIndex(), translationOffset, KisSmartMoveMeshControlMode::MoveSymmetricLock, m_d->currentArgs.meshScaleHandles());
738 smartMoveControl(*m_d->currentArgs.meshTransform(), patchIt.nodeBottomRight().controlIndex(), translationOffset, KisSmartMoveMeshControlMode::MoveSymmetricLock, m_d->currentArgs.meshScaleHandles());
739
740 offsetSegment(nearestSegment, nearestSegmentParam, segmentOffset);
741
742 } else if (m_d->mode == Private::SPLIT_SEGMENT) {
743 *m_d->currentArgs.meshTransform() = m_d->initialMeshState;
744 const bool sanitySplitResult = splitHoveredSegment(pt);
745 KIS_SAFE_ASSERT_RECOVER_NOOP(sanitySplitResult);
746
747 } else if (m_d->mode == Private::MOVE_MODE || m_d->mode == Private::OVER_NODE_WHOLE_LINE) {
748 const QPointF offset = pt - m_d->lastMousePos;
749 if (m_d->selectedNodes.size() > 1) {
750 for (auto it = m_d->selectedNodes.begin(); it != m_d->selectedNodes.end(); ++it) {
751 m_d->currentArgs.meshTransform()->node(*it).translate(offset);
752 }
753 } else {
754 m_d->currentArgs.meshTransform()->translate(offset);
755 }
756 } else if (m_d->mode == Private::SCALE_MODE) {
757 const qreal scale = 1.0 - (pt - m_d->lastMousePos).y() / m_d->initialSelectionMaxDimension;
758
759
760 const QTransform t =
761 QTransform::fromTranslate(-m_d->initialRotationCenter.x(), -m_d->initialRotationCenter.y()) *
762 QTransform::fromScale(scale, scale) *
763 QTransform::fromTranslate(m_d->initialRotationCenter.x(), m_d->initialRotationCenter.y());
764
765 if (m_d->selectedNodes.size() > 1) {
766 for (auto it = m_d->selectedNodes.begin(); it != m_d->selectedNodes.end(); ++it) {
767 m_d->currentArgs.meshTransform()->node(*it).transform(t);
768 }
769 } else {
770 m_d->currentArgs.meshTransform()->transform(t);
771 }
772
773 } else if (m_d->mode == Private::ROTATE_MODE) {
774 const QPointF oldDirection = m_d->lastMousePos - m_d->initialRotationCenter;
775 const QPointF newDirection = pt - m_d->initialRotationCenter;
776 const qreal rotateAngle = KisAlgebra2D::angleBetweenVectors(oldDirection, newDirection);
777
778 QTransform R;
779 R.rotateRadians(rotateAngle);
780
781 const QTransform t =
782 QTransform::fromTranslate(-m_d->initialRotationCenter.x(), -m_d->initialRotationCenter.y()) *
783 R *
784 QTransform::fromTranslate(m_d->initialRotationCenter.x(), m_d->initialRotationCenter.y());
785
786 if (m_d->selectedNodes.size() > 1) {
787 for (auto it = m_d->selectedNodes.begin(); it != m_d->selectedNodes.end(); ++it) {
788 m_d->currentArgs.meshTransform()->node(*it).transform(t);
789 }
790 } else {
791 m_d->currentArgs.meshTransform()->transform(t);
792 }
793 }
794
795 m_d->lastMousePos = pt;
796 m_d->recalculateSignalCompressor.start();
797}
Eigen::Matrix< double, 4, 2 > R
qreal distance(const QPointF &p1, const QPointF &p2)
control_point_iterator find(const ControlPointIndex &index)
segment_iterator endSegments()
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
Definition kis_global.h:190
T linearReshapeFunc(T x, T x0, T x1, T y0, T y1)
qreal angleBetweenVectors(const QPointF &v1, const QPointF &v2)
void smartMoveControl(Mesh< NodeArg, PatchArg > &mesh, typename Mesh< NodeArg, PatchArg >::ControlPointIndex index, const QPointF &move, SmartMoveMeshControlMode mode, bool scaleNodeMoves)
qreal curveProportionByParam(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t, const qreal error)
std::pair< QPointF, QPointF > offsetSegment(qreal t, const QPointF &offset)
moves point t of the curve by offset offset
QPointF bezierCurve(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t)

References KisAlgebra2D::angleBetweenVectors(), KisBezierUtils::bezierCurve(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::control_point_iterator_impl< is_const >::controlIndex(), KisBezierUtils::curveProportionByParam(), distance(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::endSegments(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::find(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::itP0(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::itP1(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::itP2(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::itP3(), KIS_SAFE_ASSERT_RECOVER_NOOP, KIS_SAFE_ASSERT_RECOVER_RETURN, kisDistance(), KisAlgebra2D::linearReshapeFunc(), m_d, KisMeshTransformStrategy::Private::MOVE_MODE, KisBezierUtils::offsetSegment(), KisMeshTransformStrategy::Private::OVER_NODE, KisMeshTransformStrategy::Private::OVER_NODE_WHOLE_LINE, KisMeshTransformStrategy::Private::OVER_PATCH, KisMeshTransformStrategy::Private::OVER_PATCH_LOCKED, KisMeshTransformStrategy::Private::OVER_POINT, KisMeshTransformStrategy::Private::OVER_POINT_SYMMETRIC, KisMeshTransformStrategy::Private::OVER_SEGMENT, KisMeshTransformStrategy::Private::OVER_SEGMENT_SYMMETRIC, KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::p0(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::p1(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::p2(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::p3(), R, KisMeshTransformStrategy::Private::ROTATE_MODE, KisMeshTransformStrategy::Private::SCALE_MODE, KisMeshTransformStrategy::Private::SPLIT_SEGMENT, and splitHoveredSegment().

◆ continuePrimaryAction() [2/3]

virtual void KisSimplifiedActionPolicyStrategy::continuePrimaryAction ( const QPointF & pt,
bool shiftModifierActive,
bool altModifierActive )
virtual

◆ continuePrimaryAction() [3/3]

void KisSimplifiedActionPolicyStrategy::continuePrimaryAction ( KoPointerEvent * event)
overridevirtual

HACK ALERT!

Here we explicitly check for Shift key pressed! The choice of the stroke type is usually done before the tablet press, but for some actions like constrain proportions we should be able to activate it even after the stroke has been started. For now, KisShortcutMatcher does not support it, so just hardcode this special case.

See bug 340496

Implements KisTransformStrategyBase.

Definition at line 28 of file kis_simplified_action_policy_strategy.cpp.

91{
104 const bool shiftIsActive = event->modifiers() & Qt::ShiftModifier;
105 const bool altIsActive = event->modifiers() & Qt::AltModifier;
106
107 const QPointF pos = snapDocPoint(event->point, event->modifiers());
108 QPointF imagePos = m_d->converter->documentToImage(pos);
109 m_d->lastImagePos = imagePos;
110
111 return continuePrimaryAction(imagePos, shiftIsActive, altIsActive);
112}
void continuePrimaryAction(const QPointF &pt, bool shiftModifierActive, bool altModifierActive) override

◆ endPrimaryAction() [1/3]

bool KisMeshTransformStrategy::endPrimaryAction ( )
overridevirtual

◆ endPrimaryAction() [2/3]

virtual bool KisSimplifiedActionPolicyStrategy::endPrimaryAction ( )
virtual

◆ endPrimaryAction() [3/3]

bool KisSimplifiedActionPolicyStrategy::endPrimaryAction ( KoPointerEvent * event)
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 29 of file kis_simplified_action_policy_strategy.cpp.

123{
124 const QPointF pos = snapDocPoint(event->point, event->modifiers());
125 QPointF imagePos = m_d->converter->documentToImage(pos);
126 m_d->lastImagePos = imagePos;
127
128 return endPrimaryAction();
129}

◆ externalConfigChanged()

void KisMeshTransformStrategy::externalConfigChanged ( )
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 388 of file kis_mesh_transform_strategy.cpp.

389{
391 m_d->recalculateTransformations();
392}

References m_d, and verifyExpectedMeshSize().

◆ getCurrentCursor()

QCursor KisMeshTransformStrategy::getCurrentCursor ( ) const
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 332 of file kis_mesh_transform_strategy.cpp.

333{
334 QCursor cursor;
335
336 switch (m_d->mode) {
340 cursor = KisCursor::meshCursorFree();
341 break;
348 break;
350 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->hoveredSegment || m_d->hoveredControl,
352
353 if (m_d->hoveredControl) {
354 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredControl);
355 cursor = it.isTopBorder() || it.isBottomBorder() ?
356 KisCursor::splitHCursor() : KisCursor::splitVCursor();
357
358 } else if (m_d->hoveredSegment) {
359 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredSegment);
360
361 const QRectF segmentRect(it.p0(), it.p3());
362 cursor = segmentRect.width() > segmentRect.height() ?
363 KisCursor::splitHCursor() : KisCursor::splitVCursor();
364 }
365
366 break;
367 }
369 cursor = KisCursor::crossCursor();
370 break;
372 cursor = KisCursor::moveCursor();
373 break;
375 cursor = KisCursor::rotateCursor();
376 break;
378 cursor = KisCursor::sizeVerCursor();
379 break;
380 case Private::NOTHING:
381 cursor = KisCursor::arrowCursor();
382 break;
383 }
384
385 return cursor;
386}
static QCursor crossCursor()
Definition kis_cursor.cc:34
static QCursor rotateCursor()
static QCursor moveCursor()
static QCursor arrowCursor()
Definition kis_cursor.cc:24
static QCursor meshCursorFree()
static QCursor meshCursorLocked()
static QCursor sizeVerCursor()
Definition kis_cursor.cc:64
static QCursor splitHCursor()
Definition kis_cursor.cc:99

References KisCursor::arrowCursor(), KisCursor::crossCursor(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, KisCursor::meshCursorFree(), KisCursor::meshCursorLocked(), KisMeshTransformStrategy::Private::MOVE_MODE, KisCursor::moveCursor(), KisMeshTransformStrategy::Private::MULTIPLE_POINT_SELECTION, KisMeshTransformStrategy::Private::NOTHING, KisMeshTransformStrategy::Private::OVER_NODE, KisMeshTransformStrategy::Private::OVER_NODE_WHOLE_LINE, KisMeshTransformStrategy::Private::OVER_PATCH, KisMeshTransformStrategy::Private::OVER_PATCH_LOCKED, KisMeshTransformStrategy::Private::OVER_POINT, KisMeshTransformStrategy::Private::OVER_POINT_SYMMETRIC, KisMeshTransformStrategy::Private::OVER_SEGMENT, KisMeshTransformStrategy::Private::OVER_SEGMENT_SYMMETRIC, KisMeshTransformStrategy::Private::ROTATE_MODE, KisCursor::rotateCursor(), KisMeshTransformStrategy::Private::SCALE_MODE, KisCursor::sizeVerCursor(), KisMeshTransformStrategy::Private::SPLIT_SEGMENT, KisCursor::splitHCursor(), and KisCursor::splitVCursor().

◆ handleSnapPoint()

QPointF KisMeshTransformStrategy::handleSnapPoint ( const QPointF & imagePos)
overridevirtual

Reimplemented from KisSimplifiedActionPolicyStrategy.

Definition at line 238 of file kis_mesh_transform_strategy.cpp.

239{
240 return imagePos + m_d->hoveredHandleOffset;
241}

References m_d.

◆ paint()

void KisMeshTransformStrategy::paint ( QPainter & gc,
const KoColorDisplayRendererInterface * displayRendererInterface )
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 264 of file kis_mesh_transform_strategy.cpp.

265{
266 gc.save();
267
268 gc.setOpacity(m_d->transaction.basePreviewOpacity());
269 gc.setTransform(m_d->paintingTransform, true);
270 gc.drawImage(m_d->paintingOffset, m_d->transformedImage);
271
272 gc.restore();
273
274 gc.save();
275 gc.setTransform(KisTransformUtils::imageToFlakeTransform(m_d->converter), true);
276
278 KisHandlePalette palette = displayRendererInterface->handlePaletteForDisplayColorSpace();
279
280 for (auto it = m_d->currentArgs.meshTransform()->beginSegments();
281 it != m_d->currentArgs.meshTransform()->endSegments();
282 ++it) {
283
284 if (m_d->hoveredSegment && it.segmentIndex() == *m_d->hoveredSegment) {
286 } else {
287 handlePainter.setHandleStyle(KisHandleStyle::primarySelection(palette));
288 }
289
290 QPainterPath path;
291 path.moveTo(it.p0());
292 path.cubicTo(it.p1(), it.p2(), it.p3());
293
294 handlePainter.drawPath(path);
295 }
296
297 for (auto it = m_d->currentArgs.meshTransform()->beginControlPoints();
298 it != m_d->currentArgs.meshTransform()->endControlPoints();
299 ++it) {
300
301 if (!m_d->currentArgs.meshShowHandles() && !it.isNode()) {
302 KIS_SAFE_ASSERT_RECOVER_NOOP(!m_d->hoveredControl || *m_d->hoveredControl != it.controlIndex());
303
304 continue;
305 }
306
307
308 if (m_d->hoveredControl && *m_d->hoveredControl == it.controlIndex()) {
309
310 handlePainter.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles(palette));
311
312 } else if (it.type() == KisBezierTransformMesh::ControlType::Node &&
313 m_d->selectedNodes.contains(it.nodeIndex())) {
314
315 handlePainter.setHandleStyle(KisHandleStyle::selectedPrimaryHandles(palette));
316
317 } else {
318 handlePainter.setHandleStyle(KisHandleStyle::primarySelection(palette));
319 }
320
322 handlePainter.drawHandleCircle(*it);
323 } else {
324 handlePainter.drawConnectionLine(it.node().node, *it);
325 handlePainter.drawHandleSmallCircle(*it);
326 }
327 }
328
329 gc.restore();
330}
The KisHandlePainterHelper class is a special helper for painting handles around objects....
static KisHandleStyle & highlightedPrimaryHandlesWithSolidOutline(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & selectedPrimaryHandles(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & primarySelection(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & highlightedPrimaryHandles(KisHandlePalette palette=KisHandlePalette())
static const int handleRadius
static QTransform imageToFlakeTransform(const KisCoordinatesConverter *converter)
virtual KisHandlePalette handlePaletteForDisplayColorSpace() const =0
handlePaletteForDisplayColorSpace
rgba palette[MAX_PALETTE]
Definition palette.c:35

References KisTransformStrategyBase::decorationThickness(), KisHandlePainterHelper::drawConnectionLine(), KisHandlePainterHelper::drawHandleCircle(), KisHandlePainterHelper::drawHandleSmallCircle(), KisHandlePainterHelper::drawPath(), KoColorDisplayRendererInterface::handlePaletteForDisplayColorSpace(), KisTransformUtils::handleRadius, KisHandleStyle::highlightedPrimaryHandles(), KisHandleStyle::highlightedPrimaryHandlesWithSolidOutline(), KisTransformUtils::imageToFlakeTransform(), KIS_SAFE_ASSERT_RECOVER_NOOP, m_d, palette, KisHandleStyle::primarySelection(), KisHandleStyle::selectedPrimaryHandles(), and KisHandlePainterHelper::setHandleStyle().

◆ Q_PRIVATE_SLOT()

KisMeshTransformStrategy::Q_PRIVATE_SLOT ( m_d ,
void recalculateTransformations() )
private

◆ requestCanvasUpdate

void KisMeshTransformStrategy::requestCanvasUpdate ( )
signal

◆ requestImageRecalculation

void KisMeshTransformStrategy::requestImageRecalculation ( )
signal

◆ setTransformFunction()

void KisMeshTransformStrategy::setTransformFunction ( const QPointF & mousePos,
bool perspectiveModifierActive,
bool shiftModifierActive,
bool altModifierActive )
overridevirtual

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 115 of file kis_mesh_transform_strategy.cpp.

116{
117 const qreal grabRadius = KisTransformUtils::effectiveHandleGrabRadius(m_d->converter);
118
119 boost::optional<KisBezierTransformMesh::SegmentIndex> hoveredSegment;
120 boost::optional<KisBezierTransformMesh::ControlPointIndex> hoveredControl;
121 boost::optional<KisBezierTransformMesh::PatchIndex> hoveredPatch;
123 QPointF localPatchPos;
124 qreal localSegmentPos = 0.0;
125
126 const bool symmetricalMode = shiftModifierActive ^ m_d->currentArgs.meshSymmetricalHandles();
127
128 if (m_d->currentArgs.meshShowHandles()) {
129 auto index = m_d->currentArgs.meshTransform()->hitTestControlPoint(mousePos, grabRadius);
130 if (m_d->currentArgs.meshTransform()->isIndexValid(index)) {
131 hoveredControl = index;
132 mode = symmetricalMode ? Private::OVER_POINT_SYMMETRIC : Private::OVER_POINT;
133 }
134 }
135
136 if (mode == Private::NOTHING) {
137 auto index = m_d->currentArgs.meshTransform()->hitTestNode(mousePos, grabRadius);
138 auto nodeIt = m_d->currentArgs.meshTransform()->find(index);
139
140 if (nodeIt != m_d->currentArgs.meshTransform()->endControlPoints()) {
141 hoveredControl = index;
142 mode = shiftModifierActive && nodeIt.isBorderNode() && !nodeIt.isCornerNode() ?
145 }
146 }
147
148 if (mode == Private::NOTHING) {
149 auto index = m_d->currentArgs.meshTransform()->hitTestSegment(mousePos, grabRadius, &localSegmentPos);
150 if (m_d->currentArgs.meshTransform()->isIndexValid(index)) {
151 hoveredSegment = index;
153 }
154 }
155
156 if (mode == Private::NOTHING) {
157 auto index = m_d->currentArgs.meshTransform()->hitTestPatch(mousePos, &localPatchPos);
158 if (m_d->currentArgs.meshTransform()->isIndexValid(index)) {
159 hoveredPatch = index;
160 mode = !shiftModifierActive ? Private::OVER_PATCH : Private::OVER_PATCH_LOCKED;
161 }
162 }
163
164
165 // verify that we have only one active selection at a time
166 KIS_SAFE_ASSERT_RECOVER_RETURN(bool(hoveredControl) +
167 bool(hoveredSegment) +
168 bool(hoveredPatch)<= 1);
169
170
172 m_d->currentArgs.meshTransform()->endControlPoints();
173
174 if (hoveredControl) {
175 controlIt = m_d->currentArgs.meshTransform()->find(*hoveredControl);
176 }
177
178 if (altModifierActive &&
179 ((hoveredControl &&
180 hoveredControl->isNode() &&
181 controlIt.isBorderNode() &&
182 !controlIt.isCornerNode()) ||
183 hoveredSegment)) {
184
186
187 } else {
188 if (hoveredControl || hoveredSegment) {
189 if (perspectiveModifierActive) {
191 } else if (hoveredControl &&
192 hoveredControl->isNode() &&
193 m_d->selectedNodes.size() > 1 &&
194 m_d->selectedNodes.contains(hoveredControl->nodeIndex)) {
195
196 mode = Private::MOVE_MODE;
197 }
198 } else if (!hoveredPatch) {
199 if (perspectiveModifierActive) {
200 mode = Private::SCALE_MODE;
201 } else if (shiftModifierActive) {
202 mode = Private::MOVE_MODE;
203 } else {
205 }
206 }
207 }
208
209 if (mode != m_d->mode ||
210 hoveredControl != m_d->hoveredControl ||
211 hoveredSegment != m_d->hoveredSegment ||
212 hoveredPatch != m_d->hoveredPatch) {
213
214 m_d->hoveredControl = hoveredControl;
215 m_d->hoveredSegment = hoveredSegment;
216 m_d->hoveredPatch = hoveredPatch;
217
218 m_d->mode = mode;
219 Q_EMIT requestCanvasUpdate();
220 }
221
222 m_d->localPatchPosition = localPatchPos;
223 m_d->localSegmentPosition = localSegmentPos;
224
225 if (hoveredControl) {
226 m_d->hoveredHandleOffset = *controlIt - mousePos;
227 } else if (hoveredSegment) {
229 m_d->currentArgs.meshTransform()->find(*hoveredSegment);
230 m_d->hoveredHandleOffset = segmentIt.pointAtParam(m_d->localSegmentPosition) - mousePos;
231 } else {
232 m_d->hoveredHandleOffset = QPointF();
233 }
234
236}
static qreal effectiveHandleGrabRadius(const KisCoordinatesConverter *converter)

References KisTransformUtils::effectiveHandleGrabRadius(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::control_point_iterator_impl< is_const >::isBorderNode(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::control_point_iterator_impl< is_const >::isCornerNode(), KIS_SAFE_ASSERT_RECOVER_RETURN, m_d, KisMeshTransformStrategy::Private::MOVE_MODE, KisMeshTransformStrategy::Private::MULTIPLE_POINT_SELECTION, KisMeshTransformStrategy::Private::NOTHING, KisMeshTransformStrategy::Private::OVER_NODE, KisMeshTransformStrategy::Private::OVER_NODE_WHOLE_LINE, KisMeshTransformStrategy::Private::OVER_PATCH, KisMeshTransformStrategy::Private::OVER_PATCH_LOCKED, KisMeshTransformStrategy::Private::OVER_POINT, KisMeshTransformStrategy::Private::OVER_POINT_SYMMETRIC, KisMeshTransformStrategy::Private::OVER_SEGMENT, KisMeshTransformStrategy::Private::OVER_SEGMENT_SYMMETRIC, KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::pointAtParam(), requestCanvasUpdate(), KisMeshTransformStrategy::Private::ROTATE_MODE, KisMeshTransformStrategy::Private::SCALE_MODE, KisMeshTransformStrategy::Private::SPLIT_SEGMENT, and verifyExpectedMeshSize().

◆ shiftModifierIsUsed()

bool KisMeshTransformStrategy::shiftModifierIsUsed ( ) const
overridevirtual

Reimplemented from KisSimplifiedActionPolicyStrategy.

Definition at line 243 of file kis_mesh_transform_strategy.cpp.

244{
245 return true;
246}

◆ shouldDeleteNode()

bool KisMeshTransformStrategy::shouldDeleteNode ( qreal distance,
qreal param )
private

Definition at line 470 of file kis_mesh_transform_strategy.cpp.

471{
472 const qreal grabRadius = KisTransformUtils::effectiveHandleGrabRadius(m_d->converter);
473 return
474 distance > 10 * grabRadius ||
475 qFuzzyCompare(param, 0.0) ||
476 qFuzzyCompare(param, 1.0);
477
478}
static bool qFuzzyCompare(half p1, half p2)

References distance(), KisTransformUtils::effectiveHandleGrabRadius(), m_d, and qFuzzyCompare().

◆ splitHoveredSegment()

bool KisMeshTransformStrategy::splitHoveredSegment ( const QPointF & pt)
private

Definition at line 394 of file kis_mesh_transform_strategy.cpp.

395{
396 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->hoveredSegment || m_d->hoveredControl, false);
397
398 if (m_d->hoveredControl) {
399 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredControl);
400
401 KisBezierTransformMesh::segment_iterator resultSegment = m_d->currentArgs.meshTransform()->endSegments();
402 qreal resultParam = 0;
403 qreal resultDistance = std::numeric_limits<qreal>::max();
404 KisBezierTransformMesh::NodeIndex resultRemovedNodeIndex;
405
406 auto estimateSegment =
407 [&resultParam,
408 &resultSegment,
409 &resultDistance,
410 &resultRemovedNodeIndex] (const KisBezierTransformMesh::segment_iterator &segment,
411 const QPoint &removedNodeOffset,
412 const QPointF &pt,
414 {
415 if (segment != mesh.endSegments()) {
416
417 qreal distance = 0.0;
418 qreal param = KisBezierUtils::nearestPoint({segment.p0(), segment.p1(), segment.p2(), segment.p3()}, pt, &distance);
419
420 if (distance < resultDistance) {
421 resultDistance = distance;
422 resultParam = param;
423 resultSegment = segment;
424 resultRemovedNodeIndex = segment.firstNodeIndex() + removedNodeOffset;
425 }
426 }
427 };
428
429
430 if (it.isTopBorder() || it.isBottomBorder()) {
431 estimateSegment(it.leftSegment(), QPoint(2, 0), pt, *m_d->currentArgs.meshTransform());
432 estimateSegment(it.rightSegment(), QPoint(0, 0), pt, *m_d->currentArgs.meshTransform());
433 } else {
434 estimateSegment(it.topSegment(), QPoint(0, 2), pt, *m_d->currentArgs.meshTransform());
435 estimateSegment(it.bottomSegment(), QPoint(0, 0), pt, *m_d->currentArgs.meshTransform());
436 }
437
438 if (resultSegment != m_d->currentArgs.meshTransform()->endSegments()) {
439 if (!shouldDeleteNode(resultDistance, resultParam)) {
440 const qreal eps = 0.01;
441 const qreal proportion = KisBezierUtils::curveProportionByParam(resultSegment.p0(), resultSegment.p1(), resultSegment.p2(), resultSegment.p3(), resultParam, eps);
442
443 m_d->currentArgs.meshTransform()->subdivideSegment(resultSegment.segmentIndex(), proportion);
444 m_d->currentArgs.meshTransform()->removeColumnOrRow(resultRemovedNodeIndex, !resultSegment.isHorizontal());
445
446 } else {
447 m_d->currentArgs.meshTransform()->removeColumnOrRow(m_d->hoveredControl->nodeIndex, !resultSegment.isHorizontal());
448 }
449 }
450
451 } else if (m_d->hoveredSegment) {
452 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredSegment);
453 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(it != m_d->currentArgs.meshTransform()->endSegments(), false);
454
455 qreal distance = 0;
456 const qreal t = KisBezierUtils::nearestPoint({it.p0(), it.p1(), it.p2(), it.p3()}, pt, &distance);
457
458 if (!shouldDeleteNode(distance, t)) {
459 const qreal eps = 0.01;
460 const qreal proportion = KisBezierUtils::curveProportionByParam(it.p0(), it.p1(), it.p2(), it.p3(), t, eps);
461 m_d->currentArgs.meshTransform()->subdivideSegment(it.segmentIndex(), proportion);
462 }
463 }
464
465 m_d->recalculateSignalCompressor.start();
466
467 return true;
468}
bool shouldDeleteNode(qreal distance, qreal param)
const qreal eps
qreal nearestPoint(const QList< QPointF > controlPoints, const QPointF &point, qreal *resultDistance, QPointF *resultPoint)

References KisBezierUtils::curveProportionByParam(), distance(), eps, KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::isHorizontal(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_d, KisBezierUtils::nearestPoint(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::p0(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::p1(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::p2(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::p3(), KisBezierMeshDetails::Mesh< NodeArg, PatchArg >::segment_iterator_impl< is_const >::segmentIndex(), and shouldDeleteNode().

◆ verifyExpectedMeshSize()

void KisMeshTransformStrategy::verifyExpectedMeshSize ( )
private

Definition at line 248 of file kis_mesh_transform_strategy.cpp.

249{
250 bool shouldUpdate = false;
251
252 const QSize currentMeshSize = m_d->currentArgs.meshTransform()->size();
253 if (currentMeshSize != m_d->lastMeshSize) {
254 m_d->selectedNodes.clear();
255 shouldUpdate = true;
256 }
257 m_d->lastMeshSize = currentMeshSize;
258
259 if (shouldUpdate) {
260 Q_EMIT requestCanvasUpdate();
261 }
262}

References m_d, and requestCanvasUpdate().

Member Data Documentation

◆ m_d

const QScopedPointer<Private> KisMeshTransformStrategy::m_d
private

Definition at line 65 of file kis_mesh_transform_strategy.h.


The documentation for this class was generated from the following files: