Esempio n. 1
0
RS_Vector RS_Line::getNearestPointOnEntity(const RS_Vector& coord,
                                           bool onEntity, double* dist, RS_Entity** entity)const {

	if (entity) {
        *entity = const_cast<RS_Line*>(this);
    }
    RS_Vector direction = data.endpoint-data.startpoint;
    RS_Vector vpc=coord-data.startpoint;
    double a=direction.squared();
    if( a < RS_TOLERANCE2) {
        //line too short
        vpc=getMiddlePoint();
    }else{
        //find projection on line
        const double t=RS_Vector::dotP(vpc,direction)/a;
        if( !isConstruction() && onEntity &&
                ( t<=-RS_TOLERANCE || t>=1.+RS_TOLERANCE )
                ){
            //                !( vpc.x>= minV.x && vpc.x <= maxV.x && vpc.y>= minV.y && vpc.y<=maxV.y) ) {
            //projection point not within range, find the nearest endpoint
            //            std::cout<<"not within window, returning endpoints\n";
            return getNearestEndpoint(coord,dist);
        }
        vpc = data.startpoint + direction*t;
    }

	if (dist) {
        *dist = vpc.distanceTo(coord);
    }
    return vpc;
}
Esempio n. 2
0
RS_Vector RS_Line::getNearestPointOnEntity(const RS_Vector& coord,
        bool onEntity, double* dist, RS_Entity** entity)const {

    if (entity!=NULL) {
        *entity = const_cast<RS_Line*>(this);
    }
//std::cout<<"RS_Line::getNearestPointOnEntity():"<<coord<<std::endl;
    RS_Vector direction = data.endpoint-data.startpoint;
    RS_Vector vpc=coord-data.startpoint;
    double a=direction.squared();
    if( a < RS_TOLERANCE*RS_TOLERANCE) {
        //line too short
        vpc=getMiddlePoint();
    }else{
        //find projection on line
        vpc = data.startpoint + direction*RS_Vector::dotP(vpc,direction)/a;
        if( !isHelpLayer() && onEntity &&
                ! vpc.isInWindowOrdered(minV,maxV) ){
//                !( vpc.x>= minV.x && vpc.x <= maxV.x && vpc.y>= minV.y && vpc.y<=maxV.y) ) {
            //projection point not within range, find the nearest endpoint
//            std::cout<<"not within window, returning endpoints\n";
            return getNearestEndpoint(coord,dist);
        }
    }

    if (dist!=NULL) {
        *dist = vpc.distanceTo(coord);
    }
    return vpc;
}
Esempio n. 3
0
RS_Vector RS_Line::getNearestPointOnEntity(const RS_Vector& coord,
        bool onEntity, double* dist, RS_Entity** entity) {

    if (entity!=NULL) {
        *entity = this;
    }
    RS_Vector ret;

    RS_Vector vpl = data.endpoint-data.startpoint;
    double angle=vpl.angle();
    double r=vpl.magnitude();
    RS_Vector vpc=coord-data.startpoint;
    vpc.rotate(-angle); // rotate to use the line direction as x-axis
    if ( (vpc.x >= 0. && vpc.x <= r) || ! onEntity ) { //use the projection
        ret=RS_Vector(vpc.x,0.);
        ret.rotate(angle);
        ret += data.startpoint;
    } else {// onEntity=true and projection not within range, only have to check the endpoints
        ret=getNearestEndpoint(coord,dist);
    }

    if (dist!=NULL) {
        *dist = ret.distanceTo(coord);
        }
    return ret;
}
Esempio n. 4
0
RS_Vector RS_Line::getNearestPointOnEntity(const RS_Vector& coord,
    bool onEntity, double* dist, RS_Entity** entity)
{

  if (entity!=NULL)
  {
    *entity = this;
  }

  RS_Vector ae = data.endpoint-data.startpoint;
  RS_Vector ea = data.startpoint-data.endpoint;
  RS_Vector ap = coord-data.startpoint;
  RS_Vector ep = coord-data.endpoint;

  if (ae.magnitude()<1.0e-6 || ea.magnitude()<1.0e-6)
  {
    if (dist!=NULL)
    {
      *dist = RS_MAXDOUBLE;
    }
    return RS_Vector(false);
  }

  // Orthogonal projection from both sides:
  RS_Vector ba = ae * RS_Vector::dotP(ae, ap)
                 / (ae.magnitude()*ae.magnitude());
  RS_Vector be = ea * RS_Vector::dotP(ea, ep)
                 / (ea.magnitude()*ea.magnitude());

  // Check if the projection is within this line:
  if (onEntity==true &&
      (ba.magnitude()>ae.magnitude() || be.magnitude()>ea.magnitude()))
  {
    return getNearestEndpoint(coord, dist);
  }
  else
  {
    if (dist!=NULL)
    {
      *dist = coord.distanceTo(data.startpoint+ba);
    }
    return data.startpoint+ba;
  }
}
Esempio n. 5
0
RS_Vector RS_Line::getNearestPointOnEntity(const RS_Vector& coord,
                                           bool onEntity,
                                           double* dist,
                                           RS_Entity** entity) const
{
    if (entity) {
        *entity = const_cast<RS_Line*>(this);
    }

    RS_Vector direction {data.endpoint - data.startpoint};
    RS_Vector vpc {coord - data.startpoint};
    double a {direction.squared()};

    if( a < RS_TOLERANCE2) {
        //line too short
        vpc = getMiddlePoint();
    }
    else {
        //find projection on line
        const double t {RS_Vector::dotP( vpc, direction) / a};
        if( !isConstruction()
            && onEntity
            && ( t <= -RS_TOLERANCE
                 || t >= 1. + RS_TOLERANCE ) ) {
            //projection point not within range, find the nearest endpoint
            return getNearestEndpoint( coord, dist);
        }

        vpc = data.startpoint + direction * t;
    }

    if (dist) {
        *dist = vpc.distanceTo( coord);
    }

    return vpc;
}
/**
 * Rearranges the atomic entities in this container in a way that connected
 * entities are stored in the right order and direction.
 * Non-recoursive. Only affects atomic entities in this container.
 *
 * @retval true all contours were closed
 * @retval false at least one contour is not closed

 * to do: find closed contour by flood-fill
 */
bool RS_EntityContainer::optimizeContours() {
//    std::cout<<"RS_EntityContainer::optimizeContours: begin"<<std::endl;

//    DEBUG_HEADER
//    std::cout<<"loop with count()="<<count()<<std::endl;
    RS_DEBUG->print("RS_EntityContainer::optimizeContours");

    RS_EntityContainer tmp;
    tmp.setAutoUpdateBorders(false);
    bool closed=true;

    /** accept all full circles **/
    QList<RS_Entity*> enList;
	for(auto e1: entities){
        if (!e1->isEdge() || e1->isContainer() ) {
            enList<<e1;
            continue;
        }

        //detect circles and whole ellipses
        switch(e1->rtti()){
        case RS2::EntityEllipse:
			if(static_cast<RS_Ellipse*>(e1)->isEllipticArc())
                continue;
        case RS2::EntityCircle:
            //directly detect circles, bug#3443277
            tmp.addEntity(e1->clone());
            enList<<e1;
        default:
            continue;
        }

    }
    //    std::cout<<"RS_EntityContainer::optimizeContours: 1"<<std::endl;

    /** remove unsupported entities */
    for(RS_Entity* it: enList)
        removeEntity(it);

    /** check and form a closed contour **/
//    std::cout<<"RS_EntityContainer::optimizeContours: 2"<<std::endl;
    /** the first entity **/
	RS_Entity* current(nullptr);
    if(count()>0) {
        current=entityAt(0)->clone();
        tmp.addEntity(current);
        removeEntity(entityAt(0));
    }else {
        if(tmp.count()==0) return false;
    }
//    std::cout<<"RS_EntityContainer::optimizeContours: 3"<<std::endl;
    RS_Vector vpStart;
    RS_Vector vpEnd;
	if(current){
        vpStart=current->getStartpoint();
        vpEnd=current->getEndpoint();
    }
	RS_Entity* next(nullptr);
//    std::cout<<"RS_EntityContainer::optimizeContours: 4"<<std::endl;
    /** connect entities **/
    const QString errMsg=QObject::tr("Hatch failed due to a gap=%1 between (%2, %3) and (%4, %5)");

    while(count()>0){
        double dist(0.);
        RS_Vector&& vpTmp=getNearestEndpoint(vpEnd,&dist,&next);
        if(dist>1e-8) {
            if(vpEnd.squaredTo(vpStart)<1e-8){
                RS_Entity* e2=entityAt(0);
                tmp.addEntity(e2->clone());
                vpStart=e2->getStartpoint();
                vpEnd=e2->getEndpoint();
                removeEntity(e2);
                continue;
            }
            QG_DIALOGFACTORY->commandMessage(errMsg.arg(dist).arg(vpTmp.x).arg(vpTmp.y).arg(vpEnd.x).arg(vpEnd.y));
            closed=false;
        }
		if(next && closed){ 			//workaround if next is nullptr
            next->setProcessed(true);
            RS_Entity* eTmp = next->clone();
            if(vpEnd.squaredTo(eTmp->getStartpoint())>vpEnd.squaredTo(eTmp->getEndpoint()))
                eTmp->revertDirection();
            vpEnd=eTmp->getEndpoint();
            tmp.addEntity(eTmp);
        	removeEntity(next);
		} else { 			//workaround if next is nullptr
//      	    std::cout<<"RS_EntityContainer::optimizeContours: next is nullptr" <<std::endl;

			closed=false;	//workaround if next is nullptr
			break;			//workaround if next is nullptr
		} 					//workaround if next is nullptr
    }
//    DEBUG_HEADER
    if(vpEnd.valid && vpEnd.squaredTo(vpStart)>1e-8) {
        if(closed) QG_DIALOGFACTORY->commandMessage(errMsg.arg(vpEnd.distanceTo(vpStart))
                                         .arg(vpStart.x).arg(vpStart.y).arg(vpEnd.x).arg(vpEnd.y));
        closed=false;
    }
//    std::cout<<"RS_EntityContainer::optimizeContours: 5"<<std::endl;


    // add new sorted entities:
	for(auto en: tmp){
		en->setProcessed(false);
        addEntity(en->clone());
    }
//    std::cout<<"RS_EntityContainer::optimizeContours: 6"<<std::endl;

    RS_DEBUG->print("RS_EntityContainer::optimizeContours: OK");
//    std::cout<<"RS_EntityContainer::optimizeContours: end: count()="<<count()<<std::endl;
//    std::cout<<"RS_EntityContainer::optimizeContours: closed="<<closed<<std::endl;
    return closed;
}
Esempio n. 7
0
RS_Vector RS_Ellipse::getNearestPointOnEntity(const RS_Vector& coord,
        bool onEntity, double* dist, RS_Entity** entity)
{

    RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity");
    RS_Vector ret(false);

    if( ! coord.valid ) {
        if ( dist != NULL ) *dist=RS_MAXDOUBLE;
        return ret;

    }

    if (entity!=NULL) {
        *entity = this;
    }
    ret=coord;
    ret.move(-getCenter());
    ret.rotate(-getAngle());
    double x=ret.x,y=ret.y;
    double a=getMajorRadius();
    double b=getMinorRadius();
    //std::cout<<"(a= "<<a<<" b= "<<b<<" x= "<<x<<" y= "<<y<<" )\n";
    //std::cout<<"finding minimum for ("<<x<<"-"<<a<<"*cos(t))^2+("<<y<<"-"<<b<<"*sin(t))^2\n";
    double twoa2b2=2*(a*a-b*b);
    double twoax=2*a*x;
    double twoby=2*b*y;
    double a0=twoa2b2*twoa2b2;
    double ce[4];
    double roots[4];
    unsigned int counts=0;
    //need to handle a=b
    if(a0 > RS_TOLERANCE*RS_TOLERANCE ) { // a != b , ellipse
        ce[0]=-2.*twoax/twoa2b2;
        ce[1]= (twoax*twoax+twoby*twoby)/a0-1.;
        ce[2]= - ce[0];
        ce[3]= -twoax*twoax/a0;
        //std::cout<<"1::find cosine, variable c, solve(c^4 +("<<ce[0]<<")*c^3+("<<ce[1]<<")*c^2+("<<ce[2]<<")*c+("<<ce[3]<<")=0,c)\n";
        counts=RS_Math::quarticSolver(ce,roots);
    } else {//a=b, quadratic equation for circle
        counts=2;
        a0=twoby/twoax;
        roots[0]=sqrt(1./(1.+a0*a0));
        roots[1]=-roots[0];
    }
    if(!counts) {
        //this should not happen
        std::cout<<"(a= "<<a<<" b= "<<b<<" x= "<<x<<" y= "<<y<<" )\n";
        std::cout<<"finding minimum for ("<<x<<"-"<<a<<"*cos(t))^2+("<<y<<"-"<<b<<"*sin(t))^2\n";
        std::cout<<"2::find cosine, variable c, solve(c^4 +("<<ce[0]<<")*c^3+("<<ce[1]<<")*c^2+("<<ce[2]<<")*c+("<<ce[3]<<")=0,c)\n";
        std::cout<<ce[0]<<' '<<ce[1]<<' '<<ce[2]<<' '<<ce[3]<<std::endl;
        std::cerr<<"RS_Math::RS_Ellipse::getNearestPointOnEntity() finds no root from quartic, this should not happen\n";
        return RS_Vector(coord); // better not to return invalid: return RS_Vector(false);
    }

    RS_Vector vp2(false);
    double d(RS_MAXDOUBLE),d2,s,dDistance(RS_MAXDOUBLE);
    //double ea;
    for(unsigned int i=0; i<counts; i++) {
        //I don't understand the reason yet, but I can do without checking whether sine/cosine are valid
        //if ( fabs(roots[i])>1.) continue;
        s=twoby*roots[i]/(twoax-twoa2b2*roots[i]); //sine
        //if (fabs(s) > 1. ) continue;
        d2=twoa2b2+(twoax-2.*roots[i]*twoa2b2)*roots[i]+twoby*s;
        if (d2<0) continue; // fartherest
        RS_Vector vp3;
        vp3.set(a*roots[i],b*s);
        d=vp3.distanceTo(ret);
//        std::cout<<i<<" Checking: cos= "<<roots[i]<<" sin= "<<s<<" angle= "<<atan2(roots[i],s)<<" ds2= "<<d<<" d="<<d2<<std::endl;
        if( vp2.valid && d>dDistance) continue;
        vp2=vp3;
        dDistance=d;
//			ea=atan2(roots[i],s);
    }
    if( ! vp2.valid ) {
        //this should not happen
        std::cout<<ce[0]<<' '<<ce[1]<<' '<<ce[2]<<' '<<ce[3]<<std::endl;
        std::cout<<"(x,y)=( "<<x<<" , "<<y<<" ) a= "<<a<<" b= "<<b<<" sine= "<<s<<" d2= "<<d2<<" dist= "<<d<<std::endl;
        std::cout<<"RS_Ellipse::getNearestPointOnEntity() finds no minimum, this should not happen\n";
    }
    if (dist!=NULL) {
        *dist = dDistance;
    }
    vp2.rotate(getAngle());
    vp2.move(getCenter());
    ret=vp2;
    if (onEntity) {
        if (!RS_Math::isAngleBetween(getEllipseAngle(ret), getAngle1(), getAngle2(), isReversed())) { // not on entity, use the nearest endpoint
            //std::cout<<"not on ellipse, ( "<<getAngle1()<<" "<<getEllipseAngle(ret)<<" "<<getAngle2()<<" ) reversed= "<<isReversed()<<"\n";
            ret=getNearestEndpoint(coord,dist);
        }
    }

    if(! ret.valid) {
        std::cout<<"RS_Ellipse::getNearestOnEntity() returns invalid by mistake. This should not happen!"<<std::endl;
    }
    return ret;
}
Esempio n. 8
0
double RS_Line::getDistanceToPoint(const RS_Vector& coord,
                                   RS_Entity** entity,
                                   RS2::ResolveLevel /*level*/,
                                   double /*solidDist*/)
{

  RS_DEBUG->print("RS_Line::getDistanceToPoint");

  if (entity!=NULL)
  {
    *entity = this;
  }
  // check endpoints first:
  double dist = coord.distanceTo(getStartpoint());
  if (dist<1.0e-4)
  {
    RS_DEBUG->print("RS_Line::getDistanceToPoint: OK1");
    return dist;
  }
  dist = coord.distanceTo(getEndpoint());
  if (dist<1.0e-4)
  {
    RS_DEBUG->print("RS_Line::getDistanceToPoint: OK2");
    return dist;
  }

  dist = RS_MAXDOUBLE;
  RS_Vector ae = data.endpoint-data.startpoint;
  RS_Vector ea = data.startpoint-data.endpoint;
  RS_Vector ap = coord-data.startpoint;
  RS_Vector ep = coord-data.endpoint;

  if (ae.magnitude()<1.0e-6 || ea.magnitude()<1.0e-6)
  {
    RS_DEBUG->print("RS_Line::getDistanceToPoint: OK2a");
    return dist;
  }

  // Orthogonal projection from both sides:
  RS_Vector ba = ae * RS_Vector::dotP(ae, ap) /
                 RS_Math::pow(ae.magnitude(), 2);
  RS_Vector be = ea * RS_Vector::dotP(ea, ep) /
                 RS_Math::pow(ea.magnitude(), 2);

  // Check if the projection is outside this line:
  if (ba.magnitude()>ae.magnitude() || be.magnitude()>ea.magnitude())
  {
    // return distance to endpoint
    getNearestEndpoint(coord, &dist);
    RS_DEBUG->print("RS_Line::getDistanceToPoint: OK3");
    return dist;
  }
  //RS_DEBUG->print("ba: %f", ba.magnitude());
  //RS_DEBUG->print("ae: %f", ae.magnitude());

  RS_Vector cp = RS_Vector::crossP(ap, ae);
  dist = cp.magnitude() / ae.magnitude();

  RS_DEBUG->print("RS_Line::getDistanceToPoint: OK4");

  return dist;
}
Esempio n. 9
0
/**
 * @todo Implement this.
 */
RS_Vector RS_Solid::getNearestPointOnEntity(const RS_Vector& coord,
        bool onEntity, double* dist, RS_Entity** entity)const {
//first check if point is inside solid
    bool s1 = sign(data.corner[0], data.corner[1], coord);
    bool s2 = sign(data.corner[1], data.corner[2], coord);
    bool s3 = sign(data.corner[2], data.corner[0], coord);
    if ( (s1 == s2) && (s2 == s3) ) {
		if (dist!=nullptr)
            *dist = 0.0;
        return coord;
    }
    if (data.corner[3].valid) {
        s1 = sign(data.corner[0], data.corner[2], coord);
        s2 = sign(data.corner[2], data.corner[3], coord);
        s3 = sign(data.corner[3], data.corner[0], coord);
        if ( (s1 == s2) && (s2 == s3) ) {
			if (dist!=nullptr)
                *dist = 0.0;
            return coord;
        }
    }
    //not inside of solid
    RS_Vector ret(false);
    double currDist = RS_MAXDOUBLE;
    double tmpDist;
	if (entity!=nullptr) {
        *entity = const_cast<RS_Solid*>(this);
    }
    //Find nearest distance from each edge
    int totalV = 3;
    if (data.corner[3].valid)
        totalV = 4;
    for (int i=0; i<=totalV; ++i) {
        int next =i+1;
        //closing edge
        if (next == totalV) next =0;

        RS_Vector direction = data.corner[next]-data.corner[i];
        RS_Vector vpc=coord-data.corner[i];
        double a=direction.squared();
        if( a < RS_TOLERANCE2) {
            //line too short
            vpc=data.corner[i];
        }else{
            //find projection on line
            vpc = data.corner[i] + direction*RS_Vector::dotP(vpc,direction)/a;
        }
        tmpDist = vpc.distanceTo(coord);
        if (tmpDist < currDist) {
            currDist = tmpDist;
            ret = vpc;
        }
    }
    //verify this part
    if( onEntity && !ret.isInWindowOrdered(minV,maxV) ){
        //projection point not within range, find the nearest endpoint
        ret = getNearestEndpoint(coord,dist);
        currDist = ret.distanceTo(coord);
    }

	if (dist!=nullptr) {
        *dist = currDist;
    }

    return ret;
}
Esempio n. 10
0
/**
 * @todo Implement this.
 */
RS_Vector RS_Solid::getNearestPointOnEntity(const RS_Vector& coord,
                                            bool onEntity /*= true*/,
                                            double* dist /*= nullptr*/,
                                            RS_Entity** entity /*= nullptr*/) const
{
    //first check if point is inside solid
    bool s1 {sign(data.corner[0], data.corner[1], coord)};
    bool s2 {sign(data.corner[1], data.corner[2], coord)};
    bool s3 {sign(data.corner[2], data.corner[0], coord)};

    if ((s1 == s2) && (s2 == s3)) {
        setDistPtr( dist, 0.0);
        return coord;
    }

    if (!isTriangle()) {
        s1 = sign(data.corner[0], data.corner[2], coord);
        s2 = sign(data.corner[2], data.corner[3], coord);
        s3 = sign(data.corner[3], data.corner[0], coord);
        if ((s1 == s2) && (s2 == s3)) {
            setDistPtr( dist, 0.0);
            return coord;
        }
    }

    // not inside of solid
    // Find nearest distance from each edge
    if (nullptr != entity) {
        *entity = const_cast<RS_Solid*>(this);
    }

    RS_Vector ret(false);
    double currDist {RS_MAXDOUBLE};
    double tmpDist {0.0};
    int totalV {isTriangle() ? RS_SolidData::Triangle : RS_SolidData::MaxCorners};
    for (int i = RS_SolidData::FirstCorner, next = i + 1; i <= totalV; ++i, ++next) {
        //closing edge
        if (next == totalV) {
            next = RS_SolidData::FirstCorner;
        }

        RS_Vector direction {data.corner[next] - data.corner[i]};
        RS_Vector vpc {coord-data.corner[i]};
        double a {direction.squared()};
        if( a < RS_TOLERANCE2) {
            //line too short
            vpc = data.corner[i];
        }
        else{
            //find projection on line
            vpc = data.corner[i] + direction * RS_Vector::dotP( vpc, direction) / a;
        }
        tmpDist = vpc.distanceTo( coord);
        if (tmpDist < currDist) {
            currDist = tmpDist;
            ret = vpc;
        }
    }

    //verify this part
    if (onEntity && !ret.isInWindowOrdered( minV, maxV)) {
        // projection point not within range, find the nearest endpoint
        ret = getNearestEndpoint( coord, dist);
        currDist = ret.distanceTo( coord);
    }

    setDistPtr( dist, currDist);

    return ret;
}