File indexing completed on 2024-05-19 04:36:37
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 "DiamondShape.h" 0021 #include "NodeItem.h" 0022 0023 #include <tikz/core/Style.h> 0024 #include <tikz/core/tikz.h> 0025 0026 #include <cmath> 0027 0028 namespace tikz { 0029 namespace ui { 0030 0031 class DiamondShapePrivate 0032 { 0033 public: 0034 }; 0035 0036 DiamondShape::DiamondShape(NodeItem * node) 0037 : AbstractShape(node) 0038 , d(new DiamondShapePrivate()) 0039 { 0040 } 0041 0042 DiamondShape::~DiamondShape() 0043 { 0044 delete d; 0045 } 0046 0047 tikz::Shape DiamondShape::type() const 0048 { 0049 return tikz::Shape::ShapeDiamond; 0050 } 0051 0052 void DiamondShape::adjustShapeRect(const QRectF & textRect, QRectF & shapeRect) const 0053 { 0054 // see pgflibraryshapes.geometric.code.tex 0055 0056 // calculate radius of textRect 0057 const qreal s = node()->style()->innerSep().toPoint(); 0058 const qreal w = textRect.width(); 0059 const qreal h = textRect.height(); 0060 0061 // FIXME: /pgf/aspect is not supported right now 0062 const qreal d = w + h + 4 * s; 0063 QRectF r(-d/2, -d/2, d, d); 0064 0065 if (r.width() > shapeRect.width()) { 0066 shapeRect.setWidth(r.width()); 0067 } 0068 if (r.height() > shapeRect.height()) { 0069 shapeRect.setHeight(r.height()); 0070 } 0071 } 0072 0073 QPainterPath DiamondShape::shape() const 0074 { 0075 const QRectF rect = node()->shapeRect(); 0076 QPainterPath path; 0077 path.moveTo(rect.left(), 0); 0078 path.lineTo(0, rect.top()); 0079 path.lineTo(rect.right(), 0); 0080 path.lineTo(0, rect.bottom()); 0081 path.closeSubpath(); 0082 return path; 0083 } 0084 0085 QPainterPath DiamondShape::outline() const 0086 { 0087 const QRectF rect = outlineRect(); 0088 const qreal w = rect.width() / 2.0; 0089 const qreal h = rect.height() / 2.0; 0090 0091 QPainterPath path; 0092 path.moveTo(-w, 0); 0093 path.lineTo(0, h); 0094 path.lineTo(w, 0); 0095 path.lineTo(0, -h); 0096 path.closeSubpath(); 0097 return path; 0098 } 0099 0100 QStringList DiamondShape::supportedAnchors() const 0101 { 0102 // by default, just return NoAnchor 0103 const QStringList anchors = QStringList() 0104 << QString() 0105 << QStringLiteral("center") 0106 << QStringLiteral("north") 0107 << QStringLiteral("north east") 0108 << QStringLiteral("east") 0109 << QStringLiteral("south east") 0110 << QStringLiteral("south") 0111 << QStringLiteral("south west") 0112 << QStringLiteral("west") 0113 << QStringLiteral("north west"); 0114 return anchors; 0115 } 0116 0117 QPointF DiamondShape::anchorPos(const QString & anchor) const 0118 { 0119 if (anchor.isEmpty()) { 0120 return QPointF(0, 0); 0121 } 0122 0123 const QRectF rect = outlineRect(); 0124 const qreal rx = rect.width() / 2.0; 0125 const qreal ry = rect.height() / 2.0; 0126 0127 if (anchor == QStringLiteral("center")) { 0128 return QPointF(0, 0); 0129 } else if (anchor == QStringLiteral("north")) { 0130 return QPointF(0, ry); 0131 } else if (anchor == QStringLiteral("north east")) { 0132 return QPointF(rx, ry) * 0.5; 0133 } else if (anchor == QStringLiteral("east")) { 0134 return QPointF(rx, 0); 0135 } else if (anchor == QStringLiteral("south east")) { 0136 return QPointF(rx, -ry) * 0.5; 0137 } else if (anchor == QStringLiteral("south")) { 0138 return QPointF(0, -ry); 0139 } else if (anchor == QStringLiteral("south west")) { 0140 return QPointF(-rx, -ry) * 0.5; 0141 } else if (anchor == QStringLiteral("west")) { 0142 return QPointF(-rx, 0); 0143 } else if (anchor == QStringLiteral("north west")) { 0144 return QPointF(-rx, ry) * 0.5; 0145 } 0146 0147 tikz::warn("The shape 'diamond' does not support anchor '" + anchor + "'."); 0148 0149 return QPointF(0, 0); 0150 } 0151 0152 QPointF DiamondShape::contactPoint(const QString & anchor, qreal rad) const 0153 { 0154 if (! anchor.isEmpty()) { 0155 return anchorPos(anchor); 0156 } 0157 0158 const QRectF rect = outlineRect(); 0159 const qreal rx = rect.width() / 2.0; 0160 const qreal ry = rect.height() / 2.0; 0161 const qreal len = qMax(rx, ry); 0162 0163 // create line to intersect with 0164 const qreal x = std::cos(rad); 0165 const qreal y = std::sin(rad); 0166 const QLineF radLine(0, 0, len * x, len * y); 0167 0168 // create 4 lines of the rect and find intersection 0169 const QLineF l1(-rx, 0, 0, ry); 0170 const QLineF l2(0, ry, rx, 0); 0171 const QLineF l3(rx, 0, 0, -ry); 0172 const QLineF l4(0, -ry, -rx, 0); 0173 0174 QPointF intersectionPoint; 0175 if ((l1.intersects(radLine, &intersectionPoint) == QLineF::BoundedIntersection) || 0176 (l2.intersects(radLine, &intersectionPoint) == QLineF::BoundedIntersection) || 0177 (l3.intersects(radLine, &intersectionPoint) == QLineF::BoundedIntersection) || 0178 (l4.intersects(radLine, &intersectionPoint) == QLineF::BoundedIntersection) 0179 ) { 0180 return intersectionPoint; 0181 } 0182 0183 Q_ASSERT(false); 0184 return intersectionPoint; 0185 } 0186 0187 QRectF DiamondShape::outlineRect() const 0188 { 0189 const QRectF rect = node()->shapeRect(); 0190 const qreal rx = rect.width() / 2.0; 0191 const qreal ry = rect.height() / 2.0; 0192 Q_ASSERT(rx + ry > 0); 0193 0194 // height of triangle 0195 const qreal hypothenuse = std::sqrt(rx * rx + ry * ry); 0196 const qreal height = rx * ry / hypothenuse; 0197 0198 // scale by new height 0199 const qreal d = height + node()->style()->outerSep().toPoint(); 0200 const qreal dy = ry * d / height; 0201 const qreal dx = rx * d / height; 0202 0203 return QRectF(-dx, -dy, 2 * dx, 2 * dy); 0204 } 0205 0206 } 0207 } 0208 0209 // kate: indent-width 4; replace-tabs on;