1 #include <cairo.h>
2 #include <toys/path-cairo.h>
3 #include <toys/toy-framework-2.h>
4 #include <2geom/sbasis-to-bezier.h>
5 #include <2geom/utils.h>
6 #include <sstream>
7 #include <optional>
8 
9 using namespace Geom;
10 
cairo_rectangle(cairo_t * cr,Rect const & r)11 void cairo_rectangle(cairo_t *cr, Rect const& r) {
12     cairo_rectangle(cr, r.left(), r.top(), r.width(), r.height());
13 }
14 
cairo_convex_hull(cairo_t * cr,ConvexHull const & ch)15 void 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 
cairo_curve(cairo_t * cr,Curve const & c)23 void 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 
cairo_path(cairo_t * cr,Path const & p)56 void 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 
cairo_path_stitches(cairo_t * cr,Path const & p)73 void cairo_path_stitches(cairo_t *cr, Path const &p) {
74     Path::const_iterator iter;
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 
cairo_path_handles(cairo_t *,Path const &)91 void cairo_path_handles(cairo_t */*cr*/, Path const &/*p*/) {
92     //TODO
93 }
94 
cairo_path(cairo_t * cr,PathVector const & p)95 void cairo_path(cairo_t *cr, PathVector const &p) {
96     PathVector::const_iterator it;
97     for(it = p.begin(); it != p.end(); ++it) {
98         cairo_path(cr, *it);
99     }
100 }
101 
cairo_path_stitches(cairo_t * cr,PathVector const & p)102 void cairo_path_stitches(cairo_t *cr, PathVector const &p) {
103     PathVector::const_iterator it;
104     for ( it = p.begin() ; it != p.end() ; ++it ) {
105         cairo_path_stitches(cr, *it);
106     }
107 }
108 
cairo_d2_sb(cairo_t * cr,D2<SBasis> const & B)109 void cairo_d2_sb(cairo_t *cr, D2<SBasis> const &B) {
110     cairo_path(cr, path_from_sbasis(B, 0.1));
111 }
112 
cairo_d2_sb2d(cairo_t * cr,D2<SBasis2d> const & sb2,Point,double width)113 void 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 
cairo_sb2d(cairo_t * cr,SBasis2d const & sb2,Point dir,double width)135 void 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 
cairo_d2_pw_sb(cairo_t * cr,D2<Piecewise<SBasis>> const & p)157 void cairo_d2_pw_sb(cairo_t *cr, D2<Piecewise<SBasis> > const &p) {
158     cairo_pw_d2_sb(cr, sectionize(p));
159 }
160 
cairo_pw_d2_sb(cairo_t * cr,Piecewise<D2<SBasis>> const & p)161 void cairo_pw_d2_sb(cairo_t *cr, Piecewise<D2<SBasis> > const &p) {
162     for(unsigned i = 0; i < p.size(); i++)
163         cairo_d2_sb(cr, p[i]);
164 }
165 
166 
draw_line_seg(cairo_t * cr,Geom::Point a,Geom::Point b)167 void draw_line_seg(cairo_t *cr, Geom::Point a, Geom::Point b) {
168     cairo_move_to(cr, a[0], a[1]);
169     cairo_line_to(cr, b[0], b[1]);
170     cairo_stroke(cr);
171 }
172 
draw_spot(cairo_t * cr,Geom::Point h)173 void draw_spot(cairo_t *cr, Geom::Point h) {
174     draw_line_seg(cr, h, h);
175 }
176 
draw_handle(cairo_t * cr,Geom::Point h)177 void draw_handle(cairo_t *cr, Geom::Point h) {
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 
draw_cross(cairo_t * cr,Geom::Point h)186 void draw_cross(cairo_t *cr, Geom::Point h) {
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 
draw_circ(cairo_t * cr,Geom::Point h)195 void draw_circ(cairo_t *cr, Geom::Point h) {
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 
draw_ray(cairo_t * cr,Geom::Point h,Geom::Point dir)203 void draw_ray(cairo_t *cr, Geom::Point h, Geom::Point dir) {
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 
212 void
cairo_move_to(cairo_t * cr,Geom::Point p1)213 cairo_move_to (cairo_t *cr, Geom::Point p1) {
214     cairo_move_to(cr, p1[0], p1[1]);
215 }
216 
217 void
cairo_line_to(cairo_t * cr,Geom::Point p1)218 cairo_line_to (cairo_t *cr, Geom::Point p1) {
219     cairo_line_to(cr, p1[0], p1[1]);
220 }
221 
222 void
cairo_curve_to(cairo_t * cr,Geom::Point p1,Geom::Point p2,Geom::Point p3)223 cairo_curve_to (cairo_t *cr, Geom::Point p1,
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]
convertHSVtoRGB(const double H,const double S,const double V,double & R,double & G,double & B)240 void 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 
draw_line(cairo_t * cr,double a,double b,double c,const Geom::Rect & r)257 void 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 
draw_line(cairo_t * cr,const Geom::Line & l,const Geom::Rect & r)268 void 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 
draw_line(cairo_t * cr,Geom::Point n,double dist,Geom::Rect r)275 void 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 
draw_ray(cairo_t * cr,const Geom::Ray & ray,const Geom::Rect & r)280 void 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 
draw_line_segment(cairo_t * cr,const Geom::LineSegment & ls,const Geom::Rect & r)298 void draw_line_segment(cairo_t *cr, const Geom::LineSegment& ls, const Geom::Rect& r)
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 
draw_line_seg_with_arrow(cairo_t * cr,Geom::Point a,Geom::Point b,double dangle,double radius)317 void 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 */
343