Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_transform_worker.cc File Reference
#include "kis_transform_worker.h"
#include <qmath.h>
#include <klocalizedstring.h>
#include <QTransform>
#include <KoColorSpace.h>
#include <KoCompositeOpRegistry.h>
#include <KoColor.h>
#include "kis_paint_device.h"
#include "kis_debug.h"
#include "kis_selection.h"
#include "kis_iterator_ng.h"
#include "kis_random_accessor_ng.h"
#include "kis_filter_strategy.h"
#include "kis_painter.h"
#include "kis_filter_weights_applicator.h"
#include "kis_progress_update_helper.h"
#include "kis_pixel_selection.h"
#include "kis_image.h"

Go to the source code of this file.

Functions

template<class iter >
void calcDimensions (QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
 
template<>
void calcDimensions< KisHLineIteratorSP > (QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
 
template<>
void calcDimensions< KisVLineIteratorSP > (QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
 
void mirror_impl (KisPaintDeviceSP dev, qreal axis, bool isHorizontal)
 
QRect rotateWithTf (int rotation, KisPaintDeviceSP dev, QRect boundRect, KoUpdaterPtr progressUpdater, int portion)
 
template<typename T >
void swapValues (T *a, T *b)
 
template<class iter >
void updateBounds (QRect &boundRect, const KisFilterWeightsApplicator::LinePos &newBounds)
 
template<>
void updateBounds< KisHLineIteratorSP > (QRect &boundRect, const KisFilterWeightsApplicator::LinePos &newBounds)
 
template<>
void updateBounds< KisVLineIteratorSP > (QRect &boundRect, const KisFilterWeightsApplicator::LinePos &newBounds)
 

Function Documentation

◆ calcDimensions()

template<class iter >
void calcDimensions ( QRect rc,
qint32 & srcStart,
qint32 & srcLen,
qint32 & firstLine,
qint32 & numLines )

◆ calcDimensions< KisHLineIteratorSP >()

template<>
void calcDimensions< KisHLineIteratorSP > ( QRect rc,
qint32 & srcStart,
qint32 & srcLen,
qint32 & firstLine,
qint32 & numLines )

Definition at line 155 of file kis_transform_worker.cc.

157{
158 srcStart = rc.x();
159 srcLen = rc.width();
160 firstLine = rc.y();
161 numLines = rc.height();
162}

◆ calcDimensions< KisVLineIteratorSP >()

template<>
void calcDimensions< KisVLineIteratorSP > ( QRect rc,
qint32 & srcStart,
qint32 & srcLen,
qint32 & firstLine,
qint32 & numLines )

Definition at line 164 of file kis_transform_worker.cc.

166{
167 srcStart = rc.y();
168 srcLen = rc.height();
169 firstLine = rc.x();
170 numLines = rc.width();
171
172}

◆ mirror_impl()

void mirror_impl ( KisPaintDeviceSP dev,
qreal axis,
bool isHorizontal )

We split the total mirror rect into two halves, which lay to the 'left' and 'right' from the axis. Effectively, these halves should be swapped, but there is a bit of optimization: some parts of these portions overlap and some don't. So former ones should be really swapped, but the latter ones just moved to the other side.

So the algorithm consists of two stages:

1) Move the non-overlapping portion of the mirror rect to the other side of the axis. The move may be either left-to-right or right-to-left.

2) Use slow 'swap' operation for the remaining portion of the mirrorRect.

NOTE: the algorithm works with (column, row) coordinates which are mapped to the real (x, y) depending on the value of 'isHorizontal' parameter.

If the axis is not aligned, that is crosses some pixel cell, we should just skip this column and not process it. Actually, how can we mirror the central single-pixel column?

Definition at line 444 of file kis_transform_worker.cc.

445{
446 KIS_ASSERT_RECOVER_RETURN(qFloor(axis) == axis || (axis - qFloor(axis) == 0.5));
447
448 QRect mirrorRect = dev->exactBounds();
449 if (mirrorRect.width() <= 1) return;
450
473 int leftStart;
474 int rightEnd;
475
476 if (isHorizontal) {
477 leftStart = mirrorRect.x();
478 rightEnd = mirrorRect.x() + mirrorRect.width();
479 } else {
480 leftStart = mirrorRect.y();
481 rightEnd = mirrorRect.y() + mirrorRect.height();
482 }
483
488 const bool axisNonAligned = qFloor(axis) < axis;
489
490 int leftCenterPoint = qFloor(axis);
491 int leftEnd = qMin(leftCenterPoint, rightEnd);
492
493 int rightCenterPoint = axisNonAligned ? qCeil(axis) : qFloor(axis);
494 int rightStart = qMax(rightCenterPoint, leftStart);
495
496 int leftSize = qMax(0, leftEnd - leftStart);
497 int rightSize = qMax(0, rightEnd - rightStart);
498
499 int maxDistanceToAxis = qMax(leftCenterPoint - leftStart,
500 rightEnd - rightCenterPoint);
501
502
503 // Main variables for controlling the stages of the algorithm
504 bool moveLeftToRight = leftSize > rightSize;
505 int moveAmount = qAbs(leftSize - rightSize);
506 int swapAmount = qMin(leftSize, rightSize);
507
508 // Initial position of 'left' and 'right' block iterators
509 int initialLeftCol = leftCenterPoint - maxDistanceToAxis;
510 int initialRightCol = rightCenterPoint + maxDistanceToAxis - 1;
511
512
515 const KoColor defaultPixelObject = dev->defaultPixel();
516 const quint8 *defaultPixel = defaultPixelObject.data();
517
518 const int pixelSize = dev->pixelSize();
519 QByteArray buf(pixelSize, 0);
520
521 // Map (column, row) -> (x, y)
522 int rowsRemaining;
523 int row;
524
525 if (isHorizontal) {
526 rowsRemaining = mirrorRect.height();
527 row = mirrorRect.y();
528 } else {
529 rowsRemaining = mirrorRect.width();
530 row = mirrorRect.x();
531 }
532
533 int leftColPos = 0;
534 int rightColPos = 0;
535
536 const int &leftX = isHorizontal ? leftColPos : row;
537 const int &leftY = isHorizontal ? row : leftColPos;
538
539 const int &rightX = isHorizontal ? rightColPos : row;
540 const int &rightY = isHorizontal ? row : rightColPos;
541
542 while (rowsRemaining) {
543 leftColPos = initialLeftCol;
544 rightColPos = initialRightCol;
545
546 int rows = qMin(rowsRemaining, isHorizontal ? leftIt->numContiguousRows(leftY) : leftIt->numContiguousColumns(leftX));
547 int rowStride = isHorizontal ? leftIt->rowStride(leftX, leftY) : pixelSize;
548
549 if (moveLeftToRight) {
550 for (int i = 0; i < moveAmount; i++) {
551 leftIt->moveTo(leftX, leftY);
552 rightIt->moveTo(rightX, rightY);
553
554 quint8 *leftPtr = leftIt->rawData();
555 quint8 *rightPtr = rightIt->rawData();
556
557 for (int j = 0; j < rows; j++) {
558 // left-to-right move
559 memcpy(rightPtr, leftPtr, pixelSize);
560 memcpy(leftPtr, defaultPixel, pixelSize);
561
562 leftPtr += rowStride;
563 rightPtr += rowStride;
564 }
565
566 leftColPos++;
567 rightColPos--;
568 }
569 } else {
570 for (int i = 0; i < moveAmount; i++) {
571 leftIt->moveTo(leftX, leftY);
572 rightIt->moveTo(rightX, rightY);
573
574 quint8 *leftPtr = leftIt->rawData();
575 quint8 *rightPtr = rightIt->rawData();
576
577 for (int j = 0; j < rows; j++) {
578 // right-to-left move
579 memcpy(leftPtr, rightPtr, pixelSize);
580 memcpy(rightPtr, defaultPixel, pixelSize);
581
582 leftPtr += rowStride;
583 rightPtr += rowStride;
584 }
585
586 leftColPos++;
587 rightColPos--;
588 }
589 }
590
591 for (int i = 0; i < swapAmount; i++) {
592 leftIt->moveTo(leftX, leftY);
593 rightIt->moveTo(rightX, rightY);
594
595 quint8 *leftPtr = leftIt->rawData();
596 quint8 *rightPtr = rightIt->rawData();
597
598 for (int j = 0; j < rows; j++) {
599 // swap operation
600 memcpy(buf.data(), leftPtr, pixelSize);
601 memcpy(leftPtr, rightPtr, pixelSize);
602 memcpy(rightPtr, buf.data(), pixelSize);
603
604 leftPtr += rowStride;
605 rightPtr += rowStride;
606 }
607
608 leftColPos++;
609 rightColPos--;
610 }
611
612 rowsRemaining -= rows;
613 row += rows;
614 }
615}
virtual quint8 * rawData()=0
quint32 pixelSize() const
QRect exactBounds() const
KoColor defaultPixel() const
KisRandomAccessorSP createRandomAccessorNG()
virtual qint32 rowStride(qint32 x, qint32 y) const =0
virtual qint32 numContiguousRows(qint32 y) const =0
virtual void moveTo(qint32 x, qint32 y)=0
quint8 * data()
Definition KoColor.h:144
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
void mirrorRect(Qt::Orientation dir, const QPoint &center, QRect *rc)

References KisPaintDevice::createRandomAccessorNG(), KoColor::data(), KisPaintDevice::defaultPixel(), KisPaintDevice::exactBounds(), KIS_ASSERT_RECOVER_RETURN, KisRandomConstAccessorNG::moveTo(), KisRandomConstAccessorNG::numContiguousColumns(), KisRandomConstAccessorNG::numContiguousRows(), KisPaintDevice::pixelSize(), KisBaseAccessor::rawData(), and KisRandomConstAccessorNG::rowStride().

◆ rotateWithTf()

QRect rotateWithTf ( int rotation,
KisPaintDeviceSP dev,
QRect boundRect,
KoUpdaterPtr progressUpdater,
int portion )

Definition at line 77 of file kis_transform_worker.cc.

81{
82 qint32 pixelSize = dev->pixelSize();
83 QRect r(boundRect);
84
86 tmp->prepareClone(dev);
87
89 KisRandomAccessorSP tmpAcc = tmp->createRandomAccessorNG();
90 KisProgressUpdateHelper progressHelper(progressUpdater, portion, r.height());
91
92 QTransform tf;
93 tf = tf.rotate(rotation);
94
95 int ty = 0;
96 int tx = 0;
97
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);
101 devAcc->moveTo(x, y);
102 tmpAcc->moveTo(tx, ty);
103
104 memcpy(tmpAcc->rawData(), devAcc->rawData(), pixelSize);
105 }
106 progressHelper.step();
107 }
108
109 dev->makeCloneFrom(tmp, tmp->region().boundingRect());
110 return r;
111}
const KoColorSpace * colorSpace() const
void makeCloneFrom(KisPaintDeviceSP src, const QRect &rect)

References KisPaintDevice::colorSpace(), KisPaintDevice::createRandomAccessorNG(), KisPaintDevice::makeCloneFrom(), KisRandomConstAccessorNG::moveTo(), KisPaintDevice::pixelSize(), KisBaseAccessor::rawData(), and KisProgressUpdateHelper::step().

◆ swapValues()

template<typename T >
void swapValues ( T * a,
T * b )

Definition at line 223 of file kis_transform_worker.cc.

223 {
224 T c = *a;
225 *a = *b;
226 *b = c;
227}

◆ updateBounds()

template<class iter >
void updateBounds ( QRect & boundRect,
const KisFilterWeightsApplicator::LinePos & newBounds )

◆ updateBounds< KisHLineIteratorSP >()

template<>
void updateBounds< KisHLineIteratorSP > ( QRect & boundRect,
const KisFilterWeightsApplicator::LinePos & newBounds )

Definition at line 179 of file kis_transform_worker.cc.

180{
181 boundRect.setLeft(newBounds.start());
182 boundRect.setWidth(newBounds.size());
183}

References KisFilterWeightsApplicator::LinePos::size(), and KisFilterWeightsApplicator::LinePos::start().

◆ updateBounds< KisVLineIteratorSP >()

template<>
void updateBounds< KisVLineIteratorSP > ( QRect & boundRect,
const KisFilterWeightsApplicator::LinePos & newBounds )

Definition at line 186 of file kis_transform_worker.cc.

187{
188 boundRect.setTop(newBounds.start());
189 boundRect.setHeight(newBounds.size());
190}

References KisFilterWeightsApplicator::LinePos::size(), and KisFilterWeightsApplicator::LinePos::start().