/** * Calculates the intersection point(s) between two entities. * * @param onEntities true: only return intersection points which are * on both entities. * false: return all intersection points. * * @todo support more entities * * @return All intersections of the two entities. The tangent flag in * RS_VectorSolutions is set if one intersection is a tangent point. */ RS_VectorSolutions RS_Information::getIntersection(RS_Entity* e1, RS_Entity* e2, bool onEntities) { RS_VectorSolutions ret; double tol = 1.0e-4; if (e1==NULL || e2==NULL ) { RS_DEBUG->print("RS_Information::getIntersection() for NULL entities"); return ret; } if (e1->getId() == e2->getId()) { RS_DEBUG->print("RS_Information::getIntersection() of the same entity"); return ret; } // unsupported entities / entity combinations: if ( e1->rtti()==RS2::EntityText || e2->rtti()==RS2::EntityText || isDimension(e1->rtti()) || isDimension(e2->rtti())) { return ret; } // a little check to avoid doing unneeded intersections, an attempt to avoid O(N^2) increasing of checking two-entity information if (onEntities && ( e1 -> getMin().x > e2 -> getMax().x || e1 -> getMax().x < e2 -> getMin().x || e1 -> getMin().y > e2 -> getMax().y || e1 -> getMax().y < e2 -> getMin().y ) ) { return ret; } // one entity is an ellipse: if (e1->rtti()==RS2::EntityEllipse || e2->rtti()==RS2::EntityEllipse) { if (e2->rtti()==RS2::EntityEllipse) std::swap( e1, e2); if (e2->rtti()==RS2::EntityEllipse) { ret = getIntersectionEllipseEllipse((RS_Ellipse*)e1, (RS_Ellipse *) e2); } if (e2->rtti()==RS2::EntityCircle) { ret = getIntersectionCircleEllipse((RS_Circle *)e2, (RS_Ellipse *) e1); } if (e2->rtti()==RS2::EntityArc) { ret = getIntersectionArcEllipse((RS_Arc *)e2, (RS_Ellipse *) e1); } if (e2->rtti()==RS2::EntityLine) { ret = getIntersectionLineEllipse((RS_Line*)e2, (RS_Ellipse*) e1); tol = 1.0e-1; } // not supported: else { return ret; } } else { RS_Entity* te1 = e1; RS_Entity* te2 = e2; // entity copies - so we only have to deal with lines and arcs RS_Line l1(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Line l2(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Arc a1(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); RS_Arc a2(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); // convert construction lines to lines: if (e1->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e1; l1.setStartpoint(cl->getPoint1()); l1.setEndpoint(cl->getPoint2()); te1 = &l1; } if (e2->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e2; l2.setStartpoint(cl->getPoint1()); l2.setEndpoint(cl->getPoint2()); te2 = &l2; } // convert circles to arcs: if (e1->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e1; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a1.setData(data); te1 = &a1; } if (e2->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e2; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a2.setData(data); te2 = &a2; } // line / line: // //else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityLine) { RS_Line * line1=(RS_Line*) te1; RS_Line * line2=(RS_Line*) te2; /* ToDo: 24 Aug 2011, Dongxu Li, if rtti() is not defined for the parent, the following check for splines may still cause segfault */ if ( line1->getParent() != NULL && line1->getParent() == line2->getParent()) { if ( line1->getParent()->rtti()==RS2::EntitySpline ) { //do not calculate intersections from neighboring lines of a spline if ( abs(line1->getParent()->findEntity(line1) - line1->getParent()->findEntity(line2)) <= 1 ) { return ret; } } } ret = getIntersectionLineLine(line1, line2); } // line / arc: // else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityArc) { RS_Line* line = (RS_Line*)te1; RS_Arc* arc = (RS_Arc*)te2; ret = getIntersectionLineArc(line, arc); } // arc / line: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityLine) { RS_Arc* arc = (RS_Arc*)te1; RS_Line* line = (RS_Line*)te2; ret = getIntersectionLineArc(line, arc); } // arc / arc: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityArc) { RS_Arc* arc1 = (RS_Arc*)te1; RS_Arc* arc2 = (RS_Arc*)te2; ret = getIntersectionArcArc(arc1, arc2); // ellipse / ellipse // } else { RS_DEBUG->print("RS_Information::getIntersection:: Unsupported entity type."); } } // Check all intersection points for being on entities: // if (onEntities==true) { if (!e1->isPointOnEntity(ret.get(0), tol) || !e2->isPointOnEntity(ret.get(0), tol)) { ret.set(0, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(1), tol) || !e2->isPointOnEntity(ret.get(1), tol)) { ret.set(1, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(2), tol) || !e2->isPointOnEntity(ret.get(2), tol)) { ret.set(2, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(3), tol) || !e2->isPointOnEntity(ret.get(3), tol)) { ret.set(3, RS_Vector(false)); } } int k=0; for (int i=0; i<4; ++i) { if (ret.get(i).valid) { ret.set(k, ret.get(i)); k++; } } for (int i=k; i<4; ++i) { ret.set(i, RS_Vector(false)); } return ret; }
RS_VectorSolutions RS_Information::getIntersectionEllipseEllipse(RS_Ellipse* e1, RS_Ellipse* e2) { RS_VectorSolutions ret; if (e1==NULL || e2==NULL ) { return ret; } if ( (e1->getCenter() - e2 -> getCenter() ).magnitude() < RS_TOLERANCE && ( e1->getMajorP() - e2 ->getMajorP()).magnitude() < RS_TOLERANCE && fabs(e1->getMajorRadius() - e2 ->getMajorRadius()) < RS_TOLERANCE && fabs(e1->getMinorRadius() - e2 ->getMinorRadius()) < RS_TOLERANCE ) { // overlapped ellipses, do not do overlap return ret; } RS_Ellipse *e01= ( RS_Ellipse *) e1->clone(); if( e01->getMajorRadius() < e01->getMinorRadius() ) e01->switchMajorMinor(); RS_Ellipse *e02= ( RS_Ellipse *) e2->clone(); if( e02->getMajorRadius() < e02->getMinorRadius() ) e02->switchMajorMinor(); //transform ellipse2 to ellipse1's coordinates RS_Vector shiftc1=- e01->getCenter(); double shifta1=-e01->getAngle(); e02->move(shiftc1); e02->rotate(shifta1); RS_Vector majorP2=e02->getMajorP(); double a1=e01->getMajorRadius(); double b1=e01->getMinorRadius(); double x2=e02->getCenter().x, y2=e02->getCenter().y; double a2=e02->getMajorRadius(); double b2=e02->getMinorRadius(); if( e01->getMinorRadius() < RS_TOLERANCE || e01 -> getRatio()< RS_TOLERANCE) { // treate e01 as a line RS_LineData ldata0(RS_Vector(-a1,0.),RS_Vector(a1,0.)); RS_Line *l0=new RS_Line(e1->getParent(),ldata0); ret= getIntersectionLineEllipse(l0, e02); ret.rotate(-shifta1); ret.move(-shiftc1); return ret; } if( e02->getMinorRadius() < RS_TOLERANCE || e02 -> getRatio()< RS_TOLERANCE) { // treate e02 as a line RS_LineData ldata0(RS_Vector(-a2,0.),RS_Vector(a2,0.)); RS_Line *l0=new RS_Line(e1->getParent(),ldata0); l0->rotate(RS_Vector(0.,0.),e02->getAngle()); l0->move(e02->getCenter()); ret= getIntersectionLineEllipse(l0, e01); ret.rotate(-shifta1); ret.move(-shiftc1); return ret; } //ellipse01 equation: // x^2/(a1^2) + y^2/(b1^2) - 1 =0 double t2= - e02->getAngle(); //ellipse2 equation: // ( (x - u) cos(t) - (y - v) sin(t))^2/a^2 + ( (x - u) sin(t) + (y-v) cos(t))^2/b^2 =1 // ( cos^2/a^2 + sin^2/b^2) x^2 + // ( sin^2/a^2 + cos^2/b^2) y^2 + // 2 sin cos (1/b^2 - 1/a^2) x y + // ( ( 2 v sin cos - 2 u cos^2)/a^2 - ( 2v sin cos + 2 u sin^2)/b^2) x + // ( ( 2 u sin cos - 2 v sin^2)/a^2 - ( 2u sin cos + 2 v cos^2)/b^2) y + // (u cos - v sin)^2/a^2 + (u sin + v cos)^2/b^2 -1 =0 // detect whether any ellipse radius is zero double cs=cos(t2),si=sin(t2); double ucs=x2*cs,usi=x2*si, vcs=y2*cs,vsi=y2*si; double cs2=cs*cs,si2=1-cs2; double tcssi=2.*cs*si; double ia2=1./(a2*a2),ib2=1./(b2*b2); // std::cout<<"e1: x^2/("<<a1<<")^2+y^2/("<<b1<<")^2-1 =0\n"; // std::cout<<"e2: ( (x-("<<x2<<"))*("<<cs<<")-(y-("<<y2<<"))*("<<si<<"))^2/"<<a2<<"^2+( ( x - ("<<x2<<"))*("<<si<<")+(y-("<<y2<<"))*("<<cs<<"))^2/"<<b2<<"^2 -1 =0\n"; double mc1=(ucs - vsi)*(ucs-vsi)*ia2+(usi+vcs)*(usi+vcs)*ib2 -1.; double mb10= ( y2*tcssi - 2.*x2*cs2)*ia2 - ( y2*tcssi+2*x2*si2)*ib2; //x double mb11= ( x2*tcssi - 2.*y2*si2)*ia2 - ( x2*tcssi+2*y2*cs2)*ib2; //y double ma100= cs2*ia2 + si2*ib2; // x^2 double ma101= cs*si*(ib2 - ia2); // xy term is 2*ma101*x*y double ma111= si2*ia2 + cs2*ib2; // y^2 double ma000= 1./(a1*a1),ma011=1./(b1*b1); // std::cout<<"simplified e1: "<<ma000<<"*x^2 + "<<ma011<<"*y^2 -1 =0\n"; // std::cout<<"simplified e2: "<<ma100<<"*x^2 + 2*("<<ma101<<")*x*y + "<<ma111<<"*y^2 "<<" + ("<<mb10<<")*x + ("<<mb11<<")*y + ("<<mc1<<") =0\n"; // construct the Bezout determinant double v0=2.*ma000*ma101; double v2=ma000*mb10; double v3=ma000*mb11; double v4=ma000*mc1+ma100; //double v5= 2.*ma101*ma011; //double v6= ma000*ma111; //double v7= 2.*ma101; double v8= 2.*ma011*mb10; //double v9= ma100*ma011; double v1=ma000*ma111-ma100*ma011; //double v1= v6 - v9; double u0 = v4*v4-v2*mb10; double u1 = 2.*(v3*v4-v0*mb10); double u2 = 2.*(v4*v1-ma101*v0)+v3*v3+0.5*v2*v8; double u3 = v0*v8+2.*v3*v1; double u4 = v1*v1+2.*ma101*ma011*v0; //std::cout<<"u0="<<u0<<"\tu1="<<u1<<"\tu2="<<u2<<"\tu3="<<u3<<"\tu4="<<u4<<std::endl; //std::cout<<"("<<u4<<")*x^4+("<<u3<<")*x^3+("<<u2<<")*x^2+("<<u1<<")*x+("<<u0<<")=0\n"; double ce[4]; double roots[4]; unsigned int counts=0; if ( fabs(u4) < 1.0e-75) { // this should not happen if ( fabs(u3) < 1.0e-75) { // this should not happen if ( fabs(u2) < 1.0e-75) { // this should not happen if( fabs(u1) > 1.0e-75) { counts=1; roots[0]=-u0/u1; } else { // can not determine y. this means overlapped, but overlap should have been detected before, therefore return empty set return ret; } } else { ce[0]=u1/u2; ce[1]=u0/u2; //std::cout<<"ce[2]={ "<<ce[0]<<' '<<ce[1]<<" }\n"; counts=RS_Math::quadraticSolver(ce,roots); } } else { ce[0]=u2/u3; ce[1]=u1/u3; ce[2]=u0/u3; //std::cout<<"ce[3]={ "<<ce[0]<<' '<<ce[1]<<' '<<ce[2]<<" }\n"; counts=RS_Math::cubicSolver(ce,roots); } } else { ce[0]=u3/u4; ce[1]=u2/u4; ce[2]=u1/u4; ce[3]=u0/u4; //std::cout<<"ce[4]={ "<<ce[0]<<' '<<ce[1]<<' '<<ce[2]<<' '<<ce[3]<<" }\n"; counts=RS_Math::quarticSolver(ce,roots); } // std::cout<<"Equation for y: y^4"; // for(int i=3; i>=0; i--) { // std::cout<<"+("<<ce[3-i]<<")"; // if ( i ) { // std::cout<<"*y^"<<i; // }else { // std::cout<<" ==0\n"; // } // } if (! counts ) { // no intersection found return ret; } // std::cout<<"counts="<<counts<<": "; // for(unsigned int i=0;i<counts;i++){ // std::cout<<roots[i]<<" "; // } // std::cout<<std::endl; RS_VectorSolutions vs0(8); unsigned int ivs0=0; for(unsigned int i=0; i<counts; i++) { double y=roots[i]; //double x=(ma100*(ma011*y*y-1.)-ma000*(ma111*y*y+mb11*y+mc1))/(ma000*(2.*ma101*y+mb11)); double x,d=v0*y+v2; // std::cout<<"d= "<<d<<std::endl; if( fabs(d)>RS_TOLERANCE*sqrt(RS_TOLERANCE)) {//whether there's x^1 term in bezout determinant x=-((v1*y+v3)*y+v4 )/d; if(vs0.getClosestDistance(RS_Vector(x,y),ivs0)>RS_TOLERANCE) vs0.set(ivs0++, RS_Vector(x,y)); } else { // no x^1 term, have to use x^2 term, then, have to check plus/minus sqrt x=a1*sqrt(1-y*y*ma011); if(vs0.getClosestDistance(RS_Vector(x,y),ivs0)>RS_TOLERANCE) vs0.set(ivs0++, RS_Vector(x,y)); x=-x; if(vs0.getClosestDistance(RS_Vector(x,y),ivs0)>RS_TOLERANCE) vs0.set(ivs0++, RS_Vector(x,y)); } //std::cout<<"eq1="<<ma000*x*x+ma011*y*y-1.<<std::endl; //std::cout<<"eq2="<<ma100*x*x + 2.*ma101*x*y+ma111*y*y+mb10*x+mb11*y+mc1<<std::endl; // if ( // fabs(ma100*x*x + 2.*ma101*x*y+ma111*y*y+mb10*x+mb11*y+mc1)< RS_TOLERANCE // ) {//found // vs0.set(ivs0++, RS_Vector(x,y)); // } } // for(unsigned int j=0; j<vs0.getNumber(); j++) { // std::cout<<" ( "<<vs0.get(j).x<<" , "<<vs0.get(j).y<<" ) "; // } // std::cout<<std::endl; // std::cout<<"counts= "<<counts<<"\tFound "<<ivs0<<" EllipseEllipse intersections\n"; ret.alloc(ivs0); for(unsigned i=0; i<ivs0; i++) { RS_Vector vp=vs0.get(i); vp.rotate(-shifta1); vp.move(-shiftc1); ret.set(i,vp); } return ret; }
/** * Calculates the intersection point(s) between two entities. * * @param onEntities true: only return intersection points which are * on both entities. * false: return all intersection points. * * @todo support more entities * * @return All intersections of the two entities. The tangent flag in * RS_VectorSolutions is set if one intersection is a tangent point. */ RS_VectorSolutions RS_Information::getIntersection(RS_Entity* e1, RS_Entity* e2, bool onEntities) { RS_VectorSolutions ret; double tol = 1.0e-4; if (e1==NULL || e2==NULL) { return ret; } // unsupported entities / entity combinations: if ((e1->rtti()==RS2::EntityEllipse && e2->rtti()==RS2::EntityEllipse) || e1->rtti()==RS2::EntityText || e2->rtti()==RS2::EntityText || isDimension(e1->rtti()) || isDimension(e2->rtti())) { return ret; } // (only) one entity is an ellipse: if (e1->rtti()==RS2::EntityEllipse || e2->rtti()==RS2::EntityEllipse) { if (e2->rtti()==RS2::EntityEllipse) { RS_Entity* tmp = e1; e1 = e2; e2 = tmp; } if (e2->rtti()==RS2::EntityLine) { RS_Ellipse* ellipse = (RS_Ellipse*)e1; ret = getIntersectionLineEllipse((RS_Line*)e2, ellipse); tol = 1.0e-1; } // ellipse / arc, ellipse / ellipse: not supported: else { return ret; } } else { RS_Entity* te1 = e1; RS_Entity* te2 = e2; // entity copies - so we only have to deal with lines and arcs RS_Line l1(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Line l2(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Arc a1(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); RS_Arc a2(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); // convert construction lines to lines: if (e1->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e1; l1.setStartpoint(cl->getPoint1()); l1.setEndpoint(cl->getPoint2()); te1 = &l1; } if (e2->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e2; l2.setStartpoint(cl->getPoint1()); l2.setEndpoint(cl->getPoint2()); te2 = &l2; } // convert circles to arcs: if (e1->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e1; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a1.setData(data); te1 = &a1; } if (e2->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e2; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a2.setData(data); te2 = &a2; } // line / line: // //else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityLine) { RS_Line* line1 = (RS_Line*)te1; RS_Line* line2 = (RS_Line*)te2; ret = getIntersectionLineLine(line1, line2); } // line / arc: // else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityArc) { RS_Line* line = (RS_Line*)te1; RS_Arc* arc = (RS_Arc*)te2; ret = getIntersectionLineArc(line, arc); } // arc / line: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityLine) { RS_Arc* arc = (RS_Arc*)te1; RS_Line* line = (RS_Line*)te2; ret = getIntersectionLineArc(line, arc); } // arc / arc: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityArc) { RS_Arc* arc1 = (RS_Arc*)te1; RS_Arc* arc2 = (RS_Arc*)te2; ret = getIntersectionArcArc(arc1, arc2); } else { RS_DEBUG->print("RS_Information::getIntersection:: Unsupported entity type."); } } // Check all intersection points for being on entities: // if (onEntities==true) { if (!e1->isPointOnEntity(ret.get(0), tol) || !e2->isPointOnEntity(ret.get(0), tol)) { ret.set(0, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(1), tol) || !e2->isPointOnEntity(ret.get(1), tol)) { ret.set(1, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(2), tol) || !e2->isPointOnEntity(ret.get(2), tol)) { ret.set(2, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(3), tol) || !e2->isPointOnEntity(ret.get(3), tol)) { ret.set(3, RS_Vector(false)); } } int k=0; for (int i=0; i<4; ++i) { if (ret.get(i).valid) { ret.set(k, ret.get(i)); k++; } } for (int i=k; i<4; ++i) { ret.set(i, RS_Vector(false)); } return ret; }