Krita Source Code Documentation
Loading...
Searching...
No Matches
KoPathPointMergeCommand.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2009 Jan Hambrecht <jaham@gmx.net>
3 * SPDX-FileCopyrightText: 2006, 2007 Thorsten Zachmann <zachmann@kde.org>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
9#include "KoPathPoint.h"
10#include "KoPathPointData.h"
11#include "KoPathShape.h"
12#include <klocalizedstring.h>
13#include <QPointF>
14#include "kis_assert.h"
15#include "KoPathMergeUtils.h"
16
17
18class Q_DECL_HIDDEN KoPathPointMergeCommand::Private
19{
20public:
21 Private(const KoPathPointData &pointData1, const KoPathPointData &pointData2)
22 : pathShape(pointData1.pathShape)
23 , pointIndex1(pointData1.pointIndex)
24 , pointIndex2(pointData2.pointIndex)
25 , removedPoint(0)
26 , mergedPointIndex(-1, -1)
27 , reverse(ReverseNone)
28 {
29 }
30
32 {
33 delete removedPoint;
34 }
35
37 savedNodePoint1 = point->point();
38 savedControlPoint11 = KritaUtils::fetchControlPoint(point, true);
39 savedControlPoint12 = KritaUtils::fetchControlPoint(point, false);
40 }
41
43 point->setPoint(savedNodePoint1);
44 KritaUtils::restoreControlPoint(point, true, savedControlPoint11);
45 KritaUtils::restoreControlPoint(point, false, savedControlPoint12);
46 }
47
49 {
50 QPointF mergePosition = 0.5 * (p1->point() + p2->point());
51
52 boost::optional<QPointF> mergedControlPoint1;
53 boost::optional<QPointF> mergedControlPoint2;
54
55 if (p1->activeControlPoint1()) {
56 mergedControlPoint1 = mergePosition + (p1->controlPoint1() - p1->point());
57 }
58
59 if (p2->activeControlPoint2()) {
60 mergedControlPoint2 = mergePosition + (p2->controlPoint2() - p2->point());
61 }
62
63 dstPoint->setPoint(mergePosition);
64 KritaUtils::restoreControlPoint(dstPoint, true, mergedControlPoint1);
65 KritaUtils::restoreControlPoint(dstPoint, false, mergedControlPoint2);
66 }
67
68 bool closeSubpathMode() const {
69 return pointIndex2.first == pointIndex1.first;
70 }
71
75
78
79 enum Reverse {
80 ReverseNone = 0,
81 ReverseFirst = 1,
82 ReverseSecond = 2
83 };
84
86
88
89 boost::optional<QPointF> savedControlPoint11;
90 boost::optional<QPointF> savedControlPoint12;
91};
92
100 : KUndo2Command(parent), d(new Private(pointData1, pointData2))
101{
102 KIS_ASSERT(pointData1.pathShape == pointData2.pathShape);
103 KIS_ASSERT(d->pathShape);
104
105 KIS_ASSERT(!d->pathShape->isClosedSubpath(d->pointIndex1.first));
106 KIS_ASSERT(!d->pathShape->isClosedSubpath(d->pointIndex2.first));
107
108 KIS_ASSERT(d->pointIndex1.second == 0 ||
109 d->pointIndex1.second == d->pathShape->subpathPointCount(d->pointIndex1.first) - 1);
110
111 KIS_ASSERT(d->pointIndex2.second == 0 ||
112 d->pointIndex2.second == d->pathShape->subpathPointCount(d->pointIndex2.first) - 1);
113
114 KIS_ASSERT(d->pointIndex2 != d->pointIndex1);
115
116 if (d->pointIndex2 < d->pointIndex1) {
117 std::swap(d->pointIndex2, d->pointIndex1);
118 }
119
120 // if we have two different subpaths we might need to reverse them
121 if (!d->closeSubpathMode()) {
122 if (d->pointIndex1.second == 0 &&
123 d->pathShape->subpathPointCount(d->pointIndex1.first) > 1) {
124
125 d->reverse |= Private::ReverseFirst;
126 }
127
128 if (d->pointIndex2.second != 0 &&
129 d->pathShape->subpathPointCount(d->pointIndex2.first) > 1) {
130
131 d->reverse |= Private::ReverseSecond;
132 }
133 }
134
135 setText(kundo2_i18n("Merge points"));
136}
137
142
144{
146
147 KIS_SAFE_ASSERT_RECOVER_RETURN(!d->removedPoint);
148
149 KoPathPoint * point1 = d->pathShape->pointByIndex(d->pointIndex1);
150 KoPathPoint * point2 = d->pathShape->pointByIndex(d->pointIndex2);
151
152 d->pathShape->update();
153
154 if (d->closeSubpathMode()) {
155 d->savePointState(point1);
156 d->mergePoints(point2, point1, point1);
157 d->removedPoint = d->pathShape->removePoint(d->pointIndex2);
158
159 KoPathPointIndex newStartIndex(d->pointIndex1.first, 0);
160
161 d->pathShape->closeSubpath(newStartIndex);
162 d->mergedPointIndex = newStartIndex;
163
164 } else {
165 if (d->reverse & Private::ReverseFirst) {
166 d->pathShape->reverseSubpath(d->pointIndex1.first);
167 }
168
169 if (d->reverse & Private::ReverseSecond) {
170 d->pathShape->reverseSubpath(d->pointIndex2.first);
171 }
172
173 d->pathShape->moveSubpath(d->pointIndex2.first, d->pointIndex1.first + 1);
174 d->mergedPointIndex = d->pathShape->pathPointIndex(point1);
175 d->pathShape->join(d->pointIndex1.first);
176
177 d->savePointState(point1);
178 d->mergePoints(point1, point2, point1);
179
180 KoPathPointIndex removeIndex = d->pathShape->pathPointIndex(point2);
181 d->removedPoint = d->pathShape->removePoint(removeIndex);
182 }
183
184 d->pathShape->recommendPointSelectionChange({d->mergedPointIndex});
185 d->pathShape->update();
186}
187
189{
191
192 d->pathShape->update();
193
194 KIS_SAFE_ASSERT_RECOVER_RETURN(d->removedPoint);
195
196 if (d->closeSubpathMode()) {
197 d->pathShape->openSubpath(d->mergedPointIndex);
198 d->pathShape->insertPoint(d->removedPoint, d->pointIndex2);
199 d->restorePointState(d->pathShape->pointByIndex(d->pointIndex1));
200 } else {
201 d->pathShape->breakAfter(d->mergedPointIndex);
202 d->pathShape->insertPoint(d->removedPoint, KoPathPointIndex(d->mergedPointIndex.first+1,0));
203 d->restorePointState(d->pathShape->pointByIndex(d->mergedPointIndex));
204 d->pathShape->moveSubpath(d->mergedPointIndex.first+1, d->pointIndex2.first);
205
206 // undo the reversion of the subpaths
207 if (d->reverse & Private::ReverseFirst) {
208 d->pathShape->reverseSubpath(d->pointIndex1.first);
209 }
210
211 if (d->reverse & Private::ReverseSecond) {
212 d->pathShape->reverseSubpath(d->pointIndex2.first);
213 }
214 }
215
216 // reset the removed point
217 d->removedPoint = 0;
218 d->mergedPointIndex = KoPathPointIndex(-1,-1);
219
220 d->pathShape->recommendPointSelectionChange({d->pointIndex1, d->pointIndex2});
221 d->pathShape->update();
222}
223
225{
226 return KoPathPointData(d->pathShape, d->mergedPointIndex);
227}
QPointF dstPoint
QPointF p2
QPointF p1
QPair< int, int > KoPathPointIndex
Definition KoPathShape.h:28
virtual void undo()
void setText(const KUndo2MagicString &text)
virtual void redo()
Describe a KoPathPoint by a KoPathShape and its indices.
KoPathShape * pathShape
path shape the path point belongs too
The undo / redo command for merging two subpath end points.
Private(const KoPathPointData &pointData1, const KoPathPointData &pointData2)
void restorePointState(KoPathPoint *point)
void savePointState(KoPathPoint *point)
void mergePoints(KoPathPoint *p1, KoPathPoint *p2, KoPathPoint *dstPoint)
void undo() override
revert the actions done in redo
void redo() override
redo the command
KoPathPointMergeCommand(const KoPathPointData &pointData1, const KoPathPointData &pointData2, KUndo2Command *parent=0)
boost::optional< QPointF > savedControlPoint12
boost::optional< QPointF > savedControlPoint11
KoPathPointData mergedPointData() const
A KoPathPoint represents a point in a path.
QPointF point
void setPoint(const QPointF &point)
alter the point
The position of a path point within a path shape.
Definition KoPathShape.h:63
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
KUndo2MagicString kundo2_i18n(const char *text)
void restoreControlPoint(KoPathPoint *pt, bool restoreFirst, boost::optional< QPointF > savedPoint)
boost::optional< QPointF > fetchControlPoint(KoPathPoint *pt, bool takeFirst)