//Evaluate right continuous ndu'th and ndv'th derivative data. //Function's return value is (d(ndu+ndv)f(u,v))/(du**ndu*dv**ndv). // ndu=0 and ndv=0 means positional data evaluation. MGVector MGSBRep::eval( double u, double v, // Parameter value of the surface. size_t ndu, // Order of Derivative along u. size_t ndv // Order of Derivative along v. ) const { const unsigned ku=order_u(), kv=order_v(); double cu[10],cv[10]; double *cup=cu, *cvp=cv; if(ku>10) cup=new double[ku]; //This is done to save "new" when ku<=10. if(kv>10) cvp=new double[kv]; //This is done to save "new" when kv<=10. const int num1=bdim_u()-1, nvm1=bdim_v()-1; int idu=m_uknot.eval_coef(u,cup,ndu); int idv=m_vknot.eval_coef(v,cvp,ndv); size_t i,j,m; int jj; const size_t ncd=sdim(); MGVector S(ncd); double coefall,coefu; for(m=0; m<ncd; m++){ coefall=0.; for(j=0;j<kv;j++){ coefu=0.; jj=idv+j; for(i=0;i<ku;i++) coefu=coefu+coef(idu+i,jj,m)*cup[i]; coefall=coefall+coefu*cvp[j]; } S.set(m)=coefall; } if(ku>10) delete[] cup; if(kv>10) delete[] cvp; return S; }
// 論理演算子の多重定義 // 与曲線と自身が等しいかの比較判定を行う。 //RSB and SB comparison. bool MGRSBRep::operator==(const MGSBRep& sb)const{ if(sdim()!=sb.sdim()) return 0;//Check of space dimension. if(order_u()!=sb.order_u()) return 0; //Check of order. if(order_v()!=sb.order_v()) return 0; //Check of order. size_t bdu=bdim_u(), bdv=bdim_v(); if(bdu!=sb.bdim_u()) return 0; //Check of B-Rep dimension. if(bdv!=sb.bdim_v()) return 0; //Check of B-Rep dimension. if(bdu<=0 && bdv<=0) return 1; if(!non_rational()) return 0; //Check of rationality. if(knot_vector_u() != sb.knot_vector_u()) return 0;//Check of knot vector. if(knot_vector_v() != sb.knot_vector_v()) return 0;//Check of knot vector. //Finally, check of control polygon. return m_surface.surface_bcoef().non_homogeneous()==sb.surface_bcoef(); }
MGSBRep& MGSBRep::refine( //BSUNK const MGKnotVector& uknot, // knot of u-direction const MGKnotVector& vknot) // knot of v-direction //Change an original B-Rep to new one with subdivided knot configuration. //Knots t must be subdivided knots. { int refine_kind; if(uknot!=m_uknot){ if(vknot!=m_vknot) refine_kind=3; else refine_kind=1; }else if(vknot!=m_vknot) refine_kind=2; else return *this; // refine_kind=1:u-knot only, =2:v-knot only, =3:both u and v-knot. unsigned ku=order_u(); size_t lud=bdim_u(); unsigned kv=order_v(); size_t lvd=bdim_v(); size_t is1,is2; surface_bcoef().capacity(is1,is2); size_t lud2=uknot.bdim(), lvd2=vknot.bdim(); MGSPointSeq bcoef(lud2,lvd2,3); unsigned k=ku; if(k<kv) k=kv; double* work1=new double[k*k]; double* work2=new double[lvd2*2]; bsunk_(refine_kind,ku,lud,knot_data_u(),kv,lvd,knot_data_v(),coef_data(), is1,is2,lud2,uknot.data(),lvd2,vknot.data(), lud2,lvd2,work1,work2,&bcoef(0,0,0)); delete[] work1; delete[] work2; m_uknot=uknot; m_vknot=vknot; m_surface_bcoef=bcoef; update_mark(); return *this; }
bool MGRSBRep::operator==(const MGRSBRep& rsb2)const{ size_t sd1=sdim(), sd2=rsb2.sdim(); if(sd1!=sd2) return 0; if(order_u()!=rsb2.order_u()) return 0; //Check of order. if(order_v()!=rsb2.order_v()) return 0; //Check of order. size_t bdu1=bdim_u(), bdu2=rsb2.bdim_u(); if(bdu1!=bdu2) return 0; size_t bdv1=bdim_v(), bdv2=rsb2.bdim_v(); if(bdv1!=bdv2) return 0; if(bdu1<=0 && bdv1<=0) return 1; if(knot_vector_u() != rsb2.knot_vector_u()) return 0; if(knot_vector_v() != rsb2.knot_vector_v()) return 0; double ratio=rsb2.coef(0,0,sd2)/coef(0,0,sd1); //Check if weights are equal. for(size_t i=0; i<bdu1; i++) for(size_t j=0; j<bdv1; j++) if(!MGREqual2(ratio,rsb2.coef(i,j,sd2)/coef(i,j,sd1))) return 0; return m_surface.surface_bcoef().non_homogeneous() ==rsb2.m_surface.surface_bcoef().non_homogeneous() ; }
int MGSBRep::reduce( //BSUDEC int is_u, //if true, reduce b-rep dimension of u-direction. int ndec) //Number of B-rep dimension to decrease //Change the B-Rep by decreasing B-Rep dimension by ndec. This is //an approximation of the original B-Rep. Return value is error flag. { assert(ndec>=0); if(is_u) assert(bdim_u()-ndec>=order_u()); else assert(bdim_v()-ndec>=order_v()); if(ndec<=0) return 0; size_t kdec=2; if(is_u) kdec=1; unsigned ku=order_u(); size_t lud=bdim_u(); unsigned kv=order_v(); size_t lvd=bdim_v(); unsigned maxlen=lud; if(maxlen<lvd) maxlen=lvd; size_t is1,is2; surface_bcoef().capacity(is1,is2); int lud2, lvd2; MGKnotVector tu(ku,lud), tv(kv,lvd); MGSPointSeq bcoef(lud,lvd,3); int iflag; unsigned k=ku; if(k<kv) k=kv; double* work1=new double[maxlen*(2*k-1)]; double* work2=new double[maxlen]; double* work3=new double[lvd*2]; bsudec_( ku,lud,knot_data_u(),kv,lvd,knot_data_v(),coef_data(), kdec,ndec,is1,is2,lud,lvd,work1,work2,work3, &lud2,&tu(0),&lvd2,&tv(0),&bcoef(0,0,0),&iflag); if(iflag==1){ tu.set_bdim(lud2); tv.set_bdim(lvd2); m_uknot=tu; m_vknot=tv; bcoef.set_length(lud2,lvd2); m_surface_bcoef=bcoef; iflag=0; } delete[] work1; delete[] work2; delete[] work3; update_mark(); return iflag; }
//Evaluate right continuous surface data. //Evaluate all positional data, 1st and 2nd derivatives. void MGSBRep::eval_all( double u, double v, // Parameter value of the surface. MGPosition& f, // Positional data. MGVector& fu, // df(u,v)/du MGVector& fv, // df/dv MGVector& fuv, // d**2f/(du*dv) MGVector& fuu, // d**2f/(du**2) MGVector& fvv // d**2f/(dv**2) ) const { size_t ku=order_u(), kv=order_v(); size_t ku2=ku+ku, kv2=kv+kv; double *ucoef=new double[ku*3], *vcoef=new double[kv*3]; int bdum1=bdim_u()-1, bdvm1=bdim_v()-1; int uid=m_uknot.eval_coef(u,ucoef,0); int vid=m_vknot.eval_coef(v,vcoef,0); m_uknot.eval_coef(u,ucoef+ku,1); m_uknot.eval_coef(u,ucoef+ku2,2); m_vknot.eval_coef(v,vcoef+kv,1); m_vknot.eval_coef(v,vcoef+kv2,2); double s,su,suu,c,vj,vj1; size_t i,j,k,dim=sdim(); int ii,jj; MGPosition p(dim); MGVector pu(dim),pv(dim),puv(dim),puu(dim),pvv(dim); for(k=0; k<dim; k++){ p(k)=0.0;pu.set(k)=0.0;pv.set(k)=0.0;puv.set(k)=0.0; puu.set(k)=0.0;pvv.set(k)=0.0; for(j=0; j<kv; j++){ s=su=suu=0.0; jj=vid+j; for(i=0; i<ku; i++){ ii=uid+i; c=coef(ii,jj,k); s=s+ucoef[i]*c; su=su+ucoef[i+ku]*c; suu=suu+ucoef[i+ku2]*c; } vj=vcoef[j]; vj1=vcoef[j+kv]; p(k)=p(k)+vj*s; pu.set(k)=pu.ref(k)+vj*su; pv.set(k)=pv.ref(k)+vj1*s; puv.set(k)=puv.ref(k)+vj1*su; puu.set(k)=puu.ref(k)+vj*suu; pvv.set(k)=pvv.ref(k)+vcoef[j+kv2]*s; } } f=p;fu=pu;fv=pv;fuv=puv;fuu=puu;fvv=pvv; delete[] ucoef; delete[] vcoef; }
//Evaluate all of derivative data (d(i+j)f(u,v))/(du**i*dv**j), //for 0<=i<=ndu and 0<=j<=ndv. void MGSBRep::eval_all( double u, double v, // Parameter value of the surface. size_t ndu, //Order of Derivative along u. size_t ndv, //Order of Derivative along v. double* deriv //Output. (d(i+j)f(u,v))/(du**i*dv**j) in //deriv[r+j*dim+i*(ndv+1)*dim] for 0<=r<dim=sdim(). //for 0<=i<=ndu and 0<=j<=ndv. //deriv is an array of deriv[ndu+1][ndv+1][r], //(d(i+j)f(u,v))/(du**i*dv**j) is returned in deriv[i][j][r]. ) const{ size_t i,j,jj,r, dim=sdim(); size_t ider,jder; const unsigned ku=order_u(), kv=order_v(); size_t kundu=ku*(ndu+1), kvndv=kv*(ndv+1); double cu[30],cv[30]; double *cup=cu, *cvp=cv; if(kundu>30) cup=new double[kundu]; //Done to save "new". if(kvndv>30) cvp=new double[kvndv]; //Done to save "new". int idu,idv; for(ider=0; ider<=ndu; ider++) idu=m_uknot.eval_coef(u,cup+ider*ku,ider); for(jder=0; jder<=ndv; jder++) idv=m_vknot.eval_coef(v,cvp+jder*kv,jder); double coefall,coefu; for(ider=0; ider<=ndu;ider++){ size_t iderndv1dim=ider*(ndv+1)*dim; for(jder=0; jder<=ndv; jder++){ size_t jderdim=jder*dim; for(r=0; r<dim; r++){ coefall=0.; for(j=0;j<kv;j++){ coefu=0.; jj=idv+j; for(i=0;i<ku;i++) coefu=coefu+coef(idu+i,jj,r)*cup[i+ider*ku]; coefall=coefall+coefu*cvp[j+jder*kv]; } deriv[r+jderdim+iderndv1dim]=coefall; } } } if(kundu>30) delete[] cup; if(kvndv>30) delete[] cvp; }
// Compute parameter line. MGLBRep MGSBRep::parameter_line( int is_u //Indicates x is u-value if is_u is true. , double x //Parameter value. //The value is u or v according to is_u. , unsigned nderiv //Order of derivative. )const{ unsigned ku=order_u(); size_t lud=bdim_u(); unsigned kv=order_v(); size_t lvd=bdim_v(); size_t is1,is2; surface_bcoef().capacity(is1,is2); size_t ncd=sdim(), len; int kx; int k; if(is_u){ kx=1; len=lvd; k=kv; } else { kx=0; len=lud; k=ku; } MGLBRep lb(len,k,ncd); MGBPointSeq& rcoef=lb.line_bcoef(); MGKnotVector& t=lb.knot_vector(); int n; bsepl_(ku,lud,knot_data_u(),kv,lvd,knot_data_v(),coef_data(), is1,is2,ncd,kx,x,nderiv,len,&k,&n,&t(0),&rcoef(0,0)); return lb; }
//Modify the original Surface by extrapolating the specified perimeter. //The extrapolation is C2 continuous if the order >=4. //The extrapolation is done so that extrapolating length is "length" //at the position of the parameter value "param" of the perimeter. MGRSBRep& MGRSBRep::extend( int perimeter, //perimeter number of the Surface. // =0:v=min, =1:u=max, =2:v=max, =3:u=min. double param, // parameter value of above perimeter. double length, //chord length to extend at the parameter param of the perimeter. double dk){ //Coefficient of how curvature should vary at // extrapolation start point. When dk=0, curvature keeps same, i.e. // dK/dS=0. When dk=1, curvature becomes zero at length extrapolated point, // i.e. dK/dS=-K/length at extrapolation start point. // (S=parameter of arc length, K=Curvature at start point) // That is, when dk reaches to 1 from 0, curve changes to flat. assert(sdim()<=3); assert(perimeter>=0 && perimeter<4); const size_t ncd=surface_bcoef().sdim(); int at_start=1;//starting perimeter size_t nu, nv; size_t order; size_t n,m; MGKnotVector* t; if(perimeter==1 || perimeter==3){ // Extrapolate to u-direction order=order_u(); n=bdim_u(); t=&(knot_vector_u()); if(perimeter==1) at_start=0;//ending perimeter m=nv=bdim_v(); }else{ // Extrapolate to v-direction order=order_v(); n=bdim_v(); t=&(knot_vector_v()); if(perimeter==2) at_start=0;//ending perimeter m=nu=bdim_u(); } //(nu,nv) are new surface B-Rep dimensions of u and v. //(order,n,t) is line B-rep to extrapolate. //m is the number of line B-reps to extrapolate. MGSPointSeq surf; MGRLBRep lbtemp; MGKnotVector& t1=lbtemp.knot_vector(); MGBPointSeq& coeftemp=lbtemp.line_bcoef(); coeftemp.resize(n,ncd); double tse; if(at_start) tse=t->param_s(); else tse=t->param_e(); MGPosition uv=perimeter_uv(perimeter,param);//Surface parameter value of param. size_t ndu=0,ndv=0; if(perimeter==0 || perimeter==2) ndv=1; else ndu=1; double slen=length/(eval(uv,ndu,ndv)).len(); int nnew; double firstd_len,dlen; for(size_t i=0; i<m; i++){ if(perimeter==0 || perimeter==2){ for(size_t j=0; j<n; j++) for(size_t k=0; k<ncd; k++) coeftemp(j,k)=coef(i,j,k); }else{ for(size_t j=0; j<n; j++) for(size_t k=0; k<ncd; k++) coeftemp(j,k)=coef(j,i,k); } coeftemp.set_length(n); //Compute first derivative length at the end of the extrapolating line. t1=*t; firstd_len=lbtemp.eval(tse,1).len(); dlen=firstd_len*slen; //std::cout<<"before:"<<lbtemp<<std::endl;/////// lbtemp.extend(at_start,dlen,dk); //std::cout<<"after:"<<lbtemp<<std::endl;/////// nnew=lbtemp.bdim(); if(perimeter==0 || perimeter==2){ if(i==0){ nv=nnew; surf.resize(nu,nv,ncd); } for(int j=0; j<nnew; j++) for(size_t k=0; k<ncd; k++) surf(i,j,k)=coeftemp(j,k); }else{ if(i==0){ nu=nnew; surf.resize(nu,nv,ncd); } for(int j=0; j<nnew; j++) for(size_t k=0; k<ncd; k++) surf(j,i,k)=coeftemp(j,k); } } *t=t1; surf.set_length(nu,nv); surface_bcoef()=surf; update_mark(); return *this; }
typename beziervolume<point_t>::array_type beziervolume<point_t>::ocsplit ( ) const { array_type result; std::size_t new_size_u = order_u() + degree_u(); std::size_t new_size_v = order_v() + degree_v(); std::size_t new_size_w = order_w() + degree_w(); // generate point-meshes for different steps of split pointmesh3d<point_t> cpsplit_u ( new_size_u, order_v(), order_w() ); pointmesh3d<point_t> cpsplit_uv ( new_size_u, new_size_v, order_w() ); pointmesh3d<point_t> cpsplit_uvw ( new_size_u, new_size_v, new_size_w ); converter<point_t> converter; // split in u for (std::size_t v = 0; v != order_v(); ++v) { for (std::size_t w = 0; w != order_w(); ++w) { // elevate to virtual nurbscurve to apply knot insertion std::vector<point_t> tmp_curve = _points.submesh ( 0, v, w ); // create knot vector std::vector<value_type> kv_min (order_u(), 0); std::vector<value_type> kv_max (order_u(), 1); std::multiset<value_type> kv; kv.insert ( kv_min.begin(), kv_min.end() ); kv.insert ( kv_max.begin(), kv_max.end() ); converter.knot_insertion (tmp_curve, kv, order_u(), value_type(0.5)); cpsplit_u.submesh (tmp_curve.begin(), 0, v, w); } } // split in v for (std::size_t u = 0; u != new_size_u; ++u) { for (std::size_t w = 0; w != order_w(); ++w) { // elevate to virtual nurbscurve to apply knot insertion std::vector<point_t> tmp_curve = cpsplit_u.submesh ( 1, u, w ); // create knot vector std::vector<value_type> kv_min (order_v(), 0); std::vector<value_type> kv_max (order_v(), 1); std::multiset<value_type> kv; kv.insert ( kv_min.begin(), kv_min.end() ); kv.insert ( kv_max.begin(), kv_max.end() ); converter.knot_insertion (tmp_curve, kv, order_v(), value_type(0.5)); cpsplit_uv.submesh (tmp_curve.begin(), 1, u, w); } } // split in w for (std::size_t u = 0; u != new_size_u; ++u) { for (std::size_t v = 0; v != new_size_v; ++v) { // elevate to virtual nurbscurve to apply knot insertion std::vector<point_t> tmp_curve = cpsplit_uv.submesh ( 2, u, v ); // create knot vector std::vector<value_type> kv_min (order_w(), 0); std::vector<value_type> kv_max (order_w(), 1); std::multiset<value_type> kv; kv.insert ( kv_min.begin(), kv_min.end() ); kv.insert ( kv_max.begin(), kv_max.end() ); converter.knot_insertion (tmp_curve, kv, order_w(), value_type(0.5)); cpsplit_uvw.submesh (tmp_curve.begin(), 2, u, v); } } // generate subvolumes for (std::size_t w = 0; w != 2; ++w) { for (std::size_t v = 0; v != 2; ++v) { for (std::size_t u = 0; u != 2; ++u) { pointmesh3d<point_t> submesh = cpsplit_uvw.submesh(u*degree_u(), v*degree_v(), w*degree_w(), order_u(), order_v(), order_w()); beziervolume subvolume (submesh); //result[array_index(u)][array_index(v)][array_index(w)] = subvolume; result[u][v][w] = subvolume; } } } return result; }
inline bool beziervolume<point_t>::valid ( ) const { return (_points.size() == order_u() + order_v()); }
//Test if part of the surface is planar or not within the tolerance tol. //The part of the surface is input by the surface parameter range uvbox. //Returned is 0(false) if this is not planar, 1(true) if planar. int MGSBRep::planar( const MGBox& uvbox,//This surface parameter range. double tol, //maximum deviation allowed to regard the sub surface as a plane. int* divideU//Direction to subdivide will be output, if this was not planar. //=1: u direction, =0: v direction. ) const{ MGBox uvb=param_range()&uvbox; MGPosition P; MGUnit_vector N; int direction; if(!flat(uvb,tol,direction,P,N)){ if(divideU) *divideU=direction; return 0; }; const MGInterval& urng=uvbox[0]; double u0=urng[0].value(), u1=urng[1].value(); const MGInterval& vrng=uvbox[1]; double v0=vrng[0].value(), v1=vrng[1].value(); double um=(u0+u1)*0.5, vm=(v0+v1)*0.5; int ncd=sdim(); unsigned ku=order_u(), kv=order_v(); const MGKnotVector& tv=knot_vector_v(); int j0=tv.locate(v0)-kv+1, j1=tv.locate(v1); //Coef necessary for v direction part is from j0 to j1 //(B-rep dimension is j1-j0+1). //Knot vector necessary is from j0 to j1+kv. int nunew, nvnew=j1-j0+1; tol*=1.1; size_t nu, nv, sizeu, sizev; surface_bcoef().length(nu, nv); surface_bcoef().capacity(sizeu, sizev); unsigned kmax=ku; if(kmax<kv) kmax=kv; double* work=new double[kmax*kmax]; MGSPointSeq surf1(nvnew, nu, ncd); size_t irc=nvnew*nu; int nmax=nu; if(nmax<nvnew) nmax=nvnew; int nvncd=nvnew; if(nvncd<ncd) nvncd=ncd; MGBPointSeq temp(nmax,nvncd); MGKnotVector t(kmax, nmax); double* tpointer=t.data(); double* temppointer=temp.data(); for(int k=0; k<ncd; k++){ double Pk=P[k]; bluprt_(ku, nu, knot_data_u(), coef_data(0,j0,k), sizeu,nvnew,u0,u1,nmax,work,&nunew,tpointer,temppointer,1); for(int i=0; i<nunew; i++) for(int j=0; j<nvnew; j++) surf1(j,i,k)=temp(i,j)-Pk; } //surf1.set_length(nvnew,nunew);cout<<surf1<<endl;////////// const double* tvnew=knot_data_v()+j0; int nvnew2; double x; int i,j; for(i=0; i<nunew; i++){ bluprt_(kv,nvnew,tvnew,surf1.data(0,i,0), irc,ncd,v0,v1,nmax,work,&nvnew2,tpointer,temppointer,1); //temp.set_length(nvnew2);cout<<temp<<endl;/////////// for(j=0; j<nvnew2; j++){ x=0.; for(int k=0; k<ncd; k++) x-=temp(j,k)*N[k]; if(x<0.) x=-x; if(x>tol) break; } if(j<nvnew2) break; } int retcode=1; if(i<nunew || j<nvnew2){ if(divideU){ // *divideU=direction; MGVector dfdu=eval(um,vm,1,0), dfdv=eval(um,vm,0,1); double ulen=dfdu.len()*(u1-u0), vlen=dfdv.len()*(v1-v0); if(ulen*5.<vlen) *divideU=0; else if(ulen>vlen*5.) *divideU=1; else{ //Compute maximum deviation from the plane along u direction. double udevi0, udevi1, vdevi0, vdevi1; size_t jm=nvnew2/2; x=0.; for(int k=0; k<ncd; k++) x-=surf1(jm,0,k)*N[k]; udevi0=udevi1=x; for(i=1; i<nunew; i++){ x=0.; for(int k=0; k<ncd; k++) x-=surf1(jm,i,k)*N[k]; if(x<udevi0) udevi0=x; if(x>udevi1) udevi1=x; } size_t im=nunew/2; bluprt_(kv,nvnew,tvnew,surf1.data(0,im,0), irc,ncd,v0,v1,nmax,work,&nvnew2,tpointer,temppointer,1); x=0.; for(int k=0; k<ncd; k++) x-=temp(0,k)*N[k]; vdevi0=vdevi1=x; for(j=1; j<nvnew2; j++){ x=0.; for(int k=0; k<ncd; k++) x-=temp(j,k)*N[k]; if(x<vdevi0) vdevi0=x; if(x>vdevi1) vdevi1=x; } if((udevi1-udevi0)>=(vdevi1-vdevi0)) *divideU=1; else *divideU=0; } } retcode=0; } delete[] work; return retcode; }
void beziersurface::preprocess ( std::size_t subdiv_u, std::size_t subdiv_v ) { // clear old convex hull _chull.clear(); // elevate if necessary if (_degree_u < 2) { elevate_u(); } if (_degree_v < 2) { elevate_v(); } // compute parameter domain partition if necessary //_trimdomain.partition(); // generate convex hull according to subdivision parameter pointmesh2d<point_type> cp_orig(_points.begin(), _points.end(), order_u(), order_v()); pointmesh2d<point_type> cp_u; pointmesh2d<point_type> cp_uv; trimdomain::bbox_type domainsize = _bezierdomain; double umin = _bezierdomain.min[point_type::u]; double umax = _bezierdomain.max[point_type::u]; double vmin = _bezierdomain.min[point_type::v]; double vmax = _bezierdomain.max[point_type::v]; value_type range_u = umax - umin; value_type range_v = vmax - vmin; value_type step_u = range_u / value_type(subdiv_u+1); value_type step_v = range_v / value_type(subdiv_v+1); // for each row of control polygon for (std::size_t r = 0; r <= _degree_v; ++r) { // create knot vector std::vector<value_type> hlp1(_degree_u+1, umin); std::vector<value_type> hlp2(_degree_u+1, umax); std::multiset<value_type> kv_u(hlp1.begin(), hlp1.end()); kv_u.insert(hlp2.begin(), hlp2.end()); std::vector<point_type> row = cp_orig.row(r); for (std::size_t i = 1; i <= subdiv_u; ++i) { converter3d conv; conv.knot_insertion(row, kv_u, _degree_u + 1, value_type(umin) + value_type(i) * value_type(step_u)); } cp_u.add_row(row.begin(), row.end()); } cp_u.transpose(); // for each row of transposed control polygon for (std::size_t r = 0; r < cp_u.height(); ++r) { // create knot vector std::vector<value_type> hlp1(_degree_v+1, vmin); std::vector<value_type> hlp2(_degree_v+1, vmax); std::multiset<value_type> kv_v(hlp1.begin(), hlp1.end()); kv_v.insert(hlp2.begin(), hlp2.end()); std::vector<point_type> row = cp_u.row(r); for (std::size_t i = 1; i <= subdiv_v; ++i) { converter3d conv; conv.knot_insertion(row, kv_v, _degree_v + 1, value_type(vmin) + value_type(i) * value_type(step_v)); } cp_uv.add_row(row.begin(), row.end()); } cp_uv.transpose(); std::vector<gpucast::math::vec4f> uv(cp_uv.width() * cp_uv.height()); // std::generate(uv.begin(), uv.end(), gen_uv(cp_uv.width(), cp_uv.height(), // min_u_, max_u_, min_v_, max_v_)); // for bezier patches always 0.0 - 1.0 -> min_u, max_u, min_v, max_v are only for trimming ... // ... as they transform the parameter space into the original b-spline space std::generate(uv.begin(), uv.end(), uvgenerator<gpucast::math::vec4f> ( cp_uv.width(), cp_uv.height(), float(0), float(1), float(0), float(1), bit_cast<unsigned, float>(unsigned(order_u())), bit_cast<unsigned, float>(unsigned(order_v())))); std::vector<gpucast::math::vec4f> attrib(uv.size()); pointmesh2d<gpucast::math::vec4f> cp_color (uv.begin(), uv.end(), cp_uv.width(), cp_uv.height()); pointmesh2d<gpucast::math::vec4f> cp_attrib(uv.begin(), uv.end(), cp_uv.width(), cp_uv.height()); // generate chulls for each subdivision and merge them for (std::size_t v = 0; v <= subdiv_v; ++v) { for (std::size_t u = 0; u <= subdiv_u; ++u) { // copy control points of submesh pointmesh2d<point3d> subpat = cp_uv.subpatch (u * _degree_u, (u+1)*_degree_u, v * _degree_v, (v+1)*_degree_v); // copy 4-double texture coordinate information from submesh pointmesh2d<gpucast::math::vec4f> subpat_col = cp_color.subpatch (u * _degree_u, (u+1)*_degree_u, v * _degree_v, (v+1)*_degree_v); // discard rational component of control points for convex hull generation std::vector<gpucast::math::vec3d> tmp; std::transform(subpat.begin(), subpat.end(), std::inserter(tmp, tmp.end()), gpucast::math::rational_to_euclid3d<point3d>()); // generate chull for subpatch convex_hull tmp_ch; tmp_ch.set(tmp.begin(), tmp.end(), subpat_col.begin(), subpat_col.end()); // merge chull with complete chull _chull.merge(tmp_ch); } } }