Example #1
0
/**
 * 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;
}
Example #2
0
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;
}
Example #3
0
/**
 * 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;
}