File indexing completed on 2024-05-19 04:36:37
0001 /* This file is part of the TikZKit project. 0002 * 0003 * Copyright (C) 2013 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 "EllipseShape.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 EllipseShapePrivate 0032 { 0033 public: 0034 }; 0035 0036 EllipseShape::EllipseShape(NodeItem * node) 0037 : AbstractShape(node) 0038 , d(new EllipseShapePrivate()) 0039 { 0040 } 0041 0042 EllipseShape::~EllipseShape() 0043 { 0044 delete d; 0045 } 0046 0047 tikz::Shape EllipseShape::type() const 0048 { 0049 return tikz::Shape::ShapeCircle; 0050 } 0051 0052 void EllipseShape::adjustShapeRect(const QRectF & textRect, QRectF & shapeRect) const 0053 { 0054 // see pgflibraryshapes.geometric.code.tex 0055 0056 // calculate radius of textRect 0057 qreal w = textRect.width() / 2.0 + node()->style()->innerSep().toPoint(); 0058 qreal h = textRect.height() / 2.0 + node()->style()->innerSep().toPoint(); 0059 0060 w *= 1.4142136; 0061 h *= 1.4142136; 0062 0063 // make sure the circle around textRect is contained in shapeRect 0064 if (2.0 * w > shapeRect.width()) { 0065 shapeRect.setWidth(2.0 * w); 0066 } 0067 if (2.0 * h > shapeRect.height()) { 0068 shapeRect.setHeight(2.0 * h); 0069 } 0070 } 0071 0072 QPainterPath EllipseShape::shape() const 0073 { 0074 QPainterPath path; 0075 path.addEllipse(node()->shapeRect()); 0076 return path; 0077 } 0078 0079 QPainterPath EllipseShape::outline() const 0080 { 0081 const qreal lw = node()->style()->penWidth().toPoint() / 2; 0082 QRectF rect = node()->shapeRect(); 0083 rect.adjust(-lw, -lw, lw, lw); 0084 0085 QPainterPath path; 0086 path.addEllipse(rect); 0087 return path; 0088 } 0089 0090 QStringList EllipseShape::supportedAnchors() const 0091 { 0092 // by default, just return NoAnchor 0093 const QStringList anchors = QStringList() 0094 << QString() 0095 << QStringLiteral("center") 0096 << QStringLiteral("north") 0097 << QStringLiteral("north east") 0098 << QStringLiteral("east") 0099 << QStringLiteral("south east") 0100 << QStringLiteral("south") 0101 << QStringLiteral("south west") 0102 << QStringLiteral("west") 0103 << QStringLiteral("north west"); 0104 return anchors; 0105 } 0106 0107 QPointF EllipseShape::anchorPos(const QString & anchor) const 0108 { 0109 if (anchor.isEmpty()) { 0110 return QPointF(0, 0); 0111 } 0112 0113 const QRectF shapeRect = node()->shapeRect(); 0114 const qreal rx = shapeRect.width() / 2.0 + node()->style()->outerSep().toPoint(); 0115 const qreal ry = shapeRect.height() / 2.0 + node()->style()->outerSep().toPoint(); 0116 0117 if (anchor == QStringLiteral("center")) { 0118 return QPointF(0, 0); 0119 } else if (anchor == QStringLiteral("north")) { 0120 return QPointF(0, ry); 0121 } else if (anchor == QStringLiteral("north east")) { 0122 return QPointF(rx, ry) * 0.70710678; 0123 } else if (anchor == QStringLiteral("east")) { 0124 return QPointF(rx, 0); 0125 } else if (anchor == QStringLiteral("south east")) { 0126 return QPointF(rx, -ry) * 0.70710678; 0127 } else if (anchor == QStringLiteral("south")) { 0128 return QPointF(0, -ry); 0129 } else if (anchor == QStringLiteral("south west")) { 0130 return QPointF(-rx, -ry) * 0.70710678; 0131 } else if (anchor == QStringLiteral("west")) { 0132 return QPointF(-rx, 0); 0133 } else if (anchor == QStringLiteral("north west")) { 0134 return QPointF(-rx, ry) * 0.70710678; 0135 } 0136 0137 tikz::warn("The shape 'ellipse' does not support anchor '" + anchor + "'."); 0138 0139 return QPointF(0, 0); 0140 } 0141 0142 QPointF EllipseShape::contactPoint(const QString & anchor, qreal rad) const 0143 { 0144 if (! anchor.isEmpty()) { 0145 return anchorPos(anchor); 0146 } 0147 0148 const QRectF shapeRect = node()->shapeRect(); 0149 const qreal rx = shapeRect.width() / 2.0 + node()->style()->outerSep().toPoint(); 0150 const qreal ry = shapeRect.height() / 2.0 + node()->style()->outerSep().toPoint(); 0151 0152 // use polar coordinates to calculate contact point 0153 const qreal xcosphi = ry * std::cos(rad); 0154 const qreal ysinphi = rx * std::sin(rad); 0155 const qreal denominator = sqrt(xcosphi * xcosphi + ysinphi * ysinphi); 0156 const qreal d = qFuzzyCompare(denominator, 0.0) ? 0 : rx * ry / denominator; 0157 0158 return d * QPointF(std::cos(rad), std::sin(rad)); 0159 } 0160 0161 } 0162 } 0163 0164 // kate: indent-width 4; replace-tabs on;