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 843 of file kis_grid_interpolation_tools.h.

844{
845 static const qreal eps = 1e-5;
846 static const QPointF p1(eps, 0.0);
847 static const QPointF p2(eps, eps);
848 static const QPointF p3(0.0, eps);
849
850 polygon[1] += p1;
851 polygon[2] += p2;
852 polygon[3] += p3;
853}
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 505 of file kis_grid_interpolation_tools.h.

506{
507 const int tl = col + row * gridSize.width();
508 const int tr = tl + 1;
509 const int bl = tl + gridSize.width();
510 const int br = bl + 1;
511
512 QVector<int> cellIndexes;
513 cellIndexes << tl;
514 cellIndexes << tr;
515 cellIndexes << br;
516 cellIndexes << bl;
517
518 return cellIndexes;
519}

◆ calculateCorrectSubGrid()

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

Definition at line 547 of file kis_grid_interpolation_tools.h.

547 {
548
549 if (!QRectF(originalBoundsForGrid).intersects(currentBounds)) {
550 return QRect();
551 }
552
553 QPointF imaginaryGridStartF = QPoint(originalBoundsForGrid.x()/pixelPrecision, originalBoundsForGrid.y()/pixelPrecision)*pixelPrecision;
554
555 QPointF startPointB = currentBounds.topLeft() - imaginaryGridStartF;
556 QPoint startPointG = QPoint(startPointB.x()/pixelPrecision, startPointB.y()/pixelPrecision);
557 startPointG = QPoint(kisBoundFast(0, startPointG.x(), gridSize.width()), kisBoundFast(0, startPointG.y(), gridSize.height()));
558
559 QPointF endPointB = currentBounds.bottomRight() + QPoint(1, 1) - imaginaryGridStartF;
560 QPoint endPointG = QPoint(std::ceil(endPointB.x()/pixelPrecision), std::ceil(endPointB.y()/pixelPrecision)) + QPoint(1, 1);
561 QPoint endPointPotential = endPointG;
562
563 QPoint trueEndPoint = QPoint(kisBoundFast(0, endPointPotential.x(), gridSize.width()), kisBoundFast(0, endPointPotential.y(), gridSize.height()));
564
565 QPoint size = trueEndPoint - startPointG;
566
567 return QRect(startPointG, QSize(size.x(), size.y()));
568}
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 861 of file kis_grid_interpolation_tools.h.

861 {
862 QVector<int> polygonPoints(4);
863 QPoint startPoint = subgrid.topLeft();
864 QPoint endPoint = subgrid.bottomRight();
865
866 for (int row = startPoint.y(); row < endPoint.y(); row++) {
867 for (int col = startPoint.x(); col < endPoint.x(); col++) {
868 int numExistingPoints = 0;
869
870 polygonPoints = indexesOp.calculateMappedIndexes(col, row, &numExistingPoints);
871
872 QPolygonF dstPolygon;
873
874 for (int i = 0; i < polygonPoints.count(); i++) {
875 const int index = polygonPoints[i];
876 dstPolygon << transformedPoints[index];
877 }
878
879
880 adjustAlignedPolygon(dstPolygon);
881
882
883 if (!KisAlgebra2D::isPolygonTrulyConvex(dstPolygon)) {
884 return false;
885 }
886
887 }
888 }
889 return true;
890}
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 856 of file kis_grid_interpolation_tools.h.

856 {
857 return canProcessRectsInRandomOrder(indexesOp, transformedPoints, QRect(QPoint(0, 0), grid));
858}
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 570 of file kis_grid_interpolation_tools.h.

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

625{
626 QVector<Private::PointExtension> extensionPoints;
628
629 // left
630 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(-1, 0))) >= 0 &&
631 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(-2, 0))) >= 0) {
632
633 extensionPoints << ext;
634 }
635 // top
636 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(0, -1))) >= 0 &&
637 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(0, -2))) >= 0) {
638
639 extensionPoints << ext;
640 }
641 // right
642 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(1, 0))) >= 0 &&
643 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(2, 0))) >= 0) {
644
645 extensionPoints << ext;
646 }
647 // bottom
648 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(0, 1))) >= 0 &&
649 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(0, 2))) >= 0) {
650
651 extensionPoints << ext;
652 }
653
654 if (extensionPoints.isEmpty()) {
655 // top-left
656 if ((ext.near = indexesOp.tryGetValidIndex(cellPt + QPoint(-1, -1))) >= 0 &&
657 (ext.far = indexesOp.tryGetValidIndex(cellPt + QPoint(-2, -2))) >= 0) {
658
659 extensionPoints << ext;
660 }
661 // top-right
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 // bottom-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-left
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 }
680
681 if (extensionPoints.isEmpty()) {
682 return false;
683 }
684
685 int numResultPoints = 0;
686 *srcPoint = indexesOp.getSrcPointForce(cellPt);
687 *dstPoint = QPointF();
688
689 Q_FOREACH (const Private::PointExtension &ext, extensionPoints) {
690 QPointF near = transformedPoints[ext.near];
691 QPointF far = transformedPoints[ext.far];
692
693 QPointF nearSrc = originalPoints[ext.near];
694 QPointF farSrc = originalPoints[ext.far];
695
696 QPointF base1 = nearSrc - farSrc;
697 QPointF base2 = near - far;
698
699 QPointF pt = near +
700 KisAlgebra2D::transformAsBase(*srcPoint - nearSrc, base1, base2);
701
702 *dstPoint += pt;
703 numResultPoints++;
704 }
705
706 *dstPoint /= numResultPoints;
707
708 return true;
709}
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 897 of file kis_grid_interpolation_tools.h.

902{
903 iterateThroughGrid<IncompletePolygonPolicy, PolygonOp, IndexesOp>(polygonOp, indexesOp, gridSize, originalPoints, transformedPoints, QRect(QPoint(0, 0), gridSize));
904}

◆ 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 909 of file kis_grid_interpolation_tools.h.

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

522{
523 return cellPt.x() +
524 cellPt.y() * gridSize.width();
525}

◆ 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().