File indexing completed on 2024-05-12 15:57:03
0001 /* 0002 * SPDX-FileCopyrightText: 2021 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "KisRectsGrid.h" 0008 #include "kis_assert.h" 0009 #include <QtCore/qmath.h> 0010 #include "kis_lod_transform_base.h" 0011 #include "kis_global.h" 0012 #include "kis_algebra_2d.h" 0013 #include <KisUsageLogger.h> 0014 0015 #include "kis_debug.h" 0016 0017 0018 KisRectsGrid::KisRectsGrid(int gridSize) 0019 : m_gridSize(gridSize) 0020 , m_logGridSize(qFloor(std::log2(gridSize))) 0021 { 0022 if (!qFuzzyCompare(std::log2(gridSize), qreal(m_logGridSize))) { 0023 KisUsageLogger::log(QString("Invalid grid configuration. Grid size: %1, log grid size: %2. Resetting to 64 and 6").arg(gridSize, m_logGridSize)); 0024 m_gridSize = 64; 0025 m_logGridSize = 6; 0026 } 0027 } 0028 0029 void KisRectsGrid::resize(const QRect &newMappedAreaSize) 0030 { 0031 KIS_SAFE_ASSERT_RECOVER_NOOP(m_mappedAreaSize.isEmpty() || newMappedAreaSize.contains(m_mappedAreaSize)); 0032 0033 QVector<quint8> newMapping(newMappedAreaSize.width() * newMappedAreaSize.height()); 0034 0035 const int xDiff = m_mappedAreaSize.x() - newMappedAreaSize.x(); 0036 const int yDiff = m_mappedAreaSize.y() - newMappedAreaSize.y(); 0037 0038 int dstRowStride = newMappedAreaSize.width(); 0039 int dstRowStart = xDiff + yDiff * dstRowStride; 0040 0041 for (int y = 0; y < m_mappedAreaSize.height(); y++) { 0042 int dstRowIndex = dstRowStart + dstRowStride * y; 0043 int srcRowIndex = m_mappedAreaSize.width() * y; 0044 0045 memcpy(&newMapping[dstRowIndex], &m_mapping[srcRowIndex], m_mappedAreaSize.width()); 0046 } 0047 0048 std::swap(newMapping, m_mapping); 0049 m_mappedAreaSize = newMappedAreaSize; 0050 } 0051 0052 QRect KisRectsGrid::alignRect(const QRect &rc) const 0053 { 0054 return KisLodTransformBase::alignedRect(rc, m_logGridSize); 0055 } 0056 0057 QVector<QRect> KisRectsGrid::addRect(const QRect &rc) 0058 { 0059 return addAlignedRect(alignRect(rc)); 0060 } 0061 0062 QVector<QRect> KisRectsGrid::addAlignedRect(const QRect &rc) 0063 { 0064 if (rc.isEmpty()) return QVector<QRect>(); 0065 0066 const QRect mappedRect = KisLodTransformBase::scaledRect(rc, m_logGridSize); 0067 0068 if (!m_mappedAreaSize.contains(mappedRect)) { 0069 QRect nextMappingSize = m_mappedAreaSize | mappedRect; 0070 nextMappingSize = KisAlgebra2D::blowRect(nextMappingSize, 0.2); 0071 resize(nextMappingSize); 0072 } 0073 0074 QVector<QRect> addedRects; 0075 0076 for (int y = mappedRect.y(); y <= mappedRect.bottom(); y++) { 0077 for (int x = mappedRect.x(); x <= mappedRect.right(); x++) { 0078 quint8 *ptr = &m_mapping[m_mappedAreaSize.width() * (y - m_mappedAreaSize.y()) + (x - m_mappedAreaSize.x())]; 0079 if (!*ptr) { 0080 *ptr = 1; 0081 addedRects.append(KisLodTransformBase::upscaledRect(QRect(x, y, 1, 1), m_logGridSize)); 0082 } 0083 } 0084 } 0085 return addedRects; 0086 } 0087 0088 inline QRect KisRectsGrid::shrinkRectToAlignedGrid(const QRect &srcRect, int lod) 0089 { 0090 qint32 alignment = 1 << lod; 0091 0092 qint32 x1, y1, x2, y2; 0093 srcRect.getCoords(&x1, &y1, &x2, &y2); 0094 0095 x1--; 0096 y1--; 0097 x2++; 0098 y2++; 0099 0100 KisLodTransformBase::alignByPow2ButOneHi(x1, alignment); 0101 KisLodTransformBase::alignByPow2ButOneHi(y1, alignment); 0102 0103 KisLodTransformBase::alignByPow2Lo(x2, alignment); 0104 KisLodTransformBase::alignByPow2Lo(y2, alignment); 0105 0106 x1++; 0107 y1++; 0108 x2--; 0109 y2--; 0110 0111 QRect rect; 0112 rect.setCoords(x1, y1, x2, y2); 0113 0114 return rect; 0115 } 0116 0117 QVector<QRect> KisRectsGrid::removeRect(const QRect &rc) 0118 { 0119 const QRect alignedRect = shrinkRectToAlignedGrid(rc, m_logGridSize); 0120 return !alignedRect.isEmpty() ? removeAlignedRect(alignedRect) : QVector<QRect>(); 0121 } 0122 0123 QVector<QRect> KisRectsGrid::removeAlignedRect(const QRect &rc) 0124 { 0125 const QRect mappedRect = KisLodTransformBase::scaledRect(rc, m_logGridSize); 0126 0127 // NOTE: we never shrink the size of the grid, just keep it as big as 0128 // it ever was 0129 0130 QVector<QRect> removedRects; 0131 0132 for (int y = mappedRect.y(); y <= mappedRect.bottom(); y++) { 0133 for (int x = mappedRect.x(); x <= mappedRect.right(); x++) { 0134 quint8 *ptr = &m_mapping[m_mappedAreaSize.width() * (y - m_mappedAreaSize.y()) + (x - m_mappedAreaSize.x())]; 0135 if (*ptr) { 0136 *ptr = 0; 0137 removedRects.append(KisLodTransformBase::upscaledRect(QRect(x, y, 1, 1), m_logGridSize)); 0138 } 0139 } 0140 } 0141 return removedRects; 0142 } 0143 0144 bool KisRectsGrid::contains(const QRect &rc) const 0145 { 0146 const QRect mappedRect = KisLodTransformBase::scaledRect(alignRect(rc), m_logGridSize); 0147 0148 if (!m_mappedAreaSize.contains(mappedRect)) return false; 0149 0150 for (int y = mappedRect.y(); y <= mappedRect.bottom(); y++) { 0151 for (int x = mappedRect.x(); x <= mappedRect.right(); x++) { 0152 const quint8 *ptr = &m_mapping[m_mappedAreaSize.width() * (y - m_mappedAreaSize.y()) + (x - m_mappedAreaSize.x())]; 0153 if (!*ptr) return false; 0154 } 0155 } 0156 0157 return true; 0158 } 0159 0160 QRect KisRectsGrid::boundingRect() const { 0161 QRect gridBounds; 0162 0163 for (int y = m_mappedAreaSize.y(); y <= m_mappedAreaSize.bottom(); y++) { 0164 for (int x = m_mappedAreaSize.x(); x <= m_mappedAreaSize.right(); x++) { 0165 gridBounds |= QRect(x, y, 1, 1); 0166 } 0167 } 0168 0169 return KisLodTransformBase::upscaledRect(gridBounds, m_logGridSize); 0170 }