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

#include <kis_tool_freehand_helper.h>

+ Inheritance diagram for KisToolFreehandHelper:

Classes

struct  Private
 

Signals

void requestExplicitUpdateOutline ()
 

Public Member Functions

void cursorMoved (const QPointF &cursorPos)
 
void endPaint ()
 
void initPaint (KoPointerEvent *event, const QPointF &pixelCoords, KisImageWSP image, KisNodeSP currentNode, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode=0, KisDefaultBoundsBaseSP bounds=0)
 
bool isRunning () const
 
 KisToolFreehandHelper (KisPaintingInformationBuilder *infoBuilder, KoCanvasResourceProvider *resourceManager, const KUndo2MagicString &transactionText=KUndo2MagicString(), KisSmoothingOptions *smoothingOptions=0)
 
void paintEvent (KoPointerEvent *event)
 
KisOptimizedBrushOutline paintOpOutline (const QPointF &savedCursorPos, const KoPointerEvent *event, const KisPaintOpSettingsSP globalSettings, KisPaintOpSettings::OutlineMode mode) const
 
void setSmoothness (KisSmoothingOptionsSP smoothingOptions)
 
KisSmoothingOptionsSP smoothingOptions () const
 
 ~KisToolFreehandHelper () override
 

Protected Member Functions

void cancelPaint ()
 
virtual void createPainters (QVector< KisFreehandStrokeInfo * > &strokeInfos, const KisDistanceInformation &startDist)
 
int elapsedStrokeTime () const
 
void initPaintImpl (qreal startAngle, const KisPaintInformation &pi, KoCanvasResourceProvider *resourceManager, KisImageWSP image, KisNodeSP node, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode=0, KisDefaultBoundsBaseSP bounds=0)
 
virtual void paintAt (const KisPaintInformation &pi)
 
void paintAt (int strokeInfoId, const KisPaintInformation &pi)
 
virtual void paintBezierCurve (const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2)
 
void paintBezierCurve (int strokeInfoId, const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2)
 
virtual void paintLine (const KisPaintInformation &pi1, const KisPaintInformation &pi2)
 
void paintLine (int strokeInfoId, const KisPaintInformation &pi1, const KisPaintInformation &pi2)
 
KoCanvasResourceProviderresourceManager () const
 

Private Slots

void doAirbrushing ()
 
void finishStroke ()
 
void slotSmoothingTypeChanged ()
 
void stabilizerPollAndPaint ()
 

Private Member Functions

int computeAirbrushTimerInterval () const
 
qreal currentPhysicalZoom () const
 
qreal currentZoom () const
 
KisPaintInformation getStabilizedPaintInfo (const QQueue< KisPaintInformation > &queue, const KisPaintInformation &lastPaintInfo)
 
void paint (KisPaintInformation &info)
 
void paintBezierSegment (KisPaintInformation pi1, KisPaintInformation pi2, QPointF tangent1, QPointF tangent2)
 
void stabilizerEnd ()
 
void stabilizerStart (KisPaintInformation firstPaintInfo)
 

Private Attributes

Private *const m_d
 

Detailed Description

Definition at line 31 of file kis_tool_freehand_helper.h.

Constructor & Destructor Documentation

◆ KisToolFreehandHelper()

KisToolFreehandHelper::KisToolFreehandHelper ( KisPaintingInformationBuilder * infoBuilder,
KoCanvasResourceProvider * resourceManager,
const KUndo2MagicString & transactionText = KUndo2MagicString(),
KisSmoothingOptions * smoothingOptions = 0 )

Definition at line 136 of file kis_tool_freehand_helper.cpp.

140 : m_d(new Private())
141{
143 m_d->infoBuilder = infoBuilder;
144 m_d->transactionText = transactionText;
147
150
151 m_d->strokeTimeoutTimer.setSingleShot(true);
152 connect(&m_d->strokeTimeoutTimer, SIGNAL(timeout()), SLOT(finishStroke()));
153 connect(&m_d->airbrushingTimer, SIGNAL(timeout()), SLOT(doAirbrushing()));
154 connect(&m_d->stabilizerPollTimer, SIGNAL(timeout()), SLOT(stabilizerPollAndPaint()));
155 connect(m_d->smoothingOptions.data(), SIGNAL(sigSmoothingTypeChanged()), SLOT(slotSmoothingTypeChanged()));
156
158 [this](const KisPaintInformation &pi1, const KisPaintInformation &pi2) {
159 paintLine(pi1, pi2);
160 });
162 [this]() {
164 });
165}
void setUpdateOutlineCallback(std::function< void()> requestUpdateOutline)
void setPaintLineCallback(std::function< void(const KisPaintInformation &, const KisPaintInformation &)> paintLine)
KisSmoothingOptionsSP smoothingOptions() const
KoCanvasResourceProvider * resourceManager() const
void paintLine(int strokeInfoId, const KisPaintInformation &pi1, const KisPaintInformation &pi2)
void requestExplicitUpdateOutline()
QSharedPointer< KisSmoothingOptions > KisSmoothingOptionsSP
KisPerStrokeRandomSourceSP fakeStrokeRandomSource
KoCanvasResourceProvider * resourceManager
KisStabilizerDelayedPaintHelper stabilizerDelayedPaintHelper
KisPaintingInformationBuilder * infoBuilder

References KisToolFreehandHelper::Private::airbrushingTimer, doAirbrushing(), KisToolFreehandHelper::Private::fakeDabRandomSource, KisToolFreehandHelper::Private::fakeStrokeRandomSource, finishStroke(), KisToolFreehandHelper::Private::infoBuilder, m_d, paintLine(), requestExplicitUpdateOutline(), KisToolFreehandHelper::Private::resourceManager, resourceManager(), KisStabilizerDelayedPaintHelper::setPaintLineCallback(), KisStabilizerDelayedPaintHelper::setUpdateOutlineCallback(), slotSmoothingTypeChanged(), KisToolFreehandHelper::Private::smoothingOptions, smoothingOptions(), KisToolFreehandHelper::Private::stabilizerDelayedPaintHelper, stabilizerPollAndPaint(), KisToolFreehandHelper::Private::stabilizerPollTimer, KisToolFreehandHelper::Private::strokeTimeoutTimer, and KisToolFreehandHelper::Private::transactionText.

◆ ~KisToolFreehandHelper()

KisToolFreehandHelper::~KisToolFreehandHelper ( )
override

Definition at line 167 of file kis_tool_freehand_helper.cpp.

168{
169 delete m_d;
170}

References m_d.

Member Function Documentation

◆ cancelPaint()

void KisToolFreehandHelper::cancelPaint ( )
protected

Definition at line 741 of file kis_tool_freehand_helper.cpp.

742{
743 if (!m_d->strokeId) return;
744
745 m_d->strokeTimeoutTimer.stop();
746
747 if (m_d->airbrushingTimer.isActive()) {
748 m_d->airbrushingTimer.stop();
749 }
750
753 }
754
755 if (m_d->stabilizerPollTimer.isActive()) {
756 m_d->stabilizerPollTimer.stop();
757 }
758
761 }
762
763 // see a comment in endPaint()
764 m_d->strokeInfos.clear();
765
767 m_d->strokeId.clear();
768
769}
virtual bool cancelStroke(KisStrokeId id)=0
QVector< KisFreehandStrokeInfo * > strokeInfos
KisAsynchronousStrokeUpdateHelper asyncUpdateHelper

References KisToolFreehandHelper::Private::airbrushingTimer, KisToolFreehandHelper::Private::asyncUpdateHelper, KisStabilizerDelayedPaintHelper::cancel(), KisStrokesFacade::cancelStroke(), KisAsynchronousStrokeUpdateHelper::cancelUpdateStream(), KisAsynchronousStrokeUpdateHelper::isActive(), m_d, KisStabilizerDelayedPaintHelper::running(), KisToolFreehandHelper::Private::stabilizerDelayedPaintHelper, KisToolFreehandHelper::Private::stabilizerPollTimer, KisToolFreehandHelper::Private::strokeId, KisToolFreehandHelper::Private::strokeInfos, KisToolFreehandHelper::Private::strokesFacade, and KisToolFreehandHelper::Private::strokeTimeoutTimer.

◆ computeAirbrushTimerInterval()

int KisToolFreehandHelper::computeAirbrushTimerInterval ( ) const
private

Definition at line 991 of file kis_tool_freehand_helper.cpp.

992{
994 return qMax(1, qFloor(realInterval));
995}
const qreal AIRBRUSH_INTERVAL_FACTOR

References AIRBRUSH_INTERVAL_FACTOR, KisResourcesSnapshot::airbrushingInterval(), m_d, and KisToolFreehandHelper::Private::resources.

◆ createPainters()

void KisToolFreehandHelper::createPainters ( QVector< KisFreehandStrokeInfo * > & strokeInfos,
const KisDistanceInformation & startDist )
protectedvirtual

Reimplemented in KisToolMultihandHelper.

Definition at line 1064 of file kis_tool_freehand_helper.cpp.

1066{
1067 strokeInfos << new KisFreehandStrokeInfo(startDist);
1068}

◆ currentPhysicalZoom()

qreal KisToolFreehandHelper::currentPhysicalZoom ( ) const
private

◆ currentZoom()

qreal KisToolFreehandHelper::currentZoom ( ) const
private

Definition at line 997 of file kis_tool_freehand_helper.cpp.

998{
1000}
@ EffectiveZoom
-Used only by painting tools for non-displaying purposes

References KoCanvasResource::EffectiveZoom, m_d, KoCanvasResourceProvider::resource(), and KisToolFreehandHelper::Private::resourceManager.

◆ cursorMoved()

void KisToolFreehandHelper::cursorMoved ( const QPointF & cursorPos)

◆ doAirbrushing

void KisToolFreehandHelper::doAirbrushing ( )
privateslot

Definition at line 967 of file kis_tool_freehand_helper.cpp.

968{
969 // Check that the stroke hasn't ended.
970 if (!m_d->strokeInfos.isEmpty()) {
971
972 // Add a new painting update at a point identical to the previous one, except for the time
973 // and speed information.
975 KisPaintInformation nextPaint(prevPaint.pos(),
976 prevPaint.pressure(),
977 prevPaint.xTilt(),
978 prevPaint.yTilt(),
979 prevPaint.rotation(),
980 prevPaint.tangentialPressure(),
981 prevPaint.perspective(),
983 0.0);
984 nextPaint.setCanvasRotation(prevPaint.canvasRotation());
985 nextPaint.setCanvasMirroredH(prevPaint.canvasMirroredH());
986 nextPaint.setCanvasMirroredV(prevPaint.canvasMirroredV());
987 paint(nextPaint);
988 }
989}
qreal perspective() const
reciprocal of distance on the perspective grid
const QPointF & pos() const
qreal xTilt() const
The tilt of the pen on the horizontal axis (from 0.0 to 1.0)
qreal tangentialPressure() const
tangential pressure (i.e., rate for an airbrush device)
qreal yTilt() const
The tilt of the pen on the vertical axis (from 0.0 to 1.0)
qreal rotation() const
rotation as given by the tablet event
qreal pressure() const
The pressure of the value (from 0.0 to 1.0)
void paint(KisPaintInformation &info)

References KisPaintInformation::canvasMirroredH(), KisPaintInformation::canvasMirroredV(), KisPaintInformation::canvasRotation(), elapsedStrokeTime(), m_d, paint(), KisPaintInformation::perspective(), KisPaintInformation::pos(), KisPaintInformation::pressure(), KisToolFreehandHelper::Private::previousPaintInformation, KisPaintInformation::rotation(), KisPaintInformation::setCanvasMirroredH(), KisPaintInformation::setCanvasMirroredV(), KisPaintInformation::setCanvasRotation(), KisToolFreehandHelper::Private::strokeInfos, KisPaintInformation::tangentialPressure(), KisPaintInformation::xTilt(), and KisPaintInformation::yTilt().

◆ elapsedStrokeTime()

int KisToolFreehandHelper::elapsedStrokeTime ( ) const
protected

Definition at line 771 of file kis_tool_freehand_helper.cpp.

772{
773 return m_d->strokeTime.elapsed();
774}

References m_d, and KisToolFreehandHelper::Private::strokeTime.

◆ endPaint()

void KisToolFreehandHelper::endPaint ( )

There might be some timer events still pending, so we should cancel them. Use this flag for the purpose. Please note that we are not in MT here, so no mutex is needed

Definition at line 703 of file kis_tool_freehand_helper.cpp.

704{
705 if (!m_d->hasPaintAtLeastOnce) {
707 } else if (m_d->smoothingOptions->smoothingType() != KisSmoothingOptions::NO_SMOOTHING) {
708 finishStroke();
709 }
710 m_d->strokeTimeoutTimer.stop();
711
712 if(m_d->airbrushingTimer.isActive()) {
713 m_d->airbrushingTimer.stop();
714 }
715
716 if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) {
718 }
719
722 }
723
730 m_d->strokeInfos.clear();
731
732 // last update to complete rendering if there is still something pending
735
737 m_d->strokeId.clear();
739}
virtual void endStroke(KisStrokeId id)=0
virtual void addJob(KisStrokeId id, KisStrokeJobData *data)=0
void paintAt(int strokeInfoId, const KisPaintInformation &pi)

References KisStrokesFacade::addJob(), KisToolFreehandHelper::Private::airbrushingTimer, KisToolFreehandHelper::Private::asyncUpdateHelper, KisStrokesFacade::endStroke(), KisAsynchronousStrokeUpdateHelper::endUpdateStream(), finishStroke(), KisToolFreehandHelper::Private::hasPaintAtLeastOnce, KisToolFreehandHelper::Private::infoBuilder, KisAsynchronousStrokeUpdateHelper::isActive(), m_d, KisSmoothingOptions::NO_SMOOTHING, paintAt(), KisToolFreehandHelper::Private::previousPaintInformation, KisPaintingInformationBuilder::reset(), KisToolFreehandHelper::Private::smoothingOptions, KisSmoothingOptions::STABILIZER, stabilizerEnd(), KisToolFreehandHelper::Private::strokeId, KisToolFreehandHelper::Private::strokeInfos, KisToolFreehandHelper::Private::strokesFacade, and KisToolFreehandHelper::Private::strokeTimeoutTimer.

◆ finishStroke

void KisToolFreehandHelper::finishStroke ( )
privateslot

◆ getStabilizedPaintInfo()

KisPaintInformation KisToolFreehandHelper::getStabilizedPaintInfo ( const QQueue< KisPaintInformation > & queue,
const KisPaintInformation & lastPaintInfo )
private

The first point is going to be overridden by lastPaintInfo, skip it.

Definition at line 805 of file kis_tool_freehand_helper.cpp.

807{
808 KisPaintInformation result(lastPaintInfo.pos(),
809 lastPaintInfo.pressure(),
810 lastPaintInfo.xTilt(),
811 lastPaintInfo.yTilt(),
812 lastPaintInfo.rotation(),
813 lastPaintInfo.tangentialPressure(),
814 lastPaintInfo.perspective(),
816 lastPaintInfo.drawingSpeed());
817
818 result.setCanvasRotation(lastPaintInfo.canvasRotation());
819 result.setCanvasMirroredH(lastPaintInfo.canvasMirroredH());
820 result.setCanvasMirroredV(lastPaintInfo.canvasMirroredV());
821
822 if (queue.size() > 1) {
823 QQueue<KisPaintInformation>::const_iterator it = queue.constBegin();
824 QQueue<KisPaintInformation>::const_iterator end = queue.constEnd();
825
829 it++;
830 int i = 2;
831
832 if (m_d->smoothingOptions->stabilizeSensors()) {
833 while (it != end) {
834 qreal k = qreal(i - 1) / i; // coeff for uniform averaging
835 result.KisPaintInformation::mixOtherWithoutTime(k, *it);
836 it++;
837 i++;
838 }
839 } else{
840 while (it != end) {
841 qreal k = qreal(i - 1) / i; // coeff for uniform averaging
842 result.KisPaintInformation::mixOtherOnlyPosition(k, *it);
843 it++;
844 i++;
845 }
846 }
847 }
848
849 return result;
850}

References KisPaintInformation::canvasMirroredH(), KisPaintInformation::canvasMirroredV(), KisPaintInformation::canvasRotation(), KisPaintInformation::drawingSpeed(), elapsedStrokeTime(), m_d, KisPaintInformation::perspective(), KisPaintInformation::pos(), KisPaintInformation::pressure(), KisPaintInformation::rotation(), KisPaintInformation::setCanvasMirroredH(), KisPaintInformation::setCanvasMirroredV(), KisPaintInformation::setCanvasRotation(), KisToolFreehandHelper::Private::smoothingOptions, KisPaintInformation::tangentialPressure(), KisPaintInformation::xTilt(), and KisPaintInformation::yTilt().

◆ initPaint()

void KisToolFreehandHelper::initPaint ( KoPointerEvent * event,
const QPointF & pixelCoords,
KisImageWSP image,
KisNodeSP currentNode,
KisStrokesFacade * strokesFacade,
KisNodeSP overrideNode = 0,
KisDefaultBoundsBaseSP bounds = 0 )
Parameters
eventThe event
pixelCoordsThe position of the KoPointerEvent, in pixel coordinates.
resourceManagerThe canvas resource manager
imageThe image
currentNodeThe current node
strokesFacadeThe strokes facade
overrideNodeThe override node
boundsThe bounds

Definition at line 258 of file kis_tool_freehand_helper.cpp.

264{
265 // When using touch drawing, we only get coordinates when the finger is
266 // actually pressed down, never when the finger is in the air. That means we
267 // have to clear the distance and speed information in this case, otherwise
268 // strokes start in a state depending on where the last stroke left off,
269 // which is useless. Resetting these at least makes it predictable. This
270 // can't sensibly be done in endPaint since there can be stylus or mouse
271 // events in the meantime, whose distance and speed is also unrelated.
272 if (event->isTouchEvent()) {
273 m_d->lastCursorPos.reset(pixelCoords);
275 }
276
277 QPointF prevPoint = m_d->lastCursorPos.pushThroughHistory(pixelCoords, currentZoom());
278 m_d->strokeTime.start();
281 qreal startAngle = KisAlgebra2D::directionBetweenPoints(prevPoint, pixelCoords, 0.0);
282
283 initPaintImpl(startAngle,
284 pi,
286 image,
287 currentNode,
288 strokesFacade,
289 overrideNode,
290 bounds);
291}
KisPaintInformation startStroke(KoPointerEvent *event, int timeElapsed, const KoCanvasResourceProvider *manager)
void initPaintImpl(qreal startAngle, const KisPaintInformation &pi, KoCanvasResourceProvider *resourceManager, KisImageWSP image, KisNodeSP node, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode=0, KisDefaultBoundsBaseSP bounds=0)
bool isTouchEvent() const
#define bounds(x, a, b)
qreal directionBetweenPoints(const QPointF &p1, const QPointF &p2, qreal defaultAngle)

References bounds, currentZoom(), KisAlgebra2D::directionBetweenPoints(), elapsedStrokeTime(), KisToolFreehandHelper::Private::infoBuilder, initPaintImpl(), KoPointerEvent::isTouchEvent(), KisToolFreehandHelper::Private::lastCursorPos, m_d, KisPaintOpUtils::PositionHistory::pushThroughHistory(), KisPaintingInformationBuilder::reset(), KisPaintOpUtils::PositionHistory::reset(), KisToolFreehandHelper::Private::resourceManager, KisPaintingInformationBuilder::startStroke(), and KisToolFreehandHelper::Private::strokeTime.

◆ initPaintImpl()

void KisToolFreehandHelper::initPaintImpl ( qreal startAngle,
const KisPaintInformation & pi,
KoCanvasResourceProvider * resourceManager,
KisImageWSP image,
KisNodeSP node,
KisStrokesFacade * strokesFacade,
KisNodeSP overrideNode = 0,
KisDefaultBoundsBaseSP bounds = 0 )
protected

Definition at line 298 of file kis_tool_freehand_helper.cpp.

306{
307 m_d->strokesFacade = strokesFacade;
308
309 m_d->haveTangent = false;
310 m_d->previousTangent = QPointF();
311
312 m_d->hasPaintAtLeastOnce = false;
313
315
317 currentNode,
319 bounds);
320 if(overrideNode) {
321 m_d->resources->setCurrentNode(overrideNode);
322 }
323
324 const bool airbrushing = m_d->resources->needsAirbrushing();
325 const bool useSpacingUpdates = m_d->resources->needsSpacingUpdates();
326
328 startAngle,
329 useSpacingUpdates ? SPACING_UPDATE_INTERVAL : LONG_TIME,
330 airbrushing ? TIMING_UPDATE_INTERVAL : LONG_TIME,
331 0);
332 KisDistanceInformation startDist = startDistInfo.makeDistInfo();
333
335 startDist);
336
337 KisStrokeStrategy *stroke =
343
345
346 m_d->history.clear();
347 m_d->distanceHistory.clear();
348 m_d->hasLastDrawnPixel = false;
349 m_d->hasTentativePixel = false;
350
351 if (airbrushing) {
353 m_d->airbrushingTimer.start();
356 }
357
358 if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) {
360 }
361
362 // If airbrushing, paint an initial dab immediately. This is a workaround for an issue where
363 // some paintops (Dyna, Particle, Sketch) might never initialize their spacing/timing
364 // information until paintAt is called.
365 if (airbrushing) {
366 paintAt(pi);
367 }
368}
void startUpdateStream(KisStrokesFacade *strokesFacade, KisStrokeId strokeId)
The KisResourcesSnapshot class takes a snapshot of the various resources like colors and settings use...
void setCurrentNode(KisNodeSP node)
virtual KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy)=0
void stabilizerStart(KisPaintInformation firstPaintInfo)
virtual void createPainters(QVector< KisFreehandStrokeInfo * > &strokeInfos, const KisDistanceInformation &startDist)
const qreal LONG_TIME
const qreal TIMING_UPDATE_INTERVAL
const qreal SPACING_UPDATE_INTERVAL

References KisToolFreehandHelper::Private::airbrushingTimer, KisToolFreehandHelper::Private::asyncUpdateHelper, bounds, computeAirbrushTimerInterval(), createPainters(), KisToolFreehandHelper::Private::distanceHistory, KisToolFreehandHelper::Private::hasLastDrawnPixel, KisToolFreehandHelper::Private::hasPaintAtLeastOnce, KisToolFreehandHelper::Private::hasTentativePixel, KisToolFreehandHelper::Private::haveTangent, KisToolFreehandHelper::Private::history, LONG_TIME, m_d, KisResourcesSnapshot::needsAirbrushing(), KisResourcesSnapshot::needsSpacingUpdates(), paintAt(), KisPaintInformation::pos(), KisResourcesSnapshot::presetNeedsAsynchronousUpdates(), KisToolFreehandHelper::Private::previousPaintInformation, KisToolFreehandHelper::Private::previousTangent, resourceManager(), KisToolFreehandHelper::Private::resources, KisResourcesSnapshot::setCurrentNode(), KisToolFreehandHelper::Private::smoothingOptions, SPACING_UPDATE_INTERVAL, KisSmoothingOptions::STABILIZER, stabilizerStart(), KisStrokesFacade::startStroke(), KisAsynchronousStrokeUpdateHelper::startUpdateStream(), KisToolFreehandHelper::Private::strokeId, KisToolFreehandHelper::Private::strokeInfos, KisToolFreehandHelper::Private::strokesFacade, FreehandStrokeStrategy::SupportsContinuedInterstrokeData, FreehandStrokeStrategy::SupportsTimedMergeId, TIMING_UPDATE_INTERVAL, and KisToolFreehandHelper::Private::transactionText.

◆ isRunning()

bool KisToolFreehandHelper::isRunning ( ) const

Definition at line 293 of file kis_tool_freehand_helper.cpp.

294{
295 return bool(m_d->strokeId);
296}

References m_d, and KisToolFreehandHelper::Private::strokeId.

◆ paint()

void KisToolFreehandHelper::paint ( KisPaintInformation & info)
private

Smooth the coordinates out using the history and the distance. This is a heavily modified version of an algo used in Gimp and described in https://bugs.kde.org/show_bug.cgi?id=281267 and https://w.atwiki.jp/sigetch_2007/pages/17.html. The main differences are:

1) It uses 'distance' instead of 'velocity', since time measurements are too unstable in realworld environment

2) There is no 'Quality' parameter, since the number of samples is calculated automatically

3) 'Tail Aggressiveness' is used for controlling the end of the stroke

4) The formula is a little bit different: 'Distance' parameter stands for $3 \Sigma$

Definition at line 492 of file kis_tool_freehand_helper.cpp.

493{
514 KisPaintInformation lastUsedPaintInformation;
515
517 && (m_d->smoothingOptions->smoothnessDistanceMin() > 0.0
518 || m_d->smoothingOptions->smoothnessDistanceMax() > 0.0)) {
519
520 { // initialize current distance
521 QPointF prevPos;
522
523 if (!m_d->history.isEmpty()) {
524 const KisPaintInformation &prevPi = m_d->history.last();
525 prevPos = prevPi.pos();
526 } else {
527 prevPos = m_d->previousPaintInformation.pos();
528 }
529
530 qreal currentDistance = QVector2D(info.pos() - prevPos).length();
531 m_d->distanceHistory.append(currentDistance);
532 }
533
534 m_d->history.append(info);
535
536 qreal x = 0.0;
537 qreal y = 0.0;
538
539 if (m_d->history.size() > 3) {
540 const qreal sigma = m_d->effectiveSmoothnessDistance(m_d->previousPaintInformation.drawingSpeed()) / 3.0; // '3.0' for (3 * sigma) range
541
542 qreal gaussianWeight = 1 / (sqrt(2 * M_PI) * sigma);
543 qreal gaussianWeight2 = sigma * sigma;
544 qreal distanceSum = 0.0;
545 qreal scaleSum = 0.0;
546 qreal pressure = 0.0;
547 qreal baseRate = 0.0;
548
549 Q_ASSERT(m_d->history.size() == m_d->distanceHistory.size());
550
551 for (int i = m_d->history.size() - 1; i >= 0; i--) {
552 qreal rate = 0.0;
553
554 const KisPaintInformation nextInfo = m_d->history.at(i);
555 double distance = m_d->distanceHistory.at(i);
556 Q_ASSERT(distance >= 0.0);
557
558 qreal pressureGrad = 0.0;
559 if (i < m_d->history.size() - 1) {
560 pressureGrad = nextInfo.pressure() - m_d->history.at(i + 1).pressure();
561
562 const qreal tailAggressiveness = 40.0 * m_d->smoothingOptions->tailAggressiveness();
563
564 if (pressureGrad > 0.0 ) {
565 pressureGrad *= tailAggressiveness * (1.0 - nextInfo.pressure());
566 distance += pressureGrad * 3.0 * sigma; // (3 * sigma) --- holds > 90% of the region
567 }
568 }
569
570 if (gaussianWeight2 != 0.0) {
571 distanceSum += distance;
572 rate = gaussianWeight * exp(-distanceSum * distanceSum / (2 * gaussianWeight2));
573 }
574
575 if (m_d->history.size() - i == 1) {
576 baseRate = rate;
577 } else if (baseRate / rate > 100) {
578 break;
579 }
580
581 scaleSum += rate;
582 x += rate * nextInfo.pos().x();
583 y += rate * nextInfo.pos().y();
584
585 if (m_d->smoothingOptions->smoothPressure()) {
586 pressure += rate * nextInfo.pressure();
587 }
588 }
589
590 if (scaleSum != 0.0) {
591 x /= scaleSum;
592 y /= scaleSum;
593
594 if (m_d->smoothingOptions->smoothPressure()) {
595 pressure /= scaleSum;
596 }
597 }
598
599 if ((x != 0.0 && y != 0.0) || (x == info.pos().x() && y == info.pos().y())) {
600 info.setPos(QPointF(x, y));
601 if (m_d->smoothingOptions->smoothPressure()) {
602 info.setPressure(pressure);
603 }
604 m_d->history.last() = info;
605 }
606 }
607 }
608
611 {
612 // Now paint between the coordinates, using the bezier curve interpolation
613 if (!m_d->haveTangent) {
614 m_d->haveTangent = true;
616 (info.pos() - m_d->previousPaintInformation.pos()) /
617 qMax(qreal(1.0), info.currentTime() - m_d->previousPaintInformation.currentTime());
618 } else {
619 QPointF newTangent = (info.pos() - m_d->olderPaintInformation.pos()) /
620 qMax(qreal(1.0), info.currentTime() - m_d->olderPaintInformation.currentTime());
621
622 if (newTangent.isNull() || m_d->previousTangent.isNull())
623 {
625 } else {
627 m_d->previousTangent, newTangent);
628 }
629
630 m_d->previousTangent = newTangent;
631 }
633
634 // Enable stroke timeout only when not airbrushing.
635 if (!m_d->airbrushingTimer.isActive()) {
636 m_d->strokeTimeoutTimer.start(100);
637 }
638 }
639
640 else if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::NO_SMOOTHING){
642 }
643
645 QPoint currentPixelPos = Private::toPixelPos(info.pos());
646
647 // First pixel is always perfect.
648 if (!m_d->hasLastDrawnPixel) {
649 Private::setPaintInfoPixelPos(info, currentPixelPos);
650 paintLine(info, info);
651 m_d->lastDrawnPixel = currentPixelPos;
652 m_d->hasLastDrawnPixel = true;
653 m_d->hasTentativePixel = false;
655
656 } else {
657 // Check if we need to flush a currently stashed tentative pixel.
658 bool lastTentative = m_d->isTentativePixel(currentPixelPos);
659 if (m_d->hasTentativePixel && !lastTentative) {
662 m_d->hasTentativePixel = false;
665 lastTentative = m_d->isTentativePixel(currentPixelPos);
666 }
667
668 // If this pixel is too close to the previously drawn one, we mark
669 // it as tentative and wait for further movements to make sure we
670 // don't put it down in a place that generates a jag. If there is
671 // already a tentative pixel, it will be clobbered.
672 if (lastTentative) {
673 m_d->hasTentativePixel = true;
674 m_d->tentativePixel = currentPixelPos;
676 } else {
677 Private::setPaintInfoPixelPos(info, currentPixelPos);
679 m_d->lastDrawnPixel = currentPixelPos;
681 // Don't need to fiddle with hasLastTentativePixel here, it can
682 // only ever be false here due to the previous condition.
683 }
684 }
685 }
686
687 if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) {
690 // Paint here so we don't have to rely on the timer
691 // This is just a tricky source for a relatively stable 7ms "timer"
693 }
694 } else {
696 }
697
698 if(m_d->airbrushingTimer.isActive()) {
699 m_d->airbrushingTimer.start();
700 }
701}
qreal distance(const QPointF &p1, const QPointF &p2)
void setPos(const QPointF &p)
void setPressure(qreal p)
Set the pressure.
void addEvent(const KisPaintInformation &pi)
#define M_PI
Definition kis_global.h:111
KisStabilizedEventsSampler stabilizedSampler
static void setPaintInfoPixelPos(KisPaintInformation &info, const QPoint &pixelPos)
bool isTentativePixel(const QPoint &currentPixelPos) const
static QPoint toPixelPos(const QPointF &pos)
qreal effectiveSmoothnessDistance(qreal speed) const

References KisStabilizedEventsSampler::addEvent(), KisToolFreehandHelper::Private::airbrushingTimer, KisPaintInformation::currentTime(), distance(), KisToolFreehandHelper::Private::distanceHistory, KisPaintInformation::drawingSpeed(), KisToolFreehandHelper::Private::effectiveSmoothnessDistance(), KisToolFreehandHelper::Private::hasLastDrawnPixel, KisToolFreehandHelper::Private::hasTentativePixel, KisToolFreehandHelper::Private::haveTangent, KisToolFreehandHelper::Private::history, KisToolFreehandHelper::Private::isTentativePixel(), KisToolFreehandHelper::Private::lastDrawnPixel, m_d, M_PI, KisSmoothingOptions::NO_SMOOTHING, KisToolFreehandHelper::Private::olderPaintInformation, paintBezierSegment(), paintLine(), KisStabilizerDelayedPaintHelper::paintSome(), KisSmoothingOptions::PIXEL_PERFECT, KisPaintInformation::pos(), KisPaintInformation::pressure(), KisToolFreehandHelper::Private::previousPaintInformation, KisToolFreehandHelper::Private::previousTangent, KisStabilizerDelayedPaintHelper::running(), KisToolFreehandHelper::Private::setPaintInfoPixelPos(), KisPaintInformation::setPos(), KisPaintInformation::setPressure(), KisSmoothingOptions::SIMPLE_SMOOTHING, KisToolFreehandHelper::Private::smoothingOptions, KisToolFreehandHelper::Private::stabilizedSampler, KisSmoothingOptions::STABILIZER, KisToolFreehandHelper::Private::stabilizerDelayedPaintHelper, KisToolFreehandHelper::Private::strokeTimeoutTimer, KisToolFreehandHelper::Private::tentativePaintInformation, KisToolFreehandHelper::Private::tentativePixel, KisToolFreehandHelper::Private::toPixelPos(), and KisSmoothingOptions::WEIGHTED_SMOOTHING.

◆ paintAt() [1/2]

void KisToolFreehandHelper::paintAt ( const KisPaintInformation & pi)
protectedvirtual

Reimplemented in KisToolMultihandHelper, and KisToolMultihandHelper.

Definition at line 1070 of file kis_tool_freehand_helper.cpp.

1071{
1072 paintAt(0, pi);
1073}

References paintAt().

◆ paintAt() [2/2]

◆ paintBezierCurve() [1/2]

void KisToolFreehandHelper::paintBezierCurve ( const KisPaintInformation & pi1,
const QPointF & control1,
const QPointF & control2,
const KisPaintInformation & pi2 )
protectedvirtual

Reimplemented in KisToolMultihandHelper, and KisToolMultihandHelper.

Definition at line 1081 of file kis_tool_freehand_helper.cpp.

1085{
1086 paintBezierCurve(0, pi1, control1, control2, pi2);
1087}
void paintBezierCurve(int strokeInfoId, const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2)

References paintBezierCurve().

◆ paintBezierCurve() [2/2]

void KisToolFreehandHelper::paintBezierCurve ( int strokeInfoId,
const KisPaintInformation & pi1,
const QPointF & control1,
const QPointF & control2,
const KisPaintInformation & pi2 )
protected

Definition at line 1026 of file kis_tool_freehand_helper.cpp.

1031{
1032
1033#ifdef DEBUG_BEZIER_CURVES
1036
1037 tpi1 = pi1;
1038 tpi2 = pi2;
1039
1040 tpi1.setPressure(0.3);
1041 tpi2.setPressure(0.3);
1042
1043 paintLine(tpi1, tpi2);
1044
1045 tpi1.setPressure(0.6);
1046 tpi2.setPressure(0.3);
1047
1048 tpi1.setPos(pi1.pos());
1049 tpi2.setPos(control1);
1050 paintLine(tpi1, tpi2);
1051
1052 tpi1.setPos(pi2.pos());
1053 tpi2.setPos(control2);
1054 paintLine(tpi1, tpi2);
1055#endif
1056
1057 m_d->hasPaintAtLeastOnce = true;
1059 new FreehandStrokeStrategy::Data(strokeInfoId,
1060 pi1, control1, control2, pi2));
1061
1062}

References KisStrokesFacade::addJob(), KisToolFreehandHelper::Private::hasPaintAtLeastOnce, m_d, paintLine(), KisPaintInformation::pos(), KisPaintInformation::setPos(), KisPaintInformation::setPressure(), KisToolFreehandHelper::Private::strokeId, and KisToolFreehandHelper::Private::strokesFacade.

◆ paintBezierSegment()

void KisToolFreehandHelper::paintBezierSegment ( KisPaintInformation pi1,
KisPaintInformation pi2,
QPointF tangent1,
QPointF tangent2 )
private

Definition at line 375 of file kis_tool_freehand_helper.cpp.

377{
378 if (tangent1.isNull() || tangent2.isNull()) return;
379
380 const qreal maxSanePoint = 1e6;
381
382 QPointF controlTarget1;
383 QPointF controlTarget2;
384
385 // Shows the direction in which control points go
386 QPointF controlDirection1 = pi1.pos() + tangent1;
387 QPointF controlDirection2 = pi2.pos() - tangent2;
388
389 // Lines in the direction of the control points
390 QLineF line1(pi1.pos(), controlDirection1);
391 QLineF line2(pi2.pos(), controlDirection2);
392
393 // Lines to check whether the control points lay on the opposite
394 // side of the line
395 QLineF line3(controlDirection1, controlDirection2);
396 QLineF line4(pi1.pos(), pi2.pos());
397
398 QPointF intersection;
399 if (line3.intersects(line4, &intersection) == QLineF::BoundedIntersection) {
400 qreal controlLength = line4.length() / 2;
401
402 line1.setLength(controlLength);
403 line2.setLength(controlLength);
404
405 controlTarget1 = line1.p2();
406 controlTarget2 = line2.p2();
407 } else {
408 QLineF::IntersectType type = line1.intersects(line2, &intersection);
409
410 if (type == QLineF::NoIntersection ||
411 intersection.manhattanLength() > maxSanePoint) {
412
413 intersection = 0.5 * (pi1.pos() + pi2.pos());
414// dbgKrita << "WARNING: there is no intersection point "
415// << "in the basic smoothing algorithms";
416 }
417
418 controlTarget1 = intersection;
419 controlTarget2 = intersection;
420 }
421
422 // shows how near to the controlTarget the value raises
423 qreal coeff = 0.8;
424
425 qreal velocity1 = QLineF(QPointF(), tangent1).length();
426 qreal velocity2 = QLineF(QPointF(), tangent2).length();
427
428 if (velocity1 == 0.0 || velocity2 == 0.0) {
429 velocity1 = 1e-6;
430 velocity2 = 1e-6;
431 warnKrita << "WARNING: Basic Smoothing: Velocity is Zero! Please report a bug:" << ppVar(velocity1) << ppVar(velocity2);
432 }
433
434 qreal similarity = qMin(velocity1/velocity2, velocity2/velocity1);
435
436 // the controls should not differ more than 50%
437 similarity = qMax(similarity, qreal(0.5));
438
439 // when the controls are symmetric, their size should be smaller
440 // to avoid corner-like curves
441 coeff *= 1 - qMax(qreal(0.0), similarity - qreal(0.8));
442
443 Q_ASSERT(coeff > 0);
444
445
446 QPointF control1;
447 QPointF control2;
448
449 if (velocity1 > velocity2) {
450 control1 = pi1.pos() * (1.0 - coeff) + coeff * controlTarget1;
451 coeff *= similarity;
452 control2 = pi2.pos() * (1.0 - coeff) + coeff * controlTarget2;
453 } else {
454 control2 = pi2.pos() * (1.0 - coeff) + coeff * controlTarget2;
455 coeff *= similarity;
456 control1 = pi1.pos() * (1.0 - coeff) + coeff * controlTarget1;
457 }
458
460 control1,
461 control2,
462 pi2);
463}
#define warnKrita
Definition kis_debug.h:87
#define ppVar(var)
Definition kis_debug.h:155

References paintBezierCurve(), KisPaintInformation::pos(), ppVar, and warnKrita.

◆ paintEvent()

◆ paintLine() [1/2]

void KisToolFreehandHelper::paintLine ( const KisPaintInformation & pi1,
const KisPaintInformation & pi2 )
protectedvirtual

Reimplemented in KisToolMultihandHelper, and KisToolMultihandHelper.

Definition at line 1075 of file kis_tool_freehand_helper.cpp.

1077{
1078 paintLine(0, pi1, pi2);
1079}

References paintLine().

◆ paintLine() [2/2]

void KisToolFreehandHelper::paintLine ( int strokeInfoId,
const KisPaintInformation & pi1,
const KisPaintInformation & pi2 )
protected

◆ paintOpOutline()

KisOptimizedBrushOutline KisToolFreehandHelper::paintOpOutline ( const QPointF & savedCursorPos,
const KoPointerEvent * event,
const KisPaintOpSettingsSP globalSettings,
KisPaintOpSettings::OutlineMode mode ) const

When LoD mode is active it may happen that the helper has already started a stroke, but it painted noting, because all the work is being calculated by the scaled-down LodN stroke. So at first we try to fetch the data from the lodN stroke ("buddy") and then check if there is at least something has been painted with this distance information object.

Tiny hack alert: here we fetch the distance information directly from the LodN stroke. Ideally, we should upscale its data, but here we just override it with our local copy of the coordinates.

Definition at line 182 of file kis_tool_freehand_helper.cpp.

186{
187 KisPaintOpSettingsSP settings = globalSettings;
188 QPointF prevPoint = m_d->lastCursorPos.pushThroughHistory(savedCursorPos, currentZoom());
189 qreal startAngle = KisAlgebra2D::directionBetweenPoints(prevPoint, savedCursorPos, 0);
190 KisDistanceInformation distanceInfo(prevPoint, startAngle);
191
193
194 if (!m_d->strokeInfos.isEmpty()) {
195 settings = m_d->resources->currentPaintOpPreset()->settings();
199 } else {
201 }
202
212 KisDistanceInformation *buddyDistance =
213 m_d->strokeInfos.first()->buddyDragDistance();
214
215 if (buddyDistance) {
222 distanceInfo = *buddyDistance;
223 distanceInfo.overrideLastValues(prevPoint, startAngle);
224
225 } else if (m_d->strokeInfos.first()->dragDistance->isStarted()) {
226 distanceInfo = *m_d->strokeInfos.first()->dragDistance;
227 }
228 } else {
229 info = m_d->infoBuilder->hover(savedCursorPos, event, !m_d->strokeInfos.isEmpty());
230 }
231
233 info.registerDistanceInformation(&distanceInfo);
234
237
238 KisOptimizedBrushOutline outline = settings->brushOutline(info, mode, currentPhysicalZoom());
239
240 if (m_d->resources &&
242 m_d->smoothingOptions->useDelayDistance()) {
243
244 const qreal R = m_d->smoothingOptions->delayDistance() /
246
247 outline.addEllipse(info.pos(), R, R);
248 }
249
250 return outline;
251}
Eigen::Matrix< double, 4, 2 > R
void addEllipse(const QPointF &center, qreal rx, qreal ry)
void setRandomSource(KisRandomSourceSP value)
DistanceInformationRegistrar registerDistanceInformation(KisDistanceInformation *distance)
void setPerStrokeRandomSource(KisPerStrokeRandomSourceSP value)
KisPaintInformation hover(const QPointF &imagePoint, const KoPointerEvent *event, bool isStrokeStarted)
KisPaintOpPresetSP currentPaintOpPreset() const
void overrideLastValues(const QPointF &lastPosition, qreal lastAngle)

References KisOptimizedBrushOutline::addEllipse(), KisResourcesSnapshot::currentPaintOpPreset(), currentPhysicalZoom(), currentZoom(), KisAlgebra2D::directionBetweenPoints(), KisResourcesSnapshot::effectiveZoom(), KisToolFreehandHelper::Private::fakeDabRandomSource, KisToolFreehandHelper::Private::fakeStrokeRandomSource, KisStabilizerDelayedPaintHelper::hasLastPaintInformation(), KisPaintingInformationBuilder::hover(), KisToolFreehandHelper::Private::infoBuilder, KisToolFreehandHelper::Private::lastCursorPos, KisStabilizerDelayedPaintHelper::lastPaintInformation(), m_d, KisDistanceInformation::overrideLastValues(), KisPaintInformation::pos(), KisToolFreehandHelper::Private::previousPaintInformation, KisPaintOpUtils::PositionHistory::pushThroughHistory(), R, KisPaintInformation::registerDistanceInformation(), KisToolFreehandHelper::Private::resources, KisStabilizerDelayedPaintHelper::running(), KisPaintInformation::setPerStrokeRandomSource(), KisPaintInformation::setRandomSource(), KisToolFreehandHelper::Private::smoothingOptions, KisSmoothingOptions::STABILIZER, KisToolFreehandHelper::Private::stabilizerDelayedPaintHelper, and KisToolFreehandHelper::Private::strokeInfos.

◆ requestExplicitUpdateOutline

void KisToolFreehandHelper::requestExplicitUpdateOutline ( )
signal

The signal is emitted when the outline should be updated explicitly by the tool. Used by Stabilizer option, because it paints on internal timer events instead of the on every paint() event

◆ resourceManager()

KoCanvasResourceProvider * KisToolFreehandHelper::resourceManager ( ) const
protected

Definition at line 370 of file kis_tool_freehand_helper.cpp.

371{
372 return m_d->resourceManager;
373}

References m_d, and KisToolFreehandHelper::Private::resourceManager.

◆ setSmoothness()

void KisToolFreehandHelper::setSmoothness ( KisSmoothingOptionsSP smoothingOptions)

◆ slotSmoothingTypeChanged

◆ smoothingOptions()

KisSmoothingOptionsSP KisToolFreehandHelper::smoothingOptions ( ) const

Definition at line 177 of file kis_tool_freehand_helper.cpp.

178{
179 return m_d->smoothingOptions;
180}

References m_d, and KisToolFreehandHelper::Private::smoothingOptions.

◆ stabilizerEnd()

void KisToolFreehandHelper::stabilizerEnd ( )
private

◆ stabilizerPollAndPaint

void KisToolFreehandHelper::stabilizerPollAndPaint ( )
privateslot

Definition at line 852 of file kis_tool_freehand_helper.cpp.

853{
856 std::tie(it, end) = m_d->stabilizedSampler.range();
857 QVector<KisPaintInformation> delayedPaintTodoItems;
858
859 for (; it != end; ++it) {
860 KisPaintInformation sampledInfo = *it;
861
862 bool canPaint = true;
863
864 if (m_d->smoothingOptions->useDelayDistance()) {
865 const qreal R = m_d->smoothingOptions->delayDistance() /
867
868 QPointF diff = sampledInfo.pos() - m_d->previousPaintInformation.pos();
869 qreal dx = sqrt(pow2(diff.x()) + pow2(diff.y()));
870
871 if (!(dx > R)) {
873 sampledInfo.setPos(m_d->previousPaintInformation.pos());
874 }
875 else {
876 canPaint = false;
877 }
878 }
879 }
880
881 if (canPaint) {
883
885 delayedPaintTodoItems.append(newInfo);
886 } else {
888 }
889 m_d->previousPaintInformation = newInfo;
890
891 // Push the new entry through the queue
892 m_d->stabilizerDeque.dequeue();
893 m_d->stabilizerDeque.enqueue(sampledInfo);
894 } else if (m_d->stabilizerDeque.head().pos() != m_d->previousPaintInformation.pos()) {
895 QQueue<KisPaintInformation>::iterator it = m_d->stabilizerDeque.begin();
896 QQueue<KisPaintInformation>::iterator end = m_d->stabilizerDeque.end();
897
898 while (it != end) {
900 ++it;
901 }
902 }
903 }
904
906
908 m_d->stabilizerDelayedPaintHelper.update(delayedPaintTodoItems);
909 } else {
911 }
912}
std::pair< iterator, iterator > range() const
void update(const QVector< KisPaintInformation > &newPaintInfos)
KisPaintInformation getStabilizedPaintInfo(const QQueue< KisPaintInformation > &queue, const KisPaintInformation &lastPaintInfo)
T pow2(const T &x)
Definition kis_global.h:166

References KisStabilizedEventsSampler::clear(), KisResourcesSnapshot::effectiveZoom(), getStabilizedPaintInfo(), m_d, KisResourcesSnapshot::needsAirbrushing(), paintLine(), KisPaintInformation::pos(), pow2(), KisToolFreehandHelper::Private::previousPaintInformation, R, KisStabilizedEventsSampler::range(), requestExplicitUpdateOutline(), KisToolFreehandHelper::Private::resources, KisStabilizerDelayedPaintHelper::running(), KisPaintInformation::setPos(), KisToolFreehandHelper::Private::smoothingOptions, KisToolFreehandHelper::Private::stabilizedSampler, KisToolFreehandHelper::Private::stabilizerDelayedPaintHelper, KisToolFreehandHelper::Private::stabilizerDeque, and KisStabilizerDelayedPaintHelper::update().

◆ stabilizerStart()

void KisToolFreehandHelper::stabilizerStart ( KisPaintInformation firstPaintInfo)
private

Definition at line 776 of file kis_tool_freehand_helper.cpp.

777{
778 m_d->usingStabilizer = true;
779 // FIXME: Ugly hack, this is no a "distance" in any way
780 int sampleSize = qRound(m_d->effectiveSmoothnessDistance(firstPaintInfo.drawingSpeed()));
781 sampleSize = qMax(3, sampleSize);
782
783 // Fill the deque with the current value repeated until filling the sample
784 m_d->stabilizerDeque.clear();
785 for (int i = sampleSize; i > 0; i--) {
786 m_d->stabilizerDeque.enqueue(firstPaintInfo);
787 }
788
789 // Poll and draw regularly
790 KisConfig cfg(true);
791 int stabilizerSampleSize = cfg.stabilizerSampleSize();
792 m_d->stabilizerPollTimer.setInterval(stabilizerSampleSize);
793 m_d->stabilizerPollTimer.start();
794
795 bool delayedPaintEnabled = cfg.stabilizerDelayedPaint();
796 if (delayedPaintEnabled) {
797 m_d->stabilizerDelayedPaintHelper.start(firstPaintInfo);
798 }
799
801 m_d->stabilizedSampler.addEvent(firstPaintInfo);
802}
void start(const KisPaintInformation &firstPaintInfo)

References KisStabilizedEventsSampler::addEvent(), KisStabilizedEventsSampler::clear(), KisPaintInformation::drawingSpeed(), KisToolFreehandHelper::Private::effectiveSmoothnessDistance(), m_d, KisToolFreehandHelper::Private::stabilizedSampler, KisConfig::stabilizerDelayedPaint(), KisToolFreehandHelper::Private::stabilizerDelayedPaintHelper, KisToolFreehandHelper::Private::stabilizerDeque, KisToolFreehandHelper::Private::stabilizerPollTimer, KisConfig::stabilizerSampleSize(), KisStabilizerDelayedPaintHelper::start(), and KisToolFreehandHelper::Private::usingStabilizer.

Member Data Documentation

◆ m_d

Private* const KisToolFreehandHelper::m_d
private

Definition at line 153 of file kis_tool_freehand_helper.h.


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