/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ #include "MGCLStdAfx.h" #include "mg/Box.h" #include "mg/Matrix.h" #include "mg/Transf.h" #include "mg/Straight.h" #include "mg/Ellipse.h" #include "mg/KnotArray.h" #include "mg/RLBRep.h" #include "mg/CCisect.h" #include "mg/Tolerance.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // Implements MGRLBRep Class // // Defines Rational Line B-Representation. // This NURBS is of homogeneous form, i.e., B-Coefficients have // weight included values. // When usual NURBS form is (xi, yi, zi, wi) , // MGRLBRep form is (xi*wi, yi*wi, zi*wi, wi) for i=0,..., n-1. //Construct Line NURBS, providing all the member data. MGRLBRep::MGRLBRep( const MGKnotVector& t, //Knot Vector. const MGBPointSeq& bcoef, //Line B-Coef, each of coefficients //includes weight multiplied when homogeneous=1, //and not includes when homogeneous =0. int homogeneous ):MGCurve(), m_line(t,bcoef){ assert(t.bdim()==bcoef.length()); if(!homogeneous){ double weight; int dim=bcoef.sdim()-1; //Multiply each weight to all control polygons. for(int i=0;i& weights ):MGCurve(){ assert(t.bdim()==bcoef.length()); m_line.m_knot_vector=t; int bdim=t.bdim(), dim=bcoef.sdim(); m_line.m_line_bcoef.resize(bdim,dim+1); double weight; //Multiply each weight to all control polygons. for(int i=0;isd) sd=sd1; if((sd1=P.sdim())>sd) sd=sd1; if((sd1=P2.sdim())>sd) sd=sd1; if((sd1=T2.sdim())>sd) sd=sd1; //sd is maximum space dimension. MGKnotVector t(3,3,0.,1.); //Of order 3, and B-Rep dimension 3. MGBPointSeq cp(3,sd+1); cp.store_at(0,P0);cp(0,sd)=1.; cp.store_at(1,P1);cp(1,sd)=w1; cp.store_at(2,P2);cp(2,sd)=1.; m_line=MGLBRep(t,cp); //This conic may contain infinite control point and //w1 may negative. double ca; if(w1!=0.){ MGVector P1w=P1/w1; MGVector V10(P0-P1w), V12(P2-P1w); ca=V10.cangle(V12); } if(w1<=0. || ca>=.5) split_conic(1); if(w1<0. && ca<=0.){ split_conic(3); split_conic(1); } } } //Construct 2D ellipse RLBRep, whose center is origin, //starting point is of angle1, and end point is of angle2. //The ellipse is expressed as below using parameter t. // x(t)=a*cos(t), y(t)=b*sin(t), angle1<=t<=angle2 MGRLBRep::MGRLBRep( double a, double b, double angle1, double angle2 ):MGCurve(){ double midp=(angle1+angle2)*.5; MGPosition P(a*cos(midp), b*sin(midp)); //Mid point of the ellipse. double c1=cos(angle1), s1=sin(angle1); //Starting point data. double c2=cos(angle2), s2=sin(angle2); //End point data. MGPosition P0(a*c1,b*s1), P2(a*c2,b*s2), P1; MGVector T0(-a*s1, b*c1), T2(-a*s2, b*c2); double w1; MGRLBRep_ellipse_weight(P0, T0, P, P2, T2, P1, w1); MGKnotVector kt(3,3,0.,1.); MGBPointSeq cp(3,3); cp.store_at(0,P0); cp(0,2)=1.; cp.store_at(1,P1); cp(1,2)=w1; cp.store_at(2,P2); cp(2,2)=1.; m_line=MGLBRep(kt,cp); } //Function to compute control point P1 and weight w1 of rational form of //an ellipse segment. Pi and Ti are point and tangent of start and end //for i=0,2. P is mid point of the ellipse. //Function's output is if obtained(!=0:true) or not(=0:false). //When obtained, =1:as finite control point, =2:as infinite. //***Method*** //See "The NURBS Book" of W.Tiller and L.Piegl publised by Springer. int MGRLBRep_ellipse_weight (const MGPosition& P0, const MGVector& T0, const MGPosition& P, const MGPosition& P2, const MGVector& T2, MGPosition& P1, double& w1) { MGStraight S0(MGSTRAIGHT_UNLIMIT,T0,P0), S2(MGSTRAIGHT_UNLIMIT,T2,P2); //S0 is straight line whose start point is P0 and tangent is T0, //and so on. MGCCisect is; MGPSRELATION rel=S0.relation(S2,is); //Compute isect P1 of S0 and S2. int ret_code=0; //ret_code=0 is the return code //when T0, T2, P0, and P2 are not in one plane. if(rel==MGPSREL_PARALLEL){ //When T0 and T2 are parallel. MGStraight S(MGSTRAIGHT_UNLIMIT,T0,P); //Staright that passes P and whose direction is T0. MGStraight S02(P2,P0); S02.relation(S,is); double r=S02.param_e(), r1=is.param1(); double tt=sqrt(r1/(r-r1)); double u=tt/(1.+tt); double b=2.*u*(1.-u); b=(1.-u)/b; P1=(P-S02.eval(r1))*b; w1=0.; ret_code=2; }else if(rel==MGPSREL_ISECT){ //Normal case(T0 and T1 are not parallel). P1=S0.eval(is.param1()); MGVector P1P=P1-P; MGStraight S(MGSTRAIGHT_UNLIMIT,P1P,P); //Staright that passes P1 and P. MGStraight S02(P2,P0); S02.relation(S,is); double r=S02.param_e(), r1=is.param1(); double tt=sqrt(r1/(r-r1)); double u=tt/(1.+tt); double oneu=1.-u; w1=oneu/u*((P-P0)%P1P)+u/oneu*((P-P2)%P1P); w1/=(2.*(P1P%P1P)); P1*=w1; ret_code=1; } return ret_code; } //**** 3.Conversion Constructor.**** //Approximate an original NURBS by a new knot configuration. //The new knot config must be inside the range of the original NURBS //parameter. However new knots may be coarse or fine. MGRLBRep::MGRLBRep( const MGRLBRep& old_brep,//Original NURBS. const MGKnotVector& t //knot vector ):MGCurve(old_brep), m_line(old_brep.m_line, t){ update_mark(); } //Gets new NURBS by adding knots to an original NURBS. MGRLBRep::MGRLBRep( const MGRLBRep& old_brep, //Original NURBS. const MGKnotArray& knots //Knots to add. ):MGCurve(old_brep), m_line(old_brep.m_line,knots){ update_mark(); } // Gets new NURBS by computing a part of the original. New one is exactly // the same as the original except that it is partial. //If multiple==true(!=0), knot(i)=t1 and knot(n+i)=t2 for i=0,..., k-1 //will be guaranteed. Here, n=bdim() and k=order(). //Both t1 and t2 must be inside te range of old_brep. MGRLBRep::MGRLBRep( double t1, double t2, //New parameter range. t1 must be less than t2. const MGRLBRep& old_brep, //Original NURBS. int multiple) //Indicates if start and end knot multiplicities //are necessary. =0:unnecessary, !=0:necessary. :MGCurve(old_brep), m_line(t1,t2,old_brep.m_line,multiple){ update_mark(); } // Convert from Non ratoinal to Rational form. MGRLBRep::MGRLBRep( const MGLBRep& brep, //Original LBRep. This can be ordinary LBRep, or //homogeneous form of MGRLBRep. When homogeneous form, //the last space dimension elements are weights. int homogeneous) //true(non zero): homogeneous form, //false(zero):ordinary SBRep. :MGCurve(brep), m_line(brep){ update_mark(); if(!homogeneous){ int n=brep.bdim(), dimm1=brep.sdim(); MGBPointSeq cp(n,dimm1+1); int i,j; for(i=0; i=0. // =0: start of this and start of brep1. // =1: start of this and end of brep1. // =2: end of this and start of brep1. // =3: end of this and end of brep1. // continuity and which can be obtained using continuity. const MGRLBRep& brep2) //NURBS 2. :MGCurve(brep1){ update_mark(); //Change connecting points' weight to 1. for both brep. double t1,t2; switch(which){ case 0: //Start of brep1 and start of brep2. t1=brep1.param_s(); t2=brep2.param_s(); break; case 1: //Start of brep1 and end of brep2. t1=brep1.param_s(); t2=brep2.param_e(); break; case 3: //End of brep1 and end of brep2. t1=brep1.param_e(); t2=brep2.param_e(); break; default: //Otherwise(2) End of brep1 and start of brep2. t1=brep1.param_e(); t2=brep2.param_s(); break; } int idw1=brep1.sdim(), idw2=brep2.sdim(); double weight1=brep1.m_line.eval(t1)(idw1); double weight2=brep2.m_line.eval(t2)(idw2); //Compute temporary LBReps that have the same weights at the //connecting points. MGLBRep line1(brep1.m_line), line2(brep2.m_line); line1.line_bcoef() /=weight1; line2.line_bcoef() /=weight2; //Connect two. m_line=MGLBRep(line1,continuity,which, line2); } //Construct a Line NURBS by changing space dimension and ordering of //coordinates. MGRLBRep::MGRLBRep( int dim, // New space dimension. const MGRLBRep& lbrep, // Original Line B-rep. int start1, // Destination order of new line. int start2) // Source order of original line. :MGCurve(lbrep){ update_mark(); int dim0=lbrep.sdim(); MGBPointSeq cp1(dim0,lbrep.line_bcoef());//Exclude weights. MGBPointSeq cp2(dim,cp1,start1,start2); //Change order of coordinates. MGBPointSeq cp3(dim+1,cp2); //Get area for weights. for(int i=0; i=0. int which, //which point of this to which of brep2. // =0: start of this and start of brep2. // =1: start of this and end of brep2. // =2: end of this and start of brep2. // =3: end of this and end of brep2. const MGRLBRep& brep2) //B-Rep 2. { int sd1=sdim(), sd2=brep2.sdim(); if(sd1=0. // =0: start of this to start of brep2. // =1: start of this to end of brep2. // =2: end of this to start of brep2. // =3: end of this to end of brep2. double& ratio // Ratio of 1st derivatives of the two line will // be returned when G0 continuity. // ratio= d2/d1, where d1=1st deriv of this and d2=of brep2 ) const // Function's return value is: // -1: G(-1) continuity, i.e. two lines are discontinuous. // 0: G0 continuity, i.e. two lines are connected, // but tangents are discontinuous { double start1=param_s(), end1=param_e(); double start2=brep2.param_s(), end2=brep2.param_e(); //Determine which point of brep1 is continuous to which //point of brep2. MGPosition p1[2]={eval(start1), eval(end1)}; MGPosition p2[2]={brep2.eval(start2), brep2.eval(end2)}; which=2; ratio=1.; //These values are default. double t1,t2; //Used for the parameters at connecting points. int cn=0; // Check of C-0 continuity. if(p1[0]==p2[0]) { which=0; //which=0 means start of brep1 connects // to start of brep2. t1=start1; t2=start2; } else if(p1[0]==p2[1]) { which=1; //which=1 means start of brep1 connects // to end of brep2. t1=start1; t2=end2; } else if(p1[1]==p2[0]) { which=2; //which=2 means end of brep1 connects // to start of brep2. t1=end1; t2=start2; } else if(p1[1]==p2[1]) { which=3; //which=3 means end of brep1 connects // to end of brep2. t1=end1; t2=end2; } else return -1; //Compute temporary LBReps that have the same weights at the //connecting points. int idw1=sdim(), idw2=brep2.sdim(); MGLBRep line1(m_line), line2(brep2.m_line); double weight1=line1.eval(t1)(idw1); double weight2=line2.eval(t2)(idw2); line1.line_bcoef() /=weight1; line2.line_bcoef() /=weight2; int which2; double ratio2; int cn2=line1.continuity(line2,which2,ratio2); if(cn2>cn) cn=cn2; // Compute ratio; double dlen1=eval(t1, 1).len(); double dlen2=brep2.eval(t2, 1).len(); if(!MGMZero(dlen1)) ratio=dlen2/dlen1; return cn; } // Evaluate right continuous n'th derivative data. // nderiv=0 means positional data evaluation. MGVector MGRLBRep::eval( double tau, // Parameter value. int nderiv, // Order of Derivative. int left //Left continuous(left=true) //or right continuous(left=false). )const{ int m; int dim=sdim(); MGVector result(dim); if(nderiv==0){ MGVector data=m_line.eval(tau,0,left); double weight=data[dim]; for(m=0; m16) delete[] data; if(ndp1>4) delete[] bcp_save; } // 自身に指定したパラメータ範囲のlimitをつける。 //Get the sub interval line of the original line. MGRLBRep& MGRLBRep::limit(const MGInterval& itvl){ update_mark(); m_line.limit(itvl); return *this; } //Return non_homogeneous B-Coefficients with weights of //the rational B-Spline. This MGBPointSeq includes weights. MGBPointSeq MGRLBRep::non_homogeneous_bcoef()const{ int i,j, sd=sdim(), n=bdim(); MGBPointSeq cp(n,sd+1); for(i=0; ilimit(MGInterval(t1,t2)); return rlb; } //Check if the line B-rep is planar. //Funtion's return value is; // 0: Not planar, nor a point, nor straight line. // 1: NURBS is a point. 2: NURBS is a straight line. // 3: NURBS is planar. int MGRLBRep::planar( MGPlane& plane //When Brep is not straight line nor a point, // plane is returned. //Even when not planar(return value is 0), plane nearest is returned. , MGStraight& line //When Brep is a line, line is returned. , MGPosition& point //When Brep is a point, point is returned. )const{ return m_line.line_bcoef().non_homogeneous().planar(plane,line,point); } //Split conic RLBRep at the i-th control point. //This RLBRep must be conic section. MGRLBRep& MGRLBRep::split_conic(int i){ int sd=sdim(); MGVector P0=coef(i-1), P1=coef(i), P2=coef(i+1); double w1=P1.ref(sd); double onepw1=1.+w1; double weight=sqrt(onepw1*0.5); double weight2=weight*2.; MGVector Q=(P0+P1)/weight2, R=(P1+P2)/weight2; Q(sd)=R(sd)=weight; MGVector S=(P0+2.*P1+P2)/onepw1/2.; S(sd)=1.; double tmid=(m_line.knot(i+1)+m_line.knot(i+2))*0.5; m_line.knot_vector().add_data(MGKnot(tmid,2),3); m_line.line_bcoef().store_at(i,R); m_line.line_bcoef().insert_at(i,S); m_line.line_bcoef().insert_at(i,Q); return *this; } //Operator overload //Assignment. //When the leaf object of this and obj2 are not equal, this assignment //does nothing. MGRLBRep& MGRLBRep::operator=(const MGRLBRep& gel2){ if(this==&gel2) return *this; MGCurve::operator=(gel2); m_line=gel2.m_line; return *this; } MGRLBRep& MGRLBRep::operator=(const MGGel& gel2){ const MGRLBRep* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) operator=(*gel2_is_this); return *this; } // 曲線の平行移動を行いオブジェクトを生成する。 //Translation of the curve. MGRLBRep MGRLBRep::operator+(const MGVector& v)const{ MGBPointSeq bc(m_line.line_bcoef()); bc.homogeneous_transform(v); return MGRLBRep(m_line.knot_vector(),bc); } //Translation of the curve. MGRLBRep operator+(const MGVector& v, const MGRLBRep& lb){ return lb+v; } // 与ベクトルだけ曲線を平行移動して自身とする。 //Translation of the curve. MGRLBRep& MGRLBRep::operator+= (const MGVector& v){ m_line.line_bcoef().homogeneous_transform(v); if(m_box) (*m_box)+=v; return *this; } // 曲線の逆方向に平行移動を行いオブジェクトを生成する。 //Translation of the curve. MGRLBRep MGRLBRep::operator- (const MGVector& v) const{ MGBPointSeq bc(m_line.line_bcoef()); bc.homogeneous_transform(-v); return MGRLBRep(m_line.knot_vector(),bc); } // 与ベクトルだけ曲線をマイナス方向に平行移動して自身とする。 //Translation of the curve. MGRLBRep& MGRLBRep::operator-= (const MGVector& v){ m_line.line_bcoef().homogeneous_transform(-v); if(m_box) (*m_box)-=v; return *this; } // 与えられたスケールをかけオブジェクトを生成する。 //generate line by scaling. MGRLBRep MGRLBRep::operator* (double s) const{ MGBPointSeq bc(m_line.line_bcoef()); bc.homogeneous_transform(s); return MGRLBRep(m_line.knot_vector(),bc); } // 与えられたスケールをかけオブジェクトを生成する。 //generate line by scaling. MGRLBRep operator* (double scale, const MGRLBRep& lb){ return lb*scale; } // 自身の曲線に与えられたスケールをかける。 //Scale the curve. MGRLBRep& MGRLBRep::operator*= (double s){ m_line.line_bcoef().homogeneous_transform(s); update_mark(); return *this; } // 与えられた変換で曲線の変換を行いオブジェクトを生成する。 //Matrix transformation of the curve. MGRLBRep MGRLBRep::operator* (const MGMatrix& m) const{ MGBPointSeq bc(m_line.line_bcoef()); bc.homogeneous_transform(m); return MGRLBRep(m_line.knot_vector(),bc); } // 与えられた変換で曲線の変換を行い自身の曲線とする。 //Matrix transformation of the curve. MGRLBRep& MGRLBRep::operator*= (const MGMatrix& m){ m_line.line_bcoef().homogeneous_transform(m); update_mark(); return *this; } // 与えられた変換で曲線のトランスフォームを行いオブジェクトを生成する。 //General transformation of the curve. MGRLBRep MGRLBRep::operator* (const MGTransf& t) const{ MGBPointSeq bc(m_line.line_bcoef()); bc.homogeneous_transform(t); return MGRLBRep(m_line.knot_vector(),bc); } // 与えられた変換で曲線のトランスフォームを行い自身とする。 //General transformation of the curve. MGRLBRep& MGRLBRep::operator*= (const MGTransf& t){ m_line.line_bcoef().homogeneous_transform(t); update_mark(); return *this; } // 論理演算子の多重定義 // 自身とCurveが等しいかどうか比較し判定する。 // 与曲線と自身が等しいかの比較判定を行う。 //Two curves comparison. bool MGRLBRep::operator==(const MGLBRep& gel2)const{ if(sdim()!=gel2.sdim()) return 0;//Check of space dimension. if(order()!=gel2.order()) return 0; //Check of order. int bdm=bdim(); if(bdm!=gel2.bdim()) return 0; //Check of B-Rep dimension. if(bdm<=0) return 1; if(!non_rational()) return 0; //Check of rationality. if(knot_vector() != gel2.knot_vector()) return 0;//Check of knot vector. //Finally, check of control polygon. return m_line.line_bcoef().non_homogeneous()==gel2.line_bcoef() ; } bool MGRLBRep::operator==(const MGRLBRep& rlb2)const{ int bd1=bdim(), bd2=rlb2.bdim(); if(bd1!=bd2) return 0; if(bd1<=0) return 1; int sd1=sdim(), sd2=rlb2.sdim(); if(sd1!=sd2) return 0; if(order()!=rlb2.order()) return 0; //Check of order. if(knot_vector() != rlb2.knot_vector()) return 0; double ratio=rlb2.coef(0,sd2)/coef(0,sd1); //Check if weights are equal. for(int i=1; i(&gel2); if(gel2_is_this) return operator==(*gel2_is_this); return false; } bool MGRLBRep::operator<(const MGGel& gel2)const{ const MGRLBRep* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) return operator<(*gel2_is_this); return false; }