/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ #include "MGCLStdAfx.h" #include "mg/Box.h" #include "mg/BPointSeq.h" #include "mg/Position.h" #include "mg/Curve.h" #include "mg/LBRep.h" #include "mg/RLBRep.h" #include "mg/Tolerance.h" using namespace std; #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // Implementation of knot rebuild. //曲線列のノットベクトルを再構築する //入力された複数曲線列を指定オーダーで再構築する。トレランスはline_zero()を使用している。 //オーダーが指定されていないとき曲線列のうちで最も大きいオーダーを使用する。このとき、 //Ellipse, Straightのオーダーは4として考える。 //パラメータ範囲は1次微分値の大きさが1になるようにしたときの長さの平均を使用している。 //戻り値は再構築後の曲線列が返却される。 MGPvector rebuild_knot( const std::vector& crvl, //入力曲線列 int ordr , //指定オーダー MGLBRep** tp //接続面 input and output. //if tp[i] for crvl[i] was not null, converted new tp will be output. ){ //使用するオーダーと空間次元を求める int nCrv = (int)crvl.size(), maxOrder = 0, maxSdim = 0, i = 0; int idMaxOrder=0; MGPvector rtnBrepList(nCrv); double allParam = 0.0; for(i = 0; i < nCrv; i++){ int ord = crvl[i]->order(), sdim = crvl[i]->sdim(); //if(sdim < 1){ // rtnBrepList.clear(); // return rtnBrepList; //空間次元0はエラーとする //} if(ord > maxOrder){ maxOrder = ord; idMaxOrder=i; } if(sdim > maxSdim) maxSdim = sdim; } if(!ordr) ordr = maxOrder; //オーダーが指定されていないときの処理 if(ordr <= 2) ordr = 4; //Ellipse, Straightのときオーダー4にする //LBRepでないものは、LBRepに変換してリストに入れる //全てノットベクトルが等しいLBRepのときリビルドしないでそのままの曲線を返却する bool fsame = true; for(i = 0; i < nCrv; i++){ const MGLBRep *ptempBRep = dynamic_cast(crvl[i]); if(ptempBRep){ rtnBrepList.reset(i, new MGLBRep(*ptempBRep)); if(i && fsame){ // KnotVectorが等しいかどうかのチェック const MGKnotVector& kv0 = rtnBrepList[i-1]->knot_vector(); const MGKnotVector& kv1 = rtnBrepList[i]->knot_vector(); if (kv0.param_s() != kv1.param_s() || kv0.param_e() != kv1.param_e() || kv0 != kv1) fsame = false; // if(rtnBrepList[i]->knot_vector() != rtnBrepList[i - 1]->knot_vector())fsame = false; } }else{ rtnBrepList.reset(i, new MGLBRep(*crvl[i], ordr)); fsame = false; } //1次微分値の大きさが1になるようなパラメータ範囲を求める double t0=rtnBrepList[i]->param_s(), t1=rtnBrepList[i]->param_e(); double t2=(t0+t1)*.5; double mag=rtnBrepList[i]->eval(t0,1).len(); mag+=rtnBrepList[i]->eval(t1,1).len(); mag+=rtnBrepList[i]->eval(t2,1).len(); mag /= 3.; allParam += rtnBrepList[i]->param_span() * mag; } if(fsame && tp==0) return rtnBrepList; double avgSpan = allParam / nCrv; //パラメータ範囲を合わせたノットベクトルを作成する。 for(i = 0; i< nCrv; i++){ rtnBrepList[i]->change_range(0.0, avgSpan); if(tp){ if(tp[i]) tp[i]->change_range(0.0, avgSpan); } } //全てのノットベクトルを足し合わせる。 MGNDDArray tau_temp; tau_temp.update_from_knot(rtnBrepList[idMaxOrder]->knot_vector()); if(tau_temp.length()knot_vector(); int orderti=ti.order(); int orderi= ordr<=orderti ? ordr: orderti; mixKnotVector.mix_knot_vector(MGKnotVector(tau_temp.update_from_knot(ti),orderi)); //if(tp){ // if(tp[i]) mixKnotVector.mix_knot_vector(MGKnotVector(tp[i]->knot_vector(), ordr)); //} } //std::cout<offset_div_num(MGInterval(spara, epara)); if(ndiv>maxNumDiv) maxNumDiv = ndiv; } double span = (epara - spara) / maxNumDiv, tParam = tempKnotVector(i); for(j = 0; j < maxNumDiv - 1; j++){ tParam += span; mixKnotVector.add_data(tParam, ordr - 1); //ノットベクトルを増やす } } //std::cout<eval(tau(j))); } rtnBrepList.reset(i, new MGLBRep(tau, bp, mixKnotVector)); if(tp){ if(tp[i]){ MGBPointSeq bptp(n, maxSdim); for(int j = 0; j < n; j++){ MGVector tpatj=tp[i]->eval(tau(j)); bptp.store_at(j, tpatj); tpleni+=tpatj.len(); } tp[i]=new MGLBRep(tau, bptp, mixKnotVector); tpleni/=double(n); } } tplen+=tpleni; } tplen/=double(nCrv); //曲線列のノットベクトルを精度を保持して削除を行う ::remove_knot_curves(rtnBrepList,tp,tplen); //std::cout<knot_vector()< rebuild_knot( const MGPvector& brepl, //入力曲線列 int ordr, //指定オーダー MGLBRep** tp //接続面 ){ size_t n=brepl.size(); std::vector curves(n); for(size_t i=0; i MGCurve::rebuild( int how_rebuild, //intdicates how rebuild be done. // =0: no approximation(only parameter change) // =1: if this is rational spline(MGRLBRep), reconstructed with new knot configuration // as rational spline(MGRLBRep). // Otherwise approximated by non-rational spline(MGLBRep) with new knot configuration. // =2: approximated by non-rational spline(MGLBRep) with new knot configuration, // if this is rational spline. If this is not rational spline, same as =1. int parameter_normalization, //Indicates how the parameter normalization be done: //=0: no parameter normalization. //=1: normalize to range=(0., 1.); //=2: normalize to make the average length of the 1st derivative // is as equal to 1. as possible. //=3: specify parameter range in param_range. double tol, ///=4 is recommended. ///When order=0 is input, the original order is unchanged if this curve is ///MGLBRep or MGRLBRep. Otherwise order is set to 4. const double* param_range )const{ if(parameter_normalization>=3 && param_range==0) parameter_normalization=2; double tol_old, err=tol; if(tol>0.) tol_old=MGTolerance::set_line_zero(tol); else err=MGTolerance::line_zero(); int neworder=ordr; if(neworder==0){ neworder=order(); } int reparaType=parameter_normalization; int reparaType2=reparaType; double tspan[2]={0., 1.}; double& t1=tspan[0]; double& t2=tspan[1]; if(reparaType>=2) reparaType2=1; if(reparaType==3){ t1=param_range[0]; t2=param_range[1]; if(t1>=t2){ t2=t1+1.; } } std::unique_ptr curvenew; if(how_rebuild){ const MGRLBRep* rlb=dynamic_cast(this); if(rlb && how_rebuild==1){ std::unique_ptr rlb2=rlb->rebuild_with_new_knot_configuration(err,reparaType2); curvenew.reset(rlb2.release()); }else{ MGLBRep* lbrep=new MGLBRep; approximate_as_LBRep(*lbrep,neworder,reparaType2); curvenew.reset(lbrep); } }else{ curvenew=std::unique_ptr(clone()); if(reparaType) curvenew->change_range(0.,1.); } if(reparaType==2) t2=curvenew->get_average_tangent_length(); if(reparaType>=2) curvenew->change_range(t1,t2); if(tol>0.) MGTolerance::set_line_zero(tol_old); curvenew->copy_appearance(*this); return curvenew; } ///Approximate this curve as a MGLBRep curve ///within the tolerance MGTolerance::line_zero(). ///When parameter_normalization=0, reparameterization will not be done, and ///the evaluation at the same parameter has the same values before and after ///of approximate_as_LBRep. void MGCurve::approximate_as_LBRep( MGLBRep& lb, ///=C0. multi_found=t.locate_multi(start,km1,index);//Locate C0 continuity point. if(start==k){//For the 1st span. approximate_as_LBRep2(lb,norder,start-1,index,neglectMutli);//1st approximation. //std::cout<lb.param_s() || te