/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ #include "MGCLStdAfx.h" #include "mg/Box.h" #include "mg/Position.h" #include "mg/Transf.h" #include "mg/Unit_vector.h" #include "mg/CParam_list.h" #include "mg/Straight.h" #include "mg/LBRep.h" #include "mg/RLBRep.h" #include "mg/Plane.h" #include "mg/Tolerance.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //MGStraighy Class Implementation // // // Constructor //Void constructor MGStraight::MGStraight() : MGCurve() ,m_sparam(0.0),m_endparam(-1.),m_knotV(0){;} //Straight specifying all the member data. All of the data are employed as //member data of this straight. MGStraight::MGStraight ( const MGEReal& endparam, //end parameter value const MGEReal& sparam, //start parameter value const MGVector& direction, //Direction, which will be the direction of this. const MGPosition& Origin //Origin ):m_direction(direction), m_endparam(endparam), m_knotV(0), m_root_point(Origin), m_sparam(sparam){;} //Straight specifying all the member data. All of the data are employed as //member data of this straight. MGStraight::MGStraight ( double endparam, //end parameter value double sparam, //start parameter value const MGVector& direction, //Direction, which will be the direction of this. const MGPosition& Origin //Origin ):m_direction(direction), m_endparam(endparam), m_knotV(0), m_root_point(Origin), m_sparam(sparam){;} //Copy constructor. MGStraight::MGStraight(const MGStraight& sl) :MGCurve(sl), m_direction(sl.m_direction), m_endparam(sl.m_endparam), m_knotV(0), m_root_point(sl.m_root_point), m_sparam(sl.m_sparam){;} // 始点、方向ベクトル、直線のタイプを指定して直線を生成する。 MGStraight::MGStraight ( MGSTRAIGHT_TYPE t, const MGVector& v, const MGPosition& p ):MGCurve(),m_root_point(p),m_direction(v.normalize()) ,m_sparam(0.0),m_endparam(MGINFINITE_PLUS),m_knotV(0){ if (t==MGSTRAIGHT_SEGMENT) m_endparam=v.len(); else if(t==MGSTRAIGHT_EMPTY) m_endparam=-1.; else if(t==MGSTRAIGHT_UNLIMIT) m_sparam=MGEReal(MGINFINITE_MINUS); int dimv=v.sdim(), dimp=p.sdim(); if(dimvdimp) m_root_point=MGVector(dimv,p); } // 2点から直線を生成する。 //Parameter value of the start point is set to be 0. MGStraight::MGStraight( const MGPosition& end, //End point. const MGPosition& start //Start point. ):MGCurve(),m_root_point(start),m_sparam(0.0),m_knotV(0){ // 2点から単位ベクトルを作成する。 MGVector v(end,start); m_direction = v.normalize(); // 単位方向ベクトルをもつので // 作成したベクトルの長さが終点のパラメータ値 m_endparam=v.len(); if(m_root_point.sdim()dimp) m_root_point=MGVector(dimv,p); if (m_endparam < 0.0) { m_direction = -m_direction; m_endparam = -m_endparam; } } //Construct the infinite straight line that is a perpendicular bisect //of the two point P1 and P2 and that is normal to the vector N. //The line's direction is N*(P2-P1). //N is the normal of the plane P1, P2, and the constructed line lie on. MGStraight::MGStraight ( const MGPosition& P1, //point 1. const MGPosition& P2, //point 2. const MGVector& N ):MGCurve(),m_root_point((P1+P2)*.5),m_direction(N*(P2-P1)) ,m_sparam(MGINFINITE_MINUS),m_endparam(MGINFINITE_PLUS),m_knotV(0){ } //Construct Straight Line copying original line. Able to change //space dimension and ordering of axis. MGStraight::MGStraight ( int dim, //New space dimension. const MGStraight& line2, //Original line. int start1, //store order of new line. int start2) //source order of original line. :MGCurve(line2), m_root_point(dim,line2.m_root_point,start1, start2) , m_direction(dim, line2.m_direction, start1,start2) ,m_sparam(line2.m_sparam), m_endparam(line2.m_endparam),m_knotV(0){ update_mark(); save_length_zero(); } ///Construct the unlimitted straight that pass through the point uv, ///and the direction is the middle vector of (-v0, v1). ///All of v0, v1, uv, and this straight are objects of space dimension 2. MGStraight::MGStraight( const MGVector& v0, //a vector whose end is uv. const MGVector& v1, //a vector whose start is uv. const MGPosition& uv//origin of sl. ):MGCurve(),m_knotV(0){ MGVector v2=v0*-1.; double angHalf=v1.angle2pai(v2, MGDefault::z_unit_vector()); angHalf*=.5; MGMatrix rotate; rotate.set_rotate_2D(angHalf); MGVector vmid=v1*rotate; set_straight(MGSTRAIGHT_UNLIMIT,vmid,uv); } ///////// Destructor /////////// MGStraight::~MGStraight(){ if(m_knotV) delete m_knotV; } // // メンバ関数 // ///Approximate this curve as a MGLBRep curve ///within the tolerance MGTolerance::line_zero(). ///When parameter_normalization=0, reparameterization will not done, and ///the evaluation at the same parameter has the same values before and after ///of approximate_as_LBRep. void MGStraight::approximate_as_LBRep( MGLBRep& lb, ///s2){ negate(); double save=s1; s1=s2; s2=save; } if(m_sparam.minus_infinite()&&m_endparam.plus_infinite()) return; double t1=m_sparam.value(), t2=m_endparam.value(); if(m_sparam.minus_infinite()){ m_root_point+=(t2-s2)*m_direction; m_endparam=s2; return; } if(m_endparam.plus_infinite()){ m_root_point+=(t1-s1)*m_direction; m_sparam=s1; return; } double s2ms1=s2-s1, t2mt1=t2-t1; if(MGMZero(s2ms1)){ if(MGMZero(t2mt1)){ m_root_point+=(t2-s2)*m_direction; m_sparam=s1; m_endparam=s2; } return; } double ratio=t2mt1/s2ms1; m_root_point += m_direction*(t1-s1*ratio); m_direction *= ratio; m_sparam=s1; m_endparam=s2; // std::cout<0.) (*box)(i)= MGInterval(MGINTERVAL_FINITE_BELOW,start_point().ref(i)); else (*box)(i)= MGInterval(MGINTERVAL_FINITE_ABOVE,start_point().ref(i)); } } else if (p_limit.finite_above()&&p_limit.infinite_below()) { for(int i=0; i0.) (*box)(i)= MGInterval(MGINTERVAL_FINITE_ABOVE,root_point().ref(i)); else (*box)(i)= MGInterval(MGINTERVAL_FINITE_BELOW,root_point().ref(i)); } } else { for(int i=0; i0.); const MGVector& dir=direction(); double tlen=length/dir.len(); if(start){ if(infinite_below()) return; m_sparam-=tlen; }else{ if(infinite_above()) return; m_endparam+=tlen; } if(m_knotV){ delete m_knotV; m_knotV=0; } } //Test if input parameter value is inside parameter range of the line. bool MGStraight::in_range(double t)const{ double error=MGTolerance::rc_zero()*m_direction.len(); //error is maximum distance of // two points that are assumed to be the same. double esave=MGTolerance::set_wc_zero(error); bool in=(m_sparam<=t && t<=m_endparam); MGTolerance::set_wc_zero(esave); return in; } //Test if this cure is co-planar with the 2nd curve curve2. //MGPlane expression will be out to plane if this is co-planar. //Function's return value is true if co-planar. bool MGStraight::is_coplanar(const MGCurve& curve2, MGPlane& plane)const{ const MGStraight* sl2=dynamic_cast(&curve2); if(sl2){ //When both are straight. if(direction().parallel(sl2->direction())){ plane=MGPlane(*sl2,root_point()); return true; }else{ MGUnit_vector normal=direction()*sl2->direction(); plane=MGPlane(normal,root_point()); return plane.on(sl2->root_point()); } } MGStraight line2; MGPosition point; int plkind=-1; const MGLBRep* lb=dynamic_cast(&curve2); if(lb) plkind=lb->planar(plane,line2,point); else{ const MGRLBRep* rlb=dynamic_cast(&curve2); if(rlb) plkind=lb->planar(plane,line2,point); } if(plkind==0) return false; if(plkind==1){ plane=MGPlane(*this,point); return true; }else if(plkind==2){ if(!direction().parallel(line2.direction())) return false; plane=MGPlane(line2,root_point()); return true; }else if(plkind==3){ return plane.on(*this); } //When curve2 is neither MGLBRep nor MGRLBRep. if(!curve2.is_planar(plane)) return false; return plane.on(*this); } //Test if the input parameter t is the start point parameter or not. bool MGStraight::is_startpoint_parameter(double t)const{ if(m_sparam.minus_infinite()) return false; if(m_endparam.plus_infinite()){ return m_sparam==t; } return MGREqual_base(param_s(),t,param_span()); } //Test if the input parameter t is the start point parameter or not. bool MGStraight::is_endpoint_parameter(double t)const{ if(m_endparam.plus_infinite()) return false; if(m_sparam.minus_infinite()){ return m_endparam==t; } return MGREqual_base(param_s(),t,param_span()); } //Test if this cure is linear or not, that is, is straight or not. //MGStraight expression will be out to straight if this is linear or not. //Function's return value is true if linear. bool MGStraight::is_linear(MGStraight& straight)const{ straight=(*this); return true; } //Test if this cure is planar or not. //MGPlane expression will be out to plane if this is planar. //Function's return value is true if planar. bool MGStraight::is_planar(MGPlane& plane)const{ const MGVector& sldir=direction(); double xx=sldir%mgX_UVEC; xx*=xx; double yy=sldir%mgY_UVEC; yy*=yy; double zz=sldir%mgZ_UVEC; zz*=zz; MGVector dir2; if(xx<=yy){ if(xx<=zz) dir2=mgX_UVEC; else dir2=mgZ_UVEC; }else{ if(yy<=zz) dir2=mgY_UVEC; else dir2=mgZ_UVEC; } plane=MGPlane(sldir,dir2,root_point()); return true; } //Access to i-th element of knot. //i=0, 1 and returns start or end parameter value of the straight. double MGStraight::knot(int i) const{ assert(i<=3); if(i<=1) return param_s(); else return param_e(); } //Returns the knot vector of the curve. const MGKnotVector& MGStraight::knot_vector() const{ if(!m_knotV){ m_knotV=new MGKnotVector(2,2); (*m_knotV)(0)=(*m_knotV)(1)=param_s(); (*m_knotV)(2)=(*m_knotV)(3)=param_e(); } return *m_knotV; } MGKnotVector& MGStraight::knot_vector(){ if(!m_knotV){ m_knotV=new MGKnotVector(2,2); (*m_knotV)(0)=(*m_knotV)(1)=param_s(); (*m_knotV)(2)=(*m_knotV)(3)=param_e(); } return *m_knotV; } // パラメータ値が昇順であたえられた場合正の値で、降順の場合 // 負の値でパラメータ間の直線の代数的距離を返却する。 double MGStraight::length (double d1, double d2) const { return (range(d2) - range(d1))*m_direction.len(); } // 自身の直線が有界の場合、その直線の距離を返却する。 // 非有界のとき−2を返却する。 double MGStraight::length () const { double d = -2.0; if (straight_type() == MGSTRAIGHT_SEGMENT) d=(m_endparam.value()-m_sparam.value())*m_direction.len(); else if (straight_type() == MGSTRAIGHT_EMPTY) d = 0.0; return d; } // 直線上の与えられたパラメータで示される点から指定距離はなれた点 // のパラメータ値をかえす。 double MGStraight::length_param (double t,double len) const { return range(t+len/m_direction.len()); } // 自身の直線に指定されたlimitを付与する。 MGStraight& MGStraight::limit(const MGInterval& l) { if(m_knotV){delete m_knotV; m_knotV=0;} MGInterval p_limit = param_range(); // 直線範囲のパラメータを作成 p_limit &= l; // 指定Intervalとの積をとる m_sparam=p_limit.low(); m_endparam=p_limit.high(); update_mark(); return *this; } //Compute sub straight line limitted by an box. //This box's coordinates consist of world coordinates. MGStraight& MGStraight::limit(const MGBox& box){ MGInterval prange=param_range(); MGCParam_list list; double bound, t; int dim=sdim(); for(int i=0; i>t){ if(m_direction.ref(i)>=0.) prange.set_low_point(t); else prange.set_high_point(t); } } bound=box.ref(i).high_point(); list=isect_1D(bound, i); if(list.entries()){ t=list.first(); if(prange>>t){ if(m_direction.ref(i)>=0.) prange.set_high_point(t); else prange.set_low_point(t); } } } limit(prange); return *this; } //Compute nearest point on the line to the origin. MGPosition MGStraight::nearest_to_origin() const{ double lensqr=m_direction.len(); lensqr*=lensqr; return MGPosition (root_point()-m_direction*((root_point()%m_direction)/lensqr)); } // 直線の方向を反転する(方向ベクトルを逆向きにする)。 // 始終点があるときは入れ換える。 void MGStraight::negate(){ if(m_knotV){delete m_knotV; m_knotV=0;} MGEReal save=m_sparam; m_sparam=-m_endparam; m_endparam=-save; m_direction = -m_direction; } //Obtain parameter value if this curve is negated by "negate()". double MGStraight::negate_param(double t)const{ return -t; } //Obtain so transformed 1D curve expression of this curve that //f(t)={sum(xi(t)*g[i]) for i=0(x), 1(y), 2(z)}-g[3], where f(t) is the output //of oneD and xi(t) is i-th coordinate expression of this curve. //This is used to compute intersections with a plane g[4]. std::unique_ptr MGStraight::oneD( const double g[4] //Plane expression(a,b,c,d) where ax+by+cz=d. )const{ MGStraight* sl=new MGStraight(*this); MGVector G(3,g); MGVector one(1); one(0)=G%m_direction; sl->m_direction=one; one(0)=G%m_root_point-g[3]; sl->m_root_point=one; return std::unique_ptr(sl); } //Obtain parameter space error. double MGStraight::param_error()const{ MGEReal len=m_endparam-m_sparam; if(len.finite()) return len.value()*MGTolerance::rc_zero(); else{ double vlen=m_direction.len(); return vlen*MGTolerance::rc_zero(); } } //Normalize parameter value t to the nearest knot if their distance is //within tolerance. For straight, the knots are start and end points. double MGStraight::param_normalize(double t) const{ double plen; if(straight_type()==MGSTRAIGHT_SEGMENT) plen=param_span(); else plen=1.; double tnew; if(straight_type()==MGSTRAIGHT_SEGMENT || straight_type()==MGSTRAIGHT_HALF_LIMIT){ tnew=param_s(); if(MGRZero2(t-tnew,plen)) return tnew; } if(straight_type()==MGSTRAIGHT_SEGMENT){ tnew=param_e(); if(MGRZero2(t-tnew,plen)) return tnew; } return t; } //Return parameter range of the curve(パラメータ範囲を返す) MGInterval MGStraight::param_range()const{ return MGInterval(m_sparam, m_endparam); } //Compute part of this curve from parameter t1 to t2. //Returned is the pointer to newed object, and so should be deleted //by calling program, or memory leaked. MGStraight* MGStraight::part(double t1, double t2, int multiple)const{ assert(t2>=t1); MGStraight* sl=new MGStraight(*this); sl->limit(MGInterval(t1,t2)); return sl; } // 入力パラメータをパラメータ範囲で丸めて返却する。 double MGStraight::range(double d) const { MGInterval limit = param_range(); if(straight_type()==MGSTRAIGHT_EMPTY) d=0.0; else if(limit>=d) d=m_sparam.value(); else if(limit<=d) d=m_endparam.value(); return d; } //Function to avoid m_direction.len()=zero. //The line's m_direction is set as a unit vector and m_endparam //is set to zero. void MGStraight::save_length_zero(){ double dlen=m_direction.len(); if(MGMZero(dlen)){ m_direction=m_direction.normalize(); m_endparam=m_sparam+dlen; if(m_knotV){delete m_knotV; m_knotV=0;} } } //Return space dimension int MGStraight::sdim() const{ int dim1=m_root_point.sdim(); if(dim1==0) return 0; int dim2=m_direction.sdim(); if(dim1dimp) m_root_point=MGPosition(dimv,Q); save_length_zero(); update_mark(); return *this; } // 自身の直線の始点を返却する。 //Return start(root) point of the straight. MGPosition MGStraight::start_point() const{ return eval_position(m_sparam.value()); } // 直線のタイプを返却する。 //Return the straight line type. MGSTRAIGHT_TYPE MGStraight::straight_type() const{ if(m_sparam>m_endparam) return MGSTRAIGHT_EMPTY; else if(m_sparam.finite()){ if(m_endparam.finite()) return MGSTRAIGHT_SEGMENT; else return MGSTRAIGHT_HALF_LIMIT; }else{ if(m_endparam.finite()) return MGSTRAIGHT_HALF_LIMIT; else return MGSTRAIGHT_UNLIMIT; } } // 自身の直線からlimitを取り除く。 MGCurve& MGStraight::unlimit(){ m_sparam=MGEReal(MGINFINITE_MINUS); m_endparam=MGEReal(MGINFINITE_PLUS); update_mark(); return *this; } //Unlimit parameter range of the curve to the end point direction //(終点方向にlimitをはずす) MGCurve& MGStraight::unlimit_end(){ m_endparam=MGEReal(MGINFINITE_PLUS); update_mark(); return *this; } //Unlimit parameter range of the curve to the start point direction //(始点方向にlimitをはずす) MGCurve& MGStraight::unlimit_start(){ m_sparam=MGEReal(MGINFINITE_MINUS); update_mark(); return *this; } //Update the root point of this straight. void MGStraight::update_root(const MGPosition& rootP){ m_root_point=rootP; update_mark(); } // // 演算子の多重定義 // //Assignment. //When the leaf object of this and crv2 are not equal, this assignment //does nothing. MGStraight& MGStraight::operator=(const MGStraight& sl2){ if(this==&sl2) return *this; MGCurve::operator=(sl2); m_direction=sl2.m_direction; m_endparam=sl2.m_endparam; if(m_knotV){ delete m_knotV; m_knotV=0; } m_root_point=sl2.m_root_point; m_sparam=sl2.m_sparam; return *this; } MGStraight& MGStraight::operator=(const MGGel& gel2){ const MGStraight* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) operator=(*gel2_is_this); return *this; } // 直線の平行移動を行いオブジェクトを生成する。 MGStraight MGStraight::operator+(const MGVector& vec) const{ MGStraight sl2 = *this; sl2 += vec; return sl2; } MGStraight operator+(const MGVector& v, const MGStraight& sl){ return sl+v; } // 直線の平行移動を行い自身の直線とする。 MGStraight& MGStraight::operator+=(const MGVector & v){ m_root_point += v; if(m_box) (*m_box)+=v; return *this; } // 直線の逆方向に平行移動を行いオブジェクトを生成する。 MGStraight MGStraight::operator-(const MGVector & v)const{ MGStraight sl2 = *this; sl2 -= v; return sl2; } //直線の逆方向に平行移動を行い自身の直線とする。 MGStraight& MGStraight::operator-= (const MGVector & v){ m_root_point -= v; if(m_box) (*m_box)-=v; return *this; } // 与えられたスケールで直線の変換を行いオブジェクトを生成する。 //Generate scaled straight. MGStraight MGStraight::operator*(double scale) const{ MGStraight sl(*this); sl *=scale; return sl; } // 与えられたスケールで直線の変換を行いオブジェクトを生成する。 //Generate scaled straight. MGStraight operator*(double scale, const MGStraight& sl){ return sl*scale; } // 与えられたスケールで直線の変換を行い自身の直線とする。 //Scaling the straight. MGStraight& MGStraight::operator*=(double scale){ m_root_point *=scale; m_direction *=scale; save_length_zero(); update_mark(); return *this; } // 与えられた変換で直線の変換を行いオブジェクトを生成する。 MGStraight MGStraight::operator*(const MGMatrix& t)const{ MGStraight sl2 = *this; sl2 *= t; return sl2; } // 与えられた変換で直線の変換を行い自身の直線とする。 MGStraight& MGStraight::operator*=( const MGMatrix& t ){ m_root_point *= t; m_direction *=t; save_length_zero(); update_mark(); return *this; } // 与えられた変換で直線のトランスフォームを行いオブジェクトを生成する。 MGStraight MGStraight::operator*(const MGTransf& t)const{ MGStraight sl2 = *this; sl2 *= t; return sl2; } // 与えられた変換で直線のトランスフォームを行い自身の直線とする。 MGStraight& MGStraight::operator*=(const MGTransf& t){ m_root_point *= t; m_direction *=t.affine(); save_length_zero(); update_mark(); return *this; } // // 論理演算子の多重定義 bool MGStraight::operator==(const MGStraight& sl2)const{ if(sdim()==0 && sl2.sdim()==0) return 1; return (m_root_point == sl2.m_root_point && m_direction == sl2.m_direction && m_sparam==sl2.m_sparam && m_endparam==sl2.m_endparam); } bool MGStraight::operator<(const MGStraight& gel2)const{ return m_root_point.len()(&gel2); if(gel2_is_this) return operator==(*gel2_is_this); return false; } bool MGStraight::operator<(const MGGel& gel2)const{ const MGStraight* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) return operator<(*gel2_is_this); return false; }