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 }