#include <2geom/d2.h> #include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> #include <2geom/sbasis-geometric.h> #include <2geom/bezier-to-sbasis.h> #include #include #include using std::vector; using namespace Geom; class NormalBundle : public std::vector >{ public: vector lengths; NormalBundle(){lengths.push_back(0.);} void setBase(D2 const &B, double tol); void draw(cairo_t* cr, unsigned NbSections =5,unsigned NbFibre=5); }; vector > compose(NormalBundle const &NB, D2 const &Binit, Geom::Point Origin=Geom::Point(0,0)); //-------------------------------------------- void SBasis1d_to_2d(D2 C0, D2 C1, D2 &S){ for(unsigned dim = 0; dim < 2; dim++) { //**** C0 and C1 should have the same size... for (unsigned i=C0[dim].size();i const &B, double tol=0.01) { D2 dB = derivative(B); vector cuts; Piecewise > unitV=unitVector(dB); //TODO: clean this up, use arc_length_parametrization... cuts=unitV.cuts; double t0=0,t1,L=0; for(unsigned i=1;i subB=compose(B,Linear(t0,t1)); D2 S; SBasis1d_to_2d(subB, subB+rot90(unitV[i]), S); push_back(S); SBasis s=integral(dot(compose(dB,Linear(t0,t1)),unitV[i])); L+=(s(1)-s(0))*(t1-t0); lengths.push_back(L); t0=t1; } } void NormalBundle::draw(cairo_t *cr, unsigned NbLi, unsigned NbCol) { D2 B; vector > tB; //Geom::Point Seg[2]; B[1]=Linear(-100,100); double width=*(lengths.rbegin()); if (NbCol>0) for(unsigned ui = 0; ui <= NbCol; ui++) { B[0]=Linear(ui*width/NbCol); tB = compose(*this,B); if (tB.size()>0) cairo_d2_sb(cr, tB[0]); } B[0]=SBasis(Linear(0,1)); for(unsigned ui = 0; ui <= NbLi; ui++) { B[1]=Linear(-100+ui*200/NbLi); for(unsigned i = 0; i section=composeEach((*this)[i],B); cairo_d2_sb(cr, section); } } } vector > compose(NormalBundle const &NB, D2 const &Binit, Geom::Point Origin){ vector > result; D2 B=Binit; D2 Bcut; vector Roots; std::map Cuts; unsigned idx; B = B + (-Origin); //--Find intersections with fibers over segment ends. for(unsigned i=0; i<=NB.size();i++){ Roots=roots(B[0]); for (vector::iterator root=Roots.begin(); root!=Roots.end();root++) Cuts[*root]=i; if((Cuts.count(0.)==0) and ((B[0].valueAt(0.)<=0) or i==NB.size())) Cuts[0.]=i; if((Cuts.count(1.)==0) and ((B[0].valueAt(1.)<=0) or i==NB.size())) Cuts[1.]=i; if (i::iterator cut=Cuts.begin(); std::map::iterator next=cut; next++; while(next!=Cuts.end()){ double t0=(*cut).first; unsigned idx0=(*cut).second; double t1=(*next).first; unsigned idx1=(*next).second; if (idx0 != idx1){ idx=std::min(idx0,idx1); } else if(B[0]((t0+t1)/2) < NB.lengths[idx0]) { // we have a left 'bump', idx=idx0-1; } else if(B[0]((t0+t1)/2) == NB.lengths[idx0]) { //we have a vertical segment!... idx= (idx0==NB.size())? idx0-1:idx0; } else //we have a right 'bump'. idx=idx0; //--trim version... if (idx>=0 and idx B = B_handle.asBezier(); D2 P = P_handle.asBezier(); Geom::Point O = O_handle.pos; NormalBundle NBdle; NBdle.setBase(B); Geom::Point Oo(O[0]+*(NBdle.lengths.rbegin()),O[1]); vector > Q=compose(NBdle,P,O); cairo_set_line_width (cr, 0.5); //Base lines cairo_set_source_rgba (cr, 0.9, 0., 0., 1); cairo_d2_sb(cr, B); draw_line_seg(cr, O, Oo); cairo_stroke(cr); //Sections cairo_set_source_rgba (cr, 0, 0, 0.9, 1); cairo_d2_sb(cr, P); for (unsigned i=0;i