File indexing completed on 2024-05-19 04:36:38
0001 /* This file is part of the TikZKit project. 0002 * 0003 * Copyright (C) 2014 Dominik Haumann <dhaumann@kde.org> 0004 * 0005 * This library is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU Library General Public License as published 0007 * by the Free Software Foundation, either version 2 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, see 0017 * <http://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "Grid.h" 0021 0022 #include <tikz/core/Value.h> 0023 #include <QPainter> 0024 0025 namespace tikz { 0026 namespace ui { 0027 0028 class GridPrivate 0029 { 0030 public: 0031 bool dirty = true; 0032 qreal zoom = 1.0; 0033 QRectF rect; 0034 tikz::Unit unit = tikz::Unit::Centimeter; 0035 0036 QVarLengthArray<QLineF, 256> majorLines; 0037 QVarLengthArray<QLineF, 256> minorLines; 0038 QVarLengthArray<QLineF, 256> tenthLines; 0039 0040 /** 0041 * Returns the number of lines that are visible per unit: 0042 * - 1 equals only major lines 0043 * - 2 means each unit is subdivided once 0044 * - 10 means each unit is subdivided 10 times line 0045 * The return value is guaranteed to be greater or equal to 1. 0046 */ 0047 int linesPerUnit() const 0048 { 0049 // how much space does one unit have on screen [cm] ? 0050 const tikz::Value oneUnitOnScreen = tikz::Value(zoom, unit); 0051 0052 // we want a line each 5 mm 0053 int lpu = 1; 0054 while ((oneUnitOnScreen / lpu) >= tikz::Value(10, tikz::Unit::Millimeter)) { 0055 if (lpu == 1) { 0056 lpu *= 2; 0057 } else if (lpu == 2) { 0058 lpu *= 5; 0059 } else { 0060 break; 0061 } 0062 } 0063 0064 Q_ASSERT(lpu > 0); 0065 return lpu; 0066 } 0067 0068 /** 0069 * Update the cached major and minor lines. 0070 */ 0071 void updateCache(const QRectF & r) 0072 { 0073 if (rect != r || dirty) { 0074 dirty = false; 0075 rect = r; 0076 0077 // we want a line each 5 mm 0078 const auto lpu = linesPerUnit(); 0079 // qDebug() << "lines per unit" << lpu; 0080 0081 majorLines.clear(); 0082 minorLines.clear(); 0083 tenthLines.clear(); 0084 0085 const Value one(1, unit); 0086 0087 tikz::Value left = tikz::Value(tikz::Value(rect.left()).convertTo(unit).value()); 0088 left = tikz::Value(std::floor(left.value()), unit); 0089 0090 tikz::Value top = tikz::Value(tikz::Value(rect.top()).convertTo(unit).value()); 0091 top = tikz::Value(std::ceil(top.value()), unit); 0092 0093 // 0094 // vertical lines 0095 // 0096 int i = 0; 0097 for (tikz::Value x = left; x.toPoint() < rect.right(); x += one) { 0098 QLineF l(x.toPoint(), rect.top(), x.toPoint(), rect.bottom()); 0099 majorLines.append(l); 0100 0101 if (lpu >= 2) { 0102 auto tx = x + (one / 2); 0103 minorLines.append(QLineF(tx.toPoint(), rect.top(), tx.toPoint(), rect.bottom())); 0104 } 0105 0106 if (lpu == 10) { 0107 const qreal tenth = (one / 10).toPoint(); 0108 l.translate(tenth, 0); 0109 tenthLines.append(l); 0110 l.translate(tenth, 0); 0111 tenthLines.append(l); 0112 l.translate(tenth, 0); 0113 tenthLines.append(l); 0114 l.translate(tenth, 0); 0115 tenthLines.append(l); 0116 0117 l.translate(2 * tenth, 0); 0118 tenthLines.append(l); 0119 l.translate(tenth, 0); 0120 tenthLines.append(l); 0121 l.translate(tenth, 0); 0122 tenthLines.append(l); 0123 l.translate(tenth, 0); 0124 tenthLines.append(l); 0125 } 0126 ++i; 0127 } 0128 0129 // 0130 // horizontal lines 0131 // 0132 i = 0; 0133 for (tikz::Value y = top; y.toPoint() < rect.bottom(); y += one) { 0134 QLineF l(rect.left(), y.toPoint(), rect.right(), y.toPoint()); 0135 majorLines.append(l); 0136 0137 if (lpu >= 2) { 0138 auto ty = y + (one / 2); 0139 minorLines.append(QLineF(rect.left(), ty.toPoint(), rect.right(), ty.toPoint())); 0140 } 0141 0142 if (lpu == 10) { 0143 const qreal tenth = (one / 10).toPoint(); 0144 l.translate(0, tenth); 0145 tenthLines.append(l); 0146 l.translate(0, tenth); 0147 tenthLines.append(l); 0148 l.translate(0, tenth); 0149 tenthLines.append(l); 0150 l.translate(0, tenth); 0151 tenthLines.append(l); 0152 0153 l.translate(0, 2 * tenth); 0154 tenthLines.append(l); 0155 l.translate(0, tenth); 0156 tenthLines.append(l); 0157 l.translate(0, tenth); 0158 tenthLines.append(l); 0159 l.translate(0, tenth); 0160 tenthLines.append(l); 0161 } 0162 ++i; 0163 } 0164 0165 } 0166 } 0167 }; 0168 0169 Grid::Grid(QObject * parent) 0170 : QObject(parent) 0171 , d(new GridPrivate()) 0172 { 0173 } 0174 0175 Grid::~Grid() 0176 { 0177 delete d; 0178 } 0179 0180 void Grid::draw(QPainter * p, const QRectF & rect) 0181 { 0182 d->updateCache(rect); 0183 0184 p->save(); 0185 p->setRenderHints(QPainter::Antialiasing, false); 0186 0187 QPen pen(QColor(230, 230, 230)); 0188 pen.setWidth(0); 0189 p->setPen(pen); 0190 p->drawLines(d->majorLines.data(), d->majorLines.size()); 0191 0192 pen.setDashPattern(QVector<qreal>() << 6 << 3); 0193 p->setPen(pen); 0194 p->drawLines(d->minorLines.data(), d->minorLines.size()); 0195 0196 pen.setDashPattern(QVector<qreal>() << 1 << 2); 0197 p->setPen(pen); 0198 p->drawLines(d->tenthLines.data(), d->tenthLines.size()); 0199 0200 p->restore(); 0201 } 0202 0203 void Grid::setUnit(tikz::Unit unit) noexcept 0204 { 0205 if (d->unit != unit) { 0206 d->unit = unit; 0207 d->dirty = true; 0208 } 0209 } 0210 0211 tikz::Unit Grid::unit() const noexcept 0212 { 0213 return d->unit; 0214 } 0215 0216 void Grid::setZoom(qreal zoomFactor) noexcept 0217 { 0218 if (d->zoom != zoomFactor) { 0219 d->zoom = zoomFactor; 0220 d->dirty = true; 0221 } 0222 } 0223 0224 qreal Grid::zoom() const noexcept 0225 { 0226 return d->zoom; 0227 } 0228 0229 tikz::Value Grid::snapValue(const tikz::Value & value) const 0230 { 0231 const int lpu = d->linesPerUnit(); 0232 const Value one(1.0 / lpu, d->unit); 0233 0234 // snap to the grid and return a Value using the Grid's d->unit 0235 const auto snappedValue = tikz::Value(qRound(value.convertTo(d->unit).value() / one.value()) * one.value(), d->unit); 0236 // qDebug() << value << "converts to:" << snappedValue; 0237 return snappedValue; 0238 } 0239 0240 tikz::Pos Grid::snapPos(const tikz::Pos & pos) const 0241 { 0242 return tikz::Pos(snapValue(pos.x()), snapValue(pos.y())); 0243 } 0244 0245 } 0246 } 0247 0248 // kate: indent-width 4; replace-tabs on;