File indexing completed on 2024-04-28 16:30:34

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007 * This file implements classes SKGTreeMap.
0008 *
0009 * @author Stephane MANKOWSKI
0010 */
0011 #include "skgtreemap.h"
0012 
0013 #include "skgtraces.h"
0014 
0015 SKGTreeMap::SKGTreeMap(QString  iID,
0016                        double iValue,
0017                        double iX,
0018                        double iY,
0019                        double iW,
0020                        double iH)
0021     : m_id(std::move(iID)), m_value(iValue), m_x(iX), m_y(iY), m_w(iW), m_h(iH)
0022 {}
0023 
0024 SKGTreeMap::~SKGTreeMap() = default;
0025 
0026 QString SKGTreeMap::getID() const
0027 {
0028     return m_id;
0029 }
0030 
0031 double SKGTreeMap::getValue() const
0032 {
0033     return m_value;
0034 }
0035 
0036 void SKGTreeMap::setX(double iX)
0037 {
0038     m_x = iX;
0039 }
0040 
0041 double SKGTreeMap::getX() const
0042 {
0043     return m_x;
0044 }
0045 
0046 void SKGTreeMap::setY(double iY)
0047 {
0048     m_y = iY;
0049 }
0050 
0051 double SKGTreeMap::getY() const
0052 {
0053     return m_y;
0054 }
0055 
0056 void SKGTreeMap::setW(double iW)
0057 {
0058     m_w = iW;
0059 }
0060 
0061 double SKGTreeMap::getW() const
0062 {
0063     return m_w;
0064 }
0065 
0066 void SKGTreeMap::setH(double iH)
0067 {
0068     m_h = iH;
0069 }
0070 
0071 double SKGTreeMap::getH() const
0072 {
0073     return m_h;
0074 }
0075 
0076 void SKGTreeMap::addChild(const SKGTreeMap& iChildren)
0077 {
0078     m_children.append(iChildren);
0079 }
0080 
0081 QList<SKGTreeMap> SKGTreeMap::getChildren() const
0082 {
0083     return m_children;
0084 }
0085 
0086 void SKGTreeMap::computeValuesAndSort()
0087 {
0088     // Compute the value
0089     if (m_children.count() != 0) {
0090         // Compute the value
0091         double sum = 0.0;
0092         for (auto& item : m_children) {
0093             item.computeValuesAndSort();
0094             sum += item.getValue();
0095         }
0096 
0097         // Set sum on tile
0098         m_value = sum;
0099 
0100         // Sort the children by abs(value) desc
0101         std::sort(m_children.begin(), m_children.end(), [](const SKGTreeMap & a, const SKGTreeMap & b) -> bool {
0102             if (qAbs(a.getValue() - b.getValue()) < 10e-5)
0103             {
0104                 return a.getID() < b.getID();
0105             }
0106             return a.getValue() > b.getValue();
0107         });
0108     }
0109 }
0110 
0111 QMap<QString, SKGTreeMap> SKGTreeMap::getAllTilesById() const
0112 {
0113     QMap<QString, SKGTreeMap> output;
0114     output.insert(getID(), *this);
0115     for (const auto& item : qAsConst(m_children)) {
0116         output.insert(item.getID(), item);
0117         auto children = item.getAllTilesById();
0118         for (const auto& item2 : qAsConst(children)) {
0119             output.insert(item2.getID(), item2);
0120         }
0121     }
0122     return output;
0123 }
0124 
0125 void SKGTreeMap::compute()
0126 {
0127     // Prepare all the structure
0128     computeValuesAndSort();
0129 
0130     // If value = 0
0131     bool isValueZero = (getValue() < 10e-5);
0132 
0133     // Start the layout
0134     int nb = m_children.count();
0135     if (nb == 0) {
0136         // Nothing to do
0137     } else if (nb == 1) {
0138         // The child item must take the full place
0139         m_children[0].setX(getX());
0140         m_children[0].setY(getY());
0141         m_children[0].setW(getW());
0142         m_children[0].setH(getH());
0143 
0144         m_children[0].compute();
0145     } else if (nb == 2) {
0146         if (getW() >= getH()) {
0147             // Horizontal mode
0148             // Set the first
0149             m_children[0].setX(getX());
0150             m_children[0].setY(getY());
0151             m_children[0].setW(isValueZero ? 0.0 : getW()*m_children.at(0).getValue() / getValue());
0152             m_children[0].setH(getH());
0153 
0154             m_children[0].compute();
0155 
0156             // Set the second
0157             m_children[1].setX(getX() + m_children.at(0).getW());
0158             m_children[1].setY(getY());
0159             m_children[1].setW(getW() - m_children.at(0).getW());
0160             m_children[1].setH(getH());
0161 
0162             m_children[1].compute();
0163         } else {
0164             // Vertical
0165             // Set the first
0166             m_children[0].setX(getX());
0167             m_children[0].setY(getY());
0168             m_children[0].setW(getW());
0169             m_children[0].setH(isValueZero ? 0.0 : getH()*m_children.at(0).getValue() / getValue());
0170 
0171             m_children[0].compute();
0172 
0173             // Set the second
0174             m_children[1].setX(getX());
0175             m_children[1].setY(getY() + m_children.at(0).getH());
0176             m_children[1].setW(getW());
0177             m_children[1].setH(getH() - m_children.at(0).getH());
0178 
0179             m_children[1].compute();
0180         }
0181     } else {
0182         // Compute the number of element that can be aligned
0183         double sum = 0.0;
0184         int optimum = 0;
0185         double lastratio = 1000.0;
0186         double previous_gw = 0.0;
0187         double previous_gh = 0.0;
0188         for (int i = 0; i < nb; ++i) {
0189             sum += m_children.at(i).getValue();
0190             if (getW() >= getH()) {
0191                 double gw = isValueZero ? 0.0 : getW() * sum / getValue();
0192                 double ih = isValueZero ? 0.0 : m_children.at(i).getValue() * getW() * getH() / (gw * getValue());
0193                 double ratio = qMax(ih / gw, gw / ih);
0194                 if (ratio > lastratio) {
0195                     // This ratio is worst than te previous one
0196                     sum -= m_children.at(i).getValue();
0197                     optimum = i - 1;
0198                     break;
0199                 }
0200                 lastratio = ratio;
0201                 previous_gw = gw;
0202             } else {
0203                 double gh = isValueZero ? 0.0 : getH() * sum / getValue();
0204                 double iw = isValueZero ? 0.0 : m_children.at(i).getValue() * getW() * getH() / (gh * getValue());
0205                 double ratio = qMax(gh / iw, iw / gh);
0206                 if (ratio > lastratio) {
0207                     // This ratio is worst than te previous one
0208                     sum -= m_children.at(i).getValue();
0209                     optimum = i - 1;
0210                     break;
0211                 }
0212                 lastratio = ratio;
0213                 previous_gh = gh;
0214             }
0215         }
0216 
0217         // Set the layout
0218         double current_xy = 0.0;
0219         for (int i = 0; i <= optimum; ++i) {
0220             if (getW() >= getH()) {
0221                 double ih = isValueZero ? 0.0 : m_children.at(i).getValue() * getW() * getH() / (previous_gw * getValue());
0222 
0223                 m_children[i].setX(getX());
0224                 m_children[i].setY(getY() + current_xy);
0225                 m_children[i].setW(previous_gw);
0226                 m_children[i].setH(ih);
0227                 current_xy += ih;
0228 
0229                 m_children[i].compute();
0230             } else {
0231                 double iw = isValueZero ? 0.0 : m_children.at(i).getValue() * getW() * getH() / (previous_gh * getValue());
0232 
0233                 m_children[i].setX(getX() + current_xy);
0234                 m_children[i].setY(getY());
0235                 m_children[i].setW(iw);
0236                 m_children[i].setH(previous_gh);
0237                 current_xy += iw;
0238 
0239                 m_children[i].compute();
0240             }
0241         }
0242 
0243         // Treat the rest
0244         if (optimum == -1) {
0245             optimum = 1;
0246         }
0247         if (optimum < nb - 1) {
0248             // Create a new SKGTreeMap corresponding to the rest
0249             double x = getW() >= getH() ? getX() + previous_gw : getX();
0250             double y = getW() >= getH() ? getY() : getY() + previous_gh;
0251             double w = getW() >= getH() ? getW() - previous_gw : getW();
0252             double h = getW() >= getH() ? getH() : getH() - previous_gh;
0253             SKGTreeMap rest(QLatin1String(""), getValue() - sum, x, y, w, h);
0254 
0255             // Add all items to compute
0256             for (int i = optimum + 1; i < nb; ++i) {
0257                 rest.addChild(m_children.at(i));
0258             }
0259 
0260             // Compute
0261             rest.compute();
0262             auto computed = rest.getChildren();
0263             for (int i = optimum + 1; i < nb; ++i) {
0264                 m_children[i] = computed[i - optimum - 1];
0265             }
0266         }
0267     }
0268 }