10#include <QElapsedTimer>
13#include <klocalizedstring.h>
121 m_d->resourceManager = resourceManager;
122 m_d->infoBuilder = infoBuilder;
123 m_d->transactionText = transactionText;
130 m_d->strokeTimeoutTimer.setSingleShot(
true);
131 connect(&m_d->strokeTimeoutTimer, SIGNAL(timeout()), SLOT(finishStroke()));
132 connect(&m_d->airbrushingTimer, SIGNAL(timeout()), SLOT(doAirbrushing()));
133 connect(&m_d->stabilizerPollTimer, SIGNAL(timeout()), SLOT(stabilizerPollAndPaint()));
134 connect(m_d->smoothingOptions.data(), SIGNAL(sigSmoothingTypeChanged()), SLOT(slotSmoothingTypeChanged()));
136 m_d->stabilizerDelayedPaintHelper.setPaintLineCallback(
140 m_d->stabilizerDelayedPaintHelper.setUpdateOutlineCallback(
142 Q_EMIT requestExplicitUpdateOutline();
201 distanceInfo = *buddyDistance;
238 const QPointF &pixelCoords,
356 QPointF tangent1, QPointF tangent2)
358 if (tangent1.isNull() || tangent2.isNull())
return;
360 const qreal maxSanePoint = 1e6;
362 QPointF controlTarget1;
363 QPointF controlTarget2;
366 QPointF controlDirection1 = pi1.
pos() + tangent1;
367 QPointF controlDirection2 = pi2.
pos() - tangent2;
370 QLineF line1(pi1.
pos(), controlDirection1);
371 QLineF line2(pi2.
pos(), controlDirection2);
375 QLineF line3(controlDirection1, controlDirection2);
376 QLineF line4(pi1.
pos(), pi2.
pos());
378 QPointF intersection;
379 if (line3.intersects(line4, &intersection) == QLineF::BoundedIntersection) {
380 qreal controlLength = line4.length() / 2;
382 line1.setLength(controlLength);
383 line2.setLength(controlLength);
385 controlTarget1 = line1.p2();
386 controlTarget2 = line2.p2();
388 QLineF::IntersectType type = line1.intersects(line2, &intersection);
390 if (type == QLineF::NoIntersection ||
391 intersection.manhattanLength() > maxSanePoint) {
393 intersection = 0.5 * (pi1.
pos() + pi2.
pos());
398 controlTarget1 = intersection;
399 controlTarget2 = intersection;
405 qreal velocity1 = QLineF(QPointF(), tangent1).length();
406 qreal velocity2 = QLineF(QPointF(), tangent2).length();
408 if (velocity1 == 0.0 || velocity2 == 0.0) {
411 warnKrita <<
"WARNING: Basic Smoothing: Velocity is Zero! Please report a bug:" <<
ppVar(velocity1) <<
ppVar(velocity2);
414 qreal similarity = qMin(velocity1/velocity2, velocity2/velocity1);
417 similarity = qMax(similarity, qreal(0.5));
421 coeff *= 1 - qMax(qreal(0.0), similarity - qreal(0.8));
429 if (velocity1 > velocity2) {
430 control1 = pi1.
pos() * (1.0 - coeff) + coeff * controlTarget1;
432 control2 = pi2.
pos() * (1.0 - coeff) + coeff * controlTarget2;
434 control2 = pi2.
pos() * (1.0 - coeff) + coeff * controlTarget2;
436 control1 = pi1.
pos() * (1.0 - coeff) + coeff * controlTarget1;
447 qreal zoomingCoeff = 1.0;
495 QPointF currentPixelPos = info.
pos();
496 const float PIXEL_DISTANCE_THRESHOLD = 1.7;
508 prevPos = prevPi.
pos();
513 qreal currentDistance = QVector2D(info.
pos() - prevPos).length();
525 qreal gaussianWeight = 1 / (sqrt(2 *
M_PI) * sigma);
526 qreal gaussianWeight2 = sigma * sigma;
527 qreal distanceSum = 0.0;
528 qreal scaleSum = 0.0;
529 qreal pressure = 0.0;
530 qreal baseRate = 0.0;
534 for (
int i =
m_d->
history.size() - 1; i >= 0; i--) {
541 qreal pressureGrad = 0.0;
542 if (i < m_d->history.size() - 1) {
547 if (pressureGrad > 0.0 ) {
548 pressureGrad *= tailAggressiveness * (1.0 - nextInfo.
pressure());
549 distance += pressureGrad * 3.0 * sigma;
553 if (gaussianWeight2 != 0.0) {
555 rate = gaussianWeight * exp(-distanceSum * distanceSum / (2 * gaussianWeight2));
560 }
else if (baseRate / rate > 100) {
565 x += rate * nextInfo.
pos().x();
566 y += rate * nextInfo.
pos().y();
569 pressure += rate * nextInfo.
pressure();
573 if (scaleSum != 0.0) {
578 pressure /= scaleSum;
582 if ((x != 0.0 && y != 0.0) || (x == info.
pos().x() && y == info.
pos().y())) {
583 info.
setPos(QPointF(x, y));
630 currentPixelPos = info.
pos();
759 sampleSize = qMax(3, sampleSize);
763 for (
int i = sampleSize; i > 0; i--) {
774 if (delayedPaintEnabled) {
788 lastPaintInfo.
xTilt(),
789 lastPaintInfo.
yTilt(),
800 if (queue.size() > 1) {
801 QQueue<KisPaintInformation>::const_iterator it = queue.constBegin();
802 QQueue<KisPaintInformation>::const_iterator end = queue.constEnd();
812 qreal k = qreal(i - 1) / i;
813 result.KisPaintInformation::mixOtherWithoutTime(k, *it);
819 qreal k = qreal(i - 1) / i;
820 result.KisPaintInformation::mixOtherOnlyPosition(k, *it);
837 for (; it != end; ++it) {
840 bool canPaint =
true;
847 qreal dx = sqrt(
pow2(diff.x()) +
pow2(diff.y()));
863 delayedPaintTodoItems.append(newInfo);
972 return qMax(1, qFloor(realInterval));
1006 const QPointF &control1,
1007 const QPointF &control2,
1011#ifdef DEBUG_BEZIER_CURVES
1038 pi1, control1, control2, pi2));
1060 const QPointF &control1,
1061 const QPointF &control2,
Eigen::Matrix< double, 4, 2 > R
qreal distance(const QPointF &p1, const QPointF &p2)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
@ SupportsContinuedInterstrokeData
void cancelUpdateStream()
void startUpdateStream(KisStrokesFacade *strokesFacade, KisStrokeId strokeId)
int stabilizerSampleSize(bool defaultValue=false) const
bool stabilizerDelayedPaint(bool defaultValue=false) const
void addEllipse(const QPointF ¢er, qreal rx, qreal ry)
void reset(const QPointF &pt)
QPointF pushThroughHistory(const QPointF &pt, qreal zoom)
The KisResourcesSnapshot class takes a snapshot of the various resources like colors and settings use...
void setCurrentNode(KisNodeSP node)
KisPaintOpPresetSP currentPaintOpPreset() const
qreal effectiveZoom() const
qreal airbrushingInterval() const
bool needsAirbrushing() const
bool presetNeedsAsynchronousUpdates() const
bool needsSpacingUpdates() const
void addEvent(const KisPaintInformation &pi)
void addFinishingEvent(int numSamples)
std::pair< iterator, iterator > range() const
void update(const QVector< KisPaintInformation > &newPaintInfos)
bool hasLastPaintInformation() const
void start(const KisPaintInformation &firstPaintInfo)
KisPaintInformation lastPaintInformation() const
virtual KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy)=0
virtual void endStroke(KisStrokeId id)=0
virtual void addJob(KisStrokeId id, KisStrokeJobData *data)=0
virtual bool cancelStroke(KisStrokeId id)=0
QVariant resource(int key) const
bool isTouchEvent() const
QSharedPointer< KisSmoothingOptions > KisSmoothingOptionsSP
qreal directionBetweenPoints(const QPointF &p1, const QPointF &p2, qreal defaultAngle)
@ EffectiveZoom
-Used only by painting tools for non-displaying purposes
@ EffectivePhysicalZoom
-Used by tool for displaying purposes
static KisUpdateTimeMonitor * instance()
void reportMouseMove(const QPointF &pos)