void draw(cairo_t *cr, int t) { if(t - last_time > path.domain().max()) add_section(random_d2()); if(t - last_time - length > path.cuts[1]) { Piecewise<D2<SBasis> > new_path; new_path.push_cut(0); for(unsigned i = 1; i < path.size(); i++) { new_path.push(path[i], path.cuts[i+1] - path.cuts[1]); } last_time = t - length; path = new_path; } cairo_set_source_rgb(cr, red, green, blue); Piecewise<D2<SBasis> > port = portion(path, std::max(t - last_time - length, 0.), t - last_time); cairo_pw_d2_sb(cr, port); cairo_stroke(cr); double d = 4; cairo_set_dash(cr, &d, 1, 0); for(unsigned i = 1; i < path.size(); i++) { if(path[i].at0() != path[i-1].at1()) { draw_line_seg(cr, path[i].at0(), path[i-1].at1()); } } cairo_stroke(cr); cairo_set_dash(cr, &d, 0, 0); cairo_set_source_rgb(cr, 0., 0., 1.); dot_plot(cr, path, std::max(t - last_time - length, 0.), t - last_time); }
/** Return a function which gives the angle of vect at each point. \param vect a piecewise parameteric curve. \param tol the maximum error allowed. \param order the maximum degree to use for approximation \relates Piecewise */ Piecewise<SBasis> Geom::atan2(Piecewise<D2<SBasis> > const &vect, double tol, unsigned order){ Piecewise<SBasis> result; Piecewise<D2<SBasis> > v = cutAtRoots(vect,tol); result.cuts.push_back(v.cuts.front()); for (unsigned i=0; i<v.size(); i++){ D2<SBasis> vi = RescaleForNonVanishingEnds(v.segs[i]); SBasis x=vi[0], y=vi[1]; Piecewise<SBasis> angle; angle = divide (x*derivative(y)-y*derivative(x), x*x+y*y, tol, order); //TODO: I don't understand this - sign. angle = integral(-angle); Point vi0 = vi.at0(); angle += -std::atan2(vi0[1],vi0[0]) - angle[0].at0(); //TODO: deal with 2*pi jumps form one seg to the other... //TODO: not exact at t=1 because of the integral. //TODO: force continuity? angle.setDomain(Interval(v.cuts[i],v.cuts[i+1])); result.concat(angle); } return result; }
/** 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; }
virtual void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save) { cairo_set_source_rgba (cr, 0., 0., 0., 1); cairo_set_line_width (cr, 1); Piecewise<SBasis> pws; //pws = Geom::cos(Linear(0,100)) + 3; pws = Geom::sqrt(Linear(0,100)); //pws = log(Interval(1,8)); //Piecewise<SBasis> l(Linear(-100,100)); //Piecewise<SBasis> one(Linear(1,1)); //pws = Geom::reciprocal(l*l + one)*l + l; //pws = xlogx(Interval(0.5,3)); //pws = Geom::reciprocal(pws); //pws = -integral(Geom::reciprocal(Linear(1,2)))*Piecewise<SBasis>(Linear(1,2)); pws = -pws*width/4 + width/2; pws.scaleDomain(width/2); pws.offsetDomain(width/4); cairo_pw(cr, pws); cairo_stroke(cr); cairo_set_source_rgba (cr, 0., 0., .5, 1.); cairo_horiz(cr, 500, pws.cuts); cairo_stroke(cr); *notify << "total pieces: " << pws.size(); Toy::draw(cr, notify, width, height, save); }
void reverse_direction(int t) { path = portion(path, 0, t - last_time); D2<SBasis> seg = random_d2(), last = path[path.size()-1]; for(unsigned c = 0; c < 2; c++) for(unsigned d = 1; d < seg[c].size() && d < last[c].size(); d++) seg[c][d][0] = -last[c][d][1]; add_section(seg); }
void cairo_pw(cairo_t *cr, Piecewise<SBasis> p) { for(unsigned i = 0; i < p.size(); i++) { D2<SBasis> B; B[0] = Linear(p.cuts[i], p.cuts[i+1]); B[1] = p[i]; cairo_d2_sb(cr, B); } }
void cairo_pw(cairo_t *cr, Piecewise<SBasis> p, double hscale=1., double vscale=1.) { for(unsigned i = 0; i < p.size(); i++) { D2<SBasis> B; B[0] = Linear(150+p.cuts[i]*hscale, 150+p.cuts[i+1]*hscale); B[1] = Linear(450) - p[i]*vscale; cairo_d2_sb(cr, B); } }
/** Compute the cosine of a function. \param f function \param tol maximum error \param order maximum degree polynomial to use */ Piecewise<SBasis> cos(Piecewise<SBasis> const &f, double tol, int order){ Piecewise<SBasis> result; for (unsigned i=0; i<f.size(); i++){ Piecewise<SBasis> cosfi = cos(f.segs[i],tol,order); cosfi.setDomain(Interval(f.cuts[i],f.cuts[i+1])); result.concat(cosfi); } return result; }
/** Calculates the length of a Piecewise<D2<SBasis> > through gsl integration. \param s the Element. \param tol the maximum error allowed. \relates Piecewise If you only want the total length, this routine faster and more accurate than constructing an arcLengthSb. */ double Geom::length(Piecewise<D2<SBasis> > const &s, double tol){ double result = 0; double abs_error = 0; for (unsigned i=0; i < s.size();i++){ length_integrating(s[i], result, abs_error, tol); } return result; }
/** 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 */ Piecewise<D2<SBasis> > Geom::arc_length_parametrization(Piecewise<D2<SBasis> > const &M, unsigned order, double tol){ Piecewise<D2<SBasis> > result; for (unsigned i=0; i<M.size(); i++) { result.concat( arc_length_parametrization(M[i],order,tol) ); } return result; }
/** returns a function giving the curvature at each point in M. \param M the Element. \param tol the maximum error allowed. \relates Piecewise \todo claimed incomplete. Check. */ Piecewise<SBasis> Geom::curvature(Piecewise<D2<SBasis> > const &V, double tol){ Piecewise<SBasis> result; Piecewise<D2<SBasis> > VV = cutAtRoots(V); result.cuts.push_back(VV.cuts.front()); for (unsigned i=0; i<VV.size(); i++){ Piecewise<SBasis> curv_seg; curv_seg = curvature(VV.segs[i],tol); curv_seg.setDomain(Interval(VV.cuts[i],VV.cuts[i+1])); result.concat(curv_seg); } return result; }
/** Return a Piecewise<D2<SBasis> > which points in the same direction as V_in, but has unit_length. \param V_in the original path. \param tol the maximum error allowed. \param order the maximum degree to use for approximation unitVector(x,y) is computed as (b,-a) where a and b are solutions of: ax+by=0 (eqn1) and a^2+b^2=1 (eqn2) \relates Piecewise */ Piecewise<D2<SBasis> > Geom::unitVector(Piecewise<D2<SBasis> > const &V, double tol, unsigned order){ Piecewise<D2<SBasis> > result; Piecewise<D2<SBasis> > VV = cutAtRoots(V); result.cuts.push_back(VV.cuts.front()); for (unsigned i=0; i<VV.size(); i++){ Piecewise<D2<SBasis> > unit_seg; unit_seg = unitVector(VV.segs[i],tol, order); unit_seg.setDomain(Interval(VV.cuts[i],VV.cuts[i+1])); result.concat(unit_seg); } return result; }
void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) { Geom::Point dir(1,-2); for(unsigned dim = 0; dim < 2; dim++) { Geom::Point dir(0,0); dir[dim] = 1; for(unsigned vi = 0; vi < sb2[dim].vs; vi++) for(unsigned ui = 0; ui < sb2[dim].us; ui++) for(unsigned iv = 0; iv < 2; iv++) for(unsigned iu = 0; iu < 2; iu++) { unsigned corner = iu + 2*iv; unsigned i = ui + vi*sb2[dim].us; Geom::Point base((2*(iu+ui)/(2.*ui+1)+1)*width/4., (2*(iv+vi)/(2.*vi+1)+1)*width/4.); if(vi == 0 && ui == 0) { base = Geom::Point(width/4., width/4.); } double dl = dot((hand.pts[corner+4*i] - base), dir)/dot(dir,dir); sb2[dim][i][corner] = dl/(width/2)*pow(4.0,(double)ui+vi); } } cairo_d2_sb2d(cr, sb2, dir*0.1, width); cairo_set_source_rgba (cr, 0., 0., 0, 0.5); cairo_stroke(cr); for(unsigned i = 0; i < path_a_pw.size(); i++) { D2<SBasis> B = path_a_pw[i]; //const int depth = sb2[0].us*sb2[0].vs; //const int surface_hand.pts = 4*depth; //D2<SBasis> B = hand.pts_to_sbasis<3>(hand.pts.begin() + surface_hand.pts); cairo_d2_sb(cr, B); for(unsigned dim = 0; dim < 2; dim++) { std::vector<double> r = roots(B[dim]); for(unsigned i = 0; i < r.size(); i++) draw_cross(cr, B(r[i])); r = roots(Linear(width/4) - B[dim]); for(unsigned i = 0; i < r.size(); i++) draw_cross(cr, B(r[i])); } cairo_set_source_rgba (cr, 0., 0.125, 0, 1); cairo_stroke(cr); B *= (4./width); D2<SBasis> tB = compose_each(sb2, B); B = B*(width/2) + Geom::Point(width/4, width/4); tB = tB*(width/2) + Geom::Point(width/4, width/4); cairo_d2_sb(cr, tB); } //*notify << "bo = " << sb2.index(0,0); Toy::draw(cr, notify, width, height, save,timer_stream); }
//================================================================= //TODO: what's this for?!?! Piecewise<D2<SBasis> > Geom::cutAtRoots(Piecewise<D2<SBasis> > const &M, double ZERO){ vector<double> rts; for (unsigned i=0; i<M.size(); i++){ vector<double> seg_rts = roots((M.segs[i])[0]); seg_rts = vect_intersect(seg_rts, roots((M.segs[i])[1]), ZERO); Linear mapToDom = Linear(M.cuts[i],M.cuts[i+1]); for (unsigned r=0; r<seg_rts.size(); r++){ seg_rts[r]= mapToDom(seg_rts[r]); } rts.insert(rts.end(),seg_rts.begin(),seg_rts.end()); } return partition(M,rts); }
/** * Centroid using sbasis integration. \param p the Element. \param centroid on return contains the centroid of the shape \param area on return contains the signed area of the shape. \relates Piecewise This approach uses green's theorem to compute the area and centroid using integrals. For curved shapes this is much faster than converting to polyline. Note that without an uncross operation the output is not the absolute area. * Returned values: 0 for normal execution; 2 if area is zero, meaning centroid is meaningless. */ unsigned Geom::centroid(Piecewise<D2<SBasis> > const &p, Point& centroid, double &area) { Point centroid_tmp(0,0); double atmp = 0; for(unsigned i = 0; i < p.size(); i++) { SBasis curl = dot(p[i], rot90(derivative(p[i]))); SBasis A = integral(curl); D2<SBasis> C = integral(multiply(curl, p[i])); atmp += A.at1() - A.at0(); centroid_tmp += C.at1()- C.at0(); // first moment. } // join ends centroid_tmp *= 2; Point final = p[p.size()-1].at1(), initial = p[0].at0(); const double ai = cross(final, initial); atmp += ai; centroid_tmp += (final + initial)*ai; // first moment. area = atmp / 2; if (atmp != 0) { centroid = centroid_tmp / (3 * atmp); return 0; } return 2; }
void plot3d(cairo_t *cr, Piecewise<SBasis> const &x, Piecewise<SBasis> const &y, Piecewise<SBasis> const &z, Frame frame){ Piecewise<SBasis> xx = partition(x,y.cuts); Piecewise<SBasis> xxx = partition(xx,z.cuts); Piecewise<SBasis> yyy = partition(y,xxx.cuts); Piecewise<SBasis> zzz = partition(z,xxx.cuts); for (unsigned i=0; i<xxx.size(); i++){ plot3d(cr, xxx[i], yyy[i], zzz[i], frame); } }
static void plot(cairo_t* cr, Piecewise<SBasis> const &f,double vscale=1){ D2<Piecewise<SBasis> > plot; plot[1]=-f; plot[1]*=vscale; plot[1]+=300; plot[0].cuts.push_back(f.cuts.front()); plot[0].cuts.push_back(f.cuts.back()); plot[0].segs.push_back(Linear(150,450)); cairo_d2_pw_sb(cr, plot); for (unsigned i=1; i<f.size(); i++){ cairo_move_to(cr, Point(150+f.cuts[i]*300,300)); cairo_line_to(cr, Point(150+f.cuts[i]*300,300-vscale*f.segs[i].at0())); } }
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); }
static void plot(cairo_t* cr, Piecewise<SBasis> const &f,double vscale=1){ for (unsigned i=0;i<f.size();i++){ plot(cr,f.segs[i],vscale,f.cuts[i],f.cuts[i+1]); draw_cross(cr,Geom::Point(f.cuts[i]*300 + 150, f.segs[i][0][0]*(-vscale) + 450)); } }