-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D
+// Copyright (C) 2007-2016 CEA/DEN, EDF R&D
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
a2.getCenter(centerL); radiusL=a2.getRadius();
a1.getCenter(centerB); radiusB=a1.getRadius();
}
- // dividing from the begining by radiusB^2 to keep precision
+ // dividing from the beginning by radiusB^2 to keep precision
distBetweenCenters=Node::distanceBtw2PtSq(centerL,centerB);
cst=distBetweenCenters/(radiusB*radiusB);
cst+=radiusL*radiusL/(radiusB*radiusB);
- return Node::areDoubleEqualsWP(cst,1.,2.);
+ return Node::areDoubleEqualsWPRight(cst,1.,2.);
}
bool ArcCArcCIntersector::areArcsOverlapped(const EdgeArcCircle& a1, const EdgeArcCircle& a2)
delete merge;
//
tmp=sqrt(tmp);
- if(Node::areDoubleEqualsWP(tmp,0.,1/(10*std::max(radiusL,radiusB))))
+ if(Node::areDoubleEqualsWPLeft(tmp,0.,10*std::max(radiusL,radiusB)))
return Node::areDoubleEquals(radiusL,radiusB);
double phi=EdgeArcCircle::GetAbsoluteAngleOfNormalizedVect((centerL[0]-centerB[0])/tmp,(centerL[1]-centerB[1])/tmp);
double cst2=2*radiusL*tmp/(radiusB*radiusB);
if(EdgeArcCircle::IsIn2Pi(angle0L,angleL,a))
cmpContainer[sizeOfCmpContainer++]=cst-cst2;
a=*std::max_element(cmpContainer,cmpContainer+sizeOfCmpContainer);
- return Node::areDoubleEqualsWP(a,1.,2.);
+ return Node::areDoubleEqualsWPRight(a,1.,2.);
}
void ArcCArcCIntersector::areOverlappedOrOnlyColinears(const Bounds *whereToFind, bool& obviousNoIntersection, bool& areOverlapped)
{
_dist=Node::distanceBtw2Pt(getE1().getCenter(),getE2().getCenter());
double radius1=getE1().getRadius(); double radius2=getE2().getRadius();
- if(_dist>radius1+radius2+QUADRATIC_PLANAR::_precision || _dist+std::min(radius1,radius2)+QUADRATIC_PLANAR::_precision<std::max(radius1,radius2))
+ if(_dist>radius1+radius2+QuadraticPlanarPrecision::getPrecision() || _dist+std::min(radius1,radius2)+QuadraticPlanarPrecision::getPrecision()<std::max(radius1,radius2))
{
obviousNoIntersection=true;
areOverlapped=false;
}
}
+/**
+ Heart of the algorithm for arc/arc intersection.
+ See http://mathworld.wolfram.com/Circle-CircleIntersection.html
+ The computation is done in the coordinate system where Ox is the line between the 2 circle centers.
+*/
std::list< IntersectElement > ArcCArcCIntersector::getIntersectionsCharacteristicVal() const
{
std::list< IntersectElement > ret;
const double *center1=getE1().getCenter();
const double *center2=getE2().getCenter();
double radius1=getE1().getRadius(); double radius2=getE2().getRadius();
- double d1_1=(_dist*_dist-radius2*radius2+radius1*radius1)/(2.*_dist);
+ double d1_1=(_dist*_dist-radius2*radius2+radius1*radius1)/(2.*_dist); // computation of 'x' on wolfram
double u[2];//u is normalized vector from center1 to center2.
u[0]=(center2[0]-center1[0])/_dist; u[1]=(center2[1]-center1[1])/_dist;
- double d1_1y=EdgeArcCircle::SafeSqrt(radius1*radius1-d1_1*d1_1);
+ double d1_1y=EdgeArcCircle::SafeSqrt(radius1*radius1-d1_1*d1_1); // computation of 'y' on wolfram
double angleE1=EdgeArcCircle::NormalizeAngle(getE1().getAngle0()+getE1().getAngle());
double angleE2=EdgeArcCircle::NormalizeAngle(getE2().getAngle0()+getE2().getAngle());
if(!Node::areDoubleEquals(d1_1y,0))
{
//2 intersections
double v1[2],v2[2];
+ // coming back to our coordinate system:
v1[0]=u[0]*d1_1-u[1]*d1_1y; v1[1]=u[1]*d1_1+u[0]*d1_1y;
v2[0]=u[0]*d1_1+u[1]*d1_1y; v2[1]=u[1]*d1_1-u[0]*d1_1y;
Node *node1=new Node(center1[0]+v1[0],center1[1]+v1[1]); node1->declareOn();
v4[0]=center1[0]-center2[0]+v2[0]; v4[1]=center1[1]-center2[1]+v2[1];
double angle1_2=EdgeArcCircle::GetAbsoluteAngleOfNormalizedVect(v3[0]/radius2,v3[1]/radius2);
double angle2_2=EdgeArcCircle::GetAbsoluteAngleOfNormalizedVect(v4[0]/radius2,v4[1]/radius2);
+ // Check whether intersection points are exactly ON the other arc or not
+ // -> the curvilinear distance (=radius*angle) must below eps
+ bool e1_1S=Node::areDoubleEqualsWPLeft(angle1_1,getE1().getAngle0(),radius1);
+ bool e1_1E=Node::areDoubleEqualsWPLeft(angle1_1,angleE1,radius1);
+ bool e1_2S=Node::areDoubleEqualsWPLeft(angle1_2,getE2().getAngle0(),radius1);
+ bool e1_2E=Node::areDoubleEqualsWPLeft(angle1_2,angleE2,radius1);
//
- bool e1_1S=Node::areDoubleEqualsWP(angle1_1,getE1().getAngle0(),radius1);
- bool e1_1E=Node::areDoubleEqualsWP(angle1_1,angleE1,radius1);
- bool e1_2S=Node::areDoubleEqualsWP(angle1_2,getE2().getAngle0(),radius1);
- bool e1_2E=Node::areDoubleEqualsWP(angle1_2,angleE2,radius1);
- //
- bool e2_1S=Node::areDoubleEqualsWP(angle2_1,getE1().getAngle0(),radius2);
- bool e2_1E=Node::areDoubleEqualsWP(angle2_1,angleE1,radius2);
- bool e2_2S=Node::areDoubleEqualsWP(angle2_2,getE2().getAngle0(),radius2);
- bool e2_2E=Node::areDoubleEqualsWP(angle2_2,angleE2,radius2);
+ bool e2_1S=Node::areDoubleEqualsWPLeft(angle2_1,getE1().getAngle0(),radius2);
+ bool e2_1E=Node::areDoubleEqualsWPLeft(angle2_1,angleE1,radius2);
+ bool e2_2S=Node::areDoubleEqualsWPLeft(angle2_2,getE2().getAngle0(),radius2);
+ bool e2_2E=Node::areDoubleEqualsWPLeft(angle2_2,angleE2,radius2);
ret.push_back(IntersectElement(angle1_1,angle1_2,e1_1S,e1_1E,e1_2S,e1_2E,node1,_e1,_e2,keepOrder()));
ret.push_back(IntersectElement(angle2_1,angle2_2,e2_1S,e2_1E,e2_2S,e2_2E,node2,_e1,_e2,keepOrder()));
}
v2[0]=center1[0]-center2[0]+v1[0]; v2[1]=center1[1]-center2[1]+v1[1];
double angle0_1=EdgeArcCircle::GetAbsoluteAngleOfNormalizedVect(v1[0]/radius1,v1[1]/radius1);
double angle0_2=EdgeArcCircle::GetAbsoluteAngleOfNormalizedVect(v2[0]/radius2,v2[1]/radius2);
- bool e0_1S=Node::areDoubleEqualsWP(angle0_1,getE1().getAngle0(),radius1);
- bool e0_1E=Node::areDoubleEqualsWP(angle0_1,angleE1,radius1);
- bool e0_2S=Node::areDoubleEqualsWP(angle0_2,getE2().getAngle0(),radius2);
- bool e0_2E=Node::areDoubleEqualsWP(angle0_2,angleE2,radius2);
+ bool e0_1S=Node::areDoubleEqualsWPLeft(angle0_1,getE1().getAngle0(),radius1);
+ bool e0_1E=Node::areDoubleEqualsWPLeft(angle0_1,angleE1,radius1);
+ bool e0_2S=Node::areDoubleEqualsWPLeft(angle0_2,getE2().getAngle0(),radius2);
+ bool e0_2E=Node::areDoubleEqualsWPLeft(angle0_2,angleE2,radius2);
Node *node=new Node(center1[0]+d1_1*u[0],center1[1]+d1_1*u[1]); node->declareOnTangent();
ret.push_back(IntersectElement(angle0_1,angle0_2,e0_1S,e0_1E,e0_2S,e0_2E,node,_e1,_e2,keepOrder()));
}
_cross=
((*(_e2.getStartNode()))[0]-center[0])*((*(_e2.getEndNode()))[1]-center[1])-
((*(_e2.getStartNode()))[1]-center[1])*((*(_e2.getEndNode()))[0]-center[0]);
- _determinant=getE1().getRadius()*getE1().getRadius()/_drSq-_cross*_cross/(_drSq*_drSq);
- if(_determinant>-2*QUADRATIC_PLANAR::_precision)//QUADRATIC_PLANAR::_precision*QUADRATIC_PLANAR::_precision*_drSq*_drSq/(2.*_dx*_dx))
+ _determinant = (getE1().getRadius()*getE1().getRadius()-_cross*_cross/_drSq) / _drSq;
+ if(_determinant > -2*QuadraticPlanarPrecision::getPrecision())//QuadraticPlanarPrecision::getPrecision()*QuadraticPlanarPrecision::getPrecision()*_drSq*_drSq/(2.*_dx*_dx))
obviousNoIntersection=false;
else
obviousNoIntersection=true;
{
std::list< IntersectElement > ret;
const double *center=getE1().getCenter();
- if(!(fabs(_determinant)<(2.*QUADRATIC_PLANAR::_precision)))//QUADRATIC_PLANAR::_precision*QUADRATIC_PLANAR::_precision*_drSq*_drSq/(2.*_dx*_dx))
+ if(!(fabs(_determinant)<(2.*QuadraticPlanarPrecision::getPrecision())))//QuadraticPlanarPrecision::getPrecision()*QuadraticPlanarPrecision::getPrecision()*_drSq*_drSq/(2.*_dx*_dx))
{
double determinant=EdgeArcCircle::SafeSqrt(_determinant);
double x1=(_cross*_dy/_drSq+Node::sign(_dy)*_dx*determinant)+center[0];
/*!
* 'eps' is expected to be > 0.
* 'conn' is of size 3. conn[0] is start id, conn[1] is end id and conn[2] is middle id.
- * 'offset' is typically the number of nodes already existing in global 2D curve mesh. Additionnal coords 'addCoo' ids will be put after the already existing.
+ * 'offset' is typically the number of nodes already existing in global 2D curve mesh. Additional coords 'addCoo' ids will be put after the already existing.
*/
void EdgeArcCircle::tesselate(const int *conn, int offset, double eps, std::vector<int>& newConn, std::vector<double>& addCoo) const
{
/*!
* Given a \b normalized vector defined by (ux,uy) returns its angle in ]-Pi;Pi].
- * So before using this method ux*ux+uy*uy should as much as possible close to 1.
- * This methods is quite time consuming in order to keep as much as possible precision.
- * It is NOT ALWAYS possible to do that only in one call of acos. Sometimes call to asin is necessary
- * due to imperfection of acos near 0. and Pi (cos x ~ 1-x*x/2.)
+ * Actually in the current implementation, the vector does not even need to be normalized ...
*/
double EdgeArcCircle::GetAbsoluteAngleOfNormalizedVect(double ux, double uy)
{
- //When arc is lower than 0.707 Using Asin
- if(fabs(ux)<0.707)
- {
- double ret=SafeAcos(ux);
- if(uy>0.)
- return ret;
- ret=-ret;
- return ret;
- }
- else
- {
- double ret=SafeAsin(uy);
- if(ux>0.)
- return ret;
- if(ret>0.)
- return M_PI-ret;
- else
- return -M_PI-ret;
- }
+ return atan2(uy, ux);
}
void EdgeArcCircle::GetArcOfCirclePassingThru(const double *start, const double *middle, const double *end,
+tmp2*(tmp4-tmp3+(tmp3*tmp3*tmp3-tmp4*tmp4*tmp4)/3.)/2.;
}
+/**
+ * Compute the "middle" of two points on the arc of circle.
+ * The order (p1,p2) or (p2,p1) doesn't matter. p1 and p2 have to be localized on the edge defined by this.
+ * \param[out] mid the point located half-way between p1 and p2 on the arc defined by this.
+ * \sa getMiddleOfPointsOriented() a generalisation working also when p1 and p2 are not on the arc.
+ */
void EdgeArcCircle::getMiddleOfPoints(const double *p1, const double *p2, double *mid) const
{
double dx1((p1[0]-_center[0])/_radius),dy1((p1[1]-_center[1])/_radius),dx2((p2[0]-_center[0])/_radius),dy2((p2[1]-_center[1])/_radius);
//
double myDelta1(angle1-_angle0),myDelta2(angle2-_angle0);
if(_angle>0.)
- { myDelta1=myDelta1>=0.?myDelta1:myDelta1+2.*M_PI; myDelta2=myDelta2>=0.?myDelta2:myDelta2+2.*M_PI; }
+ { myDelta1=myDelta1>-QuadraticPlanarPrecision::getPrecision()?myDelta1:myDelta1+2.*M_PI; myDelta2=myDelta2>-QuadraticPlanarPrecision::getPrecision()?myDelta2:myDelta2+2.*M_PI; }
else
- { myDelta1=myDelta1<=0.?myDelta1:myDelta1-2.*M_PI; myDelta2=myDelta2<=0.?myDelta2:myDelta2-2.*M_PI; }
+ { myDelta1=myDelta1<QuadraticPlanarPrecision::getPrecision()?myDelta1:myDelta1-2.*M_PI; myDelta2=myDelta2<QuadraticPlanarPrecision::getPrecision()?myDelta2:myDelta2-2.*M_PI; }
////
mid[0]=_center[0]+_radius*cos(_angle0+(myDelta1+myDelta2)/2.);
mid[1]=_center[1]+_radius*sin(_angle0+(myDelta1+myDelta2)/2.);
}
+/**
+ * Compute the "middle" of two points on the arc of circle.
+ * Walk on the circle from p1 to p2 using the rotation direction indicated by this->_angle (i.e. by the orientation of the arc).
+ * This function is sensitive to the ordering of p1 and p2.
+ * \param[out] mid the point located half-way between p1 and p2
+ * \sa getMiddleOfPoints() to be used when the order of p1 and p2 is not relevant.
+ */
+void EdgeArcCircle::getMiddleOfPointsOriented(const double *p1, const double *p2, double *mid) const
+{
+ double dx1((p1[0]-_center[0])/_radius),dy1((p1[1]-_center[1])/_radius),dx2((p2[0]-_center[0])/_radius),dy2((p2[1]-_center[1])/_radius);
+ double angle1(GetAbsoluteAngleOfNormalizedVect(dx1,dy1)),angle2(GetAbsoluteAngleOfNormalizedVect(dx2,dy2));
+
+ if (angle1 <= 0.0)
+ angle1 += 2.*M_PI;
+ if (angle2 <= 0.0)
+ angle2 += 2.*M_PI;
+
+ double avg;
+ if((_angle>0. && angle1 <= angle2) || (_angle<=0. && angle1 >= angle2))
+ avg = (angle1+angle2)/2.;
+ else
+ avg = (angle1+angle2)/2. - M_PI;
+
+ mid[0]=_center[0]+_radius*cos(avg);
+ mid[1]=_center[1]+_radius*sin(avg);
+}
+
+
/*!
* Characteristic value used is angle in ]_Pi;Pi[ from axe 0x.
*/
double myDelta2=val2-_angle0;
if(_angle>0.)
{
- myDelta1=myDelta1>-(_radius*QUADRATIC_PLANAR::_precision)?myDelta1:myDelta1+2.*M_PI;//in some cases val1 or val2 are so close to angle0 that myDelta is close to 0. but negative.
- myDelta2=myDelta2>-(_radius*QUADRATIC_PLANAR::_precision)?myDelta2:myDelta2+2.*M_PI;
+ myDelta1=myDelta1>-(_radius*QuadraticPlanarPrecision::getPrecision())?myDelta1:myDelta1+2.*M_PI;//in some cases val1 or val2 are so close to angle0 that myDelta is close to 0. but negative.
+ myDelta2=myDelta2>-(_radius*QuadraticPlanarPrecision::getPrecision())?myDelta2:myDelta2+2.*M_PI;
return myDelta1<myDelta2;
}
else
{
- myDelta1=myDelta1<(_radius*QUADRATIC_PLANAR::_precision)?myDelta1:myDelta1-2.*M_PI;
- myDelta2=myDelta2<(_radius*QUADRATIC_PLANAR::_precision)?myDelta2:myDelta2-2.*M_PI;
+ myDelta1=myDelta1<(_radius*QuadraticPlanarPrecision::getPrecision())?myDelta1:myDelta1-2.*M_PI;
+ myDelta2=myDelta2<(_radius*QuadraticPlanarPrecision::getPrecision())?myDelta2:myDelta2-2.*M_PI;
return myDelta2<myDelta1;
}
}