13#include <QtCore/qmath.h>
34 timeSinceSpacingUpdate(0.0),
36 timeSinceTimingUpdate(0.0),
38 lastDabInfoValid(false),
39 lastPaintInfoValid(false),
75 qreal lastMaxPressure = 0.0;
116 qreal lastAngle,
int currentDabSeqNo)
119 m_d->hasLastInfo =
true;
126 qreal lastAngle, qreal spacingUpdateInterval,
127 qreal timingUpdateInterval,
131 m_d->hasLastInfo =
true;
151 if (
m_d->spacingUpdateInterval != other.
m_d->spacingUpdateInterval
152 ||
m_d->timingUpdateInterval != other.
m_d->timingUpdateInterval
153 ||
m_d->hasLastInfo != other.
m_d->hasLastInfo)
157 if (
m_d->hasLastInfo) {
158 if (
m_d->lastPosition != other.
m_d->lastPosition
159 ||
m_d->lastAngle != other.
m_d->lastAngle)
165 if (
m_d->currentDabSeqNo != other.
m_d->currentDabSeqNo) {
180 if (
m_d->hasLastInfo) {
182 m_d->spacingUpdateInterval,
m_d->timingUpdateInterval,
183 m_d->currentDabSeqNo);
192 elt.setAttribute(
"spacingUpdateInterval", QString::number(
m_d->spacingUpdateInterval,
'g', 15));
193 elt.setAttribute(
"timingUpdateInterval", QString::number(
m_d->timingUpdateInterval,
'g', 15));
194 elt.setAttribute(
"currentDabSeqNo", QString::number(
m_d->currentDabSeqNo));
195 if (
m_d->hasLastInfo) {
196 QDomElement lastInfoElt = doc.createElement(
"LastInfo");
197 lastInfoElt.setAttribute(
"lastPosX", QString::number(
m_d->lastPosition.x(),
'g', 15));
198 lastInfoElt.setAttribute(
"lastPosY", QString::number(
m_d->lastPosition.y(),
'g', 15));
199 lastInfoElt.setAttribute(
"lastAngle", QString::number(
m_d->lastAngle,
'g', 15));
200 elt.appendChild(lastInfoElt);
212 const QDomElement lastInfoElt = elt.firstChildElement(
"LastInfo");
239 qreal timingUpdateInterval,
255 m_d->lastDabInfoValid =
true;
260 qreal spacingUpdateInterval,
261 qreal timingUpdateInterval,
280 "The distance information "
281 "should be cloned before the "
282 "actual painting is started");
287 m_d->lastPosition = t.
map(
m_d->lastPosition);
302 m_d->lastDabInfoValid =
true;
318 m_d->timeSinceSpacingUpdate = 0.0;
323 return m_d->timeSinceSpacingUpdate >=
m_d->spacingUpdateInterval;
334 m_d->timeSinceTimingUpdate = 0.0;
339 return m_d->timeSinceTimingUpdate >=
m_d->timingUpdateInterval;
344 return m_d->lastDabInfoValid;
349 return m_d->lastPosition;
354 return m_d->lastAngle;
359 return m_d->lastPaintInfoValid;
364 return m_d->lastPaintInformation;
369 return m_d->currentDabSeqNo;
374 return m_d->lastMaxPressure;
379 return m_d->lastPaintInfoValid;
386 m_d->totalDistance +=
390 m_d->lastPaintInformation = info;
391 m_d->lastPaintInfoValid =
true;
394 m_d->lastPosition = info.
pos();
395 m_d->lastDabInfoValid =
true;
400 m_d->currentDabSeqNo++;
402 m_d->lastMaxPressure = qMax(info.
pressure(),
m_d->lastMaxPressure);
411 qreal distanceFactor = -1.0;
412 if (
m_d->spacing.isDistanceSpacingEnabled()) {
413 distanceFactor =
m_d->spacing.isIsotropic() ?
419 qreal timeFactor = -1.0;
420 if (
m_d->timing.isTimedSpacingEnabled()) {
426 if (distanceFactor < 0.0) {
428 }
else if (timeFactor < 0.0) {
431 t = qMin(distanceFactor, timeFactor);
437 m_d->timeSinceSpacingUpdate += endTime - startTime;
438 m_d->timeSinceTimingUpdate += endTime - startTime;
443 m_d->timeSinceSpacingUpdate = 0.0;
444 m_d->timeSinceTimingUpdate = 0.0;
452 return m_d->spacingUpdateInterval;
457 return m_d->timingUpdateInterval;
470 qreal dragVecLength = QVector2D(end - start).length();
477 if (nextPointDistance <= 0.0) {
481 else if (nextPointDistance <= dragVecLength) {
482 t = nextPointDistance / dragVecLength;
486 m_d->accumDistance.rx() += dragVecLength;
502 qreal x =
m_d->accumDistance.x();
503 qreal y =
m_d->accumDistance.y();
505 qreal gamma =
pow2(x * a_rev) +
pow2(y * b_rev) - 1;
515 static const qreal
eps = 2e-3;
517 qreal currentRotation =
m_d->spacing.rotation();
518 if (
m_d->spacing.coordinateSystemFlipped()) {
519 currentRotation = 2 *
M_PI - currentRotation;
522 QPointF diff = end - start;
524 if (currentRotation >
eps) {
528 rot.rotateRadians(currentRotation);
529 diff = rot.map(diff);
532 qreal dx = qAbs(diff.x());
533 qreal dy = qAbs(diff.y());
535 qreal alpha =
pow2(dx * a_rev) +
pow2(dy * b_rev);
536 qreal beta = x * dx * a_rev * a_rev + y * dy * b_rev * b_rev;
537 qreal D_4 =
pow2(beta) - alpha * gamma;
542 qreal k = (-beta + qSqrt(D_4)) / alpha;
544 if (k >= 0.0 && k <= 1.0) {
551 warnKrita <<
"BUG: No solution for elliptical spacing equation has been found. This shouldn't have happened.";
561 if (!(startTime < endTime)) {
567 qreal nextPointInterval = timedSpacingInterval -
m_d->accumTime;
573 if (nextPointInterval <= 0.0) {
577 else if (nextPointInterval <= endTime - startTime) {
579 t = nextPointInterval / (endTime - startTime);
582 m_d->accumTime += endTime - startTime;
591 m_d->accumDistance = QPointF();
592 m_d->accumTime = 0.0;
597 return m_d->lockedDrawingAngleOptional;
604 if (
m_d->lockedDrawingAngleOptional) {
605 newAngle = *
m_d->lockedDrawingAngleOptional;
608 m_d->lockedDrawingAngleOptional = newAngle;
614 return m_d->totalDistance;
qreal distance(const QPointF &p1, const QPointF &p2)
#define KIS_ASSERT_RECOVER_NOOP(cond)
Point abs(const Point &pt)
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)
qreal spacingUpdateInterval
KisDistanceInitInfo & operator=(const KisDistanceInitInfo &rhs)
void toXML(QDomDocument &doc, QDomElement &elt) const
qreal timingUpdateInterval
bool operator==(const KisDistanceInitInfo &other) const
KisDistanceInformation makeDistInfo()
static KisDistanceInitInfo fromXML(const QDomElement &elt)