Ejemplo n.º 1
0
/**
  *find the tangential points from a given point, i.e., the tangent lines should pass
  * the given point and tangential points
  *
  *Author: Dongxu Li
  */
RS_VectorSolutions RS_Circle::getTangentPoint(const RS_Vector& point) const {
    RS_VectorSolutions ret;
    double r2(getRadius()*getRadius());
    if(r2<RS_TOLERANCE*RS_TOLERANCE) return ret; //circle too small
    RS_Vector vp(point-getCenter());
    double c2(vp.squared());
    if(c2<r2-getRadius()*2.*RS_TOLERANCE) {
        //inside point, no tangential point
        return ret;
    }
    if(c2>r2+getRadius()*2.*RS_TOLERANCE) {
        //external point
        RS_Vector vp1(-vp.y,vp.x);
        vp1*=getRadius()*sqrt(c2-r2)/c2;
        vp *= r2/c2;
        vp += getCenter();
        if(vp1.squared()>RS_TOLERANCE*RS_TOLERANCE) {
            ret.push_back(vp+vp1);
            ret.push_back(vp-vp1);
            return ret;
        }
    }
    ret.push_back(point);
    return ret;
}
Ejemplo n.º 2
0
/**
 * @return One or two intersection points between given entities.
 */
RS_VectorSolutions RS_Information::getIntersectionEllipseLine(RS_Line* line,
        RS_Ellipse* ellipse) {

    RS_VectorSolutions ret;

    if (line==NULL || ellipse==NULL) {
        return ret;
    }

    // rotate into normal position:

    double rx = ellipse->getMajorRadius();
    if(rx<RS_TOLERANCE) {
        //zero radius ellipse
        RS_Vector vp(line->getNearestPointOnEntity(ellipse->getCenter(), true));
        if((vp-ellipse->getCenter()).squared() <RS_TOLERANCE2){
            //center on line
            ret.push_back(vp);
        }
        return ret;
    }
    RS_Vector angleVector = ellipse->getMajorP().scale(RS_Vector(1./rx,-1./rx));
    double ry = rx*ellipse->getRatio();
    RS_Vector center = ellipse->getCenter();
    RS_Vector a1 = line->getStartpoint().rotate(center, angleVector);
    RS_Vector a2 = line->getEndpoint().rotate(center, angleVector);
//    RS_Vector origin = a1;
    RS_Vector dir = a2-a1;
    RS_Vector diff = a1 - center;
    RS_Vector mDir = RS_Vector(dir.x/(rx*rx), dir.y/(ry*ry));
    RS_Vector mDiff = RS_Vector(diff.x/(rx*rx), diff.y/(ry*ry));

    double a = RS_Vector::dotP(dir, mDir);
    double b = RS_Vector::dotP(dir, mDiff);
    double c = RS_Vector::dotP(diff, mDiff) - 1.0;
    double d = b*b - a*c;

//    std::cout<<"RS_Information::getIntersectionEllipseLine(): d="<<d<<std::endl;
    if (d < - 1.e3*RS_TOLERANCE*sqrt(RS_TOLERANCE)) {
        RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: outside 0");
        return ret;
    }
    if( d < 0. ) d=0.;
    double root = sqrt(d);
    double t_a = -b/a;
    double t_b = root/a;
    //        double t_b = (-b + root) / a;

    ret.push_back(a1.lerp(a2,t_a+t_b));
    RS_Vector vp(a1.lerp(a2,t_a-t_b));
    if ( (ret.get(0)-vp).squared()>RS_TOLERANCE2) {
        ret.push_back(vp);
    }
    angleVector.y *= -1.;
    ret.rotate(center, angleVector);
//    std::cout<<"found Ellipse-Line intersections: "<<ret.getNumber()<<std::endl;
//    std::cout<<ret<<std::endl;
    RS_DEBUG->print("RS_Information::getIntersectionEllipseLine(): done");
    return ret;
}
Ejemplo n.º 3
0
RS_VectorSolutions RS_Ellipse::getRefPoints() {
    RS_VectorSolutions ret;
    if(isArc()){
        //no start/end point for whole ellipse
        ret.push_back(getStartpoint());
        ret.push_back(getEndpoint());
    }
    ret.push_back(data.center);
    ret.appendTo(getFoci());
    return ret;
}
Ejemplo n.º 4
0
/** switch x,y for all vectors */
RS_VectorSolutions RS_VectorSolutions::flipXY(void) const
{
        RS_VectorSolutions ret;
        const int counts=vector.size();
        for(int i=0;i<counts;i++) ret.push_back(vector[i].flipXY());
        return ret;
}
Ejemplo n.º 5
0
/** switch x,y for all vectors */
RS_VectorSolutions RS_VectorSolutions::flipXY(void) const
{
        RS_VectorSolutions ret;
		for(const auto& vp: vector)
			ret.push_back(vp.flipXY());
        return ret;
}
Ejemplo n.º 6
0
void RS_Circle::moveRef(const RS_Vector& ref, const RS_Vector& offset) {
	if(ref.distanceTo(data.center)<1.0e-4){
		data.center += offset;
        return;
    }
	RS_Vector v1(data.radius, 0.0);
    RS_VectorSolutions sol;
	sol.push_back(data.center + v1);
	sol.push_back(data.center - v1);
	v1.set(0., data.radius);
	sol.push_back(data.center + v1);
	sol.push_back(data.center - v1);
    double dist;
    v1=sol.getClosest(ref,&dist);
    if(dist>1.0e-4) return;
	data.radius = data.center.distanceTo(v1 + offset);
}
Ejemplo n.º 7
0
RS_VectorSolutions RS_Polyline::getRefPoints() {
    RS_VectorSolutions ret;

    ret.push_back(data.startpoint);

    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
         e!=NULL;
         e = nextEntity(RS2::ResolveNone)) {
        if (e->isAtomic()) {
            ret.push_back(((RS_AtomicEntity*)e)->getEndpoint());
        }
    }

    ret.push_back( data.endpoint);

    return ret;
}
Ejemplo n.º 8
0
RS_Vector RS_Image::getNearestCenter(const RS_Vector& coord,
									 double* dist) const{

	RS_VectorSolutions const& corners{getCorners()};
    //bug#485, there's no clear reason to ignore snapping to center within an image
//    if(containsPoint(coord)){
//        //if coord is within image
//        if(dist) *dist=0.;
//        return coord;
//    }

	RS_VectorSolutions points;
	for (size_t i=0; i < corners.size(); ++i) {
		size_t const j = (i+1)%corners.size();
		points.push_back((corners.get(i) + corners.get(j))*0.5);
	}
	points.push_back((corners.get(0) + corners.get(2))*0.5);

    return points.getClosest(coord, dist);
}
Ejemplo n.º 9
0
RS_Vector RS_Image::getNearestCenter(const RS_Vector& coord,
                                     double* dist) {

    RS_VectorSolutions points;
    RS_VectorSolutions corners = getCorners();
    //bug#485, there's no clear reason to ignore snapping to center within an image
//    if(containsPoint(coord)){
//        //if coord is within image
//        if(dist!=NULL) *dist=0.;
//        return coord;
//    }

    points.push_back((corners.get(0) + corners.get(1))/2.0);
    points.push_back((corners.get(1) + corners.get(2))/2.0);
    points.push_back((corners.get(2) + corners.get(3))/2.0);
    points.push_back((corners.get(3) + corners.get(0))/2.0);
    points.push_back((corners.get(0) + corners.get(2))/2.0);

    return points.getClosest(coord, dist);
}
Ejemplo n.º 10
0
RS_Vector RS_Image::getNearestDist(double distance,
                                   const RS_Vector& coord,
								   double* dist) const{

	RS_VectorSolutions const& corners = getCorners();
	RS_VectorSolutions points;

	for (size_t i = 0; i < corners.size(); ++i){
		size_t const j = (i+1)%corners.size();
		RS_Line const l{corners.get(i), corners.get(j)};
		RS_Vector const& vp = l.getNearestDist(distance, coord, dist);
		points.push_back(vp);
	}

    return points.getClosest(coord, dist);
}
Ejemplo n.º 11
0
RS_VectorSolutions LC_Quadratic::getIntersection(const LC_Quadratic& l1, const LC_Quadratic& l2)
{
    RS_VectorSolutions ret;
    if( l1.isValid() && l2.isValid() == false ) return ret;
    auto p1=&l1;
    auto p2=&l2;
    if(p1->isQuadratic()==false){
        std::swap(p1,p2);
    }
    if(p1->isQuadratic()==false){
        //two lines
        QVector<QVector<double> > ce(2,QVector<double>(3,0.));
        ce[0][0]=p1->m_vLinear(0);
        ce[0][1]=p1->m_vLinear(1);
        ce[0][2]=-p1->m_dConst;
        ce[1][0]=p2->m_vLinear(0);
        ce[1][1]=p2->m_vLinear(1);
        ce[1][2]=-p2->m_dConst;
        QVector<double> sn(2,0.);
        if(RS_Math::linearSolver(ce,sn)){
            ret.push_back(RS_Vector(sn[0],sn[1]));
        }
        return ret;
    }
    if(p2->isQuadratic()==false){
        //one line, one quadratic
        //avoid division by zero
        if(fabs(p2->m_vLinear(0))<fabs(p2->m_vLinear(1))){
            return getIntersection(p1->flipXY(),p2->flipXY()).flipXY();
        }

    }
    std::vector<std::vector<double> >  ce(0);
    ce.push_back(p1->getCoefficients());
    ce.push_back(p2->getCoefficients());
//DEBUG_HEADER();
//std::cout<<*p1<<std::endl;
//std::cout<<*p2<<std::endl;
    return RS_Math::simultaneousQuadraticSolverFull(ce);

}
Ejemplo n.º 12
0
/**
  * create a circle of radius r and tangential to two given entities
  */
RS_VectorSolutions RS_Circle::createTan2(const std::vector<RS_AtomicEntity*>& circles, const double& r)
{
    if(circles.size()<2) return false;
	auto e0=circles[0]->offsetTwoSides(r);
	auto e1=circles[1]->offsetTwoSides(r);
    RS_VectorSolutions centers;
	if(e0.size() && e1.size()) {
        for(auto it0=e0.begin();it0!=e0.end();it0++){
            for(auto it1=e1.begin();it1!=e1.end();it1++){
                centers.push_back(RS_Information::getIntersection(*it0,*it1));
            }
        }
    }
    for(auto it0=e0.begin();it0!=e0.end();it0++){
        delete *it0;
    }
    for(auto it0=e1.begin();it0!=e1.end();it0++){
        delete *it0;
	}
    return centers;

}
Ejemplo n.º 13
0
RS_Vector RS_Image::getNearestPointOnEntity(const RS_Vector& coord,
        bool onEntity, double* dist, RS_Entity** entity) const{

    if (entity) {
        *entity = const_cast<RS_Image*>(this);
    }

	RS_VectorSolutions const& corners =getCorners();
    //allow selecting image by clicking within images, bug#3464626
    if(containsPoint(coord)){
        //if coord is within image
        if(dist) *dist=0.;
        return coord;
    }
	RS_VectorSolutions points;
	for (size_t i=0; i < corners.size(); ++i){
		size_t const j = (i+1)%corners.size();
		RS_Line const l{corners.at(i), corners.at(j)};
		RS_Vector const vp = l.getNearestPointOnEntity(coord, onEntity);
		points.push_back(vp);
	}

	return points.getClosest(coord, dist);
}
Ejemplo n.º 14
0
void RS_Line::draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) {
	if (! (painter && view)) {
        return;
    }

    //only draw the visible portion of line
	LC_Rect const viewportRect{view->toGraph(0, 0),
				view->toGraph(view->getWidth(), view->getHeight())};
	RS_VectorSolutions endPoints(0);
	if (viewportRect.inArea(getStartpoint(), RS_TOLERANCE))
		 endPoints.push_back(getStartpoint());
	if (viewportRect.inArea(getEndpoint(), RS_TOLERANCE))
		 endPoints.push_back(getEndpoint());

	RS_EntityContainer ec(nullptr);
	ec.addRectangle(viewportRect.minP(), viewportRect.maxP());

	if (endPoints.size()<2){
		RS_VectorSolutions vpIts;
		for(auto p: ec) {
			auto const sol=RS_Information::getIntersection(this, p, true);
			for (auto const& vp: sol) {
				if (vpIts.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
					continue;
				vpIts.push_back(vp);
			}
		}
		for (auto const& vp: vpIts) {
			if (endPoints.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
				continue;
			endPoints.push_back(vp);
		}
	}

	if (endPoints.size()<2) return;

	if ((endPoints[0] - getStartpoint()).squared() >
			(endPoints[1] - getStartpoint()).squared() )
		std::swap(endPoints[0],endPoints[1]);

	RS_Vector pStart{view->toGui(endPoints.at(0))};
	RS_Vector pEnd{view->toGui(endPoints.at(1))};
    //    std::cout<<"draw line: "<<pStart<<" to "<<pEnd<<std::endl;
	RS_Vector direction = pEnd-pStart;

	if (isConstruction(true) && direction.squared() > RS_TOLERANCE){
        //extend line on a construction layer to fill the whole view
		RS_VectorSolutions vpIts;
		for(auto p: ec) {
			auto const sol=RS_Information::getIntersection(this, p, false);
			for (auto const& vp: sol) {
				if (vpIts.getClosestDistance(vp) <= RS_TOLERANCE * 10.)
					continue;
				vpIts.push_back(vp);
			}
		}

		//draw construction lines up to viewport border
		switch (vpIts.size()) {
		case 2:
			// no need to sort intersections
			break;
		case 3:
		case 4: {
			// will use the inner two points
			size_t i{0};
			for (size_t j = 2; j < vpIts.size(); ++j) {
				if (viewportRect.inArea(vpIts.at(j), RS_TOLERANCE * 10.))
					std::swap(vpIts[j], vpIts[i++]);
			}
		}
			break;
		default:
			//should not happen
			return;
		}
		pStart=view->toGui(vpIts.get(0));
		pEnd=view->toGui(vpIts.get(1));
		direction=pEnd-pStart;
    }
    double  length=direction.magnitude();
    patternOffset -= length;
    if (( !isSelected() && (
              getPen().getLineType()==RS2::SolidLine ||
              view->getDrawingMode()==RS2::ModePreview)) ) {
        //if length is too small, attempt to draw the line, could be a potential bug
        painter->drawLine(pStart,pEnd);
        return;
    }
    //    double styleFactor = getStyleFactor(view);


    // Pattern:
    const RS_LineTypePattern* pat;
    if (isSelected()) {
//        styleFactor=1.;
        pat = &RS_LineTypePattern::patternSelected;
    } else {
        pat = view->getPattern(getPen().getLineType());
    }
	if (!pat) {
//        patternOffset -= length;
        RS_DEBUG->print(RS_Debug::D_WARNING,
                        "RS_Line::draw: Invalid line pattern");
        painter->drawLine(pStart,pEnd);
        return;
    }
//    patternOffset = remainder(patternOffset - length-0.5*pat->totalLength,pat->totalLength)+0.5*pat->totalLength;
    if(length<=RS_TOLERANCE){
        painter->drawLine(pStart,pEnd);
        return; //avoid division by zero
    }
    direction/=length; //cos(angle), sin(angle)
    // Pen to draw pattern is always solid:
    RS_Pen pen = painter->getPen();

    pen.setLineType(RS2::SolidLine);
    painter->setPen(pen);

    // index counter
	size_t i;

    // pattern segment length:
    double patternSegmentLength = pat->totalLength;

    // create pattern:
	size_t const patnum=pat->num > 0?pat->num:0;
	std::vector<RS_Vector> dp(patnum);
	std::vector<double> ds(patnum, 0.);
    if (pat->num >0 ){
        double dpmm=static_cast<RS_PainterQt*>(painter)->getDpmm();
        for (i=0; i<pat->num; ++i) {
            //        ds[j]=pat->pattern[i] * styleFactor;
            //fixme, styleFactor support needed

            ds[i]=dpmm*pat->pattern[i];
			if (fabs(ds[i]) < 1. ) ds[i] = (ds[i]>=0.)?1.:-1.;
            dp[i] = direction*fabs(ds[i]);
        }
	} else {
        RS_DEBUG->print(RS_Debug::D_WARNING,"invalid line pattern for line, draw solid line instread");
        painter->drawLine(view->toGui(getStartpoint()),
                          view->toGui(getEndpoint()));
        return;
    }
    double total= remainder(patternOffset-0.5*patternSegmentLength,patternSegmentLength) -0.5*patternSegmentLength;
    //    double total= patternOffset-patternSegmentLength;

	RS_Vector curP{pStart+direction*total};
	for (int j=0; total<length; j=(j+1)%i) {

        // line segment (otherwise space segment)
		double const t2=total+fabs(ds[j]);
		RS_Vector const& p3=curP+dp[j];
        if (ds[j]>0.0 && t2 > 0.0) {
            // drop the whole pattern segment line, for ds[i]<0:
            // trim end points of pattern segment line to line
			RS_Vector const& p1 =(total > -0.5)?curP:pStart;
			RS_Vector const& p2 =(t2<length+0.5)?p3:pEnd;
            painter->drawLine(p1,p2);
        }
        total=t2;
        curP=p3;
	}

}
Ejemplo n.º 15
0
RS_VectorSolutions LC_Quadratic::getIntersection(const LC_Quadratic& l1, const LC_Quadratic& l2)
{
    RS_VectorSolutions ret;
    if( l1.isValid()==false || l2.isValid()==false ) {
//        DEBUG_HEADER
//        std::cout<<l1<<std::endl;
//        std::cout<<l2<<std::endl;
        return ret;
    }
    auto p1=&l1;
    auto p2=&l2;
    if(p1->isQuadratic()==false){
        std::swap(p1,p2);
    }
	if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){
		DEBUG_HEADER
		std::cout<<*p1<<std::endl;
		std::cout<<*p2<<std::endl;
	}
    if(p1->isQuadratic()==false){
        //two lines
		std::vector<std::vector<double> > ce(2,std::vector<double>(3,0.));
        ce[0][0]=p1->m_vLinear(0);
        ce[0][1]=p1->m_vLinear(1);
        ce[0][2]=-p1->m_dConst;
        ce[1][0]=p2->m_vLinear(0);
        ce[1][1]=p2->m_vLinear(1);
        ce[1][2]=-p2->m_dConst;
		std::vector<double> sn(2,0.);
        if(RS_Math::linearSolver(ce,sn)){
            ret.push_back(RS_Vector(sn[0],sn[1]));
        }
        return ret;
    }
    if(p2->isQuadratic()==false){
        //one line, one quadratic
        //avoid division by zero
        if(fabs(p2->m_vLinear(0))+DBL_EPSILON<fabs(p2->m_vLinear(1))){
            ret=getIntersection(p1->flipXY(),p2->flipXY()).flipXY();
//            for(size_t j=0;j<ret.size();j++){
//                DEBUG_HEADER
//                std::cout<<j<<": ("<<ret[j].x<<", "<< ret[j].y<<")"<<std::endl;
//            }
            return ret;
        }
        std::vector<std::vector<double> >  ce(0);
		if(fabs(p2->m_vLinear(1))<RS_TOLERANCE){
            const double angle=0.25*M_PI;
            LC_Quadratic p11(*p1);
            LC_Quadratic p22(*p2);
            ce.push_back(p11.rotate(angle).getCoefficients());
            ce.push_back(p22.rotate(angle).getCoefficients());
            ret=RS_Math::simultaneousQuadraticSolverMixed(ce);
            ret.rotate(-angle);
//            for(size_t j=0;j<ret.size();j++){
//                DEBUG_HEADER
//                std::cout<<j<<": ("<<ret[j].x<<", "<< ret[j].y<<")"<<std::endl;
//            }
            return ret;
        }
        ce.push_back(p1->getCoefficients());
        ce.push_back(p2->getCoefficients());
        ret=RS_Math::simultaneousQuadraticSolverMixed(ce);
//        for(size_t j=0;j<ret.size();j++){
//            DEBUG_HEADER
//            std::cout<<j<<": ("<<ret[j].x<<", "<< ret[j].y<<")"<<std::endl;
//        }
        return ret;
    }
    if( fabs(p1->m_mQuad(0,0))<RS_TOLERANCE && fabs(p1->m_mQuad(0,1))<RS_TOLERANCE
            &&
            fabs(p2->m_mQuad(0,0))<RS_TOLERANCE && fabs(p2->m_mQuad(0,1))<RS_TOLERANCE
            ){
        if(fabs(p1->m_mQuad(1,1))<RS_TOLERANCE && fabs(p2->m_mQuad(1,1))<RS_TOLERANCE){
            //linear
            std::vector<double> ce(0);
            ce.push_back(p1->m_vLinear(0));
            ce.push_back(p1->m_vLinear(1));
            ce.push_back(p1->m_dConst);
            LC_Quadratic lc10(ce);
            ce.clear();
            ce.push_back(p2->m_vLinear(0));
            ce.push_back(p2->m_vLinear(1));
            ce.push_back(p2->m_dConst);
            LC_Quadratic lc11(ce);
            return getIntersection(lc10,lc11);
        }
        return getIntersection(p1->flipXY(),p2->flipXY()).flipXY();
    }
    std::vector<std::vector<double> >  ce(0);
    ce.push_back(p1->getCoefficients());
    ce.push_back(p2->getCoefficients());
    if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){
        DEBUG_HEADER
        std::cout<<*p1<<std::endl;
        std::cout<<*p2<<std::endl;
    }
	auto sol= RS_Math::simultaneousQuadraticSolverFull(ce);
    bool valid= sol.size()>0;
	for(auto & v: sol){
		if(v.magnitude()>=RS_MAXDOUBLE){
            valid=false;
            break;
        }
    }
    if(valid) return sol;
    ce.clear();
    ce.push_back(p1->flipXY().getCoefficients());
    ce.push_back(p2->flipXY().getCoefficients());
    sol=RS_Math::simultaneousQuadraticSolverFull(ce);
    ret.clear();
	for(auto const& v: sol){
		if(v.magnitude()<=RS_MAXDOUBLE){
			ret.push_back(v);
			if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){
				DEBUG_HEADER
				std::cout<<v<<std::endl;
			}
		}
	}
    return ret;
}
Ejemplo n.º 16
0
RS_VectorSolutions RS_Information::createQuadrilateral(const RS_EntityContainer& container)
{
	RS_VectorSolutions ret;
	if(container.count()!=4) return ret;
	RS_EntityContainer c(container);
	std::vector<RS_Line*> lines;
	for(auto e: c){
		if(e->rtti()!=RS2::EntityLine) return ret;
		lines.push_back(static_cast<RS_Line*>(e));
	}
	if(lines.size()!=4) return ret;

	//find intersections
	std::vector<RS_Vector> vertices;
	for(auto it=lines.begin()+1; it != lines.end(); ++it){
		for(auto jt=lines.begin(); jt != it; ++jt){
			RS_VectorSolutions const& sol=RS_Information::getIntersectionLineLine(*it, *jt);
			if(sol.size()){
				vertices.push_back(sol.at(0));
			}
		}
	}

//	std::cout<<"vertices.size()="<<vertices.size()<<std::endl;

	switch (vertices.size()){
	default:
		return ret;
	case 4:
		break;
	case 5:
	case 6:
		for(RS_Line* pl: lines){
			const double a0=pl->getDirection1();
			std::vector<std::vector<RS_Vector>::iterator> left;
			std::vector<std::vector<RS_Vector>::iterator> right;
			for(auto it=vertices.begin(); it != vertices.end(); ++it){
				RS_Vector const& dir=*it - pl->getNearestPointOnEntity(*it, false);
				if(dir.squared()<RS_TOLERANCE15) continue;
//				std::cout<<"angle="<<remainder(dir.angle() - a0, 2.*M_PI)<<std::endl;
				if(remainder(dir.angle() - a0, 2.*M_PI) > 0.)
					left.push_back(it);
				else
					right.push_back(it);

				if(left.size()==2 && right.size()==1){
					vertices.erase(right[0]);
					break;
				} else if(left.size()==1 && right.size()==2){
					vertices.erase(left[0]);
					break;
				}
			}
			if(vertices.size()==4) break;
		}
		break;
	}

	//order vertices
	RS_Vector center{0., 0.};
	for(const RS_Vector& vp: vertices)
		center += vp;
	center *= 0.25;
	std::sort(vertices.begin(), vertices.end(), [&center](const RS_Vector& a,
			  const RS_Vector&b)->bool{
		return center.angleTo(a)<center.angleTo(b);
	}
	);
	for(const RS_Vector& vp: vertices){
		ret.push_back(vp);
//		std::cout<<"vp="<<vp<<std::endl;
	}
	return ret;
}
Ejemplo n.º 17
0
RS_VectorSolutions RS_Information::getIntersectionEllipseEllipse(
		RS_Ellipse const* e1, RS_Ellipse const* e2) {
    RS_VectorSolutions ret;

	if (!(e1 && e2) ) {
        return ret;
    }
    if (
        (e1->getCenter() - e2 ->getCenter()).squared() < RS_TOLERANCE2 &&
        (e1->getMajorP() - e2 ->getMajorP()).squared() < RS_TOLERANCE2 &&
        fabs(e1->getRatio() - e2 ->getRatio()) < RS_TOLERANCE
    ) { // overlapped ellipses, do not do overlap
        return ret;
    }
	RS_Ellipse ellipse01(nullptr,e1->getData());

    RS_Ellipse *e01= & ellipse01;
    if( e01->getMajorRadius() < e01->getMinorRadius() ) e01->switchMajorMinor();
	RS_Ellipse ellipse02(nullptr,e2->getData());
    RS_Ellipse *e02= &ellipse02;
    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_Line *l0=new RS_Line{e1->getParent(), {{-a1,0.}, {a1,0.}}};
        ret= getIntersectionEllipseLine(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_Line *l0=new RS_Line{e1->getParent(), {{-a2,0.}, {a2,0.}}};
		l0->rotate({0.,0.}, e02->getAngle());
        l0->move(e02->getCenter());
        ret= getIntersectionEllipseLine(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::vector<double> m(0,0.);
    m.push_back( 1./(a1*a1)); //ma000
    m.push_back( 1./(b1*b1)); //ma011
    m.push_back(cs2*ia2 + si2*ib2); //ma100
    m.push_back(cs*si*(ib2 - ia2)); //ma101
    m.push_back(si2*ia2 + cs2*ib2); //ma111
    m.push_back(( y2*tcssi - 2.*x2*cs2)*ia2 - ( y2*tcssi+2*x2*si2)*ib2); //mb10
    m.push_back( ( x2*tcssi - 2.*y2*si2)*ia2 - ( x2*tcssi+2*y2*cs2)*ib2); //mb11
    m.push_back((ucs - vsi)*(ucs-vsi)*ia2+(usi+vcs)*(usi+vcs)*ib2 -1.); //mc1
	auto vs0=RS_Math::simultaneousQuadraticSolver(m);
    shifta1 = - shifta1;
    shiftc1 = - shiftc1;
	for(RS_Vector vp: vs0){
        vp.rotate(shifta1);
        vp.move(shiftc1);
        ret.push_back(vp);
    }
    return ret;
}
Ejemplo n.º 18
0
RS_VectorSolutions LC_Quadratic::getIntersection(const LC_Quadratic& l1, const LC_Quadratic& l2)
{
    RS_VectorSolutions ret;
    if( l1.isValid()==false || l2.isValid()==false ) {
//        DEBUG_HEADER();
//        std::cout<<l1<<std::endl;
//        std::cout<<l2<<std::endl;
        return ret;
    }
    auto p1=&l1;
    auto p2=&l2;
    if(p1->isQuadratic()==false){
        std::swap(p1,p2);
    }
//    DEBUG_HEADER();
//    std::cout<<*p1<<std::endl;
//    std::cout<<*p2<<std::endl;
    if(p1->isQuadratic()==false){
        //two lines
        QVector<QVector<double> > ce(2,QVector<double>(3,0.));
        ce[0][0]=p1->m_vLinear(0);
        ce[0][1]=p1->m_vLinear(1);
        ce[0][2]=-p1->m_dConst;
        ce[1][0]=p2->m_vLinear(0);
        ce[1][1]=p2->m_vLinear(1);
        ce[1][2]=-p2->m_dConst;
        QVector<double> sn(2,0.);
        if(RS_Math::linearSolver(ce,sn)){
            ret.push_back(RS_Vector(sn[0],sn[1]));
        }
        return ret;
    }
    if(p2->isQuadratic()==false){
        //one line, one quadratic
        //avoid division by zero
        if(fabs(p2->m_vLinear(0))<fabs(p2->m_vLinear(1))){
            return getIntersection(p1->flipXY(),p2->flipXY()).flipXY();
        }

    }
    if( fabs(p1->m_mQuad(0,0))<RS_TOLERANCE && fabs(p1->m_mQuad(0,1))<RS_TOLERANCE
            &&
            fabs(p2->m_mQuad(0,0))<RS_TOLERANCE && fabs(p2->m_mQuad(0,1))<RS_TOLERANCE
            ){
        if(fabs(p1->m_mQuad(1,1))<RS_TOLERANCE && fabs(p2->m_mQuad(1,1))<RS_TOLERANCE){
            //linear
            std::vector<double> ce(0);
            ce.push_back(p1->m_vLinear(0));
            ce.push_back(p1->m_vLinear(1));
            ce.push_back(p1->m_dConst);
            LC_Quadratic lc10(ce);
            ce.clear();
            ce.push_back(p2->m_vLinear(0));
            ce.push_back(p2->m_vLinear(1));
            ce.push_back(p2->m_dConst);
            LC_Quadratic lc11(ce);
            return getIntersection(lc10,lc11);
        }
        return getIntersection(p1->flipXY(),p2->flipXY()).flipXY();
    }
    std::vector<std::vector<double> >  ce(0);
    ce.push_back(p1->getCoefficients());
    ce.push_back(p2->getCoefficients());
    if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){
        DEBUG_HEADER();
        std::cout<<*p1<<std::endl;
        std::cout<<*p2<<std::endl;
    }
    return RS_Math::simultaneousQuadraticSolverFull(ce);

}
Ejemplo n.º 19
0
void RS_Line::draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) {
    if (painter==NULL || view==NULL) {
        return;
    }

    //only draw the visible portion of line
    QVector<RS_Vector> endPoints(0);
        RS_Vector vpMin(view->toGraph(0,view->getHeight()));
        RS_Vector vpMax(view->toGraph(view->getWidth(),0));
         QPolygonF visualBox(QRectF(vpMin.x,vpMin.y,vpMax.x-vpMin.x, vpMax.y-vpMin.y));
    if( getStartpoint().isInWindowOrdered(vpMin, vpMax) ) endPoints<<getStartpoint();
    if( getEndpoint().isInWindowOrdered(vpMin, vpMax) ) endPoints<<getEndpoint();
    if(endPoints.size()<2){

         QVector<RS_Vector> vertex;
         for(unsigned short i=0;i<4;i++){
             const QPointF& vp(visualBox.at(i));
             vertex<<RS_Vector(vp.x(),vp.y());
         }
         for(unsigned short i=0;i<4;i++){
             RS_Line line(NULL,RS_LineData(vertex.at(i),vertex.at((i+1)%4)));
             auto&& vpIts=RS_Information::getIntersection(static_cast<RS_Entity*>(this), &line, true);
             if( vpIts.size()==0) continue;
             endPoints<<vpIts.get(0);
         }
    }
    if(endPoints.size()<2) return;
    if( (endPoints[0] - getStartpoint()).squared() >
            (endPoints[1] - getStartpoint()).squared() ) std::swap(endPoints[0],endPoints[1]);

    RS_Vector pStart(view->toGui(endPoints.at(0)));
    RS_Vector pEnd(view->toGui(endPoints.at(1)));
    //    std::cout<<"draw line: "<<pStart<<" to "<<pEnd<<std::endl;
    RS_Vector direction=pEnd-pStart;
    if(isHelpLayer(true) && direction.squared() > RS_TOLERANCE){
        //extend line on a help layer to fill the whole view
        RS_Vector lb(0,0);
        RS_Vector rt(view->getWidth(),view->getHeight());
        QList<RS_Vector> rect;
        rect<<lb<<RS_Vector(rt.x,lb.y);
        rect<<rt<<RS_Vector(lb.x,rt.y);
        rect<<lb;
        RS_VectorSolutions sol;
        RS_Line dLine(pStart,pEnd);
        for(int i=0;i<4;i++){
            RS_Line bLine(rect.at(i),rect.at(i+1));
            RS_VectorSolutions sol2=RS_Information::getIntersection(&bLine, &dLine);
            if( sol2.getNumber()>0 && bLine.isPointOnEntity(sol2.get(0),RS_TOLERANCE)) {
                sol.push_back(sol2.get(0));
            }
        }
        switch(sol.getNumber()){
        case 2:
            pStart=sol.get(0);
            pEnd=sol.get(1);
            break;
        case 3:
        case 4:
            pStart=sol.get(0);
            pEnd=sol.get(2);
            break;
        default:
            return;
        }
        direction=pEnd-pStart;
    }
    double  length=direction.magnitude();
    patternOffset -= length;
    if (( !isSelected() && (
              getPen().getLineType()==RS2::SolidLine ||
              view->getDrawingMode()==RS2::ModePreview)) ) {
        //if length is too small, attempt to draw the line, could be a potential bug
        painter->drawLine(pStart,pEnd);
        return;
    }
    //    double styleFactor = getStyleFactor(view);


    // Pattern:
    RS_LineTypePattern* pat;
    if (isSelected()) {
//        styleFactor=1.;
        pat = &patternSelected;
    } else {
        pat = view->getPattern(getPen().getLineType());
    }
    if (pat==NULL) {
//        patternOffset -= length;
        RS_DEBUG->print(RS_Debug::D_WARNING,
                        "RS_Line::draw: Invalid line pattern");
        painter->drawLine(pStart,pEnd);
        return;
    }
//    patternOffset = remainder(patternOffset - length-0.5*pat->totalLength,pat->totalLength)+0.5*pat->totalLength;
    if(length<=RS_TOLERANCE){
        painter->drawLine(pStart,pEnd);
        return; //avoid division by zero
    }
    direction/=length; //cos(angle), sin(angle)
    // Pen to draw pattern is always solid:
    RS_Pen pen = painter->getPen();

    pen.setLineType(RS2::SolidLine);
    painter->setPen(pen);

    // index counter
    int i;

    // pattern segment length:
    double patternSegmentLength = pat->totalLength;

    // create pattern:
    RS_Vector* dp=new RS_Vector[pat->num > 0?pat->num:0];
    double* ds=new double[pat->num > 0?pat->num:0];
    if (pat->num >0 ){
        double dpmm=static_cast<RS_PainterQt*>(painter)->getDpmm();
        for (i=0; i<pat->num; ++i) {
            //        ds[j]=pat->pattern[i] * styleFactor;
            //fixme, styleFactor support needed

            ds[i]=dpmm*pat->pattern[i];
            if( fabs(ds[i]) < 1. ) ds[i] = (ds[i]>=0.)?1.:-1.;
            dp[i] = direction*fabs(ds[i]);
        }
    }else {
        delete[] dp;
        delete[] ds;
        RS_DEBUG->print(RS_Debug::D_WARNING,"invalid line pattern for line, draw solid line instread");
        painter->drawLine(view->toGui(getStartpoint()),
                          view->toGui(getEndpoint()));
        return;
    }
    double total= remainder(patternOffset-0.5*patternSegmentLength,patternSegmentLength) -0.5*patternSegmentLength;
    //    double total= patternOffset-patternSegmentLength;

    RS_Vector p1,p2,p3;
    RS_Vector curP(pStart+direction*total);
    double t2;
    for(int j=0;total<length;j=(j+1)%i) {

        // line segment (otherwise space segment)
        t2=total+fabs(ds[j]);
        p3=curP+dp[j];
        if (ds[j]>0.0 && t2 > 0.0) {
            // drop the whole pattern segment line, for ds[i]<0:
            // trim end points of pattern segment line to line
            p1 =(total > -0.5)? curP:pStart;
            p2 =(t2<length+0.5)?p3:pEnd;
            painter->drawLine(p1,p2);
        }
        total=t2;
        curP=p3;
    }
    delete[] dp;
    delete[] ds;

}
Ejemplo n.º 20
0
void RS_Line::draw(RS_Painter* painter, RS_GraphicView* view, double& patternOffset) {
    if (painter==NULL || view==NULL) {
        return;
    }
    //visible in grahic view
    if(isVisibleInWindow(view)==false) return;
    RS_Vector pStart(view->toGui(getStartpoint()));
    RS_Vector pEnd(view->toGui(getEndpoint()));

    //    std::cout<<"draw line: "<<pStart<<" to "<<pEnd<<std::endl;
    RS_Vector direction=pEnd-pStart;
    if(isHelpLayer(true) && direction.squared() > RS_TOLERANCE){
        //extend line on a help layer to fill the whole view
        RS_Vector lb(0,0);
        RS_Vector rt(view->getWidth(),view->getHeight());
        QList<RS_Vector> rect;
        rect<<lb<<RS_Vector(rt.x,lb.y);
        rect<<rt<<RS_Vector(lb.x,rt.y);
        rect<<lb;
        RS_VectorSolutions sol;
        RS_Line dLine(pStart,pEnd);
        for(int i=0;i<4;i++){
            RS_Line bLine(rect.at(i),rect.at(i+1));
            RS_VectorSolutions sol2=RS_Information::getIntersection(&bLine, &dLine);
            if( sol2.getNumber()>0 && bLine.isPointOnEntity(sol2.get(0),RS_TOLERANCE)) {
                sol.push_back(sol2.get(0));
            }
        }
        switch(sol.getNumber()){
        case 2:
            pStart=sol.get(0);
            pEnd=sol.get(1);
            break;
        case 3:
        case 4:
            pStart=sol.get(0);
            pEnd=sol.get(2);
            break;
        default:
            return;
        }
        direction=pEnd-pStart;
    }
    double  length=direction.magnitude();
    patternOffset -= length;
    if (( !isSelected() && (
              getPen().getLineType()==RS2::SolidLine ||
              view->getDrawingMode()==RS2::ModePreview)) ) {
        //if length is too small, attempt to draw the line, could be a potential bug
        painter->drawLine(pStart,pEnd);
        return;
    }
    //    double styleFactor = getStyleFactor(view);


    // Pattern:
    RS_LineTypePattern* pat;
    if (isSelected()) {
//        styleFactor=1.;
        pat = &patternSelected;
    } else {
        pat = view->getPattern(getPen().getLineType());
    }
    if (pat==NULL) {
//        patternOffset -= length;
        RS_DEBUG->print(RS_Debug::D_WARNING,
                        "RS_Line::draw: Invalid line pattern");
        painter->drawLine(pStart,pEnd);
        return;
    }
//    patternOffset = remainder(patternOffset - length-0.5*pat->totalLength,pat->totalLength)+0.5*pat->totalLength;
    if(length<=RS_TOLERANCE){
        painter->drawLine(pStart,pEnd);
        return; //avoid division by zero
    }
    direction/=length; //cos(angle), sin(angle)
    // Pen to draw pattern is always solid:
    RS_Pen pen = painter->getPen();

    pen.setLineType(RS2::SolidLine);
    painter->setPen(pen);

    // index counter
    int i;

    // pattern segment length:
    double patternSegmentLength = pat->totalLength;

    // create pattern:
    RS_Vector* dp=new RS_Vector[pat->num > 0?pat->num:0];
    double* ds=new double[pat->num > 0?pat->num:0];
    if (pat->num >0 ){
        for (i=0; i<pat->num; ++i) {
            //        ds[j]=pat->pattern[i] * styleFactor;
            //fixme, styleFactor support needed
            ds[i]=pat->pattern[i] ;
            dp[i] = direction*fabs(ds[i]);
        }
    }else {
        delete[] dp;
        delete[] ds;
        RS_DEBUG->print(RS_Debug::D_WARNING,"invalid line pattern for line, draw solid line instread");
        painter->drawLine(view->toGui(getStartpoint()),
                          view->toGui(getEndpoint()));
        return;
    }
    double total= remainder(patternOffset-0.5*patternSegmentLength,patternSegmentLength) -0.5*patternSegmentLength;
    //    double total= patternOffset-patternSegmentLength;

    RS_Vector p1,p2,p3;
    RS_Vector curP(pStart+direction*total);
    double t2;
    for(int j=0;total<length;j=(j+1)%i) {

        // line segment (otherwise space segment)
        t2=total+fabs(ds[j]);
        p3=curP+dp[j];
        if (ds[j]>0.0 && t2 > 0.0) {
            // drop the whole pattern segment line, for ds[i]<0:
            // trim end points of pattern segment line to line
            p1 =(total > -0.5)? curP:pStart;
            p2 =(t2<length+0.5)?p3:pEnd;
            painter->drawLine(p1,p2);
        }
        total=t2;
        curP=p3;
    }
    delete[] dp;
    delete[] ds;

}
Ejemplo n.º 21
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;
    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.push_back(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.push_back(RS_Vector(x,y));
            x=-x;
            if(vs0.getClosestDistance(RS_Vector(x,y),ivs0)>RS_TOLERANCE)
                vs0.push_back(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);
    shifta1 = - shifta1;
    shiftc1 = - shiftc1;
    for(unsigned i=0; i<vs0.getNumber(); i++) {
        RS_Vector vp=vs0.get(i);
        vp.rotate(shifta1);
        vp.move(shiftc1);
        ret.push_back(vp);
    }
    return ret;
}
Ejemplo n.º 22
0
    /**
     * Creates a tangent between a given point and a circle or arc.
     * Out of the 2 possible tangents, the one closest to
     * the given coordinate is returned.
     *
     * @param coord Coordinate to define which tangent we want (typically a
     *              mouse coordinate).
     * @param point Point.
     * @param circle Circle, arc or ellipse entity.
     */
    RS_Line* RS_Creation::createTangent1(const RS_Vector& coord,
                                         const RS_Vector& point,
                                         RS_Entity* circle) {
        RS_Line* ret = NULL;
        RS_Vector circleCenter;

        // check given entities:
        if (circle==NULL || !point.valid ||
                (circle->rtti()!=RS2::EntityArc && circle->rtti()!=RS2::EntityCircle
                 && circle->rtti()!=RS2::EntityEllipse)) {

            return NULL;
        }

        if (circle->rtti()==RS2::EntityCircle) {
            circleCenter = ((RS_Circle*)circle)->getCenter();
        } else if (circle->rtti()==RS2::EntityArc) {
            circleCenter = ((RS_Arc*)circle)->getCenter();
        } else if (circle->rtti()==RS2::EntityEllipse) {
            circleCenter = ((RS_Ellipse*)circle)->getCenter();
        }

        // the two tangent points:
        RS_VectorSolutions sol;

        // calculate tangent points for arcs / circles:
        if (circle->rtti()!=RS2::EntityEllipse) {
            // create temp. thales circle:
            RS_Vector tCenter = (point + circleCenter)/2.0;
            double tRadius = point.distanceTo(tCenter);

            RS_Circle tmp(NULL, RS_CircleData(tCenter, tRadius));

            // get the two intersection points which are the tangent points:
            sol = RS_Information::getIntersection(&tmp, circle, false);
        }

        // calculate tangent points for ellipses:
        else {
            RS_Ellipse* el = (RS_Ellipse*)circle;
            //sol.alloc(2);
            //sol.set(0, circleCenter);
            //sol.set(1, circleCenter);


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

            // rotate and move point:
            RS_Vector point2 = point;
            point2.move(-el->getCenter());
            point2.rotate(-el->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);
            yt1 = (t - bf) / (af * 2.0);
            xt1 = e - d * yt1;
            yt2 = (-t - bf) / (af * 2.0);
            xt2 = e - d * yt2;

            RS_Vector s1 = RS_Vector(xt1, yt1);
            RS_Vector s2 = RS_Vector(xt2, yt2);

            s1.rotate(el->getAngle());
            s1.move(el->getCenter());

            s2.rotate(el->getAngle());
            s2.move(el->getCenter());

            sol.push_back(s1);
            sol.push_back(s2);


        }

        if (sol.getNumber() < 2 ) {
                return NULL;
        }
        if (!sol.get(0).valid || !sol.get(1).valid) {
            return NULL;
        }

        // create all possible tangents:
        RS_Line* poss[2];

        RS_LineData d;

        d = RS_LineData(sol.get(0), point);
        poss[0] = new RS_Line(NULL, d);
        d = RS_LineData(sol.get(1), point);
        poss[1] = new RS_Line(NULL, d);

        // find closest tangent:
        double minDist = RS_MAXDOUBLE;
        double dist;
        int idx = -1;
        for (int i=0; i<2; ++i) {
            dist = poss[i]->getDistanceToPoint(coord);
            if (dist<minDist) {
                minDist = dist;
                idx = i;
            }
        }

        // create the closest tangent:
        if (idx!=-1) {
            RS_LineData d = poss[idx]->getData();

            for (int i=0; i<2; ++i) {
                delete poss[i];
            }

            if (document!=NULL && handleUndo) {
                document->startUndoCycle();
            }

            ret = new RS_Line(container, d);
            ret->setLayerToActive();
            ret->setPenToActive();
            if (container!=NULL) {
                container->addEntity(ret);
            }
            if (document!=NULL && handleUndo) {
                document->addUndoable(ret);
                document->endUndoCycle();
            }
            if (graphicView!=NULL) {
                graphicView->drawEntity(ret);
            }
        } else {
            ret = NULL;
        }

        return ret;
    }