Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
path-cairo.cpp
Go to the documentation of this file.
1#include <cairo.h>
2#include <toys/path-cairo.h>
5#include <2geom/utils.h>
6#include <sstream>
7#include <optional>
8
9using namespace Geom;
10
11void cairo_rectangle(cairo_t *cr, Rect const& r) {
12 cairo_rectangle(cr, r.left(), r.top(), r.width(), r.height());
13}
14
15void cairo_convex_hull(cairo_t *cr, ConvexHull const& ch) {
16 if(ch.empty()) return;
17 cairo_move_to(cr, ch[ch.size()-1]);
18 for(auto i : ch) {
19 cairo_line_to(cr, i);
20 }
21}
22
23void cairo_curve(cairo_t *cr, Curve const& c) {
24 if(!cairo_has_current_point(cr))
25 cairo_move_to(cr, c.initialPoint());
26
27 if(LineSegment const* line_segment = dynamic_cast<LineSegment const*>(&c)) {
28 cairo_line_to(cr, (*line_segment)[1][0], (*line_segment)[1][1]);
29 }
30 else if(QuadraticBezier const *quadratic_bezier = dynamic_cast<QuadraticBezier const*>(&c)) {
31 std::vector<Point> points = quadratic_bezier->controlPoints();
32 Point b1 = points[0] + (2./3) * (points[1] - points[0]);
33 Point b2 = b1 + (1./3) * (points[2] - points[0]);
34 cairo_curve_to(cr, b1[0], b1[1],
35 b2[0], b2[1],
36 points[2][0], points[2][1]);
37 }
38 else if(CubicBezier const *cubic_bezier = dynamic_cast<CubicBezier const*>(&c)) {
39 std::vector<Point> points = cubic_bezier->controlPoints();
40 cairo_curve_to(cr, points[1][0], points[1][1], points[2][0], points[2][1], points[3][0], points[3][1]);
41 }
42// else if(EllipticalArc const *svg_elliptical_arc = dynamic_cast<EllipticalArc *>(c)) {
43// //TODO: get at the innards and spit them out to cairo
44// }
45 else {
46 //this case handles sbasis as well as all other curve types
47 Path sbasis_path = cubicbezierpath_from_sbasis(c.toSBasis(), 0.1);
48
49 //recurse to convert the new path resulting from the sbasis to svgd
50 for(const auto & iter : sbasis_path) {
51 cairo_curve(cr, iter);
52 }
53 }
54}
55
56void cairo_path(cairo_t *cr, Path const &p) {
57 cairo_move_to(cr, p.initialPoint()[0], p.initialPoint()[1]);
58 if(p.size() == 0) { // naked moveto
59 cairo_move_to(cr, p.finalPoint()+Point(8,0));
60 cairo_line_to(cr, p.finalPoint()+Point(-8,0));
61 cairo_move_to(cr, p.finalPoint()+Point(0,8));
62 cairo_line_to(cr, p.finalPoint()+Point(0,-8));
63 return;
64 }
65
66 for(const auto & iter : p) {
67 cairo_curve(cr, iter);
68 }
69 if(p.closed())
70 cairo_close_path(cr);
71}
72
73void cairo_path_stitches(cairo_t *cr, Path const &p) {
75 for ( iter = p.begin() ; iter != p.end() ; ++iter ) {
76 Curve const &c=*iter;
77 if (dynamic_cast<Path::StitchSegment const *>(&c)) {
78 cairo_move_to(cr, c.initialPoint()[X], c.initialPoint()[Y]);
79 cairo_line_to(cr, c.finalPoint()[X], c.finalPoint()[Y]);
80
81 std::stringstream s;
82 s << L1(c.finalPoint() - c.initialPoint());
83 std::string ss = s.str();
84 draw_text(cr, c.initialPoint()+Point(5,5), ss.c_str(), false, "Serif 6");
85
86 //std::cout << c.finalPoint() - c.initialPoint() << std::endl;
87 }
88 }
89}
90
91void cairo_path_handles(cairo_t */*cr*/, Path const &/*p*/) {
92 //TODO
93}
94
95void cairo_path(cairo_t *cr, PathVector const &p) {
97 for(it = p.begin(); it != p.end(); ++it) {
98 cairo_path(cr, *it);
99 }
100}
101
104 for ( it = p.begin() ; it != p.end() ; ++it ) {
105 cairo_path_stitches(cr, *it);
106 }
107}
108
109void cairo_d2_sb(cairo_t *cr, D2<SBasis> const &B) {
110 cairo_path(cr, path_from_sbasis(B, 0.1));
111}
112
113void cairo_d2_sb2d(cairo_t* cr, D2<SBasis2d> const &sb2, Point /*dir*/, double width) {
114 D2<SBasis> B;
115 for(int ui = 0; ui <= 10; ui++) {
116 double u = ui/10.;
117 B[0] = extract_u(sb2[0], u);// + Linear(u);
118 B[1] = extract_u(sb2[1], u);
119 for(unsigned i = 0; i < 2; i ++) {
120 B[i] = B[i]*(width/2) + Linear(width/4);
121 }
122 cairo_d2_sb(cr, B);
123 }
124 for(int vi = 0; vi <= 10; vi++) {
125 double v = vi/10.;
126 B[1] = extract_v(sb2[1], v);// + Linear(v);
127 B[0] = extract_v(sb2[0], v);
128 for(unsigned i = 0; i < 2; i ++) {
129 B[i] = B[i]*(width/2) + Linear(width/4);
130 }
131 cairo_d2_sb(cr, B);
132 }
133}
134
135void cairo_sb2d(cairo_t* cr, SBasis2d const &sb2, Point dir, double width) {
136 D2<SBasis> B;
137 for(int ui = 0; ui <= 10; ui++) {
138 double u = ui/10.;
139 B[0] = extract_u(sb2, u)*dir[0] + Linear(u);
140 B[1] = SBasis(Linear(0,1)) + extract_u(sb2, u)*dir[1];
141 for(unsigned i = 0; i < 2; i ++) {
142 B[i] = B[i]*(width/2) + Linear(width/4);
143 }
144 cairo_d2_sb(cr, B);
145 }
146 for(int vi = 0; vi <= 10; vi++) {
147 double v = vi/10.;
148 B[1] = extract_v(sb2, v)*dir[1] + Linear(v);
149 B[0] = SBasis(Linear(0,1)) + extract_v(sb2, v)*dir[0];
150 for(unsigned i = 0; i < 2; i ++) {
151 B[i] = B[i]*(width/2) + Linear(width/4);
152 }
153 cairo_d2_sb(cr, B);
154 }
155}
156
159}
160
162 for(unsigned i = 0; i < p.size(); i++)
163 cairo_d2_sb(cr, p[i]);
164}
165
166
168 cairo_move_to(cr, a[0], a[1]);
169 cairo_line_to(cr, b[0], b[1]);
170 cairo_stroke(cr);
171}
172
174 draw_line_seg(cr, h, h);
175}
176
178 double x = h[Geom::X];
179 double y = h[Geom::Y];
180 cairo_move_to(cr, x-3, y);
181 cairo_line_to(cr, x+3, y);
182 cairo_move_to(cr, x, y-3);
183 cairo_line_to(cr, x, y+3);
184}
185
187 double x = h[Geom::X];
188 double y = h[Geom::Y];
189 cairo_move_to(cr, x-3, y-3);
190 cairo_line_to(cr, x+3, y+3);
191 cairo_move_to(cr, x+3, y-3);
192 cairo_line_to(cr, x-3, y+3);
193}
194
196 int x = int(h[Geom::X]);
197 int y = int(h[Geom::Y]);
198 cairo_new_sub_path(cr);
199 cairo_arc(cr, x, y, 3, 0, M_PI*2);
200 cairo_stroke(cr);
201}
202
204 draw_line_seg(cr, h, h+dir);
205 Point unit = 3*unit_vector(dir),
206 rot = rot90(unit);
207 draw_line_seg(cr, h+dir, h + dir - unit + rot);
208 draw_line_seg(cr, h+dir, h + dir - unit - rot);
209}
210
211
212void
214 cairo_move_to(cr, p1[0], p1[1]);
215}
216
217void
219 cairo_line_to(cr, p1[0], p1[1]);
220}
221
222void
224 Geom::Point p2, Geom::Point p3) {
225 cairo_curve_to(cr, p1[0], p1[1],
226 p2[0], p2[1],
227 p3[0], p3[1]);
228}
229/*
230 void draw_string(GtkWidget *widget, string s, int x, int y) {
231 PangoLayout *layout = gtk_widget_create_pango_layout(widget, s.c_str());
232 cairo_t* cr = gdk_cairo_create (widget->window);
233 cairo_move_to(cr, x, y);
234 pango_cairo_show_layout(cr, layout);
235 cairo_destroy (cr);
236 }*/
237
238// H in [0,360)
239// S, V, R, G, B in [0,1]
240void convertHSVtoRGB(const double H, const double S, const double V,
241 double& R, double& G, double& B) {
242 int Hi = int(floor(H/60.)) % 6;
243 double f = H/60. - Hi;
244 double p = V*(1-S);
245 double q = V*(1-f*S);
246 double t = V*(1-(1-f)*S);
247 switch(Hi) {
248 case 0: R=V, G=t, B=p; break;
249 case 1: R=q, G=V, B=p; break;
250 case 2: R=p, G=V, B=t; break;
251 case 3: R=p, G=q, B=V; break;
252 case 4: R=t, G=p, B=V; break;
253 case 5: R=V, G=p, B=q; break;
254 }
255}
256
257void draw_line(cairo_t *cr, double a, double b, double c, const Geom::Rect& r) {
258 Geom::Line l(a, b, c);
259 std::optional<Geom::LineSegment> seg = l.clip(r);
260 if (seg) {
261 cairo_move_to(cr, seg->initialPoint());
262 cairo_line_to(cr, seg->finalPoint());
263 cairo_stroke(cr);
264 }
265}
266
267
268void draw_line(cairo_t* cr, const Geom::Line& l, const Geom::Rect& r)
269{
270 std::vector<double> coeff = l.coefficients();
271 draw_line (cr, coeff[0], coeff[1], coeff[2], r);
272}
273
274
275void draw_line(cairo_t *cr, Geom::Point n, double dist, Geom::Rect r) {
276 draw_line(cr, n[0], n[1], dist, r);
277}
278
279
280void draw_ray(cairo_t *cr, const Geom::Ray& ray, const Geom::Rect& r)
281{
282 LineSegment ls;
283
284 for (size_t i = 0; i < 4; ++i)
285 {
286 ls.setInitial (r.corner(i));
287 ls.setFinal (r.corner(i+1));
288 OptCrossing cx = intersection (ls, ray);
289 if (cx)
290 {
291 Point P = ray.pointAt ((*cx).tb);
292 draw_line_seg (cr, ray.origin(), P);
293 break;
294 }
295 }
296}
297
299{
300 if(r.contains(ls[0])) {
301 if(r.contains(ls[1])) {
302 draw_line_seg(cr, ls[0], ls[1]);
303 } else {
304 draw_ray(cr, Geom::Ray(ls[0], ls[1]), r);
305 }
306
307 } else {
308 if(r.contains(ls[1])) {
309 draw_ray(cr, Geom::Ray(ls[1], ls[0]), r);
310 } else {
311 draw_line(cr, Geom::Line(ls[0], ls[1]), r);
312 }
313
314 }
315}
316
317void draw_line_seg_with_arrow(cairo_t *cr, Geom::Point a, Geom::Point b, double dangle, double radius) {
318 double angle = atan2(a-b);
319 cairo_move_to(cr, a);
320 cairo_line_to(cr, b);
321
322 cairo_move_to(cr, b);
323 cairo_line_to(cr, Point::polar(angle + dangle, radius) + b);
324 cairo_move_to(cr, b);
325 cairo_line_to(cr, Point::polar(angle - dangle, radius) + b);
326 cairo_stroke(cr);
327}
328
329
330
331
332/*
333 Local Variables:
334 mode:c++
335 c-file-style:"stroustrup"
336 c-file-offsets:((innamespace . 0)(substatement-open . 0))
337 indent-tabs-mode:nil
338 c-brace-offset:0
339 fill-column:99
340 End:
341 vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
342*/
Various utility functions.
void setInitial(Point const &v) override
Change the starting point of the curve.
void setFinal(Point const &v) override
Change the ending point of the curve.
Convex hull based on the Andrew's monotone chain algorithm.
bool empty() const
Check for emptiness.
size_t size() const
Get the number of points in the hull.
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
bool contains(GenericRect< C > const &r) const
Check whether the rectangle includes all points in the given rectangle.
C top() const
Return top coordinate of the rectangle (+Y is downwards).
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint corner(unsigned i) const
Return the n-th corner of the rectangle.
Infinite line on a plane.
Definition line.h:53
std::vector< double > coefficients() const
Get the coefficients of the line equation as a vector.
Definition line.cpp:120
std::optional< LineSegment > clip(Rect const &r) const
Return the portion of the line that is inside the given rectangle.
Definition line.cpp:151
Function that interpolates linearly between two values.
Definition linear.h:55
Sequence of subpaths.
Definition pathvector.h:122
Sequence::const_iterator const_iterator
Definition pathvector.h:127
iterator begin()
Definition pathvector.h:151
iterator end()
Definition pathvector.h:152
Sequence of contiguous curves, aka spline.
Definition path.h:353
bool closed() const
Check whether the path is closed.
Definition path.h:503
Point finalPoint() const
Get the last point in the path.
Definition path.h:709
const_iterator end() const
Definition path.h:465
Point initialPoint() const
Get the first point in the path.
Definition path.h:705
size_type size() const
Natural size of the path.
Definition path.h:490
const_iterator begin() const
Definition path.h:464
Function defined as discrete pieces.
Definition piecewise.h:71
Two-dimensional point that doubles as a vector.
Definition point.h:66
Straight ray from a specific point to infinity.
Definition ray.h:53
Point origin() const
Definition ray.h:68
Point pointAt(Coord t) const
Definition ray.h:86
Axis aligned, non-empty rectangle.
Definition rect.h:92
Polynomial in symmetric power basis.
Definition sbasis.h:70
double c[8][4]
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
auto floor(Geom::Rect const &rect)
Definition geom.h:131
Various utility functions.
Definition affine.h:22
Path path_from_sbasis(D2< SBasis > const &B, double tol, bool only_cubicbeziers=false)
Make a path from a d2 sbasis.
Coord L1(Point const &p)
Linear extract_v(Linear2d const &a, double v)
Definition sbasis-2d.h:96
std::optional< Crossing > OptCrossing
Definition crossing.h:64
double atan2(Point const &p)
OptCrossing intersection(Ray const &r1, Line const &l2)
Definition line.h:545
Piecewise< D2< SBasis > > sectionize(D2< Piecewise< SBasis > > const &a)
Definition d2-sbasis.cpp:65
Path cubicbezierpath_from_sbasis(D2< SBasis > const &B, double tol)
Linear extract_u(Linear2d const &a, double u)
Definition sbasis-2d.h:90
Point unit_vector(Point const &a)
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
void draw_line_seg_with_arrow(cairo_t *cr, Geom::Point a, Geom::Point b, double dangle, double radius)
void draw_spot(cairo_t *cr, Geom::Point h)
void cairo_curve(cairo_t *cr, Curve const &c)
void cairo_line_to(cairo_t *cr, Geom::Point p1)
void cairo_path_stitches(cairo_t *cr, Path const &p)
void draw_cross(cairo_t *cr, Geom::Point h)
void draw_line_segment(cairo_t *cr, const Geom::LineSegment &ls, const Geom::Rect &r)
void draw_line(cairo_t *cr, double a, double b, double c, const Geom::Rect &r)
void cairo_d2_pw_sb(cairo_t *cr, D2< Piecewise< SBasis > > const &p)
void cairo_pw_d2_sb(cairo_t *cr, Piecewise< D2< SBasis > > const &p)
void draw_ray(cairo_t *cr, Geom::Point h, Geom::Point dir)
void draw_circ(cairo_t *cr, Geom::Point h)
void cairo_path_handles(cairo_t *, Path const &)
void cairo_sb2d(cairo_t *cr, SBasis2d const &sb2, Point dir, double width)
void draw_handle(cairo_t *cr, Geom::Point h)
void cairo_path(cairo_t *cr, Path const &p)
void cairo_d2_sb2d(cairo_t *cr, D2< SBasis2d > const &sb2, Point, double width)
void cairo_convex_hull(cairo_t *cr, ConvexHull const &ch)
void cairo_move_to(cairo_t *cr, Geom::Point p1)
void cairo_d2_sb(cairo_t *cr, D2< SBasis > const &B)
void cairo_rectangle(cairo_t *cr, Rect const &r)
void cairo_curve_to(cairo_t *cr, Geom::Point p1, Geom::Point p2, Geom::Point p3)
void convertHSVtoRGB(const double H, const double S, const double V, double &R, double &G, double &B)
void draw_line_seg(cairo_t *cr, Geom::Point a, Geom::Point b)
struct _cairo cairo_t
Definition path-cairo.h:16
Conversion between SBasis and Bezier basis polynomials.
double width
void draw_text(cairo_t *cr, Geom::Point pos, const char *txt, bool bottom=false, const char *fontdesc="Sans")