示例#1
0
double REllipse::angleToParam(double a) const {
    double p;
    if (fabs(a - 2*M_PI)<RS::AngleTolerance) {
        p = 2*M_PI;
    }
    else if (fabs(a)<RS::AngleTolerance) {
        p = 0.0;
    }
    else {
        REllipse normEllipse = *this;
        normEllipse.move(-center);
        normEllipse.rotate(-getAngle());
        normEllipse.setStartParam(0.0);
        normEllipse.setEndParam(2*M_PI);

        RLine line(RVector(0,0), RVector::createPolar(getMajorRadius()*2, a));
        QList<RVector> r = RShape::getIntersectionPoints(line, normEllipse, true);
        if (r.length()!=1) {
            return RNANDOUBLE;
        }

        p = acos(r[0].x / getMajorRadius());
    }

    if (RMath::getNormalizedAngle(a) > M_PI) {
        p = 2*M_PI-p;
    }

    return p;
}
示例#2
0
RS_Vector RS_Ellipse::getNearestMiddle(const RS_Vector& coord,
                                       double* dist,
                                       int middlePoints
                                      ) {
    if ( ! ( std::isnormal(getAngle1()) || std::isnormal(getAngle2()))) {
        //no middle point for whole ellipse, angle1=angle2=0
        if (dist!=NULL) {
            *dist = RS_MAXDOUBLE;
        }
        return RS_Vector(false);
    }
    if ( getMajorRadius() < RS_TOLERANCE || getMinorRadius() < RS_TOLERANCE ) {
        //zero radius, return the center
        RS_Vector vp(getCenter());
        if (dist!=NULL) {
            *dist = vp.distanceTo(coord);
        }
        return vp;
    }
    double angle=getAngle();
    double amin=getCenter().angleTo(getStartpoint());
    double amax=getCenter().angleTo(getEndpoint());
    if(isReversed()) {
        std::swap(amin,amax);
    }
    int i=middlePoints + 1;
    double da=fmod(amax-amin+2.*M_PI, 2.*M_PI);
    if ( da < RS_TOLERANCE ) {
        da = 2.*M_PI; //whole ellipse
    }
    da /= i;
    int j=1;
    double curDist=RS_MAXDOUBLE;
    //double a=RS_Math::correctAngle(amin+da-angle);
    double a=amin-angle+da;
    RS_Vector curPoint;
    RS_Vector scaleFactor(RS_Vector(1./getMajorRadius(),1./getMinorRadius()));
    do {
        RS_Vector vp(a);
        RS_Vector vp2=vp;
        vp2.scale(scaleFactor);
        vp.scale(1./vp2.magnitude());
        vp.rotate(angle);
        vp.move(getCenter());
        double d=coord.distanceTo(vp);
        if(d<curDist) {
            curDist=d;
            curPoint=vp;
        }
        j++;
        a += da;
    } while (j<i);
    if (dist!=NULL) {
        *dist = curDist;
    }
    RS_DEBUG->print("RS_Ellipse::getNearestMiddle: angle1=%g, angle2=%g, middle=%g\n",amin,amax,a);
    return curPoint;
}
示例#3
0
/**
 * \return Point on ellipse at given ellipse angle.
 */
RVector REllipse::getPointAt(double angle) const {
    RVector v(cos(angle)*getMajorRadius(),
              sin(angle)*getMinorRadius());
    v.rotate(getAngle());
    v.move(center);
    return v;
}
示例#4
0
RBox REllipse::getBoundingBox() const {
    double radius1 = getMajorRadius();
    double radius2 = getMinorRadius();
    double angle = getAngle();
    double a1 = ((!isReversed()) ? startParam : endParam);
    double a2 = ((!isReversed()) ? endParam : startParam);
    RVector startPoint = getStartPoint();
    RVector endPoint = getEndPoint();

    double minX = qMin(startPoint.x, endPoint.x);
    double minY = qMin(startPoint.y, endPoint.y);
    double maxX = qMax(startPoint.x, endPoint.x);
    double maxY = qMax(startPoint.y, endPoint.y);

    // kind of a brute force. TODO: exact calculation
    RVector vp;
    double a = a1;
    do {
        vp.set(center.x + radius1 * cos(a),
               center.y + radius2 * sin(a));
        vp.rotate(angle, center);

        minX = qMin(minX, vp.x);
        minY = qMin(minY, vp.y);
        maxX = qMax(maxX, vp.x);
        maxY = qMax(maxY, vp.y);

        a += 0.03;
    } while (RMath::isAngleBetween(a, a1, a2, false) && a<4*M_PI);

    return RBox(RVector(minX,minY), RVector(maxX,maxY));
}
示例#5
0
/* Dongxu Li's Version, 19 Aug 2011
 * scale an ellipse
 * Find the eigen vactors and eigen values by optimization
 * original ellipse equation,
 * x= a cos t
 * y= b sin t
 * rotated by angle,
 *
 * x = a cos t cos (angle) - b sin t sin(angle)
 * y = a cos t sin (angle) + b sin t cos(angle)
 * scaled by ( kx, ky),
 * x *= kx
 * y *= ky
 * find the maximum and minimum of x^2 + y^2,
 */
void RS_Ellipse::scale(RS_Vector center, RS_Vector factor) {
    data.center.scale(center, factor);
    RS_Vector vpStart=getStartpoint().scale(getCenter(),factor);
    RS_Vector vpEnd=getEndpoint().scale(getCenter(),factor);;
    double ct=cos(getAngle());
    double ct2 = ct*ct; // cos^2 angle
    double st=sin(getAngle());
    double st2=1.0 - ct2; // sin^2 angle
    double kx2= factor.x * factor.x;
    double ky2= factor.y * factor.y;
    double a=getMajorRadius();
    double b=getMinorRadius();
    double cA=0.5*a*a*(kx2*ct2+ky2*st2);
    double cB=0.5*b*b*(kx2*st2+ky2*ct2);
    double cC=a*b*ct*st*(ky2-kx2);
    RS_Vector vp(cA-cB,cC);
    setMajorP(RS_Vector(a,b).scale(RS_Vector(vp.angle())).rotate(RS_Vector(ct,st)).scale(factor));
    a=cA+cB;
    b=vp.magnitude();
    setRatio( sqrt((a - b)/(a + b) ));
    if(   std::isnormal(getAngle1()) || std::isnormal(getAngle2() ) )  {
        //only reset start/end points for ellipse arcs, i.e., angle1 angle2 are not both zero
        setAngle1(getEllipseAngle(vpStart));
        setAngle2(getEllipseAngle(vpEnd));
    }
    correctAngles();//avoid extra 2.*M_PI in angles
    //calculateEndpoints();
    calculateBorders();
}
示例#6
0
/**
 * \return Length of the ellipse segment from angle a1 to angle a2.
 */
double REllipse::getSimpsonLength(double a1, double a2) const {
    double df = (a2-a1) / 20;
    double R = getMajorRadius();
    double r = getMinorRadius();

    double sum = 0.0;
    double q = 1.0;

    for (int i=0; i<=20; ++i) {
        double y = sqrt(::pow(R * sin(a1 + i * df), 2) + ::pow(r * cos(a1 + i * df), 2));
        if (i==0 || i==20) {
            q = 1.0;
        }
        else {
            if (i%2==0) {
                q = 2.0;
            }
            else {
                q = 4.0;
            }
        }

        sum += q * y;
    }

    return (df / 3.0) * sum;
}
示例#7
0
bool REllipseData::moveReferencePoint(const RVector& referencePoint,
        const RVector& targetPoint) {

    RVector startPoint = getStartPoint();
    RVector endPoint = getEndPoint();

    if (!isFullEllipse()) {
        if (referencePoint.equalsFuzzy(startPoint)) {
            moveStartPoint(targetPoint, true);
            return true;
        }
        if (referencePoint.equalsFuzzy(endPoint)) {
            moveEndPoint(targetPoint, true);
            return true;
        }
    }

    if (referencePoint.equalsFuzzy(center+majorPoint)) {
        double minorRadius = getMinorRadius();
        majorPoint = targetPoint-center;
        setRatio(minorRadius / getMajorRadius());
        return true;
    }

    if (referencePoint.equalsFuzzy(center-majorPoint)) {
        double minorRadius = getMinorRadius();
        majorPoint = -(targetPoint-center);
        setRatio(minorRadius / getMajorRadius());
        return true;
    }

    if (referencePoint.equalsFuzzy(center+getMinorPoint())) {
        setMinorPoint(targetPoint-center);
        return true;
    }
    if (referencePoint.equalsFuzzy(center-getMinorPoint())) {
        setMinorPoint(-(targetPoint-center));
        return true;
    }

    if (referencePoint.equalsFuzzy(center)) {
        center = targetPoint;
        return true;
    }

    return false;
}
示例#8
0
bool REllipse::contains(const RVector& p) const {
    RVector pt = p;
    pt.move(-center);
    pt.rotate(-getAngle());
    double rx = getMajorRadius();
    double ry = getMinorRadius();
    return (pt.x*pt.x) / (rx*rx) + (pt.y*pt.y) / (ry*ry) <= 1.0;
}
示例#9
0
RVector REllipse::getEndPoint() const {
    RVector p(
        center.x + cos(endParam) * getMajorRadius(),
        center.y + sin(endParam) * getMinorRadius()
    );
    p.rotate(getAngle(), center);
    return p;
}
示例#10
0
/**
 * @param tolerance Tolerance.
 *
 * @retval true if the given point is on this entity.
 * @retval false otherwise
 */
bool RS_Ellipse::isPointOnEntity(const RS_Vector& coord,
                                 double tolerance) {
    if ( getCenter().distanceTo(coord) < tolerance ) {
        if (getMajorRadius() < tolerance || getMinorRadius() < tolerance ) {
            return true;
        } else {
            return false;
        }
    }
    double dist = getDistanceToPoint(coord, NULL, RS2::ResolveNone);
    return (dist<=tolerance);
}
示例#11
0
void REllipse::print(QDebug dbg) const {
    dbg.nospace() << "REllipse(";
    RShape::print(dbg);
    dbg.nospace() << ", startPoint: " << getStartPoint()
                  << ", endPoint: " << getEndPoint()
                  << ", center: " << getCenter()
                  << ", majorPoint: " << getMajorPoint()
                  << ", majorRadius: " << getMajorRadius()
                  << ", minorRadius: " << getMinorRadius()
                  << ", ratio: " << getRatio()
                  << ", startAngle: " << RMath::rad2deg(getStartParam())
                  << ", endAngle: " << RMath::rad2deg(getEndParam())
                  << ", full: " << isFullEllipse()
                  << ", clockwise: " << isReversed()
                  << ")";
}
示例#12
0
RS_Vector RS_Ellipse::getNearestOrthTan(const RS_Vector& coord,
                                        const RS_Line& normal,
                                        bool onEntity )
{
    if ( !coord.valid ) {
        return RS_Vector(false);
    }
    RS_Vector direction=normal.getEndpoint() - normal.getStartpoint();
    if (RS_Vector::dotP(direction,direction)< RS_TOLERANCE*RS_TOLERANCE) {
        //undefined direction
        return RS_Vector(false);
    }
    //scale to ellipse angle
    direction.rotate(-getAngle());
    double angle=direction.scale(RS_Vector(1.,getRatio())).angle();
    direction.set(getMajorRadius()*cos(angle),getMinorRadius()*sin(angle));//relative to center
    QList<RS_Vector> sol;
    for(int i=0; i<2; i++) {
        if(!onEntity ||
                RS_Math::isAngleBetween(angle,getAngle1(),getAngle2(),isReversed())) {
            if(i) {
                sol.append(- direction);
            } else {
                sol.append(direction);
            }
        }
        angle=RS_Math::correctAngle(angle+M_PI);
    }
    RS_Vector vp;
    switch(sol.count()) {
    case 0:
        return RS_Vector(false);
    case 2:
        if( RS_Vector::dotP(sol[1]-getCenter(),coord-getCenter())>0.) {
            vp=sol[1];
            break;
        }
    default:
        vp=sol[0];
    }
    return getCenter() + vp.rotate(getAngle());
}
示例#13
0
/**
 * Calculates the boundary box of this ellipse.
 *
 * @todo Fix that - the algorithm used is really bad / slow.
 */
void RS_Ellipse::calculateBorders() {
	RS_DEBUG->print("RS_Ellipse::calculateBorders");

    double radius1 = getMajorRadius();
    double radius2 = getMinorRadius();
    double angle = getAngle();
    double a1 = ((!isReversed()) ? data.angle1 : data.angle2);
    double a2 = ((!isReversed()) ? data.angle2 : data.angle1);
	RS_Vector startpoint = getStartpoint();
	RS_Vector endpoint = getEndpoint();

    double minX = std::min(startpoint.x, endpoint.x);
    double minY = std::min(startpoint.y, endpoint.y);
    double maxX = std::max(startpoint.x, endpoint.x);
    double maxY = std::max(startpoint.y, endpoint.y);

    // kind of a brute force. TODO: calculation
    RS_Vector vp;
	double a = a1;
	do {
        vp.set(data.center.x + radius1 * cos(a),
               data.center.y + radius2 * sin(a));
        vp.rotate(data.center, angle);

        minX = std::min(minX, vp.x);
        minY = std::min(minY, vp.y);
        maxX = std::max(maxX, vp.x);
        maxY = std::max(maxY, vp.y);

		a += 0.03;
    } while (RS_Math::isAngleBetween(RS_Math::correctAngle(a), a1, a2, false) && 
			a<4*M_PI);


    minV.set(minX, minY);
    maxV.set(maxX, maxY);
	RS_DEBUG->print("RS_Ellipse::calculateBorders: OK");
}
示例#14
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;
}
示例#15
0
/**
 * @todo Implement this.
 */
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 (entity!=NULL) {
        *entity = this;
    }

    double step;
    double a1;
    double a2;
    double d;
    double minDist = RS_MAXDOUBLE;

    if (!onEntity) {
        a1 = 0.0;
        a2 = 2*M_PI;
    } else {
        if (!data.reversed) {
            a1 = data.angle1;
            a2 = data.angle2;
        } else {
            a1 = data.angle2;
            a2 = data.angle1;
        }
    }

    // find closest point (approximate)
    RS_Vector vp;
    double bestMatch = 0.0;
    step = 0.01;
    double a = a1+step;
	int eternal = 0;
    do {
		// point on elllipse (wanders from a1 to a2)
        vp.set(data.center.x+cos(a)*getMajorRadius(),
               data.center.y+sin(a)*getMinorRadius());
        vp.rotate(data.center, getAngle());

        d = vp.distanceTo(coord);
        if (d<minDist) {
            minDist = d;
            bestMatch = a;
            ret = vp;
        }

        a += step;
		eternal++;
    } while (eternal<10000 && 
	    RS_Math::isAngleBetween(RS_Math::correctAngle(a), a1, a2, false) &&
		(onEntity || a<2*M_PI));

    // correct:
	/*
    a = bestMatch;
    step = 0.03;
    do {
        vp.set(data.center.x+cos(a)*getMajorRadius(),
               data.center.y+sin(a)*getMinorRadius());
        vp.rotate(data.center, getAngle());

        d = vp.distanceTo(coord);
        if (d<minDist) {
            minDist = d;
            bestMatch = a;
            ret = vp;
        } else {
            // change direction and decrease step amount
            step*=-0.3;
        }

        a += step;
    } while (fabs(step)>1.0e-6);
	*/

    // check endpoints:
    if (onEntity) {
        d = getStartpoint().distanceTo(coord);
        if (d<minDist) {
            ret = getStartpoint();
        }
        d = getEndpoint().distanceTo(coord);
        if (d<minDist) {
            ret = getEndpoint();
        }
    }

    if (dist!=NULL) {
        if (ret.valid) {
            *dist = ret.distanceTo(coord);
        } else {
            *dist = RS_MAXDOUBLE;
        }
    }
	RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: OK");

    return ret;
}
示例#16
0
void RS_Ellipse::draw(RS_Painter* painter, RS_GraphicView* view, double patternOffset) {

    if (painter==NULL || view==NULL) {
        return;
    }


    if (getPen().getLineType()==RS2::SolidLine ||
            isSelected() ||
            view->getDrawingMode()==RS2::ModePreview) {

        painter->drawEllipse(view->toGui(getCenter()),
                             getMajorRadius() * view->getFactor().x,
                             getMinorRadius() * view->getFactor().x,
                             getAngle(),
                             getAngle1(), getAngle2(),
                             isReversed());
    } else {
    	double styleFactor = getStyleFactor(view);
		if (styleFactor<0.0) {
        	painter->drawEllipse(view->toGui(getCenter()),
                             getMajorRadius() * view->getFactor().x,
                             getMinorRadius() * view->getFactor().x,
                             getAngle(),
                             getAngle1(), getAngle2(),
                             isReversed());
			return;
		}
		
        // Pattern:
        RS_LineTypePattern* pat;
        if (isSelected()) {
            pat = &patternSelected;
        } else {
            pat = view->getPattern(getPen().getLineType());
        }

        if (pat==NULL) {
            return;
        }

        // Pen to draw pattern is always solid:
        RS_Pen pen = painter->getPen();
        pen.setLineType(RS2::SolidLine);
        painter->setPen(pen);

        double* da;     // array of distances in x.
        int i;          // index counter

        double length = getAngleLength();

        // create pattern:
        da = new double[pat->num];

        double tot=0.0;
        i=0;
        bool done = false;
        double curA = getAngle1();
        double curR;
        RS_Vector cp = view->toGui(getCenter());
        double r1 = getMajorRadius() * view->getFactor().x;
        double r2 = getMinorRadius() * view->getFactor().x;

        do {
            curR = sqrt(RS_Math::pow(getMinorRadius()*cos(curA), 2.0)
                        + RS_Math::pow(getMajorRadius()*sin(curA), 2.0));

            if (curR>1.0e-6) {
                da[i] = fabs(pat->pattern[i] * styleFactor) / curR;
                if (pat->pattern[i] * styleFactor > 0.0) {

                    if (tot+fabs(da[i])<length) {
                        painter->drawEllipse(cp,
                                             r1, r2,
                                             getAngle(),
                                             curA,
                                             curA + da[i],
                                             false);
                    } else {
                        painter->drawEllipse(cp,
                                             r1, r2,
                                             getAngle(),
                                             curA,
                                             getAngle2(),
                                             false);
                    }
                }
            }
            curA+=da[i];
            tot+=fabs(da[i]);
            done=tot>length;

            i++;
            if (i>=pat->num) {
                i=0;
            }
        } while(!done);

        delete[] da;
    }
}
示例#17
0
/**
 * Overrides drawing of subentities. This is only ever called for solid fills.
 */
void RS_Hatch::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) {

    if (!data.solid) {
        for (RS_Entity* se=firstEntity();
                se!=NULL;
                se = nextEntity()) {

            view->drawEntity(painter,se);
        }
        return;
    }

    QPainterPath path;
    QList<QPolygon> paClosed;
    QPolygon pa;
//    QPolygon jp;   // jump points

    // loops:
    if (needOptimization==true) {
        for (RS_Entity* l=firstEntity(RS2::ResolveNone);
                l!=NULL;
                l=nextEntity(RS2::ResolveNone)) {

            if (l->rtti()==RS2::EntityContainer) {
                RS_EntityContainer* loop = (RS_EntityContainer*)l;

                loop->optimizeContours();
            }
        }
        needOptimization = false;
    }

    // loops:
    for (RS_Entity* l=firstEntity(RS2::ResolveNone);
         l!=NULL;
         l=nextEntity(RS2::ResolveNone)) {

        l->setLayer(getLayer());

        if (l->rtti()==RS2::EntityContainer) {
            RS_EntityContainer* loop = (RS_EntityContainer*)l;

            // edges:
            for (RS_Entity* e=loop->firstEntity(RS2::ResolveNone);
                 e!=NULL;
                 e=loop->nextEntity(RS2::ResolveNone)) {

                e->setLayer(getLayer());
                switch (e->rtti()) {
                case RS2::EntityLine: {
                    QPoint pt1(RS_Math::round(view->toGuiX(e->getStartpoint().x)),
                               RS_Math::round(view->toGuiY(e->getStartpoint().y)));
                    QPoint pt2(RS_Math::round(view->toGuiX(e->getEndpoint().x)),
                               RS_Math::round(view->toGuiY(e->getEndpoint().y)));

//                    if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) {
//                        jp<<pt1;
//                    }

                    pa<<pt1<<pt2;
                }
                    break;

                case RS2::EntityArc: {
//                    QPoint pt1(RS_Math::round(view->toGuiX(e->getStartpoint().x)),
//                               RS_Math::round(view->toGuiY(e->getStartpoint().y)));
//                    if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) {
//                        jp<<pt1;
//                    }

                    QPolygon pa2;
                    RS_Arc* arc=static_cast<RS_Arc*>(e);
                    painter->createArc(pa2, view->toGui(arc->getCenter()),
                                       view->toGuiDX(arc->getRadius()),
                                       arc->getAngle1(),
                                       arc->getAngle2(),
                                       arc->isReversed());
                    pa<<pa2;

                }
                    break;

                case RS2::EntityCircle: {
                    RS_Circle* circle = static_cast<RS_Circle*>(e);
//                    QPoint pt1(RS_Math::round(view->toGuiX(circle->getCenter().x+circle->getRadius())),
//                               RS_Math::round(view->toGuiY(circle->getCenter().y)));
//                    if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) {
//                        jp<<pt1;
//                    }

                    RS_Vector c=view->toGui(circle->getCenter());
                    double r=view->toGuiDX(circle->getRadius());
#if QT_VERSION >= 0x040400
                    path.addEllipse(QPoint(c.x,c.y),r,r);
#else
                    path.addEllipse(c.x - r, c.y + r, 2.*r, 2.*r);
//                    QPolygon pa2;
//                    painter->createArc(pa2, view->toGui(circle->getCenter()),
//                                       view->toGuiDX(circle->getRadius()),
//                                       0.0,
//                                       2*M_PI,
//                                       false);
//                    pa<<pa2;
#endif
                }
                    break;
                case RS2::EntityEllipse:
                if(static_cast<RS_Ellipse*>(e)->isArc()) {
                    QPolygon pa2;
                    auto ellipse=static_cast<RS_Ellipse*>(e);
                    painter->createEllipse(pa2,
                                           view->toGui(ellipse->getCenter()),
                                           view->toGuiDX(ellipse->getMajorRadius()),
                                           view->toGuiDX(ellipse->getMinorRadius()),
                                           ellipse->getAngle(),
                                           ellipse->getAngle1(), ellipse->getAngle2(),
                                           ellipse->isReversed()
                                           );
                    pa<<pa2;
                }else{
                    QPolygon pa2;
                    auto ellipse=static_cast<RS_Ellipse*>(e);
                    painter->createEllipse(pa2,
                                           view->toGui(ellipse->getCenter()),
                                           view->toGuiDX(ellipse->getMajorRadius()),
                                           view->toGuiDX(ellipse->getMinorRadius()),
                                           ellipse->getAngle(),
                                           ellipse->getAngle1(), ellipse->getAngle2(),
                                           ellipse->isReversed()
                                           );
                    path.addPolygon(pa2);
                }
                    break;
                default:
                    break;
                }
                if( pa.size()>2 && pa.first() == pa.last()) {
                    paClosed<<pa;
                    pa.clear();
                }

            }

        }
    }
    if(pa.size()>2){
        pa<<pa.first();
        paClosed<<pa;
    }
    for(int i=0;i<paClosed.size();i++){
        path.addPolygon(paClosed.at(i));
    }
        painter->setBrush(painter->getPen().getColor());
        painter->disablePen();
        painter->drawPath(path);

//    pa<<jp;

//    painter->setBrush(painter->getPen().getColor());
//    painter->disablePen();
//    painter->drawPolygon(pa);

}
示例#18
0
/**
 * Overrides drawing of subentities. This is only ever called for solid fills.
 */
void RS_Hatch::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) {

    if (!data.solid) {
		for(auto se: entities){

            view->drawEntity(painter,se);
        }
        return;
    }

    //area of solid fill. Use polygon approximation, except trivial cases
    QPainterPath path;
    QList<QPolygon> paClosed;
    QPolygon pa;
//    QPolygon jp;   // jump points

    // loops:
    if (needOptimization==true) {
		for(auto l: entities){

            if (l->rtti()==RS2::EntityContainer) {
                RS_EntityContainer* loop = (RS_EntityContainer*)l;

                loop->optimizeContours();
            }
        }
        needOptimization = false;
    }

    // loops:
	for(auto l: entities){
        l->setLayer(getLayer());

        if (l->rtti()==RS2::EntityContainer) {
            RS_EntityContainer* loop = (RS_EntityContainer*)l;

            // edges:
			for(auto e: *loop){

                e->setLayer(getLayer());
                switch (e->rtti()) {
                case RS2::EntityLine: {
                    QPoint pt1(RS_Math::round(view->toGuiX(e->getStartpoint().x)),
                               RS_Math::round(view->toGuiY(e->getStartpoint().y)));
                    QPoint pt2(RS_Math::round(view->toGuiX(e->getEndpoint().x)),
                               RS_Math::round(view->toGuiY(e->getEndpoint().y)));

//                    if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) {
//                        jp<<pt1;
//                    }
                    if(pa.size() && (pa.last()-pt1).manhattanLength()>=1)
                        pa<<pt1;
                    pa<<pt2;
                }
                    break;

                case RS2::EntityArc: {
//                    QPoint pt1(RS_Math::round(view->toGuiX(e->getStartpoint().x)),
//                               RS_Math::round(view->toGuiY(e->getStartpoint().y)));
//                    if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) {
//                        jp<<pt1;
//                    }

                    QPolygon pa2;
                    RS_Arc* arc=static_cast<RS_Arc*>(e);

                    painter->createArc(pa2, view->toGui(arc->getCenter()),
                                       view->toGuiDX(arc->getRadius())
                                       ,arc->getAngle1(),arc->getAngle2(),arc->isReversed());
                    if(pa.size() &&pa2.size()&&(pa.last()-pa2.first()).manhattanLength()<1)
                        pa2.remove(0,1);
                    pa<<pa2;

                }
                    break;

                case RS2::EntityCircle: {
                    RS_Circle* circle = static_cast<RS_Circle*>(e);
//                    QPoint pt1(RS_Math::round(view->toGuiX(circle->getCenter().x+circle->getRadius())),
//                               RS_Math::round(view->toGuiY(circle->getCenter().y)));
//                    if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) {
//                        jp<<pt1;
//                    }

                    RS_Vector c=view->toGui(circle->getCenter());
                    double r=view->toGuiDX(circle->getRadius());
#if QT_VERSION >= 0x040400
                    path.addEllipse(QPoint(c.x,c.y),r,r);
#else
                    path.addEllipse(c.x - r, c.y + r, 2.*r, 2.*r);
//                    QPolygon pa2;
//                    painter->createArc(pa2, view->toGui(circle->getCenter()),
//                                       view->toGuiDX(circle->getRadius()),
//                                       0.0,
//                                       2*M_PI,
//                                       false);
//                    pa<<pa2;
#endif
                }
                    break;
                case RS2::EntityEllipse:
                if(static_cast<RS_Ellipse*>(e)->isArc()) {
                    QPolygon pa2;
                    auto ellipse=static_cast<RS_Ellipse*>(e);

                    painter->createEllipse(pa2,
                                           view->toGui(ellipse->getCenter()),
                                           view->toGuiDX(ellipse->getMajorRadius()),
                                           view->toGuiDX(ellipse->getMinorRadius()),
                                           ellipse->getAngle()
                                           ,ellipse->getAngle1(),ellipse->getAngle2(),ellipse->isReversed()
                                           );
//                    qDebug()<<"ellipse: "<<ellipse->getCenter().x<<","<<ellipse->getCenter().y;
//                    qDebug()<<"ellipse: pa2.size()="<<pa2.size();
//                    qDebug()<<"ellipse: pa2="<<pa2;
                    if(pa.size() && pa2.size()&&(pa.last()-pa2.first()).manhattanLength()<1)
                        pa2.remove(0,1);
                    pa<<pa2;
                }else{
                    QPolygon pa2;
                    auto ellipse=static_cast<RS_Ellipse*>(e);
                    painter->createEllipse(pa2,
                                           view->toGui(ellipse->getCenter()),
                                           view->toGuiDX(ellipse->getMajorRadius()),
                                           view->toGuiDX(ellipse->getMinorRadius()),
                                           ellipse->getAngle(),
                                           ellipse->getAngle1(), ellipse->getAngle2(),
                                           ellipse->isReversed()
                                           );
                    path.addPolygon(pa2);
                }
                    break;
                default:
                    break;
                }
//                qDebug()<<"pa="<<pa;
                if( pa.size()>2 && pa.first() == pa.last()) {
                    paClosed<<pa;
                    pa.clear();
                }

            }

        }
    }
    if(pa.size()>2){
        pa<<pa.first();
        paClosed<<pa;
    }

    for(auto& p:paClosed){
        path.addPolygon(p);
    }

    //bug#474, restore brush after solid fill
    const QBrush brush(painter->brush());
    const RS_Pen pen=painter->getPen();
    painter->setBrush(pen.getColor());
    painter->disablePen();
    painter->drawPath(path);
    painter->setBrush(brush);
    painter->setPen(pen);


}
示例#19
0
/**
 * Calculates the boundary box of this ellipse.
 */
void RS_Ellipse::calculateBorders() {
    RS_DEBUG->print("RS_Ellipse::calculateBorders");

    double radius1 = getMajorRadius();
    double radius2 = getMinorRadius();
    double angle = getAngle();
    //double a1 = ((!isReversed()) ? data.angle1 : data.angle2);
    //double a2 = ((!isReversed()) ? data.angle2 : data.angle1);
    RS_Vector startpoint = getStartpoint();
    RS_Vector endpoint = getEndpoint();

    double minX = std::min(startpoint.x, endpoint.x);
    double minY = std::min(startpoint.y, endpoint.y);
    double maxX = std::max(startpoint.x, endpoint.x);
    double maxY = std::max(startpoint.y, endpoint.y);

    RS_Vector vp;
    // kind of a brute force. TODO: exact calculation
//    double a = a1;

//    do {
//        vp.set(data.center.x + radius1 * cos(a),
//               data.center.y + radius2 * sin(a));
//        vp.rotate(data.center, angle);
//
//        minX = std::min(minX, vp.x);
//        minY = std::min(minY, vp.y);
//        maxX = std::max(maxX, vp.x);
//        maxY = std::max(maxY, vp.y);
//
//        a += 0.03;
//    } while (RS_Math::isAngleBetween(RS_Math::correctAngle(a), a1, a2, false) &&
//             a<4*M_PI);
//    std::cout<<"a1="<<a1<<"\ta2="<<a2<<std::endl<<"Old algorithm:\nminX="<<minX<<"\tmaxX="<<maxX<<"\nminY="<<minY<<"\tmaxY="<<maxY<<std::endl;

    // Exact algorithm, based on rotation:
    // ( r1*cos(a), r2*sin(a)) rotated by angle to
    // (r1*cos(a)*cos(angle)-r2*sin(a)*sin(angle),r1*cos(a)*sin(angle)+r2*sin(a)*cos(angle))
    // both coordinates can be further reorganized to the form rr*cos(a+ theta),
    // with rr and theta angle defined by the coordinates given above
    double amin,amax;
//      x range
    vp.set(radius1*cos(angle),radius2*sin(angle));

    amin=RS_Math::correctAngle(getAngle1()+vp.angle()); // to the range of 0 to 2*M_PI
    amax=RS_Math::correctAngle(getAngle2()+vp.angle()); // to the range of 0 to 2*M_PI
    if( RS_Math::isAngleBetween(M_PI,amin,amax,isReversed()) ) {
        //if( (amin<=M_PI && delta_a >= M_PI - amin) || (amin > M_PI && delta_a >= 3*M_PI - amin)) {
        minX= data.center.x-vp.magnitude();
    }
    //    else

//       minX=data.center.x +vp.magnitude()*std::min(cos(amin),cos(amin+delta_a));
    if( RS_Math::isAngleBetween(2.*M_PI,amin,amax,isReversed()) ) {
        //if( delta_a >= 2*M_PI - amin ) {
        maxX= data.center.x+vp.magnitude();
    }//    else
//       maxX= data.center.x+vp.magnitude()*std::max(cos(amin),cos(amin+delta_a));
//      y range
    vp.set(radius1*sin(angle),-radius2*cos(angle));
    amin=RS_Math::correctAngle(getAngle1()+vp.angle()); // to the range of 0 to 2*M_PI
    amax=RS_Math::correctAngle(getAngle2()+vp.angle()); // to the range of 0 to 2*M_PI
    if( RS_Math::isAngleBetween(M_PI,amin,amax,isReversed()) ) {
        //if( (amin<=M_PI &&delta_a >= M_PI - amin) || (amin > M_PI && delta_a >= 3*M_PI - amin)) {
        minY= data.center.y-vp.magnitude();
    }//    else
//        minY=data.center.y +vp.magnitude()*std::min(cos(amin),cos(amin+delta_a));
    if( RS_Math::isAngleBetween(2.*M_PI,amin,amax,isReversed()) ) {
        //if( delta_a >= 2*M_PI - amin ) {
        maxY= data.center.y+vp.magnitude();
    }
    //    else
//        maxY= data.center.y+vp.magnitude()*std::max(cos(amin),cos(amin+delta_a));
//std::cout<<"New algorithm:\nminX="<<minX<<"\tmaxX="<<maxX<<"\nminY="<<minY<<"\tmaxY="<<maxY<<std::endl;

    minV.set(minX, minY);
    maxV.set(maxX, maxY);
    RS_DEBUG->print("RS_Ellipse::calculateBorders: OK");
}
示例#20
0
QList<RLine> REllipse::getTangents(const RVector& point) const {
    QList<RLine> ret;

    if (getDistanceTo(point, false) < RS::PointTolerance) {
        // point is on ellipse:
        return ret;
    }

    // point is at center (prevents recursion when swapping ellipse minor / major):
    if (point.getDistanceTo(getCenter())<RS::PointTolerance) {
        return ret;
    }

    // swap ellipse minor / major if point is on minor axis
    // 20120928: and not also on major axis (prevent recursion):
    RLine minorAxis(getCenter(), getCenter() + getMinorPoint());
    RLine majorAxis(getCenter(), getCenter() + getMajorPoint());
    if (minorAxis.isOnShape(point, false) && !majorAxis.isOnShape(point, false)) {
        REllipse e2 =*this;
        e2.majorPoint = getMinorPoint();
        e2.ratio = 1.0/ratio;
        return e2.getTangents(point);
    }

    double a = getMajorRadius();     // the length of the major axis / 2
    double b = getMinorRadius();     // the length of the minor axis / 2

    // rotate and move point:
    RVector point2 = point;
    point2.move(-getCenter());
    point2.rotate(-getAngle());

    double xp = point2.x;             // coordinates of the given point
    double yp = point2.y;

    double xt1;                      // Tangent point 1
    double yt1;
    double xt2;                      // Tangent point 2
    double yt2;

    double a2 = a * a;
    double b2 = b * b;
    double d = a2 / b2 * yp / xp;
    double e = a2 / xp;
    double af = b2 * d * d + a2;
    double bf = -b2 * d * e * 2.0;
    double cf = b2 * e * e - a2 * b2;
    double t = sqrt(bf * bf - af * cf * 4.0);
    if (RMath::isNaN(t)) {
        return ret;
    }

    yt1 = (t - bf) / (af * 2.0);
    xt1 = e - d * yt1;
    yt2 = (-t - bf) / (af * 2.0);
    xt2 = e - d * yt2;

    RVector s1(xt1, yt1);
    s1.rotate(getAngle());
    s1.move(getCenter());

    RVector s2(xt2, yt2);
    s2.rotate(getAngle());
    s2.move(getCenter());

    if (s1.isValid()) {
        ret.append(RLine(point, s1));
    }

    if (s2.isValid()) {
        ret.append(RLine(point, s2));
    }

    return ret;
}
示例#21
0
RVector REllipse::getVectorTo(const RVector& point, bool limited, double strictRange) const {
    Q_UNUSED(strictRange)

    RVector ret = RVector::invalid;

    double ang = getAngle();
    //double dDistance = RMAXDOUBLE;
    bool swap = false;
    bool majorSwap = false;

    RVector normalized = (point - center).rotate(-ang);

    // special case: point in line with major axis:
    if (fabs(normalized.getAngle()) < RS::AngleTolerance || fabs(normalized.getAngle()) > 2*M_PI-RS::AngleTolerance) {
        ret = RVector(getMajorRadius(), 0.0);
        //dDistance = ret.distanceTo(normalized);
    }

    else if (fabs(normalized.getAngle()-M_PI) < RS::AngleTolerance) {
        ret = RVector(-getMajorRadius(), 0.0);
        //dDistance = ret.distanceTo(normalized);
    }
    else {
        double dU = normalized.x;
        double dV = normalized.y;
        double dA = getMajorRadius();
        double dB = getMinorRadius();
        double dEpsilon = 1.0e-8;
        // iteration maximum
        int iMax = 32;
        double rdX = 0.0;
        double rdY = 0.0;

        if (dA<dB) {
            double dum = dA;
            dA = dB;
            dB = dum;
            dum = dU;
            dU = dV;
            dV = dum;
            majorSwap = true;
        }

        if (dV<0.0) {
            dV*=-1.0;
            swap = true;
        }

        // initial guess:
        double dT = dB*(dV - dB);

        // newton's method:
        int i;
        for (i = 0; i < iMax; i++) {
            double dTpASqr = dT + dA*dA;
            double dTpBSqr = dT + dB*dB;
            double dInvTpASqr = 1.0/dTpASqr;
            double dInvTpBSqr = 1.0/dTpBSqr;
            double dXDivA = dA*dU*dInvTpASqr;
            double dYDivB = dB*dV*dInvTpBSqr;
            double dXDivASqr = dXDivA*dXDivA;
            double dYDivBSqr = dYDivB*dYDivB;
            double dF = dXDivASqr + dYDivBSqr - 1.0;
            if (fabs(dF) < dEpsilon) {
                // f(t0) is very close to zero:
                rdX = dXDivA*dA;
                rdY = dYDivB*dB;
                break;
            }
            double dFDer = 2.0*(dXDivASqr*dInvTpASqr + dYDivBSqr*dInvTpBSqr);

            double dRatio = dF/dFDer;

            if ( fabs(dRatio) < dEpsilon ) {
                // t1-t0 is very close to zero:
                rdX = dXDivA*dA;
                rdY = dYDivB*dB;
                break;
            }
            dT += dRatio;
        }

        if (i == iMax) {
            // failed to converge:
            //dDistance = RMAXDOUBLE;
            ret = RVector::invalid;
        }
        else {
            //double dDelta0 = rdX - dU;
            //double dDelta1 = rdY - dV;
            //dDistance = sqrt(dDelta0*dDelta0 + dDelta1*dDelta1);
            ret = RVector(rdX, rdY);
        }
    }

    if (ret.isValid()) {
        if (swap) {
            ret.y*=-1.0;
        }
        if (majorSwap) {
            double dum = ret.x;
            ret.x = ret.y;
            ret.y = dum;
        }
        ret = (ret.rotate(ang) + center);

        if (limited) {
            double a1 = center.getAngleTo(getStartPoint());
            double a2 = center.getAngleTo(getEndPoint());
            double a = center.getAngleTo(ret);
            if (!RMath::isAngleBetween(a, a1, a2, reversed)) {
                ret = RVector::invalid;
            }
        }
    }

    /*
    if (dist!=NULL) {
        if (ret.valid) {
            *dist = dDistance;
        } else {
            *dist = RS_MAXDOUBLE;
        }
    }

    if (entity!=NULL) {
        if (ret.valid) {
            *entity = this;
        }
        else {
            *entity = NULL;
        }
    }
    */

    return point - ret;
}
示例#22
0
/**
 * \return Radius of ellipse at given ellipse angle.
 */
double REllipse::getRadiusAt(double angle) const {
    RVector v(cos(angle)*getMajorRadius(),
              sin(angle)*getMinorRadius());
    return v.getMagnitude();
}
示例#23
0
/**
 * Sets the minor point relative to the center point.
 */
void REllipse::setMinorPoint(const RVector& p) {
    double angle = RMath::getNormalizedAngle(p.getAngle() - M_PI/2.0);
    majorPoint.setPolar(getMajorRadius(), angle);
    setRatio(p.getMagnitude() / getMajorRadius());
}