/** Reparameterise M to have unit speed. \param M the Element. \param tol the maximum error allowed. \param order the maximum degree to use for approximation \relates Piecewise, D2 */ Piecewise<D2<SBasis> > Geom::arc_length_parametrization(D2<SBasis> const &M, unsigned order, double tol){ Piecewise<D2<SBasis> > u; u.push_cut(0); Piecewise<SBasis> s = arcLengthSb(Piecewise<D2<SBasis> >(M),tol); for (unsigned i=0; i < s.size();i++){ double t0=s.cuts[i],t1=s.cuts[i+1]; if ( are_near(s(t0),s(t1)) ) { continue; } D2<SBasis> sub_M = compose(M,Linear(t0,t1)); D2<SBasis> sub_u; for (unsigned dim=0;dim<2;dim++){ SBasis sub_s = s.segs[i]; sub_s-=sub_s.at0(); sub_s/=sub_s.at1(); sub_u[dim]=compose_inverse(sub_M[dim],sub_s, order, tol); } u.push(sub_u,s(t1)); } return u; }
void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save) { Geom::Point dir(1,-2); D2<Piecewise<SBasis> > B = make_cuts_independent(path_a_pw); cairo_set_source_rgba (cr, 0., 0.125, 0, 1); if(0) { D2<Piecewise<SBasis> > tB(cos(B[0]*0.1)*(brush_handle.pos[0]/100) + B[0], cos(B[1]*0.1)*(brush_handle.pos[1]/100) + B[1]); cairo_d2_pw_sb(cr, tB); } else { Piecewise<SBasis> r2 = (dot(path_a_pw - brush_handle.pos, path_a_pw - brush_handle.pos)); Piecewise<SBasis> rc; rc.push_cut(0); rc.push(SBasis(Linear(1, 1)), 2); rc.push(SBasis(Linear(1, 0)), 4); rc.push(SBasis(Linear(0, 0)), 30); rc *= 10; rc.scaleDomain(1000); Piecewise<SBasis> swr; swr.push_cut(0); swr.push(SBasis(Linear(0, 1)), 2); swr.push(SBasis(Linear(1, 0)), 4); swr.push(SBasis(Linear(0, 0)), 30); swr *= 10; swr.scaleDomain(1000); cairo_pw(cr, swr);// + (height - 100)); D2<Piecewise<SBasis> > uB = make_cuts_independent(unitVector(path_a_pw - brush_handle.pos)); D2<Piecewise<SBasis> > tB(compose(rc, (r2))*uB[0] + B[0], compose(rc, (r2))*uB[1] + B[1]); cairo_d2_pw_sb(cr, tB); //path_a_pw = sectionize(tB); } cairo_stroke(cr); *notify << path_a_pw.size(); Toy::draw(cr, notify, width, height, save); }
void draw( cairo_t *cr, std::ostringstream *notify, int width, int height, bool save ) { Point p = ph.pos; Point np = p; std::vector<Point> nps; cairo_set_line_width (cr, 0.3); cairo_set_source_rgb(cr, 0,0,0); switch ( choice ) { case '1': { LineSegment seg(psh.pts[0], psh.pts[1]); cairo_move_to(cr, psh.pts[0]); cairo_curve(cr, seg); double t = seg.nearestPoint(p); np = seg.pointAt(t); if ( toggles[0].on ) { nps.push_back(np); } break; } case '2': { SVGEllipticalArc earc; bool earc_constraints_satisfied = true; try { earc.set(psh.pts[0], 200, 150, 0, true, true, psh.pts[1]); } catch( RangeError e ) { earc_constraints_satisfied = false; } if ( earc_constraints_satisfied ) { cairo_d2_sb(cr, earc.toSBasis()); if ( toggles[0].on ) { std::vector<double> t = earc.allNearestPoints(p); for ( unsigned int i = 0; i < t.size(); ++i ) nps.push_back(earc.pointAt(t[i])); } else { double t = earc.nearestPoint(p); np = earc.pointAt(t); } } break; } case '3': { D2<SBasis> A = psh.asBezier(); cairo_d2_sb(cr, A); if ( toggles[0].on ) { std::vector<double> t = Geom::all_nearest_points(p, A); for ( unsigned int i = 0; i < t.size(); ++i ) nps.push_back(A(t[i])); } else { double t = nearest_point(p, A); np = A(t); } break; } case '4': { D2<SBasis> A = handles_to_sbasis(psh.pts.begin(), 3); D2<SBasis> B = handles_to_sbasis(psh.pts.begin() + 3, 3); D2<SBasis> C = handles_to_sbasis(psh.pts.begin() + 6, 3); D2<SBasis> D = handles_to_sbasis(psh.pts.begin() + 9, 3); cairo_d2_sb(cr, A); cairo_d2_sb(cr, B); cairo_d2_sb(cr, C); cairo_d2_sb(cr, D); Piecewise< D2<SBasis> > pwc; pwc.push_cut(0); pwc.push_seg(A); pwc.push_cut(0.25); pwc.push_seg(B); pwc.push_cut(0.50); pwc.push_seg(C); pwc.push_cut(0.75); pwc.push_seg(D); pwc.push_cut(1); if ( toggles[0].on ) { std::vector<double> t = Geom::all_nearest_points(p, pwc); for ( unsigned int i = 0; i < t.size(); ++i ) nps.push_back(pwc(t[i])); } else { double t = Geom::nearest_point(p, pwc); np = pwc(t); } break; } case '5': { closed_toggle = true; BezierCurve<2> A(psh.pts[0], psh.pts[1], psh.pts[2]); BezierCurve<3> B(psh.pts[2], psh.pts[3], psh.pts[4], psh.pts[5]); BezierCurve<3> C(psh.pts[5], psh.pts[6], psh.pts[7], psh.pts[8]); Path path; path.append(A); path.append(B); path.append(C); SVGEllipticalArc D; bool earc_constraints_satisfied = true; try { D.set(psh.pts[8], 160, 80, 0, true, true, psh.pts[9]); } catch( RangeError e ) { earc_constraints_satisfied = false; } if ( earc_constraints_satisfied ) path.append(D); if ( toggles[1].on ) path.close(true); cairo_path(cr, path); if ( toggles[0].on ) { std::vector<double> t = path.allNearestPoints(p); for ( unsigned int i = 0; i < t.size(); ++i ) nps.push_back(path.pointAt(t[i])); } else { double t = path.nearestPoint(p); np = path.pointAt(t); } break; } case '6': { closed_toggle = true; PathVector pathv = paths_b*Translate(psh.pts[0]-paths_b[0][0].initialPoint()); //std::cout << pathv.size() << std::endl; cairo_path(cr, pathv); if ( toggles[0].on ) { std::vector<PathVectorPosition> t = allNearestPoints(pathv, p); for ( unsigned int i = 0; i < t.size(); ++i ) nps.push_back(pointAt(pathv, t[i])); } else { boost::optional<PathVectorPosition> t = nearestPoint(pathv, p); if(t) np = pointAt(pathv, *t); } break; } default: { *notify << std::endl; for (int i = FIRST_ITEM; i < TOTAL_ITEMS; ++i) { *notify << " " << i << " - " << menu_items[i] << std::endl; } Toy::draw(cr, notify, width, height, save); return; } } if ( toggles[0].on ) { for ( unsigned int i = 0; i < nps.size(); ++i ) { cairo_move_to(cr, p); cairo_line_to(cr, nps[i]); } } else { cairo_move_to(cr, p); cairo_line_to(cr, np); } cairo_stroke(cr); toggles[0].bounds = Rect( Point(10, height - 50), Point(10, height - 50) + Point(80,25) ); toggles[0].draw(cr); if ( closed_toggle ) { toggles[1].bounds = Rect( Point(100, height - 50), Point(100, height - 50) + Point(80,25) ); toggles[1].draw(cr); closed_toggle = false; } Toy::draw(cr, notify, width, height, save); }