File indexing completed on 2024-05-05 04:35:17
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 "BezierCurve.h" 0021 0022 #include <cmath> 0023 0024 BezierCurve::BezierCurve() 0025 { 0026 } 0027 0028 BezierCurve::BezierCurve(const QPointF& p1, 0029 const QPointF& p2, 0030 const QPointF& c1, 0031 const QPointF& c2) 0032 : m_p1(p1) 0033 , m_p2(p2) 0034 , m_c1(c1) 0035 , m_c2(c2) 0036 { 0037 } 0038 0039 BezierCurve::~BezierCurve() 0040 { 0041 } 0042 0043 void BezierCurve::setP1(const QPointF& p1) 0044 { 0045 m_p1 = p1; 0046 } 0047 0048 void BezierCurve::setP2(const QPointF& p2) 0049 { 0050 m_p2 = p2; 0051 } 0052 0053 void BezierCurve::setC1(const QPointF& c1) 0054 { 0055 m_c1 = c1; 0056 } 0057 0058 void BezierCurve::setC2(const QPointF& c2) 0059 { 0060 m_c2 = c2; 0061 } 0062 0063 QPointF BezierCurve::p1() const 0064 { 0065 return m_p1; 0066 } 0067 0068 QPointF BezierCurve::p2() const 0069 { 0070 return m_p2; 0071 } 0072 0073 QPointF BezierCurve::c1() const 0074 { 0075 return m_c1; 0076 } 0077 0078 QPointF BezierCurve::c2() const 0079 { 0080 return m_c2; 0081 } 0082 0083 inline static qreal interpolateBezierCurve(qreal t, 0084 qreal p1, 0085 qreal p2, 0086 qreal c1, 0087 qreal c2) 0088 { 0089 return (-p1 + 3*c1 -3*c2 + p2) * t*t*t + (3*p1 - 6*c1 + 3*c2) * t*t + (-3*p1 + 3*c1) * t + p1; 0090 } 0091 0092 inline static QPointF interpolateBezierCurve(qreal t, 0093 const QPointF& p1, 0094 const QPointF& p2, 0095 const QPointF& c1, 0096 const QPointF& c2) 0097 { 0098 return (-p1 + 3*c1 -3*c2 + p2) * t*t*t + (3*p1 - 6*c1 + 3*c2) * t*t + (-3*p1 + 3*c1) * t + p1; 0099 } 0100 0101 QPointF BezierCurve::pointAtPercent(qreal t) const 0102 { 0103 Q_ASSERT(t >= 0.0); 0104 Q_ASSERT(t <= 1.0); 0105 0106 return interpolateBezierCurve(t, m_p1, m_p2, m_c1, m_c2); 0107 } 0108 0109 QPainterPath BezierCurve::toPath(int samplePoints) const 0110 { 0111 QPainterPath path; 0112 path.moveTo(m_p1); 0113 for (int i = 1; i <= samplePoints; ++i) { 0114 path.lineTo(pointAtPercent(static_cast<qreal>(i) / samplePoints)); 0115 } 0116 return path; 0117 } 0118 0119 QPainterPath BezierCurve::toPath(qreal t1, qreal t2, int samplePoints) const 0120 { 0121 Q_ASSERT(t1 >= 0); 0122 Q_ASSERT(t1 <= 1); 0123 Q_ASSERT(t2 >= 0); 0124 Q_ASSERT(t2 <= 1); 0125 0126 QPainterPath path; 0127 path.moveTo(pointAtPercent(t1)); 0128 0129 const qreal tau = (t2 - t1) / samplePoints; 0130 for (int i = 1; i <= samplePoints; ++i) { 0131 path.lineTo(pointAtPercent(t1 + i * tau)); 0132 } 0133 return path; 0134 } 0135 0136 BezierCurve BezierCurve::subPath(qreal t1, qreal t2) const 0137 { 0138 Q_ASSERT(t1 >= 0.0); 0139 Q_ASSERT(t1 < 1.0); 0140 Q_ASSERT(t2 > 0.0); 0141 Q_ASSERT(t2 <= 1.0); 0142 Q_ASSERT(t1 < t2); 0143 0144 // copy this curve 0145 BezierCurve c(*this); 0146 0147 // adapt start, if requried 0148 if (t1 > 0.0) { 0149 const QPointF x0 = c.m_p1 + t1 * (c.m_c1 - c.m_p1); 0150 const QPointF x1 = c.m_c1 + t1 * (c.m_c2 - c.m_c1); 0151 const QPointF x2 = c.m_c2 + t1 * (c.m_p2 - c.m_c2); 0152 0153 const QPointF x3 = x0 + t1 * (x1 - x0); 0154 const QPointF x4 = x1 + t1 * (x2 - x1); 0155 0156 c.m_p1 = x3 + t1 * (x4 - x3); 0157 c.m_c1 = x4; 0158 c.m_c2 = x2; 0159 } 0160 0161 // adapt end, if requried 0162 if (t2 < 1.0) { 0163 const QPointF x0 = c.m_p1 + t2 * (c.m_c1 - c.m_p1); 0164 const QPointF x1 = c.m_c1 + t2 * (c.m_c2 - c.m_c1); 0165 const QPointF x2 = c.m_c2 + t2 * (c.m_p2 - c.m_c2); 0166 0167 const QPointF x3 = x0 + t2 * (x1 - x0); 0168 const QPointF x4 = x1 + t2 * (x2 - x1); 0169 0170 c.m_c1 = x0; 0171 c.m_c2 = x3; 0172 c.m_p2 = x3 + t2 * (x4 - x3); 0173 } 0174 0175 return c; 0176 } 0177 0178 qreal BezierCurve::intersect(const QPainterPath & path) 0179 { 0180 const int samplePoints = 50; 0181 0182 const qreal tau = 1.0 / samplePoints; 0183 0184 for (int a = 0; a < samplePoints; ++a) { 0185 QLineF line1(pointAtPercent(a * tau), 0186 pointAtPercent((a + 1) * tau)); 0187 for (int b = 0; b < samplePoints; ++b) { 0188 QLineF line2(path.pointAtPercent(b * tau), 0189 path.pointAtPercent((b + 1) * tau)); 0190 0191 QPointF crossing; 0192 if (QLineF::BoundedIntersection == line1.intersects(line2, &crossing)) { 0193 return a * tau; 0194 } 0195 } 0196 } 0197 0198 return 0.0; 0199 } 0200 0201 // kate: indent-width 4; replace-tabs on;