Krita Source Code Documentation
Loading...
Searching...
No Matches
StarShape.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 SPDX-FileCopyrightText: 2006-2009 Jan Hambrecht <jaham@gmx.net>
3 SPDX-FileCopyrightText: 2009 Thomas Zander <zander@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "StarShape.h"
9
10#include <KoParameterShape_p.h>
11#include <KoPathPoint.h>
14#include <KoXmlNS.h>
15#include <KoXmlWriter.h>
16
17#include <math.h>
18
20 : m_cornerCount(5)
21 , m_zoomX(1.0)
22 , m_zoomY(1.0)
23 , m_convex(false)
24{
25 m_radius[base] = 25.0;
26 m_radius[tip] = 50.0;
29
30 m_center = QPointF(50, 50);
31 updatePath(QSize(100, 100));
32}
33
35 : KoParameterShape(rhs),
36 m_cornerCount(rhs.m_cornerCount),
37 m_radius(rhs.m_radius),
38 m_angles(rhs.m_angles),
39 m_zoomX(rhs.m_zoomX),
40 m_zoomY(rhs.m_zoomY),
41 m_roundness(rhs.m_roundness),
42 m_center(rhs.m_center),
43 m_convex(rhs.m_convex)
44{
45}
46
50
52{
53 return new StarShape(*this);
54}
55
56
58{
59 if (cornerCount >= 3) {
60 double oldDefaultAngle = defaultAngleRadian();
62 double newDefaultAngle = defaultAngleRadian();
63 m_angles[base] += newDefaultAngle - oldDefaultAngle;
64 m_angles[tip] += newDefaultAngle - oldDefaultAngle;
65
66 updatePath(QSize());
67 }
68}
69
71{
72 return m_cornerCount;
73}
74
75void StarShape::setBaseRadius(qreal baseRadius)
76{
77 m_radius[base] = fabs(baseRadius);
78 updatePath(QSize());
79}
80
82{
83 return m_radius[base];
84}
85
86void StarShape::setTipRadius(qreal tipRadius)
87{
88 m_radius[tip] = fabs(tipRadius);
89 updatePath(QSize());
90}
91
93{
94 return m_radius[tip];
95}
96
97void StarShape::setBaseRoundness(qreal baseRoundness)
98{
99 m_roundness[base] = baseRoundness;
100 updatePath(QSize());
101}
102
103void StarShape::setTipRoundness(qreal tipRoundness)
104{
105 m_roundness[tip] = tipRoundness;
106 updatePath(QSize());
107}
108
109void StarShape::setConvex(bool convex)
110{
112 updatePath(QSize());
113}
114
116{
117 return m_convex;
118}
119
121{
122 return m_center;
123}
124
125void StarShape::moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers)
126{
127 if (modifiers & Qt::ShiftModifier) {
128 QPointF handle = handles()[handleId];
129 QPointF tangentVector = point - handle;
130 qreal distance = sqrt(tangentVector.x() * tangentVector.x() + tangentVector.y() * tangentVector.y());
131 QPointF radialVector = handle - m_center;
132 // cross product to determine in which direction the user is dragging
133 qreal moveDirection = radialVector.x() * tangentVector.y() - radialVector.y() * tangentVector.x();
134 // make the roundness stick to zero if distance is under a certain value
135 float snapDistance = 3.0;
136 if (distance >= 0.0) {
137 distance = distance < snapDistance ? 0.0 : distance - snapDistance;
138 } else {
139 distance = distance > -snapDistance ? 0.0 : distance + snapDistance;
140 }
141 // control changes roundness on both handles, else only the actual handle roundness is changed
142 if (modifiers & Qt::ControlModifier) {
143 m_roundness[handleId] = moveDirection < 0.0f ? distance : -distance;
144 } else {
145 m_roundness[base] = m_roundness[tip] = moveDirection < 0.0f ? distance : -distance;
146 }
147 } else {
148 QPointF distVector = point - m_center;
149 // unapply scaling
150 distVector.rx() /= m_zoomX;
151 distVector.ry() /= m_zoomY;
152 m_radius[handleId] = sqrt(distVector.x() * distVector.x() + distVector.y() * distVector.y());
153
154 qreal angle = atan2(distVector.y(), distVector.x());
155 if (angle < 0.0) {
156 angle += 2.0 * M_PI;
157 }
158 qreal diffAngle = angle - m_angles[handleId];
159 qreal radianStep = M_PI / static_cast<qreal>(m_cornerCount);
160 if (handleId == tip) {
161 m_angles[tip] += diffAngle - radianStep;
162 m_angles[base] += diffAngle - radianStep;
163 } else {
164 // control make the base point move freely
165 if (modifiers & Qt::ControlModifier) {
166 m_angles[base] += diffAngle - 2 * radianStep;
167 } else {
169 }
170 }
171 }
172}
173
174void StarShape::updatePath(const QSizeF &size)
175{
176 Q_UNUSED(size);
177 qreal radianStep = M_PI / static_cast<qreal>(m_cornerCount);
178
180
181 KoSubpath &points = *subpaths()[0];
182
183 uint index = 0;
184 for (uint i = 0; i < 2 * m_cornerCount; ++i) {
185 uint cornerType = i % 2;
186 if (cornerType == base && m_convex) {
187 continue;
188 }
189 qreal radian = static_cast<qreal>((i + 1) * radianStep) + m_angles[cornerType];
190 QPointF cornerPoint = QPointF(m_zoomX * m_radius[cornerType] * cos(radian), m_zoomY * m_radius[cornerType] * sin(radian));
191
192 points[index]->setPoint(m_center + cornerPoint);
193 points[index]->unsetProperty(KoPathPoint::StopSubpath);
194 points[index]->unsetProperty(KoPathPoint::CloseSubpath);
195 if (m_roundness[cornerType] > 1e-10 || m_roundness[cornerType] < -1e-10) {
196 // normalized cross product to compute tangential vector for handle point
197 QPointF tangentVector(cornerPoint.y() / m_radius[cornerType], -cornerPoint.x() / m_radius[cornerType]);
198 points[index]->setControlPoint2(points[index]->point() - m_roundness[cornerType] * tangentVector);
199 points[index]->setControlPoint1(points[index]->point() + m_roundness[cornerType] * tangentVector);
200 } else {
201 points[index]->removeControlPoint1();
202 points[index]->removeControlPoint2();
203 }
204 index++;
205 }
206
207 // first path starts and closes path
208 points[0]->setProperty(KoPathPoint::StartSubpath);
209 points[0]->setProperty(KoPathPoint::CloseSubpath);
210 // last point stops and closes path
211 points.last()->setProperty(KoPathPoint::StopSubpath);
212 points.last()->setProperty(KoPathPoint::CloseSubpath);
213
214 normalize();
215
217 handles.push_back(points.at(tip)->point());
218 if (!m_convex) {
219 handles.push_back(points.at(base)->point());
220 }
222
224}
225
226void StarShape::createPoints(int requiredPointCount)
227{
228 if (subpaths().count() != 1) {
229 clear();
230 subpaths().append(new KoSubpath());
231 }
232 int currentPointCount = subpaths()[0]->count();
233 if (currentPointCount > requiredPointCount) {
234 for (int i = 0; i < currentPointCount - requiredPointCount; ++i) {
235 delete subpaths()[0]->front();
236 subpaths()[0]->pop_front();
237 }
238 } else if (requiredPointCount > currentPointCount) {
239 for (int i = 0; i < requiredPointCount - currentPointCount; ++i) {
240 subpaths()[0]->append(new KoPathPoint(this, QPointF()));
241 }
242 }
243
245}
246
247void StarShape::setSize(const QSizeF &newSize)
248{
249 QTransform matrix(resizeMatrix(newSize));
250 m_zoomX *= matrix.m11();
251 m_zoomY *= matrix.m22();
252
253 // this transforms the handles
255
257}
258
260{
261 KoSubpath &points = *subpaths()[0];
262
263 QPointF center(0, 0);
264 for (uint i = 0; i < m_cornerCount; ++i) {
265 if (m_convex) {
266 center += points[i]->point();
267 } else {
268 center += points[2 * i]->point();
269 }
270 }
271 if (m_cornerCount > 0) {
272 return center / static_cast<qreal>(m_cornerCount);
273 }
274 return center;
275
276}
277
279{
280 return StarShapeId;
281}
282
284{
285 qreal radianStep = M_PI / static_cast<qreal>(m_cornerCount);
286
287 return M_PI_2 - 2 * radianStep;
288}
qreal distance(const QPointF &p1, const QPointF &p2)
unsigned int uint
QList< KoPathPoint * > KoSubpath
a KoSubpath contains a path from a moveTo until a close or a new moveTo
Definition KoPathShape.h:31
#define StarShapeId
Definition StarShape.h:13
QPointF normalize() override
Normalizes the path data.
QList< QPointF > handles
the handles that the user can grab and change
void setSize(const QSizeF &size) override
reimplemented from KoShape
void setHandles(const QList< QPointF > &handles)
A KoPathPoint represents a point in a path.
@ StartSubpath
it starts a new subpath by a moveTo command
Definition KoPathPoint.h:38
@ CloseSubpath
it closes a subpath (only applicable on StartSubpath and StopSubpath)
Definition KoPathPoint.h:40
@ StopSubpath
it stops a subpath (last point of subpath)
Definition KoPathPoint.h:39
const KoSubpathList & subpaths() const
QTransform resizeMatrix(const QSizeF &newSize) const
QSizeF size() const override
reimplemented
void notifyPointsChanged()
void clear()
Removes all subpaths and their points from the path.
QString pathShapeId() const override
reimplemented
uint cornerCount() const
Returns the number of corners.
Definition StarShape.cpp:70
qreal m_zoomY
scaling in y
Definition StarShape.h:126
bool m_convex
controls if the star is convex
Definition StarShape.h:129
~StarShape() override
Definition StarShape.cpp:47
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers=Qt::NoModifier) override
Updates the internal state of a KoParameterShape.
void setSize(const QSizeF &newSize) override
reimplemented
void setBaseRadius(qreal baseRadius)
Definition StarShape.cpp:75
uint m_cornerCount
number of corners
Definition StarShape.h:122
QPointF starCenter() const
std::array< qreal, 2 > m_radius
the different radii
Definition StarShape.h:123
void setCornerCount(uint cornerCount)
Definition StarShape.cpp:57
QPointF computeCenter() const
Computes the star center point from the inner points.
bool convex() const
Returns if the star represents a regular polygon.
qreal m_zoomX
scaling in x
Definition StarShape.h:125
double defaultAngleRadian() const
Returns the default offset angle in radian.
void setTipRadius(qreal tipRadius)
Definition StarShape.cpp:86
KoShape * cloneShape() const override
creates a deep copy of the shape or shape's subtree
Definition StarShape.cpp:51
void setTipRoundness(qreal tipRoundness)
qreal baseRadius() const
Returns the base radius.
Definition StarShape.cpp:81
void createPoints(int requiredPointCount)
recreates the path points when the corner count or convexity changes
qreal tipRadius() const
Returns the tip radius.
Definition StarShape.cpp:92
std::array< qreal, 2 > m_roundness
the roundness at the handles
Definition StarShape.h:127
std::array< qreal, 2 > m_angles
the offset angles
Definition StarShape.h:124
void updatePath(const QSizeF &size) override
Update the path of the parameter shape.
void setBaseRoundness(qreal baseRoundness)
Definition StarShape.cpp:97
void setConvex(bool convex)
QPointF m_center
the star center point
Definition StarShape.h:128
#define M_PI
Definition kis_global.h:111