14#include <klocalizedstring.h>
36 double xscale,
double yscale,
37 double xshear,
double yshear,
39 qreal xtranslate, qreal ytranslate,
66 return SC *
S *
R * T;
72 QPainterPath outlineCache = pixelSelection->
outlineCache();
86 tmp->prepareClone(dev);
93 tf = tf.rotate(rotation);
98 for (qint32 y = r.y(); y <= r.height() + r.y(); ++y) {
99 for (qint32 x = r.x(); x <= r.width() + r.x(); ++x) {
100 tf.map(x, y, &tx, &ty);
106 progressHelper.
step();
118 QRect r =
rotateWithTf(90, dev, boundRect, progressUpdater, portion);
119 dev->
moveTo(dev->
x() - 1, dev->
y());
120 return QRect(- r.top() - r.height(), r.x(), r.height(), r.width());
128 QRect r =
rotateWithTf(270, dev, boundRect, progressUpdater, portion);
129 dev->
moveTo(dev->
x(), dev->
y() - 1);
130 return QRect(r.top(), - r.x() - r.width(), r.height(), r.width());
138 QRect r =
rotateWithTf(180, dev, boundRect, progressUpdater, portion);
139 dev->
moveTo(dev->
x() - 1, dev->
y() -1);
140 return QRect(- r.x() - r.width(), - r.top() - r.height(), r.width(), r.height());
153template <
class iter>
void calcDimensions(QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines);
156(QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
161 numLines = rc.height();
165(QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
168 srcLen = rc.height();
170 numLines = rc.width();
181 boundRect.setLeft(newBounds.
start());
182 boundRect.setWidth(newBounds.
size());
188 boundRect.setTop(newBounds.
start());
189 boundRect.setHeight(newBounds.
size());
194 double floatscale,
double shear,
double dx,
198 bool clampToEdge = shear == 0.0;
200 qint32 srcStart, srcLen, firstLine, numLines;
201 calcDimensions<T>(
m_boundRect, srcStart, srcLen, firstLine, numLines);
209 for (
int i = firstLine; i < firstLine + numLines; i++) {
213 dstPos = applicator.
processLine<T>(srcPos, i, &buf, filterStrategy->
support(buf.weightsPositionScale().toFloat()));
214 dstBounds.
unite(dstPos);
216 progressHelper.
step();
242 Q_ASSERT_X(
m_xscale != 0 && m_xscale_fixedPoint != 0,
"KisTransformer::run() validation step",
"xscale == 0");
243 Q_ASSERT_X(
m_yscale != 0 && m_yscale_fixedPoint != 0,
"KisTransformer::run() validation step",
"yscale == 0");
246 if (
m_xscale == 0 ||
m_yscale == 0 || m_xscale_fixedPoint == 0 || m_yscale_fixedPoint == 0)
return false;
272 if (scalePresent || (xShearPresent && yShearPresent)) {
275 }
else if (xShearPresent) {
277 }
else if (yShearPresent) {
285 if (rotation < 0.0) {
286 rotation = -fmod(-rotation, 2 *
M_PI) + 2 *
M_PI;
288 rotation = fmod(rotation, 2 *
M_PI);
291 int rotQuadrant = int(rotation / (
M_PI / 2) + 0.5) & 3;
292 rotation -= rotQuadrant *
M_PI / 2;
306 const bool simpleTransform =
315 int progressTotalSteps = qMax(1, 2 * (!simpleTransform) + (rotQuadrant != 0));
316 int progressPortion = 100 / progressTotalSteps;
323 switch (rotQuadrant) {
340 if (simpleTransform) {
345 double center_x =
bounds.topLeft().x() +
bounds.width() / 2.0;
346 xtranslate -= 2 * center_x;
353 double center_y =
bounds.topLeft().y() +
bounds.height() / 2.0;
354 ytranslate -= 2 * center_y;
359 const int intXTranslate = qRound(xtranslate);
360 const int intYTranslate = qRound(ytranslate);
362 m_boundRect.translate(intXTranslate, intYTranslate);
366 QTransform SC = QTransform::fromScale(xscale, yscale);
367 QTransform
R;
R.rotateRadians(rotation);
368 QTransform T = QTransform::fromTranslate(xtranslate, ytranslate);
369 QTransform m = SC *
R * T;
380 qreal d = m.m12() / m.m11();
381 qreal e = m.m22() - m.m21() * m.m12() / m.m11();
382 qreal f = m.m32() - m.m31() * m.m12() / m.m11();
398 qreal a = m.m11() - m.m21() * m.m12() / m.m22();
399 qreal b = m.m21() / m.m22();
400 qreal c = m.m31() - m.m21() * m.m32() / m.m22();
414 yshear = sin(rotation);
415 xshear = -tan(rotation / 2);
416 xtranslate -= int(xshear * ytranslate);
449 if (mirrorRect.width() <= 1)
return;
477 leftStart = mirrorRect.x();
478 rightEnd = mirrorRect.x() + mirrorRect.width();
480 leftStart = mirrorRect.y();
481 rightEnd = mirrorRect.y() + mirrorRect.height();
488 const bool axisNonAligned = qFloor(axis) < axis;
490 int leftCenterPoint = qFloor(axis);
491 int leftEnd = qMin(leftCenterPoint, rightEnd);
493 int rightCenterPoint = axisNonAligned ? qCeil(axis) : qFloor(axis);
494 int rightStart = qMax(rightCenterPoint, leftStart);
496 int leftSize = qMax(0, leftEnd - leftStart);
497 int rightSize = qMax(0, rightEnd - rightStart);
499 int maxDistanceToAxis = qMax(leftCenterPoint - leftStart,
500 rightEnd - rightCenterPoint);
504 bool moveLeftToRight = leftSize > rightSize;
505 int moveAmount = qAbs(leftSize - rightSize);
506 int swapAmount = qMin(leftSize, rightSize);
509 int initialLeftCol = leftCenterPoint - maxDistanceToAxis;
510 int initialRightCol = rightCenterPoint + maxDistanceToAxis - 1;
516 const quint8 *defaultPixel = defaultPixelObject.
data();
519 QByteArray buf(pixelSize, 0);
526 rowsRemaining = mirrorRect.height();
527 row = mirrorRect.y();
529 rowsRemaining = mirrorRect.width();
530 row = mirrorRect.x();
536 const int &leftX = isHorizontal ? leftColPos : row;
537 const int &leftY = isHorizontal ? row : leftColPos;
539 const int &rightX = isHorizontal ? rightColPos : row;
540 const int &rightY = isHorizontal ? row : rightColPos;
542 while (rowsRemaining) {
543 leftColPos = initialLeftCol;
544 rightColPos = initialRightCol;
547 int rowStride = isHorizontal ? leftIt->
rowStride(leftX, leftY) : pixelSize;
549 if (moveLeftToRight) {
550 for (
int i = 0; i < moveAmount; i++) {
551 leftIt->
moveTo(leftX, leftY);
552 rightIt->
moveTo(rightX, rightY);
554 quint8 *leftPtr = leftIt->
rawData();
555 quint8 *rightPtr = rightIt->
rawData();
557 for (
int j = 0; j < rows; j++) {
559 memcpy(rightPtr, leftPtr, pixelSize);
560 memcpy(leftPtr, defaultPixel, pixelSize);
562 leftPtr += rowStride;
563 rightPtr += rowStride;
570 for (
int i = 0; i < moveAmount; i++) {
571 leftIt->
moveTo(leftX, leftY);
572 rightIt->
moveTo(rightX, rightY);
574 quint8 *leftPtr = leftIt->
rawData();
575 quint8 *rightPtr = rightIt->
rawData();
577 for (
int j = 0; j < rows; j++) {
579 memcpy(leftPtr, rightPtr, pixelSize);
580 memcpy(rightPtr, defaultPixel, pixelSize);
582 leftPtr += rowStride;
583 rightPtr += rowStride;
591 for (
int i = 0; i < swapAmount; i++) {
592 leftIt->
moveTo(leftX, leftY);
593 rightIt->
moveTo(rightX, rightY);
595 quint8 *leftPtr = leftIt->
rawData();
596 quint8 *rightPtr = rightIt->
rawData();
598 for (
int j = 0; j < rows; j++) {
600 memcpy(buf.data(), leftPtr, pixelSize);
601 memcpy(leftPtr, rightPtr, pixelSize);
602 memcpy(rightPtr, buf.data(), pixelSize);
604 leftPtr += rowStride;
605 rightPtr += rowStride;
612 rowsRemaining -= rows;
641 mirror_impl(dev, axis, orientation == Qt::Horizontal);
646 Q_ASSERT(wrapRect == wrapRect.normalized());
649 int sx = wrapRect.x();
650 int sy = wrapRect.y();
652 int width = wrapRect.width();
653 int height = wrapRect.height();
656 int offsetX = offsetPosition.x();
657 int offsetY = offsetPosition.y();
669 if ((offsetX == 0) && (offsetY == 0))
682 width = qBound<int>(0, width - offsetX, width);
683 height = qBound<int>(0, height - offsetY, height);
685 if ((width != 0) && (height != 0)) {
690 srcX = wrapRect.width() - offsetX;
691 srcY = wrapRect.height() - offsetY;
693 destX = (srcX + offsetX) % wrapRect.width();
694 destY = (srcY + offsetY) % wrapRect.height();
696 if (offsetX != 0 && offsetY != 0) {
701 KisPainter::copyAreaOptimized(QPoint(destX + sx, (destY + offsetY) + sy), device, offsetDevice, QRect(srcX + sx, 0 + sy, offsetX, wrapRect.height() - offsetY));
705 KisPainter::copyAreaOptimized(QPoint((destX + offsetX) + sx, destY + sy), device, offsetDevice, QRect(0 + sx, srcY + sy, wrapRect.width() - offsetX, offsetY));
709 QRect resultRect(sx, sy, wrapRect.width(), wrapRect.height());
float value(const T *src, size_t ch)
Eigen::Matrix< double, 4, 2 > S
Eigen::Matrix< double, 4, 2 > R
virtual quint8 * rawData()=0
virtual qreal support(qreal weightsPositionScale)
void unite(const LinePos &rhs)
LinePos processLine(LinePos srcLine, int line, KisFilterWeightsBuffer *buffer, qreal filterSupport)
quint32 pixelSize() const
QRect exactBounds() const
void purgeDefaultPixels()
const KoColorSpace * colorSpace() const
KoColor defaultPixel() const
void moveTo(qint32 x, qint32 y)
void makeCloneFrom(KisPaintDeviceSP src, const QRect &rect)
KisRandomAccessorSP createRandomAccessorNG()
static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect)
virtual qint32 rowStride(qint32 x, qint32 y) const =0
virtual qint32 numContiguousRows(qint32 y) const =0
virtual void moveTo(qint32 x, qint32 y)=0
virtual qint32 numContiguousColumns(qint32 x) const =0
static bool qFuzzyCompare(half p1, half p2)
#define KIS_ASSERT_RECOVER_RETURN(cond)
QPainterPath outlineCache
void setOutlineCache(const QPainterPath &cache)