File indexing completed on 2024-04-28 03:42:27

0001 /*
0002     SPDX-FileCopyrightText: 2023 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "imagemask.h"
0008 #include "cmath"
0009 
0010 ImageMask::ImageMask(const uint16_t width, const uint16_t height)
0011 {
0012     m_width  = width;
0013     m_height = height;
0014 }
0015 
0016 void ImageMask::setImageGeometry(const uint16_t width, const uint16_t height)
0017 {
0018     m_width  = width;
0019     m_height = height;
0020     refresh();
0021 }
0022 
0023 bool ImageMask::isVisible(uint16_t posX, uint16_t posY)
0024 {
0025     return posX >= 0 && posX < m_width && posY >= 0 && posY < m_height;
0026 }
0027 
0028 uint16_t ImageMask::width() const
0029 {
0030     return m_width;
0031 }
0032 
0033 uint16_t ImageMask::height() const
0034 {
0035     return m_height;
0036 }
0037 
0038 ImageRingMask::ImageRingMask(const float innerRadius, const float outerRadius, const uint16_t width,
0039                              const uint16_t height) : ImageMask(width, height)
0040 {
0041     m_innerRadius = innerRadius;
0042     m_outerRadius = outerRadius;
0043 }
0044 
0045 void ImageRingMask::refresh()
0046 {
0047     long const sqDiagonal = (long) (m_width * m_width / 4 + m_height * m_height / 4);
0048     m_InnerRadiusSquare = std::lround(sqDiagonal * innerRadius() * innerRadius());
0049     m_OuterRadiusSquare = std::lround(sqDiagonal * outerRadius() * outerRadius());
0050 }
0051 
0052 bool ImageRingMask::isVisible(uint16_t posX, uint16_t posY)
0053 {
0054     bool result = ImageMask::isVisible(posX, posY);
0055     // outside of the image?
0056     if (result == false)
0057         return false;
0058 
0059     double const x = posX - m_width / 2;
0060     double const y = posY - m_height / 2;
0061 
0062     double const sqRadius = x * x + y * y;
0063 
0064     return sqRadius >= m_InnerRadiusSquare && sqRadius < m_OuterRadiusSquare;
0065 }
0066 
0067 float ImageRingMask::innerRadius() const
0068 {
0069     return m_innerRadius;
0070 }
0071 
0072 void ImageRingMask::setInnerRadius(float newInnerRadius)
0073 {
0074     m_innerRadius = newInnerRadius;
0075     refresh();
0076 }
0077 
0078 float ImageRingMask::outerRadius() const
0079 {
0080     return m_outerRadius;
0081 }
0082 
0083 void ImageRingMask::setOuterRadius(float newOuterRadius)
0084 {
0085     m_outerRadius = newOuterRadius;
0086     refresh();
0087 }
0088 
0089 ImageMosaicMask::ImageMosaicMask(const uint16_t tileWidth, const uint16_t space, const uint16_t width,
0090                                  const uint16_t height) : ImageMask(width, height)
0091 {
0092     m_tileWidth = tileWidth;
0093     m_space = space;
0094     // initialize the tiles
0095     for (int i = 0; i < 9; i++)
0096         m_tiles.append(QRect());
0097 }
0098 
0099 bool ImageMosaicMask::isVisible(uint16_t posX, uint16_t posY)
0100 {
0101     for (auto it = m_tiles.begin(); it != m_tiles.end(); it++)
0102         if (it->contains(posX, posY))
0103             return true;
0104     // no matching tile found
0105     return false;
0106 }
0107 
0108 QPointF ImageMosaicMask::translate(QPointF original)
0109 {
0110     int pos = 0;
0111     const auto tileWidth = std::lround(m_width * m_tileWidth / 100);
0112     const float spacex = (m_width - 3 * tileWidth - 2 * m_space) / 2;
0113     const float spacey = (m_height - 3 * tileWidth - 2 * m_space) / 2;
0114     for (QRect tile : m_tiles)
0115     {
0116         // matrix tile position
0117         int posx = pos % 3;
0118         int posy = pos++ / 3;
0119         if (tile.contains(original.x(), original.y()))
0120             return QPointF(original.x() - posx * spacex, original.y() - posy * spacey);
0121     }
0122     // this should not happen for filtered positions
0123     return QPointF(-1, -1);
0124 }
0125 
0126 const QVector<QRect> ImageMosaicMask::tiles()
0127 {
0128     return m_tiles;
0129 }
0130 
0131 float ImageMosaicMask::tileWidth() const
0132 {
0133     return m_tileWidth;
0134 }
0135 
0136 void ImageMosaicMask::setTileWidth(float newTileWidth)
0137 {
0138     m_tileWidth = newTileWidth;
0139     refresh();
0140 }
0141 
0142 uint16_t ImageMosaicMask::space() const
0143 {
0144     return m_space;
0145 }
0146 
0147 void ImageMosaicMask::setSpace(uint16_t newSpace)
0148 {
0149     m_space = newSpace;
0150     refresh();
0151 }
0152 
0153 void ImageMosaicMask::refresh()
0154 {
0155     m_tiles.clear();
0156     uint16_t tileWidth = std::lround(m_width * m_tileWidth / 100);
0157     if (m_width > 0 && m_height > 0)
0158     {
0159         const auto x1 = std::lround((m_width - tileWidth) / 2);
0160         const auto x2 = m_width - tileWidth - 1;
0161         const auto y1 = std::lround((m_height - tileWidth) / 2);
0162         const auto y2 = m_height - tileWidth - 1;
0163 
0164         m_tiles.append(QRect(0, 0, tileWidth, tileWidth));
0165         m_tiles.append(QRect(x1, 0, tileWidth, tileWidth));
0166         m_tiles.append(QRect(x2, 0, tileWidth, tileWidth));
0167         m_tiles.append(QRect(0, y1, tileWidth, tileWidth));
0168         m_tiles.append(QRect(x1, y1, tileWidth, tileWidth));
0169         m_tiles.append(QRect(x2, y1, tileWidth, tileWidth));
0170         m_tiles.append(QRect(0, y2, tileWidth, tileWidth));
0171         m_tiles.append(QRect(x1, y2, tileWidth, tileWidth));
0172         m_tiles.append(QRect(x2, y2, tileWidth, tileWidth));
0173     }
0174 }