/********************************************************************/ /* 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/LBRep.h" #include "mg/RLBRep.h" #include "mg/Straight.h" #include "mg/SPointSeq.h" #include "mg/SBRep.h" #include "mg/RSBRep.h" #include "mg/Tolerance.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif using namespace std; // Implementation of knot remove. //ノット削除関数(B表現曲線のみ) //トレランスはline_zeroを使用する。元のノットが細かいものほど削除しやすい //removal knot. line_zero tolerance is used. void MGCurve::remove_knot(){;} #define START_DELNUM 4000 //Remove knot if removed line has the difference less than line_zero(); //The difference is checked only for the space id of coef(.,j+k) //for k=0, ..., nd-1. void MGLBRep::remove_knot(int j, int nd){ int k=order(); int km1 = k-1; //次元数 int i, n=bdim(); int mid=(km1+n)/2; if(mid<=km1) mid=k; else if(mid>START_DELNUM){mid=START_DELNUM;} double totalTol = 0.0; const double line0=MGTolerance::line_zero(); //std::cout<<(*this)<=mid;){ int ndel = remove_knot_one(line0,i,totalTol,num_remained,j,nd); i-=int(ndel+num_remained); } // std::cout<<(*this)<nt){ remove_knot_one(line0,i,totalTol,num_remained,j,nd); i+=num_remained; } // std::cout<<(*this)<=k && tau==knot(m); m--) multi++; num_knot=multi; //const double line0=MGTolerance::line_zero(); MGBPointSeq temp_bp(2 * km1 + 1, sd); int last = id - multi; int first = id - km1; int ndel; //削除したノットの数 if(k == 2){ //オーダー2のときの処理 const int off = first - 1; bcoef.point(off,sid,snum,P); bcoef.point(last+1,sid,snum,Q); MGStraight st1(P, Q); bcoef.point(first,sid,snum,R); double tmpTol = st1.distance(R); totalTol += tmpTol; if(line0>0. && totalTol>line0) ndel=0; //誤差合計がトレランス以上の場合ノット削除を行わない else ndel=1; }else{ //オーダー3以上のときの処理 for(ndel = 0; ndel ndel){ double ti=knot(i), tjmndel=knot(j - ndel); double alfi = (tau-ti) / (knot(i+k+ndel) - ti); double alfj = (tau - tjmndel) / (knot(j+k) - tjmndel); temp_bp.store_at(ii, (coef(i) - (1.0 - alfi) * temp_bp(ii-1)) / alfi); temp_bp.store_at(jj, (coef(j) - alfj * temp_bp(jj+1)) / (1.0 - alfj)); i++; j--; ii++; jj--; } if((j-i) < ndel){ temp_bp.point(ii - 1,sid,snum,P); temp_bp.point(jj + 1,sid,snum,Q); totalTol += (P - Q).len(); }else{ double ti=knot(i); double alfi = (tau - ti) / (knot(i+k+ndel) - ti); temp_bp.point(ii+ndel+1,sid,snum,P); temp_bp.point(ii-1,sid,snum,Q); bcoef.point(i,sid,snum,R); totalTol += (R - (alfi*P + (1.0 - alfi)*Q)).len(); } //誤差合計がトレランス以上の場合ノット削除を行わない if(line0>0. && totalTol > line0) break; i = first; j = last; while((j-i) > ndel){ m_line_bcoef.store_at(i, temp_bp(i - off)); m_line_bcoef.store_at(j, temp_bp(j - off)); i++; j--; } first--; last++; } } if(!ndel){totalTol=0.; return 0;} int l = id + 1; const int num_end_knot = n + km1; //最終ノットの番号 for(; l <= num_end_knot; l++) knot(l-ndel) = knot(l); int j = (2*id - multi - km1)/2;//最初のコントロールポイント id int i = j; for(l = 1; l < ndel; l++){ if((l % 2) == 1)i++; else j--; } for(l = i+1; l Pmax) Pmax = P; if(W < Wmin) Wmin = W; } double save=MGTolerance::line_zero(); double tol = save* Wmin /(1 + Pmax); MGTolerance::set_line_zero(tol); m_line.remove_knot(); MGTolerance::set_line_zero(save); } //ノット削除関数 //トレランスはline_zeroを使用する。元のノットが細かいものほど削除しやすい void MGSBRep::remove_knot(){ remove_knot_u(); exchange_uv(); remove_knot_u(); exchange_uv(); } //uノットを削除する int MGSBRep::remove_knot_u(){ int k = order_u(), n = bdim_u();//order and bdim along u. int km1=k-1; int mid=(km1+n)/2; if(mid<=km1) mid=k; int num_remained; int nDel = 0; //削除したノットの数 double totalTol = 0.0; double line0=MGTolerance::line_zero(); int i; for(i=n-1; i>=mid;){ int nDelOne = remove_knot_u_one(line0,i, totalTol, num_remained); i-=(nDelOne+num_remained); nDel+=nDelOne; } i=k; int nt=bdim_u()-mid-1; if(nt<0) nt=0; totalTol=0.; while(int(bdim_u())-i>nt){ int nDelOne=remove_knot_u_one(line0,i,totalTol,num_remained); i+=num_remained; nDel+=nDelOne; } return nDel; } //uノットを削除する //関数の戻り値は削除したノットの数 int MGSBRep::remove_knot_u_one( double line0, //Tolerance allowed for the knot removal. //When line0<=0., removal will be done uncoditionally. int id, //削除しようとするノットの番号 double& totalTol, //最初は0を入力する。あとはremove_knot_u_oneが管理する。 //削除を繰り返しているときは誤差が加算される。これ以上削除できない時0クリアされる。 int& num_knot //Remained knot number at knot(id) after removed. ){ const int k = order_u(); //オーダー const int km1 = k - 1; //次数 const int m = bdim_u(), n = bdim_v(); const int sd=sdim(); const double tau=knot_u(id); //Get the multiplicity of knot(id). //We need the end knot id of the multiplicity in 'id'. int a, multi=1, idold=id; for(a=id+1; a=k && tau==knot_u(a); a--) multi++; num_knot=multi; int last = id - multi; int first = id - km1; int l; int ndel=0; //削除したノットの数 if(k==2){ //オーダー2のときの処理 const int off = first - 1; double maxTol = 0.0; int l; for(l=0; l0. && tmpTol>line0){ndel= 0; break;}//ノットが削除できなかった if(tmpTol>maxTol) maxTol = tmpTol; } if(l>=n){//When possible to delete knot. ndel=1;totalTol += maxTol; } }else{ //オーダー3以上のときの処理 for(ndel = 0; ndel < multi; ndel++){ MGSPointSeq temp(2*km1+1,n,sd); const int off = first - 1; int i, j, ii, jj; double maxTol = 0.0; for(l=0; l ndel){ double ti=knot_u(i), tjmndel=knot_u(j-ndel); alfi = (tau-ti) / (knot_u(i+k+ndel) - ti); alfj = (tau-tjmndel) / (knot_u(j+k) - tjmndel); temp.store_at(ii,l,(coef(i,l) - (1.0 - alfi)*temp(ii-1,l)) / alfi); temp.store_at(jj, l, (coef(j,l) - alfj * temp(jj+1,l)) / (1.-alfj)); i++; j--; ii++; jj--; } if((j-i) < ndel){ tmpTol = (temp(ii-1,l) - temp(jj+1,l)).len(); if(line0>0. && tmpTol>line0){ maxTol=tmpTol; break;} }else{ double ti=knot_u(i); alfi = (tau-ti) / (knot_u(i+k+ndel)-ti); tmpTol=(coef(i,l)-(alfi * temp(ii+ndel+1,l)+(1.-alfi)*temp(ii-1,l))).len(); if(line0>0. && tmpTol>line0){ maxTol=tmpTol; break;} } if(tmpTol > maxTol) maxTol=tmpTol; } totalTol += maxTol; if(line0>0. && totalTol>line0) break; i = first; j = last; while((j-i) > ndel){ for(int vk=0; vkPmax) Pmax = P; if(W& brepList, //曲線列 MGLBRep** tp, //接続面 input and output. //if tp[i] for crvl[i] was not null, converted new tp will be output. double tp_length ){ MGLBRep& lb0=*(brepList[0]); int nCrv = (int)brepList.size(); //曲線数 int k = lb0.order(),n = lb0.bdim();//次元数&B表現次元 int km1=k-1; int mid=(km1+n)/2; if(mid<=km1) mid=k; const double line0=MGTolerance::line_zero(); const double rc0=tp_length*MGTolerance::angle_zero(); int num_remained; int preDel, nDel, nDel2; std::vector totalTol(nCrv,0.); std::vector totalTolTP(nCrv,0.); std::vector lb(nCrv), tpSave(nCrv); std::vector tp_specified(nCrv); int i; for(i=n-1; i >= mid;){ int j=0; for(; jremove_knot_one(rc0,i, totalTolTP[j],num_remained); } if(j == 0) preDel = nDel; if(!nDel || nDel!=nDel2 || preDel!=nDel){//ノット削除に失敗したときの処理 std::fill(totalTol.begin(), totalTol.end(), 0.0); //誤差合計をクリアする std::fill(totalTolTP.begin(), totalTolTP.end(), 0.0); //誤差合計をクリアする int j2=j; while(j2>=0){ MGLBRep& lbj2=*(brepList[j2]); lbj2=lb[j2]; //曲線を元に戻す if(tp_specified[j2]) *(tp[j2])=tpSave[j2]; j2--; } break; } } if(j>=nCrv) i-=(nDel+num_remained); else i--; } std::fill(totalTol.begin(), totalTol.end(), 0.0); //誤差合計をクリアする std::fill(totalTolTP.begin(), totalTolTP.end(), 0.0);//誤差合計をクリアする i=k; int nt=lb0.bdim()-mid; while(lb0.bdim()-i>nt){ int j=0; for(; jremove_knot_one(rc0,i, totalTolTP[j],num_remained); } if(j == 0) preDel = nDel; if(!nDel || nDel!=nDel2 || preDel!=nDel){//ノット削除に失敗したときの処理 std::fill(totalTol.begin(), totalTol.end(), 0.0); //誤差合計をクリアする std::fill(totalTolTP.begin(), totalTolTP.end(), 0.0); //誤差合計をクリアする int j2=j; while(j2>=0){ MGLBRep& lbj2=*(brepList[j2]); lbj2=lb[j2]; //曲線を元に戻す if(tp_specified[j2]) *(tp[j2])=tpSave[j2]; j2--; } break; } } if(j>=nCrv) i+=num_remained; else i++; } } #define INCNUM 20 ///Rebuild this NURBS by reconstructing new knot configuration. std::unique_ptr MGRLBRep::rebuild_with_new_knot_configuration( double error, //Error alowed to rebuild. If error<=0., MGTolerance::line_zero() //will be employed. 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. )const{ if(error<=0.) error=MGTolerance::line_zero(); double esave=MGTolerance::set_line_zero(error); //制御点を生成する MGKnotVector t=knot_vector(); int len = t.length(); t.change_number(len*INCNUM); std::unique_ptr rlb=std::unique_ptr(new MGRLBRep(*this,t)); rlb->remove_knot(); MGTolerance::set_line_zero(esave); if(parameter_normalization){ rlb->change_range(0.,1.); if(parameter_normalization==2){ MGVector v0=rlb->eval(0.,1); MGVector v1=rlb->eval(0.5,1); MGVector v2=rlb->eval(1.,1); double t2=(v0.len()+v1.len()+v2.len())/3.; rlb->change_range(0.,t2); } } return rlb; }