/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ #include "MGCLStdAfx.h" #include "mg/Box.h" #include "mg/Position_list.h" #include "mg/Transf.h" #include "mg/Unit_vector.h" #include "mg/Curve.h" #include "mg/Straight.h" #include "mg/SurfCurve.h" #include "mg/BSumCurve.h" #include "mg/Ellipse.h" #include "mg/RLBRep.h" #include "mg/CParam_list.h" #include "mg/CCisect_list.h" #include "mg/CSisect_list.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 "mg/Tolerance.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // MGEllipse.cc // // MGEllipse is a class to define an ellipse of 2D or 3D. // Ellipse is expressed as below using parameter t: // Point(t) = m_center + m_m * cos(t) + m_n * sin(t) // メンバ関数 //Extrapolate this curve by an (approximate) chord length. //The extrapolation is C2 continuous. void MGEllipse::extend( double len, //approximate chord length to extend. bool start //Flag of which point to extend, start or end point of the line. //If start is true extend on the start point. ){ double t, ts=param_s(), te=param_e(), extlen; double ts2, te2; double whole_length1=length(ts, te); MGEllipse el2(*this); el2.unlimit(); double whole_length2=el2.length(el2.param_s(), el2.param_e()); double remain=whole_length2-whole_length1; if(remain=mgDBLPAI; } // Ellipse と Curve の交点を求める。 MGCCisect_list MGEllipse::isect( const MGCurve& curve2 )const{ MGCCisect_list list=curve2.isect(*this); return list.replace12(); } // Ellipse と Straight の交点を求める。 MGCCisect_list MGEllipse::isect( const MGStraight& st )const{ MGCCisect_list list(this, &st); // リストの領域を得る if(!has_common(st)) return list; if((st.direction()).orthogonal(m_normal)){ // When st and ellipse are parallel MGVector vt(m_center, st.root_point()); if(vt.is_zero_vector() | m_normal.orthogonal(vt)){ //When ellipse and straight line lie on a same plane. double t[2],angle[2]; int tangen; MGTransf tr(m_m, m_n, m_center); // tr is transform to transform // ellipes to lie on xy plane and the center to be origin. MGPosition stpt=st.root_point()*tr; MGUnit_vector dir=st.direction()*tr.affine(); double dirlen=st.direction_len(); int n=isect2d(stpt, dir,t,angle,tangen); if(n){ double p; for(int i=0; i=d && (d+r1)>=r2 && (d+r2)>=r1){ //When intersections of whole circles exist. const MGEllipse *e1p, *e2p; double cosval; if(r1>=r2){ e1p=this; e2p=&e2; cosval=(d/r1-(r2*r2)/(r1*d)+r1/d)*0.5; } else{ e2p=this; e1p=&e2; cosval=(d/r2-(r1*r1)/(r2*d)+r2/d)*0.5; c1toc2=-c1toc2; } double angle=acos(cosval); MGMatrix mat1;mat1.set_rotate_3D(m_normal,angle); MGMatrix mat2;mat2.set_rotate_3D(m_normal,-angle); MGVector vec1=c1toc2*mat1, vec2=c1toc2*mat2; MGCCisect_list list1=(*e1p).isect (MGStraight(MGSTRAIGHT_HALF_LIMIT,vec1,(*e1p).m_center)); if(list1.entries()){ MGCCisect isect=list1.first(); double t2; MGPosition P=isect.point(); if((*e2p).on(P,t2)){ if(r1>=r2) list.append(P,isect.param1(),t2); else list.append(P,t2,isect.param1()); } } list1=(*e1p).isect (MGStraight(MGSTRAIGHT_HALF_LIMIT,vec2,(*e1p).m_center)); if(list1.entries()){ MGCCisect isect=list1.first(); double t2; MGPosition P=isect.point(); if((*e2p).on(P,t2)){ if(r1>=r2) list.append(P,isect.param1(),t2); else list.append(P,t2,isect.param1()); } } } return list; }else return intersect(e2); } // Ellipse と Curve の交点を求める。 MGCCisect_list MGEllipse::isect( const MGSurfCurve& curve2 )const{ MGCCisect_list list=curve2.isect(*this); return list.replace12(); } // Ellipse と Curve の交点を求める。 MGCCisect_list MGEllipse::isect( const MGBSumCurve& curve2 )const{ MGCCisect_list list=curve2.isect(*this); return list.replace12(); } //Intersection of Ellipse and Surface MGCSisect_list MGEllipse::isect(const MGSurface& surf) const{ return surf.isect(*this); } //Intersection of Ellipse and a plane. MGCSisect_list MGEllipse::isect(const MGPlane& plane) const{ return plane.isect(*this); } //Intersection of Spline and Surface MGCSisect_list MGEllipse::isect(const MGSphere& surf)const{ return surf.intersect(*this); } //Intersection of Spline and Surface MGCSisect_list MGEllipse::isect(const MGCylinder& surf)const{ return surf.intersect(*this); } //Intersection of Spline and Surface MGCSisect_list MGEllipse::isect(const MGRSBRep& surf)const{ return surf.intersect(*this); } //Intersection of Spline and Surface MGCSisect_list MGEllipse::isect(const MGSBRep& surf)const{ return surf.intersect(*this); } //Intersection of Spline and Surface MGCSisect_list MGEllipse::isect(const MGBSumSurf& surf)const{ return surf.intersect(*this); } //Compute intersection point of 1D sub curve of original curve. //Parameter values of intersection point will be returned. MGCParam_list MGEllipse::intersect_1D( double f, // Coordinate value int coordinate // Coordinate kind of the data f(from 0). )const{ MGCParam_list list(this); double a=m_m.ref(coordinate), b=m_n.ref(coordinate); double c=m_center.ref(coordinate); double ab2=a*a+b*b; double sq_ab2=sqrt(ab2); if(MGMZero(sq_ab2)) return list; //Intersection can be obtained as the solution of // c+a*cos(angle)+b*sin(angle) = f , i.e. // cos(angle)=(a*(f-c) +- b*sqrt(a*a+b*b-(d-c)**2))/(a*a+b*b) // sin(angle)=((f-c)-a*cos(angle))/b // =(b*(f-c) -+ a*sqrt(a*a+b*b-(d-c)**2))/(a*a+b*b) . double fmc=f-c; double cosa, sina, angle; if(MGREqual2(fabs(fmc),sq_ab2)){ if(fmc<0.){ cosa=-a/sq_ab2; sina=-b/sq_ab2;} else { cosa= a/sq_ab2; sina= b/sq_ab2;} angle=MGAngle(cosa,sina); if(in_RelativeRange_of_radian(angle)) list.append(radian_to_gp(RelativeRange_in_radian(angle))); }else{ if(fmc<(-sq_ab2) || fmc>sq_ab2) return list; double ab2mfmc2=sqrt(ab2-fmc*fmc); cosa=(a*fmc+b*ab2mfmc2)/ab2; sina=(b*fmc-a*ab2mfmc2)/ab2; angle=MGAngle(cosa,sina); if(in_RelativeRange_of_radian(angle)) list.append(radian_to_gp(RelativeRange_in_radian(angle))); cosa=(a*fmc-b*ab2mfmc2)/ab2; sina=(b*fmc+a*ab2mfmc2)/ab2; angle=MGAngle(cosa,sina); if(in_RelativeRange_of_radian(angle)) list.append(radian_to_gp(RelativeRange_in_radian(angle))); } return list; } // 与ポイントから楕円への垂線の足 のパラメータ値を求める。 // Function's return value is !=0 if point is obtained, 0 if not. int MGEllipse::perp_point ( const MGPosition &p, // 与ポイント double &d, // パラメータ値 const double *g // guess parameter value. ) const { int i; if(ellipse_type() == MGELLIPSE_EMPTY) {d = 0.0; return 0;} double theta[4]; MGPosition p2d=p*MGTransf(m_m, m_n, m_center); int nump=perp2d(p2d.ref(0), p2d.ref(1), theta); d=theta[0]; if(nump){ int j=0; if(nump>1){ if(g){ //Compute nearest param to *g double tg=gp_to_radian(*g); double param=RelativeRange_in_radian(tg); double plen=param_length(param, theta[0]); for(i=1; ilenep) list.append(MGPosition(param_s(),s)); else list.append(MGPosition(param_e(),s)); }else{ if(lensp4) ndiv=4; double incr=range/double(ndiv); te=ts+incr; MGPosition ppair; //Compute by subdividing the ellipse to parts of half pai at most. MGEllipse el(*this, true); for(int i=0; i=fabs(by)) t=asin(p/bx); else t=asin(q/by); }else if(MGAZero(by)) t=0.; else t=MGAngle((p-bx/by*q)/a, q/by); on=in_RelativeRange_of_radian(t); t=RelativeRange_in_radian(t); }else on=0; if(!on){ // Compute nearest point. t=m_prange[0]; double len=(point-eval_in_radian2(t)).len(); MGCParam_list tlist=perps(point); MGCParam_list::Citerator i=tlist.begin(), iend=tlist.end(); double lent; while(i!=tlist.end()){ double t1=*i++; lent=(point-eval_position(t1)).len(); if(lentlent){ t=m_prange[1]; len=lent; } if(len<=MGTolerance::wc_zero()) on=1; } } param=radian_to_gp(t); return on; } //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 MGEllipse::oneD( const double g[4] //Plane expression(a,b,c,d) where ax+by+cz=d. ) const{ MGVector G(3,g); MGEllipse* el1=new MGEllipse(); MGVector one(1); one(0)=G%center()-g[3]; el1->m_center=one; el1->m_circle=0; if(m_gprange){ double* rng=new double[2]; rng[0]=m_gprange[0]; rng[1]=m_gprange[1]; el1->m_gprange=rng; } one(0)=G%major_axis(); el1->m_m=one; one(0)=G%minor_axis(); el1->m_n=one; one(0)=1.; el1->m_normal=one; el1->m_prange[0]=m_prange[0]; el1->m_prange[1]=m_prange[1]; el1->m_r=(el1->m_m[0]+el1->m_n[0])*.5; return std::unique_ptr(el1); } //Compute intesection points of 2D ellipse whose center is origin and //a straight line of 2D. int MGEllipse::isect2d( const MGPosition& sp,//Start point of straight line. const MGVector& dir, //Direction unit vector of the straight line double t[2], //Parameter of intersection point of the straight. double angle[2], // angles of ellipse in radian. int& tangen // Return if isect is tangent point(1) or not(0). ) const{ //Return value of isect2D is number of intersetion points: 0, 1, or 2. double a=m_m.len(), b=m_n.len(); //Length of x and y axis. //parameter arrangement value of the straight when using sp1 instead of sp. if(m_m.orthogonal(m_n)){//When normal ellipse. double dir2=dir%dir; double spdirbydir2=(sp%dir)/dir2; MGPosition sp1=sp-dir*spdirbydir2; //sp1 is nearest point to the origin. //sp1 is used instead of sp to minimize computation error. double sp1tosp=(sp1%dir)/dir2-spdirbydir2; double u=dir.ref(0), v=dir.ref(1); double x1=sp1.ref(0), y1=sp1.ref(1); //Using a, b, u, v, x1, and y1, isect of the ellipse and the straight line whose //root point and direction are sp1 and dir can be expressed as: // t= (-(u*b*b*x1+v*a*a*y1)(+-)a*b*sqrt(avbu-(u*y1-v*x1)**2))/avbu // , where avbu=a*a*v*v+b*b*u*u. double ca,sa, ang; double avbu=a*a*v*v+b*b*u*u; double uyvx=(u*y1-v*x1); uyvx *= uyvx; double ubxvay=-(u*b*b*x1+v*a*a*y1); double p=uyvx/avbu, q=ubxvay/avbu; if(MGREqual(p, 1.)){ // Point is tangent point. tangen=1; t[0]=q+sp1tosp; ca=(x1+u*q)/a; sa=(y1+v*q)/b; ang=MGAngle(ca,sa); if(in_RelativeRange_of_radian(ang)){ angle[0]=RelativeRange_in_radian(ang); return 1; }else return 0; }else if(p>1.) return 0; else{ // Points are not tangent points. tangen=0; int count=0; double r=a*b*sqrt((1.-p)/avbu); t[0]=q+r; ca=(x1+u*t[0])/a; sa=(y1+v*t[0])/b; t[0]+=sp1tosp; ang=MGAngle(ca,sa); if(in_RelativeRange_of_radian(ang)){ angle[0]=RelativeRange_in_radian(ang); count+=1; } t[count]=q-r; ca=(x1+u*t[count])/a; sa=(y1+v*t[count])/b; t[count]+=sp1tosp; ang=MGAngle(ca,sa); if(in_RelativeRange_of_radian(ang)){ angle[count]=RelativeRange_in_radian(ang); count+=1; } return count; } }else{//When Projected ellipse whose axises are not orthogonal. MGStraight sl(MGSTRAIGHT_UNLIMIT, dir, sp); MGStraight sl2(sl); double apb=a+b; MGBox box(MGPosition(-apb,-apb), MGPosition(apb,apb)); sl2.limit(box); MGEllipse el(*this,true);//el's parameter range is in radian. el*=MGTransf(m_m,m_n,m_center); MGCCisect_list list=el.intersect(sl2); tangen=0; int i=0; while(list.entries()){ MGCCisect is=list.removeFirst(); angle[i]=is.param1(); t[i++]=sl.param(is.point()); if(i==2) break; } return i; } } //Compute angles of elllipse points that are perpendicular to a point (p,q). //This function is 2-D version of perp_point. //Function's return value is number of points obtained. int MGEllipse::perp2d( double p, //x-coordinate of the point. double q, //y-coordinate of the point. double theta[4]) //angles of the ellipse. const{ if(!m_m.orthogonal(m_n)){//When two axises are not orthogonal. MGPosition P(p,q); MGEllipse el(*this, true); el*=MGTransf(m_m,m_n,m_center); MGCParam_list list=el.MGCurve::perps(P); int i=0; while(list.entries()){ theta[i++]=list.removeFirst(); if(i==4) break; } return i; } int nump=0; int pzero=MGRZero2(p,m_r), qzero=MGRZero2(q,m_r); double plen,pu,qu,pangle; if(!pzero || !qzero){ plen=sqrt(p*p+q*q); pu=p/plen, qu=q/plen; pangle=MGAngle(pu, qu); } if(pzero&&qzero){ //Case that (p,q) is origin. theta[1]=mgHALFPAI; theta[3]=mgHALFPAI+mgPAI; theta[0]=0.0; theta[2]=mgPAI; nump=4; } else if(pzero){ //Case that the point is on y-axis. theta[0]=mgHALFPAI; theta[1]=mgHALFPAI+mgPAI; nump=2; } else if(qzero){ //Case that the point is on x-axis. theta[0]=0.0; theta[1]=mgPAI; nump=2; } else if(m_circle){ //Case that the ellipse is a circle. theta[0]=pangle; if(pangle>mgPAI) theta[1]=pangle-mgPAI; else theta[1]=pangle+mgPAI; nump=2; } else{ // Genaral case. double a=m_m.len(), b=m_n.len(); //Length of x and y axis. double a2mb2=a*a-b*b, ap=a*p, bq=b*q, sinv, cosv; double sign1, sign2, ang1, ang2; double angs; double error=MGTolerance::angle_zero(); double ang, signt; if(p>=0.){ if(q>=0.) angs=0.0; else angs=mgHALFPAI+mgPAI; } else { if(q>=0.) angs=mgHALFPAI; else angs=mgPAI; } //Angle is computed using bisection algorithm. Sign of the following //expression is use to determine if solution can be located between //two angle ang1 and ang2: // sign=(a*a-b*b)*cosv*sinv-a*p*sinv+b*q*cosv; //This sign is signed length of the vector product of the two vectors, //vector1:from a point P on the ellipse to the point (p,q), //vector2:normal vector of the ellipse on P. //Case1: Angle is smaller than angle of (p,q) and //greater than nearest half PAI. ang1=angs; sinv=sin(ang1); cosv=cos(ang1); sign1=a2mb2*cosv*sinv-ap*sinv+bq*cosv; ang2=pangle; sinv=qu; cosv=pu ; sign2=a2mb2*cosv*sinv-ap*sinv+bq*cosv; if(sign1*sign2 <= 0.0){ while((ang2-ang1)>error){ ang=(ang1+ang2)/2.; sinv=sin(ang); cosv=cos(ang); signt=a2mb2*cosv*sinv-ap*sinv+bq*cosv; if(sign1*signt <= 0.0) ang2=ang; else ang1=ang; } theta[nump]=(ang1+ang2)/2.; nump +=1; } //Case2: Angle is greater than angle of (p,q) and //smaller than nearest half PAI. ang1=pangle; sinv=qu; cosv=pu ; sign1=a2mb2*cosv*sinv-ap*sinv+bq*cosv; ang2=angs+mgHALFPAI; sinv=sin(ang2); cosv=cos(ang2); sign2=a2mb2*cosv*sinv-ap*sinv+bq*cosv; if(sign1*sign2 <= 0.0){ while((ang2-ang1)>error){ ang=(ang1+ang2)/2.; sinv=sin(ang); cosv=cos(ang); signt=a2mb2*cosv*sinv-ap*sinv+bq*cosv; if(sign1*signt <= 0.0) ang2=ang; else ang1=ang; } theta[nump]=(ang1+ang2)/2.; nump +=1; } //Case3:Check all other three half pai ranges. for(int i=0; i<3; i++){ angs += mgHALFPAI; angs=fmod(angs, mgDBLPAI); ang1=angs; sinv=sin(ang1); cosv=cos(ang1); sign1=a2mb2*cosv*sinv-ap*sinv+bq*cosv; ang2=angs+mgHALFPAI; sinv=sin(ang2); cosv=cos(ang2); sign2=a2mb2*cosv*sinv-ap*sinv+bq*cosv; if(sign1*sign2 <= 0.0){ while((ang2-ang1)>error){ ang=(ang1+ang2)/2.; sinv=sin(ang); cosv=cos(ang); signt=a2mb2*cosv*sinv-ap*sinv+bq*cosv; if(sign1*signt <= 0.0) ang2=ang; else ang1=ang; } theta[nump]=(ang1+ang2)/2.; nump +=1; } } } double save=RelativeRange_in_radian(theta[0]); int i=0; while(i