Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
curve.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
15#include "display/curve.h"
16
17#include <glib.h> // g_error
20#include <2geom/point.h>
21
23{
24 auto path = Geom::Path{rect.corner(0)};
25
26 for (int i = 3; i >= 0; --i) {
27 path.appendNew<Geom::LineSegment>(rect.corner(i));
28 }
29
30 // When _constrained_ snapping to a path, the 2geom::SimpleCrosser will be invoked which doesn't consider the closing segment.
31 // of a path. Consequently, in case we want to snap to for example the page border, we must provide all four sides of the
32 // rectangle explicitly
33
34 return path;
35}
36
38{
39 if (path.size() > 0 && dynamic_cast<Geom::LineSegment const *>(&path.back_open())) {
40 path.erase_last();
41 } else {
42 path.setFinal(path.initialPoint());
43 }
44 path.close();
45}
46
47bool is_closed(Geom::PathVector const &pathv)
48{
49 if (pathv.empty()) {
50 return false;
51 }
52
53 for (auto const &path : pathv) {
54 if (!path.closed()) {
55 return false;
56 }
57 }
58
59 return true;
60}
61
63{
64 if (pathv.empty() || pathv.back().empty()) {
65 return nullptr;
66 }
67 return &pathv.back().back_default();
68}
69
71{
72 if (pathv.empty() || pathv.front().empty()) {
73 return nullptr;
74 }
75 return &pathv.front().front();
76}
77
78void pathvector_append(Geom::PathVector &to, Geom::PathVector const &pathv, bool use_lineto)
79{
80 if (pathv.empty()) {
81 return;
82 }
83
84 if (use_lineto) {
85 auto it = pathv.begin();
86 if (!to.empty()) {
87 Geom::Path &lastpath = to.back();
88 lastpath.appendNew<Geom::LineSegment>(it->initialPoint());
89 lastpath.append(*it);
90 } else {
91 to.push_back(*it);
92 }
93
94 for (++it; it != pathv.end(); ++it) {
95 to.push_back(*it);
96 }
97 } else {
98 for (auto const &it : pathv) {
99 to.push_back(it);
100 }
101 }
102}
103
104bool pathvector_append_continuous(Geom::PathVector &to, Geom::PathVector const &pathv, double tolerance)
105{
106 if (is_closed(to) || is_closed(pathv)) {
107 return false;
108 }
109
110 if (pathv.empty()) {
111 return true;
112 }
113
114 if (to.empty()) {
115 to = pathv;
116 return true;
117 }
118
119 if (Geom::LInfty(to.finalPoint() - pathv.initialPoint()) <= tolerance) {
120 // c1's first subpath can be appended to this curve's last subpath
121 Geom::PathVector::const_iterator path_it = pathv.begin();
122 Geom::Path &lastpath = to.back();
123
124 Geom::Path newfirstpath(*path_it);
125 newfirstpath.setInitial(lastpath.finalPoint());
126 lastpath.append(newfirstpath);
127
128 for (++path_it; path_it != pathv.end(); ++path_it) {
129 to.push_back(*path_it);
130 }
131
132 } else {
133 pathvector_append(to, pathv, true);
134 }
135
136 return true;
137}
138
140{
141 if (pathv.empty()) {
142 return;
143 }
144 backspace(pathv.back());
145}
146
148{
149 if (!path.empty()) {
150 path.erase_last();
151 path.close(false);
152 }
153}
154
164void stretch_endpoints(Geom::PathVector &pathv, Geom::Point const &new_p0, Geom::Point const &new_p1)
165{
166 if (pathv.empty()) {
167 return;
168 }
169
170 auto const offset0 = new_p0 - pathv.initialPoint();
171 auto const offset1 = new_p1 - pathv.finalPoint();
172
175 if (arclength.lastValue() <= 0) {
176 g_error("stretch_endpoints - arclength <= 0");
177 }
178 arclength *= 1./arclength.lastValue();
179 auto const A = offset0;
180 auto const B = offset1;
181 Geom::Piecewise<Geom::SBasis> offsetx = (arclength*-1.+1)*A[0] + arclength*B[0];
182 Geom::Piecewise<Geom::SBasis> offsety = (arclength*-1.+1)*A[1] + arclength*B[1];
184 pwd2 += offsetpath;
185 pathv = Geom::path_from_piecewise(pwd2, 0.001);
186}
187
188void move_endpoints(Geom::PathVector &pathv, Geom::Point const &new_p0, Geom::Point const &new_p1)
189{
190 if (!pathv.empty()) {
191 move_endpoints(pathv.front(), new_p0, new_p1);
192 }
193}
194
195void move_endpoints(Geom::Path &path, Geom::Point const &new_p0, Geom::Point const &new_p1)
196{
197 path.setInitial(new_p0);
198 path.setFinal(new_p1);
199}
200
201size_t node_count(Geom::PathVector const &pathv)
202{
203 size_t nr = 0;
204
205 for (auto const &path : pathv) {
206 // if the path does not have any segments, it is a naked moveto,
207 // and therefore any path has at least one valid node
208 size_t psize = std::max<size_t>(1, path.size_closed());
209 nr += psize;
210 if (path.closed() && path.size_closed() > 0) {
211 auto const &closingline = path.back_closed();
212 // the closing line segment is always of type
213 // Geom::LineSegment.
214 if (Geom::are_near(closingline.initialPoint(), closingline.finalPoint())) {
215 // closingline.isDegenerate() did not work, because it only checks for
216 // *exact* zero length, which goes wrong for relative coordinates and
217 // rounding errors...
218 // the closing line segment has zero-length. So stop before that one!
219 nr -= 1;
220 }
221 }
222 }
223
224 return nr;
225}
226
228{
229 if (pathv.empty()) {
230 return;
231 }
232
233 pathv.back().setFinal(pathv.back().finalPoint() + p);
234
235 // Move handle as well when the last segment is a cubic bezier segment:
236 // TODO: what to do for quadratic beziers?
237 if (auto const lastcube = dynamic_cast<Geom::CubicBezier const *>(&pathv.back().back())) {
238 auto newcube = Geom::CubicBezier{*lastcube};
239 newcube.setPoint(2, newcube[2] + p);
240 pathv.back().replace(--pathv.back().end(), newcube);
241 }
242}
243
244Geom::Path path_from_curve(std::unique_ptr<Geom::Curve> curve)
245{
246 auto path = Geom::Path{curve->initialPoint()};
247 path.append(curve.release());
248 return path;
249}
250
252{
253 return path_from_curve(std::unique_ptr<Geom::Curve>(curve.duplicate()));
254}
255
256/*
257 Local Variables:
258 mode:c++
259 c-file-style:"stroustrup"
260 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
261 indent-tabs-mode:nil
262 fill-column:99
263 End:
264*/
265// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:
Cartesian point / 2D vector and related operations.
void setPoint(unsigned ix, Point const &v)
Modify a control point.
Abstract continuous curve on a plane defined on [0,1].
Definition curve.h:78
Adaptor that creates 2D functions from 1D ones.
Definition d2.h:55
CPoint corner(unsigned i) const
Return the n-th corner of the rectangle.
Sequence of subpaths.
Definition pathvector.h:122
void push_back(Path const &path)
Append a path at the end.
Definition pathvector.h:172
Sequence::const_iterator const_iterator
Definition pathvector.h:127
Point finalPoint() const
Get the last point in the last path of the vector.
Definition pathvector.h:222
Point initialPoint() const
Get the first point in the first path of the vector.
Definition pathvector.h:217
bool empty() const
Check whether the vector contains any paths.
Definition pathvector.h:145
iterator begin()
Definition pathvector.h:151
iterator end()
Definition pathvector.h:152
Sequence of contiguous curves, aka spline.
Definition path.h:353
Point finalPoint() const
Get the last point in the path.
Definition path.h:709
void close(bool closed=true)
Set whether the path is closed.
Definition path.cpp:322
bool empty() const
Check whether path is empty.
Definition path.h:500
Piecewise< D2< SBasis > > toPwSb() const
Definition path.cpp:388
const_iterator end() const
Definition path.h:465
Curve const & back() const
Access the last curve in the path.
Definition path.h:447
Curve const & back_open() const
Definition path.h:448
Curve const & back_default() const
Definition path.h:457
void append(Curve *curve)
Add a new curve to the end of the path.
Definition path.h:750
Point initialPoint() const
Get the first point in the path.
Definition path.h:705
Curve const & front() const
Access the first curve in the path.
Definition path.h:443
void setFinal(Point const &p)
Definition path.h:740
void erase_last()
Definition path.h:700
size_type size() const
Natural size of the path.
Definition path.h:490
void replace(iterator replaced, Curve const &curve)
Definition path.cpp:943
void setInitial(Point const &p)
Definition path.h:734
void appendNew(Args &&... args)
Append a new curve to the path.
Definition path.h:804
Function defined as discrete pieces.
Definition piecewise.h:71
output_type lastValue() const
Definition piecewise.h:109
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
void backspace(Geom::PathVector &pathv)
Remove last segment of curve.
Definition curve.cpp:139
size_t node_count(Geom::PathVector const &pathv)
returns the number of nodes in a path, used for statusbar text when selecting an spcurve.
Definition curve.cpp:201
void move_endpoints(Geom::PathVector &pathv, Geom::Point const &new_p0, Geom::Point const &new_p1)
Sets start of first path to new_p0, and end of first path to new_p1.
Definition curve.cpp:188
void pathvector_append(Geom::PathVector &to, Geom::PathVector const &pathv, bool use_lineto)
Append pathv to to.
Definition curve.cpp:78
Geom::Curve const * get_last_segment(Geom::PathVector const &pathv)
Return last pathsegment (possibly the closing path segment) of the last path in PathVector or null.
Definition curve.cpp:62
void stretch_endpoints(Geom::PathVector &pathv, Geom::Point const &new_p0, Geom::Point const &new_p1)
TODO: add comments about what this method does and what assumptions are made and requirements are put...
Definition curve.cpp:164
Geom::Path path_from_curve(std::unique_ptr< Geom::Curve > curve)
Construct an open Geom::Path from Geom::Curve. Fixme: Should be in 2geom.
Definition curve.cpp:244
Geom::Path rect_to_open_path(Geom::Rect const &rect)
Authors: Lauris Kaplinski lauris@kaplinski.com Johan Engelen.
Definition curve.cpp:22
Geom::Curve const * get_first_segment(Geom::PathVector const &pathv)
Return first pathsegment in PathVector or NULL.
Definition curve.cpp:70
void closepath_current(Geom::Path &path)
Close path by setting the end point to the start point instead of adding a new lineto.
Definition curve.cpp:37
bool pathvector_append_continuous(Geom::PathVector &to, Geom::PathVector const &pathv, double tolerance)
Append pathv to to with possible fusing of close endpoints.
Definition curve.cpp:104
void last_point_additive_move(Geom::PathVector &pathv, Geom::Point const &p)
Add p to the last point (and last handle if present) of the last path.
Definition curve.cpp:227
bool is_closed(Geom::PathVector const &pathv)
Whether all subpaths are closed. Returns false if the curve is empty.
Definition curve.cpp:47
Piecewise< D2< SBasis > > sectionize(D2< Piecewise< SBasis > > const &a)
Definition d2-sbasis.cpp:65
PathVector path_from_piecewise(Piecewise< D2< SBasis > > const &B, double tol, bool only_cubicbeziers=false)
Make a path from a d2 sbasis.
Piecewise< SBasis > arcLengthSb(D2< SBasis > const &M, double tol=.01)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
Coord LInfty(Point const &p)
two-dimensional geometric operators.
Conversion between SBasis and Bezier basis polynomials.
Definition curve.h:24