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) 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 QPainterPath getCursorOutline () const
 
 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 94 of file kis_mesh_transform_strategy.cpp.

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

References connect(), and m_d.

◆ ~KisMeshTransformStrategy()

KisMeshTransformStrategy::~KisMeshTransformStrategy ( )
override

Definition at line 110 of file kis_mesh_transform_strategy.cpp.

111{
112}

Member Function Documentation

◆ acceptsClicks()

bool KisMeshTransformStrategy::acceptsClicks ( ) const
overridevirtual

◆ beginPrimaryAction() [1/3]

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

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 478 of file kis_mesh_transform_strategy.cpp.

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

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

387{
389 m_d->recalculateTransformations();
390}

References m_d, and verifyExpectedMeshSize().

◆ getCurrentCursor()

QCursor KisMeshTransformStrategy::getCurrentCursor ( ) const
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 330 of file kis_mesh_transform_strategy.cpp.

331{
332 QCursor cursor;
333
334 switch (m_d->mode) {
338 cursor = KisCursor::meshCursorFree();
339 break;
346 break;
348 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->hoveredSegment || m_d->hoveredControl,
350
351 if (m_d->hoveredControl) {
352 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredControl);
353 cursor = it.isTopBorder() || it.isBottomBorder() ?
354 KisCursor::splitHCursor() : KisCursor::splitVCursor();
355
356 } else if (m_d->hoveredSegment) {
357 auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredSegment);
358
359 const QRectF segmentRect(it.p0(), it.p3());
360 cursor = segmentRect.width() > segmentRect.height() ?
361 KisCursor::splitHCursor() : KisCursor::splitVCursor();
362 }
363
364 break;
365 }
367 cursor = KisCursor::crossCursor();
368 break;
370 cursor = KisCursor::moveCursor();
371 break;
373 cursor = KisCursor::rotateCursor();
374 break;
376 cursor = KisCursor::sizeVerCursor();
377 break;
378 case Private::NOTHING:
379 cursor = KisCursor::arrowCursor();
380 break;
381 }
382
383 return cursor;
384}
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 237 of file kis_mesh_transform_strategy.cpp.

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

References m_d.

◆ paint()

void KisMeshTransformStrategy::paint ( QPainter & gc)
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 263 of file kis_mesh_transform_strategy.cpp.

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

References KisTransformStrategyBase::decorationThickness(), KisHandlePainterHelper::drawConnectionLine(), KisHandlePainterHelper::drawHandleCircle(), KisHandlePainterHelper::drawHandleSmallCircle(), KisHandlePainterHelper::drawPath(), KisTransformUtils::handleRadius, KisHandleStyle::highlightedPrimaryHandles(), KisHandleStyle::highlightedPrimaryHandlesWithSolidOutline(), KisTransformUtils::imageToFlakeTransform(), KIS_SAFE_ASSERT_RECOVER_NOOP, m_d, 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 114 of file kis_mesh_transform_strategy.cpp.

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

243{
244 return true;
245}

◆ shouldDeleteNode()

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

Definition at line 468 of file kis_mesh_transform_strategy.cpp.

469{
470 const qreal grabRadius = KisTransformUtils::effectiveHandleGrabRadius(m_d->converter);
471 return
472 distance > 10 * grabRadius ||
473 qFuzzyCompare(param, 0.0) ||
474 qFuzzyCompare(param, 1.0);
475
476}
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 392 of file kis_mesh_transform_strategy.cpp.

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

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

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: