Krita Source Code Documentation
Loading...
Searching...
No Matches
GridIterationTools Namespace Reference

Namespaces

namespace  Private
 

Classes

struct  AlwaysCompletePolygonPolicy
 
struct  CellOp
 
struct  IncompletePolygonPolicy
 
struct  PaintDevicePolygonOp
 
struct  QImagePolygonOp
 
struct  RegularGridIndexesOp
 

Functions

void adjustAlignedPolygon (QPolygonF &polygon)
 
int calcGridDimension (int start, int end, const int pixelPrecision)
 
QSize calcGridSize (const QRect &srcBounds, const int pixelPrecision)
 
QVector< int > calculateCellIndexes (int col, int row, const QSize &gridSize)
 
QRect calculateCorrectSubGrid (QRect originalBoundsForGrid, int pixelPrecision, QRectF currentBounds, QSize gridSize)
 
template<class IndexesOp >
bool canProcessRectsInRandomOrder (IndexesOp &indexesOp, const QVector< QPointF > &transformedPoints, QRect subgrid)
 
template<class IndexesOp >
bool canProcessRectsInRandomOrder (IndexesOp &indexesOp, const QVector< QPointF > &transformedPoints, QSize grid)
 
QList< QRectF > cutOutSubgridFromBounds (QRect subGrid, QRect srcBounds, const QSize &gridSize, const QVector< QPointF > &originalPoints)
 
template<class IndexesOp >
bool getOrthogonalPointApproximation (const QPoint &cellPt, const QVector< QPointF > &originalPoints, const QVector< QPointF > &transformedPoints, IndexesOp indexesOp, QPointF *srcPoint, QPointF *dstPoint)
 
template<template< class PolygonOp, class IndexesOp > class IncompletePolygonPolicy, class PolygonOp , class IndexesOp >
void iterateThroughGrid (PolygonOp &polygonOp, IndexesOp &indexesOp, const QSize &gridSize, const QVector< QPointF > &originalPoints, const QVector< QPointF > &transformedPoints)
 
template<template< class PolygonOp, class IndexesOp > class IncompletePolygonPolicy, class PolygonOp , class IndexesOp >
void iterateThroughGrid (PolygonOp &polygonOp, IndexesOp &indexesOp, const QSize &gridSize, const QVector< QPointF > &originalPoints, const QVector< QPointF > &transformedPoints, const QRect subGrid)
 
int pointToIndex (const QPoint &cellPt, const QSize &gridSize)
 
template<class ProcessCell >
void processGrid (ProcessCell &cellOp, const QRect &srcBounds, const int pixelPrecision)
 
template<class ProcessPolygon , class ForwardTransform >
void processGrid (ProcessPolygon &polygonOp, ForwardTransform &transformOp, const QRect &srcBounds, const int pixelPrecision)
 

Function Documentation

◆ adjustAlignedPolygon()

void GridIterationTools::adjustAlignedPolygon ( QPolygonF & polygon)
inline

There is a weird problem in fetching correct bounds of the polygon. If the rightmost (bottommost) point of the polygon is integral, then QRectF() will end exactly on it, but when converting into QRect the last point will not be taken into account. It happens due to the difference between center-point/topleft-point point representation. In many cases the latter is expected, but we don't work with it in Qt/Krita.

Definition at line 849 of file kis_grid_interpolation_tools.h.

850{
851 static const qreal eps = 1e-5;
852 static const QPointF p1(eps, 0.0);
853 static const QPointF p2(eps, eps);
854 static const QPointF p3(0.0, eps);
855
856 polygon[1] += p1;
857 polygon[2] += p2;
858 polygon[3] += p3;
859}
QPointF p2
QPointF p3
QPointF p1
const qreal eps

References eps, p1, p2, and p3.

◆ calcGridDimension()

int GridIterationTools::calcGridDimension ( int start,
int end,
const int pixelPrecision )
inline

Definition at line 33 of file kis_grid_interpolation_tools.h.

34{
35 const int alignmentMask = ~(pixelPrecision - 1);
36
37 int alignedStart = (start + pixelPrecision - 1) & alignmentMask;
38 int alignedEnd = end & alignmentMask;
39
40 int size = 0;
41
42 if (alignedEnd > alignedStart) {
43 size = (alignedEnd - alignedStart) / pixelPrecision + 1;
44 size += alignedStart != start;
45 size += alignedEnd != end;
46 } else {
47 size = 2 + (end - start >= pixelPrecision);
48 }
49
50 return size;
51}
int size(const Forest< T > &forest)
Definition KisForest.h:1232

◆ calcGridSize()

QSize GridIterationTools::calcGridSize ( const QRect & srcBounds,
const int pixelPrecision )
inline

Definition at line 53 of file kis_grid_interpolation_tools.h.

53 {
54 return QSize(calcGridDimension(srcBounds.x(), srcBounds.right(), pixelPrecision),
55 calcGridDimension(srcBounds.y(), srcBounds.bottom(), pixelPrecision));
56}
int calcGridDimension(int start, int end, const int pixelPrecision)

References calcGridDimension().

◆ calculateCellIndexes()

QVector< int > GridIterationTools::calculateCellIndexes ( int col,
int row,
const QSize & gridSize )
inline

A--—B The polygons will be in the following order: | | | | polygon << A << B << D << C; C--—D

Definition at line 511 of file kis_grid_interpolation_tools.h.

512{
513 const int tl = col + row * gridSize.width();
514 const int tr = tl + 1;
515 const int bl = tl + gridSize.width();
516 const int br = bl + 1;
517
518 QVector<int> cellIndexes;
519 cellIndexes << tl;
520 cellIndexes << tr;
521 cellIndexes << br;
522 cellIndexes << bl;
523
524 return cellIndexes;
525}

◆ calculateCorrectSubGrid()

QRect GridIterationTools::calculateCorrectSubGrid ( QRect originalBoundsForGrid,
int pixelPrecision,
QRectF currentBounds,
QSize gridSize )
inline

Definition at line 553 of file kis_grid_interpolation_tools.h.

553 {
554
555 if (!QRectF(originalBoundsForGrid).intersects(currentBounds)) {
556 return QRect();
557 }
558
559 QPoint offsetB = originalBoundsForGrid.topLeft();
560
561 QPointF startPointB = currentBounds.topLeft() - offsetB;
562 QPoint startPointG = QPoint(startPointB.x()/pixelPrecision, startPointB.y()/pixelPrecision);
563 startPointG = QPoint(kisBoundFast(0, startPointG.x(), gridSize.width()), kisBoundFast(0, startPointG.y(), gridSize.height()));
564
565 QPointF endPointB = currentBounds.bottomRight() + QPoint(1, 1) - offsetB; // *true* bottomRight
566 QPoint endPointG = QPoint(std::ceil(endPointB.x()/pixelPrecision), std::ceil(endPointB.y()/pixelPrecision));
567 QPoint endPointPotential = endPointG;
568
569 QPoint trueEndPoint = QPoint(kisBoundFast(0, endPointPotential.x(), gridSize.width()), kisBoundFast(0, endPointPotential.y(), gridSize.height()));
570
571 QPoint size = trueEndPoint - startPointG;
572
573 return QRect(startPointG, QSize(size.x(), size.y()));
574}
constexpr const T & kisBoundFast(const T &min, const T &val, const T &max)
Definition kis_global.h:37

References kisBoundFast().

◆ canProcessRectsInRandomOrder() [1/2]

template<class IndexesOp >
bool GridIterationTools::canProcessRectsInRandomOrder ( IndexesOp & indexesOp,
const QVector< QPointF > & transformedPoints,
QRect subgrid )

Definition at line 867 of file kis_grid_interpolation_tools.h.

867 {
868 QVector<int> polygonPoints(4);
869 QPoint startPoint = subgrid.topLeft();
870 QPoint endPoint = subgrid.bottomRight();
871
872
873 int polygonsChecked = 0;
874
875 for (int row = startPoint.y(); row < endPoint.y(); row++) {
876 for (int col = startPoint.x(); col < endPoint.x(); col++) {
877 int numExistingPoints = 0;
878
879 polygonPoints = indexesOp.calculateMappedIndexes(col, row, &numExistingPoints);
880
881 QPolygonF dstPolygon;
882
883 for (int i = 0; i < polygonPoints.count(); i++) {
884 const int index = polygonPoints[i];
885 dstPolygon << transformedPoints[index];
886 }
887
888
889 adjustAlignedPolygon(dstPolygon);
890
891
892 if (!KisAlgebra2D::isPolygonTrulyConvex(dstPolygon)) {
893 return false;
894 }
895
896 }
897 }
898 return true;
899}
bool isPolygonTrulyConvex(const QVector< T > &polygon)

References adjustAlignedPolygon(), and KisAlgebra2D::isPolygonTrulyConvex().

◆ canProcessRectsInRandomOrder() [2/2]

template<class IndexesOp >
bool GridIterationTools::canProcessRectsInRandomOrder ( IndexesOp & indexesOp,
const QVector< QPointF > & transformedPoints,
QSize grid )

Definition at line 862 of file kis_grid_interpolation_tools.h.

862 {
863 return canProcessRectsInRandomOrder(indexesOp, transformedPoints, QRect(QPoint(0, 0), grid));
864}
bool canProcessRectsInRandomOrder(IndexesOp &indexesOp, const QVector< QPointF > &transformedPoints, QSize grid)

References canProcessRectsInRandomOrder().

◆ cutOutSubgridFromBounds()

QList< QRectF > GridIterationTools::cutOutSubgridFromBounds ( QRect subGrid,
QRect srcBounds,
const QSize & gridSize,
const QVector< QPointF > & originalPoints )
inline

Definition at line 576 of file kis_grid_interpolation_tools.h.

576 {
577 if (subGrid.width() == 0 || subGrid.height() == 0) {
578 return QList<QRectF> {srcBounds};
579 }
580 QPoint topLeft = subGrid.topLeft();
581 QPoint bottomRight = subGrid.topLeft() + QPoint(subGrid.width() - 1, subGrid.height() - 1);
582
583 int topLeftIndex = pointToIndex(topLeft, gridSize);
584 int bottomRightIndex = pointToIndex(bottomRight, gridSize);
585
586 topLeftIndex = qMax(0, qMin(topLeftIndex, originalPoints.length() - 1));
587 bottomRightIndex = qMax(0, qMin(bottomRightIndex, originalPoints.length() - 1));
588
589 QPointF topLeftReal = originalPoints[topLeftIndex];
590 QPointF bottomRightReal = originalPoints[bottomRightIndex];
591 QRectF cutOut = QRectF(topLeftReal, bottomRightReal);
592
593 QList<QRectF> response;
594 // *-----------*
595 // | top |
596 // |-----------|
597 // | l |xxx| r |
598 // | e |xxx| i |
599 // | f |xxx| g |
600 // | t |xxx| h |
601 // | |xxx| t |
602 // |-----------|
603 // | bottom |
604 // *-----------*
605
606
607 QRectF top = QRectF(srcBounds.topLeft(), QPointF(srcBounds.right() + 1, topLeftReal.y()));
608 QRectF bottom = QRectF(QPointF(srcBounds.left(), bottomRightReal.y()), srcBounds.bottomRight() + QPointF(1, 1));
609 QRectF left = QRectF(QPointF(srcBounds.left(), cutOut.top()), QPointF(cutOut.left(), cutOut.bottom()));
610 QRectF right = QRectF(QPointF(cutOut.right(), cutOut.top()), QPointF(srcBounds.right() + 1, cutOut.bottom()));
611 QList<QRectF> rects = {top, left, right, bottom};
612 for (int i = 0; i < rects.length(); i++) {
613 if (!rects[i].isEmpty()) {
614 response << rects[i];
615 }
616 }
617 return response;
618
619}
int pointToIndex(const QPoint &cellPt, const QSize &gridSize)

References pointToIndex().

◆ getOrthogonalPointApproximation()

template<class IndexesOp >
bool GridIterationTools::getOrthogonalPointApproximation ( const QPoint & cellPt,
const QVector< QPointF > & originalPoints,
const QVector< QPointF > & transformedPoints,
IndexesOp indexesOp,
QPointF * srcPoint,
QPointF * dstPoint )

Definition at line 625 of file kis_grid_interpolation_tools.h.

631{
632 QVector<Private::PointExtension> extensionPoints;
634
635 // left
636 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(-1, 0))) >= 0 &&
637 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(-2, 0))) >= 0) {
638
639 extensionPoints << ext;
640 }
641 // top
642 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(0, -1))) >= 0 &&
643 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(0, -2))) >= 0) {
644
645 extensionPoints << ext;
646 }
647 // right
648 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(1, 0))) >= 0 &&
649 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(2, 0))) >= 0) {
650
651 extensionPoints << ext;
652 }
653 // bottom
654 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(0, 1))) >= 0 &&
655 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(0, 2))) >= 0) {
656
657 extensionPoints << ext;
658 }
659
660 if (extensionPoints.isEmpty()) {
661 // top-left
662 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(-1, -1))) >= 0 &&
663 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(-2, -2))) >= 0) {
664
665 extensionPoints << ext;
666 }
667 // top-right
668 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(1, -1))) >= 0 &&
669 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(2, -2))) >= 0) {
670
671 extensionPoints << ext;
672 }
673 // bottom-right
674 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(1, 1))) >= 0 &&
675 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(2, 2))) >= 0) {
676
677 extensionPoints << ext;
678 }
679 // bottom-left
680 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(-1, 1))) >= 0 &&
681 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(-2, 2))) >= 0) {
682
683 extensionPoints << ext;
684 }
685 }
686
687 if (extensionPoints.isEmpty()) {
688 return false;
689 }
690
691 int numResultPoints = 0;
692 *srcPoint = indexesOp.getSrcPointForce(cellPt);
693 *dstPoint = QPointF();
694
695 Q_FOREACH (const Private::PointExtension &ext, extensionPoints) {
696 QPointF near = transformedPoints[ext.near];
697 QPointF far = transformedPoints[ext.far];
698
699 QPointF nearSrc = originalPoints[ext.near];
700 QPointF farSrc = originalPoints[ext.far];
701
702 QPointF base1 = nearSrc - farSrc;
703 QPointF base2 = near - far;
704
705 QPointF pt = near +
706 KisAlgebra2D::transformAsBase(*srcPoint - nearSrc, base1, base2);
707
708 *dstPoint += pt;
709 numResultPoints++;
710 }
711
712 *dstPoint /= numResultPoints;
713
714 return true;
715}
QPointF dstPoint
QPointF transformAsBase(const QPointF &pt, const QPointF &base1, const QPointF &base2)

References dstPoint, GridIterationTools::Private::PointExtension::far, GridIterationTools::Private::PointExtension::near, and KisAlgebra2D::transformAsBase().

◆ iterateThroughGrid() [1/2]

template<template< class PolygonOp, class IndexesOp > class IncompletePolygonPolicy, class PolygonOp , class IndexesOp >
void GridIterationTools::iterateThroughGrid ( PolygonOp & polygonOp,
IndexesOp & indexesOp,
const QSize & gridSize,
const QVector< QPointF > & originalPoints,
const QVector< QPointF > & transformedPoints )

Definition at line 906 of file kis_grid_interpolation_tools.h.

911{
912 iterateThroughGrid<IncompletePolygonPolicy, PolygonOp, IndexesOp>(polygonOp, indexesOp, gridSize, originalPoints, transformedPoints, QRect(QPoint(0, 0), gridSize));
913}

◆ iterateThroughGrid() [2/2]

template<template< class PolygonOp, class IndexesOp > class IncompletePolygonPolicy, class PolygonOp , class IndexesOp >
void GridIterationTools::iterateThroughGrid ( PolygonOp & polygonOp,
IndexesOp & indexesOp,
const QSize & gridSize,
const QVector< QPointF > & originalPoints,
const QVector< QPointF > & transformedPoints,
const QRect subGrid )

Definition at line 918 of file kis_grid_interpolation_tools.h.

924{
925 QVector<int> polygonPoints(4);
926 QPoint startPoint = subGrid.topLeft();
927 QPoint endPoint = subGrid.bottomRight(); // it's weird but bottomRight on QRect point does give us one unit of margin on both x and y
928 // when start is on (0, 0), and size is (500, 500), bottomRight is on (499, 499)
929 // but remember that it also only needs a top left corner of the polygon
930
931 KIS_SAFE_ASSERT_RECOVER(startPoint.x() >= 0 && startPoint.y() >= 0 && endPoint.x() <= gridSize.width() - 1 && endPoint.y() <= gridSize.height() - 1) {
932 startPoint = QPoint(qMax(startPoint.x(), 0), qMax(startPoint.y(), 0));
933 endPoint = QPoint(qMin(endPoint.x(), gridSize.width() - 1), qMin(startPoint.y(), gridSize.height() - 1));
934 }
935
936 for (int row = startPoint.y(); row < endPoint.y(); row++) {
937 for (int col = startPoint.x(); col < endPoint.x(); col++) {
938 int numExistingPoints = 0;
939
940 polygonPoints = indexesOp.calculateMappedIndexes(col, row, &numExistingPoints);
941
942 if (!IncompletePolygonPolicy<PolygonOp, IndexesOp>::
943 tryProcessPolygon(col, row,
944 numExistingPoints,
945 polygonOp,
946 indexesOp,
947 polygonPoints,
948 originalPoints,
949 transformedPoints)) {
950
951 QPolygonF srcPolygon;
952 QPolygonF dstPolygon;
953
954 for (int i = 0; i < 4; i++) {
955 const int index = polygonPoints[i];
956 srcPolygon << originalPoints[index];
957 dstPolygon << transformedPoints[index];
958 }
959
960 adjustAlignedPolygon(srcPolygon);
961 adjustAlignedPolygon(dstPolygon);
962
963 polygonOp(srcPolygon, dstPolygon);
964 }
965 }
966 }
967
968 polygonOp.finalize();
969}
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
void adjustAlignedPolygon(QPolygonF &polygon)

References adjustAlignedPolygon(), and KIS_SAFE_ASSERT_RECOVER.

◆ pointToIndex()

int GridIterationTools::pointToIndex ( const QPoint & cellPt,
const QSize & gridSize )
inline

Definition at line 527 of file kis_grid_interpolation_tools.h.

528{
529 return cellPt.x() +
530 cellPt.y() * gridSize.width();
531}

◆ processGrid() [1/2]

template<class ProcessCell >
void GridIterationTools::processGrid ( ProcessCell & cellOp,
const QRect & srcBounds,
const int pixelPrecision )

Definition at line 110 of file kis_grid_interpolation_tools.h.

113{
114 if (srcBounds.isEmpty()) return;
115
116 const int alignmentMask = ~(pixelPrecision - 1);
117
118 int prevRow = std::numeric_limits<int>::max();
119 int prevCol = std::numeric_limits<int>::max();
120
121 int rowIndex = 0;
122 int colIndex = 0;
123
124 for (int row = srcBounds.top(); row <= srcBounds.bottom();) {
125 for (int col = srcBounds.left(); col <= srcBounds.right();) {
126
127 cellOp.processPoint(col, row,
128 prevCol, prevRow,
129 colIndex, rowIndex);
130
131 prevCol = col;
132 col += pixelPrecision;
133 colIndex++;
134
135 if (col > srcBounds.right() &&
136 col <= srcBounds.right() + pixelPrecision - 1) {
137
138 col = srcBounds.right();
139 } else {
140 col &= alignmentMask;
141 }
142 }
143
144 cellOp.nextLine();
145 colIndex = 0;
146
147 prevRow = row;
148 row += pixelPrecision;
149 rowIndex++;
150
151 if (row > srcBounds.bottom() &&
152 row <= srcBounds.bottom() + pixelPrecision - 1) {
153
154 row = srcBounds.bottom();
155 } else {
156 row &= alignmentMask;
157 }
158 }
159}

◆ processGrid() [2/2]

template<class ProcessPolygon , class ForwardTransform >
void GridIterationTools::processGrid ( ProcessPolygon & polygonOp,
ForwardTransform & transformOp,
const QRect & srcBounds,
const int pixelPrecision )

Definition at line 162 of file kis_grid_interpolation_tools.h.

164{
165 CellOp<ProcessPolygon, ForwardTransform> cellOp(polygonOp, transformOp);
166 processGrid(cellOp, srcBounds, pixelPrecision);
167}
void processGrid(ProcessCell &cellOp, const QRect &srcBounds, const int pixelPrecision)

References processGrid().