/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ #include "MGCLStdAfx.h" #include "mg/Tolerance.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/CCisect_list.h" #include "mg/CSisect_list.h" #include "mg/CSisect.h" #include "mg/Position_list.h" #include "mg/Straight.h" #include "mg/LBRep.h" #include "mg/RLBRep.h" #include "mg/Ellipse.h" #include "mg/SurfCurve.h" #include "mg/BSumCurve.h" #include "mg/Plane.h" #include "mg/Sphere.h" #include "mg/Cylinder.h" #include "mg/SBRep.h" #include "mg/RSBRep.h" #include "mg/BSumSurf.h" #include "topo/Face.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //MGStraighy Class Implementation // // // メンバ関数 // ///Compute the closest point parameter value of this curve from a point. double MGStraight::closest(const MGPosition& point)const{ double t=perp_param(point);//t is the parameter value of the closest point on this. double error=MGTolerance::rc_zero()*m_direction.len(); double esave=MGTolerance::set_wc_zero(error); t=range(t); MGTolerance::set_wc_zero(esave); return t; } ///Compute the closest point parameter value pair of this curve and curve2. ///MGPosition P of the function return contains this and curve2's parameter ///as: P(0)=this curve's parameter, P(1)=curve2's parameter value. MGPosition MGStraight::closest(const MGCurve& curve2)const{ const MGStraight* sl2=dynamic_cast(&curve2); if(sl2) return closestSL(*sl2); MGUnit_vector sldir=direction(); const MGPosition p_on_crv2=curve2.center(); MGPosition origin=eval_position_unlimitted(perp_param(p_on_crv2)); MGMatrix M; M.set_axis(sldir,2); std::unique_ptr crv2dP(curve2.clone()); MGCurve& crv2d=*crv2dP; crv2d-=origin; crv2d*=M; MGPosition param(2); double* tout=param.data(); double& otherParam=tout[1]=crv2d.closest2D(MGDefault::origin_2D()); double& thisParam=tout[0]=perp_param(curve2.eval(tout[1])); MGVector V=curve2.eval(otherParam)-eval(thisParam); double d=V%V; double paramS=param_s(), paramE=param_e(); MGPosition SPoint=eval(paramS); double otherParam2=curve2.closest(SPoint); MGVector VS=curve2.eval(otherParam2)-SPoint; double dS=VS%VS; if(dSm_endparam) d=(p-end_point()).len(); else{ d= v1len*v1len - hs*hs; if(d<0.) d=0.; d= sqrt(d); // 点と無限直線の最短距離。 } // 最短距離を返す。 return d; } ///Compute the closest point parameter value pair of this MGStraight and straight2. ///MGPosition P of the function return contains this and straight2's parameter ///as: P(0)=this MGStraight's parameter, P(1)=straight2's parameter value. MGPosition MGStraight::closestSL(const MGStraight& straight2)const{ // 与えられた直線との関係を調べる。 MGCCisect is; MGPSRELATION rl=relation(straight2,is); MGPosition st(is.param1(), is.param2()); //Function's return value: [0] this straight's parameter, //[1]: straight2's parameter. double& s=st(0); double& t=st(1); switch(rl){ case MGPSREL_ISECT: case MGPSREL_PARALLEL: case MGPSREL_COIN: break; default://MGPSREL_VIRTUAL_ISECT, or MGPSREL_TORSION, //and s_in_range=false or t_in_range=false. bool s_in_range=in_range(s); bool t_in_range=straight2.in_range(t); if(s_in_range && t_in_range) break; //case that !s_in_range or !t_in_range holds. double distance1=-1., distance2=-1; double s1,s2, t1,t2; if(!s_in_range){ s1=range(s); MGPosition P=eval(s1); t1=straight2.closest(P); MGVector V=P-straight2.eval(t1); distance1=V%V; } if(!t_in_range){ t2=straight2.range(t); MGPosition Q=straight2.eval(t2); s2=closest(Q); MGVector V=Q-eval(s2); distance2=V%V; } if(s_in_range){ //case of !t_in_range s=s2; t=t2; }else if(t_in_range){ //case of !s_in_range s=s1; t=t1; }else{ //!s_in_range and !t_in_range if(distance1isectSl(*this,f.box_param()); MGCSisect_list::CSiterator i=list.begin(), iend=list.end(), i1; while(i!=iend){ i1=i; i1++; if(!f.in_range((*i).param_surface())) list.removeAt(i); i=i1; } return list; } //Compute intersection point of 1D sub curve of original curve. //Parameter values of intersection point will be returned. MGCParam_list MGStraight::intersect_1D( double f, // Coordinate value int coordinate // Coordinate kind of the data f(from 0). )const{ MGCParam_list list(this); double u=direction().ref(coordinate); if(MGMZero(u)){ if(MGAEqual(f,m_root_point(coordinate))) list.append(m_sparam.value()); }else{ double p=f-root_point().ref(coordinate); double t=p/u; if(in_range(t)) list.append(t); } return list; } //isect2D returns parameter values of this(t) and l2(s) // of the intersection point of both 2D straight lines. // This and l2 are treated as infinite lines. //Function's return value is: // true if two lines are parallel(or one of the directin is zero) // false if intersection was obtained. bool MGStraight::isect2D(const MGStraight& l2,double& t,double& s)const{ double x1, a1, y1, b1, x2, a2, y2, b2; x1=root_point().ref(0); a1=m_direction.ref(0); y1=root_point().ref(1); b1=m_direction.ref(1); x2=l2.root_point().ref(0); a2=l2.m_direction.ref(0); y2=l2.root_point().ref(1); b2=l2.m_direction.ref(1); double det = a1*b2-b1*a2; if(MGMZero(det)) return true; double y1my2=y1-y2; double x2mx1=x2-x1; t=(a2*y1my2+b2*x2mx1)/det; s=(a1*y1my2+b1*x2mx1)/det; return false; } // 点が直線上にあるかを試験する。直線上にあれば,その点のパラメーター値を, // 直線上になくても最近傍点のパラメーター値を返す。 bool MGStraight::on( const MGPosition& p, // 指定点 double& d // パラメータ値 )const{ bool on; double t; if(perp_point(p, t)) on=MGAZero(MGVector(p,eval(t)).len()); else on=false; d=range(t); return on; } // 直線が平面上にあるか調べる。(平面上ならばtrue) bool MGStraight::on( const MGPlane& pl // Plane )const{ MGPosition uv(2); return direction().orthogonal(pl.normal()) && pl.on(root_point(), uv); } // 直線上の与えられたポイントにおけるパラメータ値を返す。 // If input point is not on the curve, return the nearest point on the // curve. double MGStraight::param(const MGPosition& p)const{ // 垂線の足を求める。 double d2; perp_point(p,d2); // パラメータ値を返す。 return range(d2); } // 与点から直線への垂線の足のパラメータ値を返却する。 //Return the foot of the straight line that is perpendicular to this line. //Function's return value is parameter value of this straight line, //may ***NOT*** be in_range. double MGStraight::perp_param( const MGPosition& point // 与点 )const{ MGVector v2(point,root_point());// 始点から与点へのベクトル double lensqr=m_direction.len(); lensqr*=lensqr; return v2%m_direction/lensqr; // 与点から直線への垂線の足と始点との距離 } // 与えられたポイントから曲線への垂線の足、そのパラメータ値を返却する。 // Function's return value is if point is obtained(1) or not(0) int MGStraight::perp_point( const MGPosition& point, // 指定点 double& d1, // 垂線の足のパラメータ値 const double* d2 // guess parameter value of d1. )const{ d1=perp_param(point); return in_range(d1); } // 与ポイントから直線へ下ろした垂線の足の,直線のパラメータ値を // すべて求める。 MGCParam_list MGStraight::perps( const MGPosition& point // 与ポイント )const{ MGCParam_list tlist(this); double l =perp_param(point); if(in_range(l)) tlist.append(l); return tlist; } //Compute all the perpendicular points of this curve and the second one. //That is, if f(s) and g(t) are the points of the two curves f and g, //then obtains points where the following conditions are satisfied: // fs*(f-g)=0. gt*(g-f)=0. //Here fs and gt are 1st derivatives at s and t of f and g. //MGPosition P in the MGPosition_list contains this and crv2's parameter //as: P(0)=this curve's parameter, P(1)=crv2's parameter value. MGPosition_list MGStraight::perps( const MGCurve& crv2 //The second curve )const{ MGPosition_list list=crv2.perps(*this); return MGPosition_list(list,1,0); } MGPosition_list MGStraight::perps( const MGStraight& l2 //The second curve )const{ if(MGMZero(m_direction.sangle(l2.m_direction)))// 平行 return relation_parallel(l2); MGPosition P; perp_guess(1.,0.,l2,1.,0.,0.,0.,P); MGPosition_list list; if(in_range(P.ref(0)) && l2.in_range(P.ref(1))) list.append(P); return list; } MGPosition_list MGStraight::perps( const MGRLBRep& crv2 //The second curve )const{ MGPosition_list list=crv2.perps(*this); return MGPosition_list(list,1,0); } MGPosition_list MGStraight::perps( const MGEllipse& crv2 //The second curve )const{ MGPosition_list list=crv2.perps(*this); return MGPosition_list(list,1,0); } MGPosition_list MGStraight::perps( const MGSurfCurve& crv2 //The second curve )const{ MGPosition_list list=crv2.perps(*this); return MGPosition_list(list,1,0); } MGPosition_list MGStraight::perps( const MGBSumCurve& crv2 //The second curve )const{ MGPosition_list list=crv2.perps(*this); return MGPosition_list(list,1,0); } //Compute two straight lines relationship of parallel or coincidence. //Parallelness of the two is assumed. //Obtain the relationship when two lines coinside. //ip of a intersection or nearest point will be returned. //When this and sl2 do not coincide, MGPSREL_PARALLEL will be returned as //the function's return value. MGPSRELATION MGStraight::relation_coincide( const MGStraight& sl2, MGCCisect& ip )const{ MGPSRELATION rl; if(straight_type()==MGSTRAIGHT_SEGMENT) return relation_coincide1(sl2,ip); else if(sl2.straight_type()==MGSTRAIGHT_SEGMENT){ rl=sl2.relation_coincide1(*this,ip); ip.exchange12(); return rl; } double& t1=ip.param1(); double& t2=ip.param2(); MGPosition P1, P2; if(straight_type()==MGSTRAIGHT_UNLIMIT){ P2=sl2.center(); t2=sl2.perp_param(P2); t1=perp_param(P2); P1=eval_position_unlimitted(t1); }else if(sl2.straight_type()==MGSTRAIGHT_UNLIMIT){ P1=center(); t1=perp_param(P1); t2=sl2.perp_param(P1); P2=sl2.eval_position_unlimitted(t2); }else{ //Following are the cases that this and sl2 are both MGSTRAIGHT_HALF_LIMIT. if(m_sparam.finite()){ t1=param_s(); P1=start_point(); }else{ t1=param_e(); P1=end_point(); } double s1, s2; s2=sl2.perp_param(P1); if(sl2.in_range(s2)){ t2=s2; P2=sl2.eval_position_unlimitted(s2); }else{ if(sl2.m_sparam.finite()){ t2=sl2.param_s(); P2=sl2.start_point(); }else{ t2=sl2.param_e(); P2=sl2.end_point(); } s1=perp_param(P2); if(in_range(s1)){ t1=s1; P1=eval_position_unlimitted(t1); } } } ip.point()=(P1+P2)*.5; MGVector dif=P1-P2; if(dif%dif<=MGTolerance::wc_zero_sqr()) return MGPSREL_COIN; else return MGPSREL_PARALLEL; } //relation_coincide when this is MGSTRAIGHT_SEGMENTt. MGPSRELATION MGStraight::relation_coincide1( const MGStraight& sl2, MGCCisect& ip )const{ double& t1=ip.param1(); double& t2=ip.param2(); MGPosition Ps=start_point(); MGPosition Pe=end_point(); double t1s=sl2.perp_param(Ps); double t1e=sl2.perp_param(Pe); MGInterval t1I(t1s); t1I.expand(t1e);//Parameter range of this in sl2 parameter. bool t1s_is_low=(t1s