Geom::Piecewise<Geom::D2<Geom::SBasis> > LPEOffset::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { using namespace Geom; Piecewise<D2<SBasis> > output; double t = nearest_point(offset_pt, pwd2_in); Point A = pwd2_in.valueAt(t); double offset = L2(A - offset_pt); Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in)); Piecewise<D2<SBasis> > n = rot90(der); output = pwd2_in + n * offset; append_half_circle(output, pwd2_in.lastValue(), n.lastValue() * offset); output.continuousConcat(reverse(pwd2_in - n * offset)); append_half_circle(output, pwd2_in.firstValue(), -n.firstValue() * offset); // TODO: here we should remove self-overlaps by applying the "union" boolop // but we'd need to convert the path to a Shape, which is currently // broken in 2geom, so we return the unaltered path return output; }
Geom::Piecewise<Geom::D2<Geom::SBasis> > LPERuler::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { using namespace Geom; const int mminterval = static_cast<int>(major_mark_steps); const int i_shift = static_cast<int>(shift) % mminterval; int sign = (mark_dir == MARKDIR_RIGHT ? 1 : -1 ); Piecewise<D2<SBasis> >output(pwd2_in); Piecewise<D2<SBasis> >speed = derivative(pwd2_in); Piecewise<SBasis> arclength = arcLengthSb(pwd2_in); double totlength = arclength.lastValue(); //find at which times to draw a mark: std::vector<double> s_cuts; double real_mark_distance = mark_distance; gboolean success = sp_convert_distance(&real_mark_distance, unit, &sp_unit_get_by_id(SP_UNIT_PX)); double real_offset = offset; success = sp_convert_distance(&real_offset, unit, &sp_unit_get_by_id(SP_UNIT_PX)); for (double s = real_offset; s<totlength; s+=real_mark_distance){ s_cuts.push_back(s); } std::vector<std::vector<double> > roots = multi_roots(arclength, s_cuts); std::vector<double> t_cuts; for (unsigned v=0; v<roots.size();v++){ //FIXME: 2geom multi_roots solver seem to sometimes "repeat" solutions. //Here, we are supposed to have one and only one solution for each s. if(roots[v].size()>0) t_cuts.push_back(roots[v][0]); } //draw the marks for (unsigned i=0; i<t_cuts.size(); i++){ Point A = pwd2_in(t_cuts[i]); Point n = rot90(unit_vector(speed(t_cuts[i])))*sign; if ((i % mminterval) == i_shift) { output.concat (ruler_mark(A, n, MARK_MAJOR)); } else { output.concat (ruler_mark(A, n, MARK_MINOR)); } } //eventually draw a mark at start if ((border_marks == BORDERMARK_START || border_marks == BORDERMARK_BOTH) && (offset != 0.0 || i_shift != 0)){ Point A = pwd2_in.firstValue(); Point n = rot90(unit_vector(speed.firstValue()))*sign; output.concat (ruler_mark(A, n, MARK_MAJOR)); } //eventually draw a mark at end if (border_marks == BORDERMARK_END || border_marks == BORDERMARK_BOTH){ Point A = pwd2_in.lastValue(); Point n = rot90(unit_vector(speed.lastValue()))*sign; //speed.lastValue() is somtimes wrong when the path is closed: a tiny line seg might added at the end to fix rounding errors... //TODO: Find a better fix!! (How do we know if the path was closed?) if ( A == pwd2_in.firstValue() && speed.segs.size() > 1 && speed.segs.back()[X].size() <= 1 && speed.segs.back()[Y].size() <= 1 && speed.segs.back()[X].tailError(0) <= 1e-10 && speed.segs.back()[Y].tailError(0) <= 1e-10 ){ n = rot90(unit_vector(speed.segs[speed.segs.size()-2].at1()))*sign; } output.concat (ruler_mark(A, n, MARK_MAJOR)); } return output; }
void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) { srand(10); for(unsigned i=0; i<NB_SLIDER; i++){ adjuster[i].pos[X] = 30+i*20; if (adjuster[i].pos[Y]<100) adjuster[i].pos[Y] = 100; if (adjuster[i].pos[Y]>400) adjuster[i].pos[Y] = 400; cairo_move_to(cr, Point(30+i*20,100)); cairo_line_to(cr, Point(30+i*20,400)); cairo_set_line_width (cr, .5); cairo_set_source_rgba (cr, 0., 0., 0., 1); cairo_stroke(cr); } double tol = (400-adjuster[0].pos[Y])/300.*5+0.05; double tau = (400-adjuster[1].pos[Y])/300.; // double scale_topback = (250-adjuster[2].pos[Y])/150.*5; // double scale_botfront = (250-adjuster[3].pos[Y])/150.*5; // double scale_botback = (250-adjuster[4].pos[Y])/150.*5; // double growth = 1+(250-adjuster[5].pos[Y])/150.*.1; // double rdmness = 1+(400-adjuster[6].pos[Y])/300.*.9; // double bend_amount = (250-adjuster[7].pos[Y])/300.*100.; b1_handle.pts.back() = b2_handle.pts.front(); b1_handle.pts.front() = b2_handle.pts.back(); D2<SBasis> B1 = b1_handle.asBezier(); D2<SBasis> B2 = b2_handle.asBezier(); cairo_set_line_width(cr, 0.3); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_d2_sb(cr, B1); cairo_d2_sb(cr, B2); cairo_set_line_width (cr, .5); cairo_set_source_rgba (cr, 0., 0., 0., 1); cairo_stroke(cr); Piecewise<D2<SBasis> >B; B.concat(Piecewise<D2<SBasis> >(B1)); B.continuousConcat(Piecewise<D2<SBasis> >(B2)); Piecewise<SBasis> are; Point centroid_tmp(0,0); are = integral(dot(B, rot90(derivative(B))))*0.5; are = (are - are.firstValue())*(height/10) / (are.lastValue() - are.firstValue()); D2<Piecewise<SBasis> > are_graph(Piecewise<SBasis>(Linear(0, width)), are ); std::cout << are.firstValue() << "," << are.lastValue() << std::endl; cairo_save(cr); cairo_d2_pw_sb(cr, are_graph); cairo_set_line_width (cr, .5); cairo_set_source_rgba (cr, 0., 0., 0., 1); cairo_stroke(cr); cairo_restore(cr); #if 0 std::vector<Piecewise<D2<SBasis> > >f = split_at_discontinuities(B); std::list<Point> p = toPoly( f, tol); uncross(p); cairo_move_to(cr, p.front()); for (std::list<Point>::iterator pt = p.begin(); pt!=p.end(); ++pt){ cairo_line_to(cr, *pt); //if (i++>p.size()*tau) break; } cairo_set_line_width (cr, 3); cairo_set_source_rgba (cr, 1., 0., 0., .5); cairo_stroke(cr); if ( p.size()<3) return; double tot_area = 0; std::list<Point>::iterator a = p.begin(), b=a; b++; while(b!=p.end()){ tot_area += ((*b)[X]-(*a)[X]) * ((*b)[Y]+(*a)[Y])/2; a++;b++; } bool clockwise = tot_area < 0; std::vector<Triangle> tri; int nbiter =0; triangulate(p,tri,clockwise); cairo_set_source_rgba (cr, 1., 1., 0., 1); cairo_stroke(cr); for (unsigned i=0; i<tri.size(); i++){ cairo_move_to(cr, tri[i].a); cairo_line_to(cr, tri[i].b); cairo_line_to(cr, tri[i].c); cairo_line_to(cr, tri[i].a); cairo_set_line_width (cr, .5); cairo_set_source_rgba (cr, 0., 0., .9, .5); cairo_stroke(cr); cairo_move_to(cr, tri[i].a); cairo_line_to(cr, tri[i].b); cairo_line_to(cr, tri[i].c); cairo_line_to(cr, tri[i].a); cairo_set_source_rgba (cr, 0.5, 0., .9, .1); cairo_fill(cr); } #endif RandomGenerator rdm = RandomGenerator(B, tol); for(int i = 0; i < rdm.area()/5*tau; i++) { draw_handle(cr, rdm.pt()); } cairo_set_source_rgba (cr, 0., 0., 0., 1); cairo_stroke(cr); Toy::draw(cr, notify, width, height, save,timer_stream); }