Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
scribble.cpp
Go to the documentation of this file.
1#include <2geom/d2.h>
2#include <2geom/sbasis.h>
3#include <2geom/sbasis-2d.h>
5#include <2geom/sbasis-math.h>
10#include <2geom/transforms.h>
11#include <2geom/angle.h>
12
13#include <toys/path-cairo.h>
15#include <sstream>
16
17using std::vector;
18using namespace Geom;
19using namespace std;
20
21// TODO:
22// use path2
23// replace Ray stuff with path2 line segments.
24
25//-----------------------------------------------
26
27void draw_segment(cairo_t* cr, Point const& p1, Point const& p2)
28{
29 cairo_move_to(cr, p1);
30 cairo_line_to(cr, p2);
31}
32
33void draw_segment(cairo_t* cr, Point const& p1, double angle, double length)
34{
35 Point p2;
36 p2[X] = length * std::cos(angle);
37 p2[Y] = length * std::sin(angle);
38 p2 += p1;
39 draw_segment(cr, p1, p2);
40}
41
42void draw_segment(cairo_t* cr, LineSegment const& ls)
43{
44 draw_segment(cr, ls[0], ls[1]);
45}
46
47int num = 30;
48vector<double> c1_bot;
49vector<double> c1_top;
50vector<double> c2_bot;
51vector<double> c2_top;
52vector<double> c3_bot;
53vector<double> c3_top;
54vector<double> c4_bot;
55vector<double> c4_top;
56
57CubicBezier create_bezier(Point const &anchor, double angle /* in degrees */,
58 double length, double dx1, double dx2, cairo_t *cr = NULL) {
59 Point A = anchor;
60 Point dir = Point(1.0, 0) * Rotate(-angle) * length;
61 Point B = anchor + dir;
62
63 Point C = A - Point(1.0, 0) * dx1;
64 Point D = B + Point(1.0, 0) * dx1;
65 Point E = A + Point(1.0, 0) * dx2;
66 Point F = B - Point(1.0, 0) * dx2;
67
68 if (cr) {
69 draw_cross(cr, A);
70 draw_cross(cr, B);
71 draw_cross(cr, C);
72 draw_cross(cr, D);
73 draw_cross(cr, E);
74 draw_cross(cr, F);
75 }
76
77 return CubicBezier(C, E, F, D);
78}
79
80/*
81 * Draws a single "scribble segment" (we use many of these to cover the whole curve).
82 *
83 * Let I1, I2 be two adjacent intervals (bounded by the points A1, A2, A3) on the lower and J1, J2
84 * two adjacent intervals (bounded by B1, B2, B3) on the upper parallel. Then we specify:
85 *
86 * - The point in I1 where the scribble line starts (given by a value in [0,1])
87 * - The point in J2 where the scribble line ends (given by a value in [0,1])
88 * - A point in I2 (1st intermediate point of the Bezier curve)
89 * - A point in J1 (2nd intermediate point of the Bezier curve)
90 *
91 */
93create_bezier_again(Point const &anchor1, Point const &anchor2, Point const &dir1, Point const &dir2,
94 double /*c1*/, double /*c2*/, double c3, double c4, double mu, cairo_t *cr = NULL) {
95 Point A = anchor1;// - dir * c1;
96 Point B = anchor1 + dir1 * (c3 + mu);
97 Point C = anchor2 - dir2 * (c4 + mu);
98 Point D = anchor2;// + dir * c2;
99
100 if (cr) {
101 draw_cross(cr, A);
102 //draw_cross(cr, B);
103 //draw_cross(cr, C);
104 //draw_cross(cr, D);
105 }
106
107 return CubicBezier(A, B, C, D);
108}
109
112 Piecewise<D2<SBasis> > const &curve2,
113 double segdist,
114 Coord const t1, Coord const t2, Point const &n,
115 double c1, double c2, double /*c3*/, double /*c4*/, double /*mu*/, cairo_t *cr = NULL) {
116 cout << "create_bezier_along_curve -- start" << endl;
117 /*
118 Point A = curve1.valueAt(t1 - c1);
119 Point B = curve1.valueAt(t1) + n * (c3 + mu);
120 Point C = curve2.valueAt(t2) - n * (c4 + mu);
121 Point D = curve2.valueAt(t2 + c2);
122 */
123 Point A = curve1.valueAt(t1 - c1 * segdist);
124 Point B = curve1.valueAt(t1) + n * 0.1;
125 Point C = curve2.valueAt(t2) - n * 0.1;
126 Point D = curve2.valueAt(t2 + c2 * segdist);
127
128 if (cr) {
129 draw_cross(cr, A);
130 //draw_cross(cr, B);
131 //draw_cross(cr, C);
132 //draw_cross(cr, D);
133 }
134
135 cout << "create_bezier_along_curve -- end" << endl;
136 return CubicBezier(A, B, C, D);
137}
138
139class OffsetTester: public Toy {
140 PointSetHandle psh;
141 PointSetHandle psh_rand;
142
143 void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
144 double w = 600;
145 double slider_top = w/4.;
146 double slider_bot = w*3./4.;
147 double slider_margin = 40;
148 double slider_middle = (slider_top + slider_bot) / 2;
149
150 if(psh.pts.empty()) {
151 psh.pts.emplace_back(200,300);
152 psh.pts.emplace_back(350,250);
153 psh.pts.emplace_back(500,280);
154 psh.pts.emplace_back(700,300);
155
156 psh.pts.emplace_back(400,300);
157 psh.pts.emplace_back(550,250);
158 psh.pts.emplace_back(700,280);
159 psh.pts.emplace_back(900,300);
160
161 psh.pts.emplace_back(900,500);
162 psh.pts.emplace_back(700,480);
163 psh.pts.emplace_back(550,450);
164 psh.pts.emplace_back(400,500);
165
166 psh_rand.pts.emplace_back(slider_margin,slider_bot);
167 psh_rand.pts.emplace_back(slider_margin,slider_top);
168 psh_rand.pts.emplace_back(slider_margin,slider_top);
169 psh_rand.pts.emplace_back(slider_margin,slider_top);
170 psh_rand.pts.emplace_back(slider_margin,slider_top);
171 psh_rand.pts.emplace_back(slider_margin,slider_bot);
172 psh_rand.pts.emplace_back(slider_margin,slider_middle);
173 }
174
175 psh_rand.pts[0][X] = slider_margin;
176 if (psh_rand.pts[0][Y]<slider_top) psh_rand.pts[0][Y] = slider_top;
177 if (psh_rand.pts[0][Y]>slider_bot) psh_rand.pts[0][Y] = slider_bot;
178 psh_rand.pts[1][X] = slider_margin + 15;
179 if (psh_rand.pts[1][Y]<slider_top) psh_rand.pts[1][Y] = slider_top;
180 if (psh_rand.pts[1][Y]>slider_bot) psh_rand.pts[1][Y] = slider_bot;
181 psh_rand.pts[2][X] = slider_margin + 30;
182 if (psh_rand.pts[2][Y]<slider_top) psh_rand.pts[2][Y] = slider_top;
183 if (psh_rand.pts[2][Y]>slider_bot) psh_rand.pts[2][Y] = slider_bot;
184 psh_rand.pts[3][X] = slider_margin + 45;
185 if (psh_rand.pts[3][Y]<slider_top) psh_rand.pts[3][Y] = slider_top;
186 if (psh_rand.pts[3][Y]>slider_bot) psh_rand.pts[3][Y] = slider_bot;
187 psh_rand.pts[4][X] = slider_margin + 60;
188 if (psh_rand.pts[4][Y]<slider_top) psh_rand.pts[4][Y] = slider_top;
189 if (psh_rand.pts[4][Y]>slider_bot) psh_rand.pts[4][Y] = slider_bot;
190 psh_rand.pts[5][X] = slider_margin + 75;
191 if (psh_rand.pts[5][Y]<slider_top) psh_rand.pts[5][Y] = slider_top;
192 if (psh_rand.pts[5][Y]>slider_bot) psh_rand.pts[5][Y] = slider_bot;
193 psh_rand.pts[6][X] = slider_margin + 90;
194 if (psh_rand.pts[6][Y]<slider_top) psh_rand.pts[6][Y] = slider_top;
195 if (psh_rand.pts[6][Y]>slider_bot) psh_rand.pts[6][Y] = slider_bot;
196
197 *notify << "Sliders:" << endl << endl << endl << endl;
198 *notify << "0 - segment distance" << endl;
199 *notify << "1 - start anchor randomization" << endl;
200 *notify << "2 - end anchor randomization" << endl;
201 *notify << "3 - start rounding randomization" << endl;
202 *notify << "4 - end rounding randomization" << endl;
203 *notify << "5 - start/end rounding increase randomization" << endl;
204 *notify << "6 - additional offset of the upper anchors (to modify the segment angle)" << endl;
205
206 for(unsigned i = 0; i < psh_rand.size(); ++i) {
207 cairo_move_to(cr,Geom::Point(slider_margin + 15.0 * i, slider_bot));
208 cairo_line_to(cr,Geom::Point(slider_margin + 15.0 * i, slider_top));
209 }
210 cairo_set_line_width(cr,.5);
211 cairo_set_source_rgba (cr, 0., 0.3, 0., 1.);
212 cairo_stroke(cr);
213
214 cairo_set_line_width (cr, 2);
215 cairo_set_source_rgba (cr, 0., 0., 0.8, 1);
216
217 // Draw the curve and its offsets
218 D2<SBasis> B = psh.asBezier();
219 cairo_d2_sb(cr, B);
220 cairo_stroke(cr);
221
222 Coord offset = 30;
224 Piecewise<D2<SBasis> > offset_curve1 = Piecewise<D2<SBasis> >(B)+n*offset;
225 Piecewise<D2<SBasis> > offset_curve2 = Piecewise<D2<SBasis> >(B)-n*offset;
226 PathVector offset_path1 = path_from_piecewise(offset_curve1, 0.1);
227 PathVector offset_path2 = path_from_piecewise(offset_curve2, 0.1);
228 Piecewise<D2<SBasis> > tangent1 = unitVector(derivative(offset_curve1));
229 Piecewise<D2<SBasis> > tangent2 = unitVector(derivative(offset_curve2));
230 cairo_set_line_width (cr, 1);
231 cairo_path(cr, offset_path1);
232 cairo_path(cr, offset_path2);
233 cairo_stroke(cr);
234
235 cairo_set_source_rgba (cr, 0., 0.5, 0., 1);
236
237 double lambda1 = 1.0 - (psh_rand.pts[1][Y] - slider_top) * 2.0/w;
238 double lambda2 = 1.0 - (psh_rand.pts[2][Y] - slider_top) * 2.0/w;
239 double lambda3 = 1.0 - (psh_rand.pts[3][Y] - slider_top) * 2.0/w;
240 double lambda4 = 1.0 - (psh_rand.pts[4][Y] - slider_top) * 2.0/w;
241 double mu = 1.0 - (psh_rand.pts[5][Y] - slider_top) * 2.0/w;
242 //Point dir = Point(1,0) * (slider_bot - psh_rand.pts[0][Y]) / 2.5;
243 double off = 0.5 - (psh_rand.pts[6][Y] - slider_top) * 2.0/w;
244
245 double segdist = (slider_bot - psh_rand.pts[0][Y]) / (slider_bot - slider_top) * 0.1;
246 if (segdist < 0.01) {
247 segdist = 0.01;
248 }
249
250 vector<Point> pts_bot;
251 vector<Point> pts_top;
252 vector<Point> dirs_bot;
253 vector<Point> dirs_top;
254 int counter = 0;
255 for(double i = 0.0; i < 1.0; i += segdist) {
256 draw_cross(cr, offset_curve1.valueAt(i));
257 pts_bot.push_back(offset_curve1.valueAt(i + segdist * c1_bot[counter] * lambda1));
258 pts_top.push_back(offset_curve2.valueAt(i + segdist * (c2_top[counter] * lambda2 + 1/2.0) + off));
259 dirs_bot.push_back(tangent1.valueAt(i) * 20);
260 dirs_top.push_back(tangent2.valueAt(i) * 20);
261 ++counter;
262 }
263
264 for(int i = 0; i < num; ++i) {
265 cout << "c1_bot[" << i << "]: " << c1_bot[i] << endl;
266 }
267
268 for (int i = 0; i < num-1; ++i) {
269 Path path1;
270 //cout << "dirs_bot[" << i << "]: " << dirs_bot[i] << endl;
271 cout << "c3_bot[" << i << "]: " << c3_bot[i] << endl;
272 CubicBezier bc = create_bezier_again(pts_bot[i], pts_top[i],
273 dirs_bot[i], dirs_top[i],
274 0, 0, c3_bot[i] * lambda3, c4_top[i] * lambda4, mu, cr);
275 //c1_bot[i] * lambda1,
276 //c2_top[i] * lambda2,
277 //c3_bot[i] * lambda3,
278 //c4_top[i] * lambda4, mu, cr);
279
280 path1.append(bc);
281 cairo_path(cr, path1);
282
283 Path path2;
284 bc = create_bezier_again(pts_top[i], pts_bot[i+1],
285 dirs_top[i], dirs_bot[i+1],
286 0, 0, c4_bot[i] * lambda4, c3_top[i] * lambda3, mu, cr);
287 /*
288 bc = create_bezier_again(pts_top[i+1], pts_bot[i], dir,
289 1.0 - c2_top[i] * lambda2,
290 1.0 - c1_bot[i+1] * lambda1,
291 c3_top[i] * lambda3,
292 c4_bot[i] * lambda4, mu, cr);
293 */
294 path2.append(bc);
295 cairo_path(cr, path2);
296 }
297
298 cairo_stroke(cr);
299
300 Toy::draw(cr, notify, width, height, save,timer_stream);
301 }
302
303public:
304 OffsetTester() {
305 handles.push_back(&psh);
306 handles.push_back(&psh_rand);
307 /*
308 psh.pts.clear();
309 Point A(100,300);
310 //Point B(100,200);
311 //Point C(200,330);
312 Point D(200,100);
313 psh.push_back(A);
314 //psh.push_back(B);
315 //psh.push_back(C);
316 psh.push_back(D);
317 psh.push_back(Geom::Point(slider_margin,slider_bot));
318 */
319
320 for (int i = 0; i < num; ++i) {
321 c1_bot.push_back(uniform() - 0.5);
322 c1_top.push_back(uniform() - 0.5);
323 //c1_bot.push_back(1.0);
324 //c1_top.push_back(1.0);
325 c2_bot.push_back(uniform() - 0.5);
326 c2_top.push_back(uniform() - 0.5);
327
328 c3_bot.push_back(uniform());
329 c3_top.push_back(uniform());
330 c4_bot.push_back(uniform());
331 c4_top.push_back(uniform());
332 }
333
334 /*
335 for (int i = 0; i < num; ++i) {
336 c1_bot[i] = c1_bot[i] / 10.0;
337 c2_bot[i] = c2_bot[i] / 10.0;
338 c3_bot[i] = c3_bot[i] / 10.0;
339 c4_bot[i] = c4_bot[i] / 10.0;
340
341 c1_top[i] = c1_top[i] / 10.0;
342 c2_top[i] = c2_top[i] / 10.0;
343 c3_top[i] = c3_top[i] / 10.0;
344 c4_top[i] = c4_top[i] / 10.0;
345 }
346 */
347 }
348};
349
350int main(int argc, char **argv) {
351 init(argc, argv, new OffsetTester);
352 return 0;
353}
354
355/*
356 Local Variables:
357 mode:c++
358 c-file-style:"stroustrup"
359 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
360 indent-tabs-mode:nil
361 fill-column:99
362 End:
363*/
364//vim:filetype = cpp:expandtab:shiftwidth = 4:tabstop = 8:softtabstop = 4:encoding = utf-8:textwidth = 99 :
365
366
Various trigoniometric helper functions.
int main()
Bezier curve.
Conversion between Bezier control points and SBasis curves.
Adaptor that creates 2D functions from 1D ones.
Definition d2.h:55
Sequence of subpaths.
Definition pathvector.h:122
Sequence of contiguous curves, aka spline.
Definition path.h:353
void append(Curve *curve)
Add a new curve to the end of the path.
Definition path.h:750
Function defined as discrete pieces.
Definition piecewise.h:71
output_type valueAt(double t) const
Definition piecewise.h:102
Two-dimensional point that doubles as a vector.
Definition point.h:66
Rotation around the origin.
Definition transforms.h:187
Geom::D2< Geom::SBasis > asBezier()
std::vector< Geom::Point > pts
vector< Handle * > handles
virtual void save(FILE *f)
virtual void draw(cairo_t *cr, std::ostringstream *notify, int w, int h, bool save, std::ostringstream *timing_stream)
const double w
Definition conic-4.cpp:19
Lifts one dimensional objects into 2D.
BezierCurveN< 3 > CubicBezier
Cubic (order 3) Bezier curve.
double Coord
Floating point type used to store coordinates.
Definition coord.h:76
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
double offset
Various utility functions.
Definition affine.h:22
Coord length(LineSegment const &seg)
PathVector path_from_piecewise(Piecewise< D2< SBasis > > const &B, double tol, bool only_cubicbeziers=false)
Make a path from a d2 sbasis.
Bezier derivative(Bezier const &a)
Definition bezier.cpp:282
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
Piecewise< D2< SBasis > > unitVector(D2< SBasis > const &vect, double tol=.01, unsigned order=3)
int n
Definition spiro.cpp:57
STL namespace.
static gint counter
Definition box3d.cpp:39
void cairo_line_to(cairo_t *cr, Geom::Point p1)
void draw_cross(cairo_t *cr, Geom::Point h)
struct _cairo cairo_t
Definition path-cairo.h:16
void cairo_path(cairo_t *cr, Geom::Path const &p)
void cairo_move_to(cairo_t *cr, Geom::Point p1)
void cairo_d2_sb(cairo_t *cr, Geom::D2< Geom::SBasis > const &p)
Path intersection.
int off
Obsolete 2D SBasis function class.
two-dimensional geometric operators.
some std functions to work with (pw)s-basis
Conversion between SBasis and Bezier basis polynomials.
Polynomial in symmetric power basis (S-basis)
CubicBezier create_bezier_along_curve(Piecewise< D2< SBasis > > const &curve1, Piecewise< D2< SBasis > > const &curve2, double segdist, Coord const t1, Coord const t2, Point const &n, double c1, double c2, double, double, double, cairo_t *cr=NULL)
Definition scribble.cpp:111
vector< double > c1_top
Definition scribble.cpp:49
vector< double > c1_bot
Definition scribble.cpp:48
vector< double > c3_top
Definition scribble.cpp:53
vector< double > c4_bot
Definition scribble.cpp:54
int num
Definition scribble.cpp:47
vector< double > c2_top
Definition scribble.cpp:51
vector< double > c3_bot
Definition scribble.cpp:52
vector< double > c4_top
Definition scribble.cpp:55
CubicBezier create_bezier(Point const &anchor, double angle, double length, double dx1, double dx2, cairo_t *cr=NULL)
Definition scribble.cpp:57
void draw_segment(cairo_t *cr, Point const &p1, Point const &p2)
Definition scribble.cpp:27
vector< double > c2_bot
Definition scribble.cpp:50
CubicBezier create_bezier_again(Point const &anchor1, Point const &anchor2, Point const &dir1, Point const &dir2, double, double, double c3, double c4, double mu, cairo_t *cr=NULL)
Definition scribble.cpp:93
double height
double width
double uniform()
void cairo_set_source_rgba(cairo_t *cr, colour c)
void init(int argc, char **argv, Toy *t, int width=600, int height=600)
Affine transformation classes.