#include <2geom/d2.h> #include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> #include <2geom/sbasis-geometric.h> #include <2geom/sbasis-math.h> #include <2geom/bezier-to-sbasis.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/path-intersection.h> #include <2geom/bezier-curve.h> #include <2geom/transforms.h> #include <2geom/angle.h> #include #include #include using std::vector; using namespace Geom; using namespace std; // TODO: // use path2 // replace Ray stuff with path2 line segments. //----------------------------------------------- void draw_segment(cairo_t* cr, Point const& p1, Point const& p2) { cairo_move_to(cr, p1); cairo_line_to(cr, p2); } void draw_segment(cairo_t* cr, Point const& p1, double angle, double length) { Point p2; p2[X] = length * std::cos(angle); p2[Y] = length * std::sin(angle); p2 += p1; draw_segment(cr, p1, p2); } void draw_segment(cairo_t* cr, LineSegment const& ls) { draw_segment(cr, ls[0], ls[1]); } int num = 30; vector c1_bot; vector c1_top; vector c2_bot; vector c2_top; vector c3_bot; vector c3_top; vector c4_bot; vector c4_top; CubicBezier create_bezier(Point const &anchor, double angle /* in degrees */, double length, double dx1, double dx2, cairo_t *cr = NULL) { Point A = anchor; Point dir = Point(1.0, 0) * Rotate(-angle) * length; Point B = anchor + dir; Point C = A - Point(1.0, 0) * dx1; Point D = B + Point(1.0, 0) * dx1; Point E = A + Point(1.0, 0) * dx2; Point F = B - Point(1.0, 0) * dx2; if (cr) { draw_cross(cr, A); draw_cross(cr, B); draw_cross(cr, C); draw_cross(cr, D); draw_cross(cr, E); draw_cross(cr, F); } return CubicBezier(C, E, F, D); } /* * Draws a single "scribble segment" (we use many of these to cover the whole curve). * * Let I1, I2 be two adjacent intervals (bounded by the points A1, A2, A3) on the lower and J1, J2 * two adjacent intervals (bounded by B1, B2, B3) on the upper parallel. Then we specify: * * - The point in I1 where the scribble line starts (given by a value in [0,1]) * - The point in J2 where the scribble line ends (given by a value in [0,1]) * - A point in I2 (1st intermediate point of the Bezier curve) * - A point in J1 (2nd intermediate point of the Bezier curve) * */ CubicBezier create_bezier_again(Point const &anchor1, Point const &anchor2, Point const &dir1, Point const &dir2, double /*c1*/, double /*c2*/, double c3, double c4, double mu, cairo_t *cr = NULL) { Point A = anchor1;// - dir * c1; Point B = anchor1 + dir1 * (c3 + mu); Point C = anchor2 - dir2 * (c4 + mu); Point D = anchor2;// + dir * c2; if (cr) { draw_cross(cr, A); //draw_cross(cr, B); //draw_cross(cr, C); //draw_cross(cr, D); } return CubicBezier(A, B, C, D); } CubicBezier create_bezier_along_curve(Piecewise > const &curve1, Piecewise > const &curve2, double segdist, Coord const t1, Coord const t2, Point const &n, double c1, double c2, double /*c3*/, double /*c4*/, double /*mu*/, cairo_t *cr = NULL) { cout << "create_bezier_along_curve -- start" << endl; /* Point A = curve1.valueAt(t1 - c1); Point B = curve1.valueAt(t1) + n * (c3 + mu); Point C = curve2.valueAt(t2) - n * (c4 + mu); Point D = curve2.valueAt(t2 + c2); */ Point A = curve1.valueAt(t1 - c1 * segdist); Point B = curve1.valueAt(t1) + n * 0.1; Point C = curve2.valueAt(t2) - n * 0.1; Point D = curve2.valueAt(t2 + c2 * segdist); if (cr) { draw_cross(cr, A); //draw_cross(cr, B); //draw_cross(cr, C); //draw_cross(cr, D); } cout << "create_bezier_along_curve -- end" << endl; return CubicBezier(A, B, C, D); } class OffsetTester: public Toy { PointSetHandle psh; PointSetHandle psh_rand; void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override { double w = 600; double slider_top = w/4.; double slider_bot = w*3./4.; double slider_margin = 40; double slider_middle = (slider_top + slider_bot) / 2; if(psh.pts.empty()) { psh.pts.emplace_back(200,300); psh.pts.emplace_back(350,250); psh.pts.emplace_back(500,280); psh.pts.emplace_back(700,300); psh.pts.emplace_back(400,300); psh.pts.emplace_back(550,250); psh.pts.emplace_back(700,280); psh.pts.emplace_back(900,300); psh.pts.emplace_back(900,500); psh.pts.emplace_back(700,480); psh.pts.emplace_back(550,450); psh.pts.emplace_back(400,500); psh_rand.pts.emplace_back(slider_margin,slider_bot); psh_rand.pts.emplace_back(slider_margin,slider_top); psh_rand.pts.emplace_back(slider_margin,slider_top); psh_rand.pts.emplace_back(slider_margin,slider_top); psh_rand.pts.emplace_back(slider_margin,slider_top); psh_rand.pts.emplace_back(slider_margin,slider_bot); psh_rand.pts.emplace_back(slider_margin,slider_middle); } psh_rand.pts[0][X] = slider_margin; if (psh_rand.pts[0][Y]slider_bot) psh_rand.pts[0][Y] = slider_bot; psh_rand.pts[1][X] = slider_margin + 15; if (psh_rand.pts[1][Y]slider_bot) psh_rand.pts[1][Y] = slider_bot; psh_rand.pts[2][X] = slider_margin + 30; if (psh_rand.pts[2][Y]slider_bot) psh_rand.pts[2][Y] = slider_bot; psh_rand.pts[3][X] = slider_margin + 45; if (psh_rand.pts[3][Y]slider_bot) psh_rand.pts[3][Y] = slider_bot; psh_rand.pts[4][X] = slider_margin + 60; if (psh_rand.pts[4][Y]slider_bot) psh_rand.pts[4][Y] = slider_bot; psh_rand.pts[5][X] = slider_margin + 75; if (psh_rand.pts[5][Y]slider_bot) psh_rand.pts[5][Y] = slider_bot; psh_rand.pts[6][X] = slider_margin + 90; if (psh_rand.pts[6][Y]slider_bot) psh_rand.pts[6][Y] = slider_bot; *notify << "Sliders:" << endl << endl << endl << endl; *notify << "0 - segment distance" << endl; *notify << "1 - start anchor randomization" << endl; *notify << "2 - end anchor randomization" << endl; *notify << "3 - start rounding randomization" << endl; *notify << "4 - end rounding randomization" << endl; *notify << "5 - start/end rounding increase randomization" << endl; *notify << "6 - additional offset of the upper anchors (to modify the segment angle)" << endl; for(unsigned i = 0; i < psh_rand.size(); ++i) { cairo_move_to(cr,Geom::Point(slider_margin + 15.0 * i, slider_bot)); cairo_line_to(cr,Geom::Point(slider_margin + 15.0 * i, slider_top)); } cairo_set_line_width(cr,.5); cairo_set_source_rgba (cr, 0., 0.3, 0., 1.); cairo_stroke(cr); cairo_set_line_width (cr, 2); cairo_set_source_rgba (cr, 0., 0., 0.8, 1); // Draw the curve and its offsets D2 B = psh.asBezier(); cairo_d2_sb(cr, B); cairo_stroke(cr); Coord offset = 30; Piecewise > n = rot90(unitVector(derivative(B))); Piecewise > offset_curve1 = Piecewise >(B)+n*offset; Piecewise > offset_curve2 = Piecewise >(B)-n*offset; PathVector offset_path1 = path_from_piecewise(offset_curve1, 0.1); PathVector offset_path2 = path_from_piecewise(offset_curve2, 0.1); Piecewise > tangent1 = unitVector(derivative(offset_curve1)); Piecewise > tangent2 = unitVector(derivative(offset_curve2)); cairo_set_line_width (cr, 1); cairo_path(cr, offset_path1); cairo_path(cr, offset_path2); cairo_stroke(cr); cairo_set_source_rgba (cr, 0., 0.5, 0., 1); double lambda1 = 1.0 - (psh_rand.pts[1][Y] - slider_top) * 2.0/w; double lambda2 = 1.0 - (psh_rand.pts[2][Y] - slider_top) * 2.0/w; double lambda3 = 1.0 - (psh_rand.pts[3][Y] - slider_top) * 2.0/w; double lambda4 = 1.0 - (psh_rand.pts[4][Y] - slider_top) * 2.0/w; double mu = 1.0 - (psh_rand.pts[5][Y] - slider_top) * 2.0/w; //Point dir = Point(1,0) * (slider_bot - psh_rand.pts[0][Y]) / 2.5; double off = 0.5 - (psh_rand.pts[6][Y] - slider_top) * 2.0/w; double segdist = (slider_bot - psh_rand.pts[0][Y]) / (slider_bot - slider_top) * 0.1; if (segdist < 0.01) { segdist = 0.01; } vector pts_bot; vector pts_top; vector dirs_bot; vector dirs_top; int counter = 0; for(double i = 0.0; i < 1.0; i += segdist) { draw_cross(cr, offset_curve1.valueAt(i)); pts_bot.push_back(offset_curve1.valueAt(i + segdist * c1_bot[counter] * lambda1)); pts_top.push_back(offset_curve2.valueAt(i + segdist * (c2_top[counter] * lambda2 + 1/2.0) + off)); dirs_bot.push_back(tangent1.valueAt(i) * 20); dirs_top.push_back(tangent2.valueAt(i) * 20); ++counter; } for(int i = 0; i < num; ++i) { cout << "c1_bot[" << i << "]: " << c1_bot[i] << endl; } for (int i = 0; i < num-1; ++i) { Path path1; //cout << "dirs_bot[" << i << "]: " << dirs_bot[i] << endl; cout << "c3_bot[" << i << "]: " << c3_bot[i] << endl; CubicBezier bc = create_bezier_again(pts_bot[i], pts_top[i], dirs_bot[i], dirs_top[i], 0, 0, c3_bot[i] * lambda3, c4_top[i] * lambda4, mu, cr); //c1_bot[i] * lambda1, //c2_top[i] * lambda2, //c3_bot[i] * lambda3, //c4_top[i] * lambda4, mu, cr); path1.append(bc); cairo_path(cr, path1); Path path2; bc = create_bezier_again(pts_top[i], pts_bot[i+1], dirs_top[i], dirs_bot[i+1], 0, 0, c4_bot[i] * lambda4, c3_top[i] * lambda3, mu, cr); /* bc = create_bezier_again(pts_top[i+1], pts_bot[i], dir, 1.0 - c2_top[i] * lambda2, 1.0 - c1_bot[i+1] * lambda1, c3_top[i] * lambda3, c4_bot[i] * lambda4, mu, cr); */ path2.append(bc); cairo_path(cr, path2); } cairo_stroke(cr); Toy::draw(cr, notify, width, height, save,timer_stream); } public: OffsetTester() { handles.push_back(&psh); handles.push_back(&psh_rand); /* psh.pts.clear(); Point A(100,300); //Point B(100,200); //Point C(200,330); Point D(200,100); psh.push_back(A); //psh.push_back(B); //psh.push_back(C); psh.push_back(D); psh.push_back(Geom::Point(slider_margin,slider_bot)); */ for (int i = 0; i < num; ++i) { c1_bot.push_back(uniform() - 0.5); c1_top.push_back(uniform() - 0.5); //c1_bot.push_back(1.0); //c1_top.push_back(1.0); c2_bot.push_back(uniform() - 0.5); c2_top.push_back(uniform() - 0.5); c3_bot.push_back(uniform()); c3_top.push_back(uniform()); c4_bot.push_back(uniform()); c4_top.push_back(uniform()); } /* for (int i = 0; i < num; ++i) { c1_bot[i] = c1_bot[i] / 10.0; c2_bot[i] = c2_bot[i] / 10.0; c3_bot[i] = c3_bot[i] / 10.0; c4_bot[i] = c4_bot[i] / 10.0; c1_top[i] = c1_top[i] / 10.0; c2_top[i] = c2_top[i] / 10.0; c3_top[i] = c3_top[i] / 10.0; c4_top[i] = c4_top[i] / 10.0; } */ } }; int main(int argc, char **argv) { init(argc, argv, new OffsetTester); return 0; } /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ //vim:filetype = cpp:expandtab:shiftwidth = 4:tabstop = 8:softtabstop = 4:encoding = utf-8:textwidth = 99 :