bool RS_ActionDrawCircleTan3::preparePreview(){
	if(getStatus() != SetCenter || valid==false) {
		valid=false;
		return false;
	}
	//find the nearest circle
	size_t index=candidates.size();
	double dist=RS_MAXDOUBLE*RS_MAXDOUBLE;
	for(size_t i=0;i<candidates.size();++i){

		preview->addEntity(new RS_Point(preview.get(), RS_PointData(candidates.at(i)->center)));
		double d;
		RS_Circle(nullptr, *candidates.at(i)).getNearestPointOnEntity(coord,false,&d);
		double dCenter=coord.distanceTo(candidates.at(i)->center);
		d=std::min(d,dCenter);
		if(d<dist){
			dist=d;
			index=i;
		}
	}
	if( index<candidates.size()){
		cData=candidates.at(index);
		valid=true;
	}else{
		valid=false;
	}
	return valid;
}
Example #2
0
QList<RS_Circle> RS_Circle::createTan3(const QVector<RS_AtomicEntity*>& circles)
{
    QList<RS_Circle> ret;
    if(circles.size()!=3) return ret;
     QList<RS_Circle> cs;
     for(unsigned short i=0;i<3;i++){
         cs<<RS_Circle(NULL,RS_CircleData(circles.at(i)->getCenter(),circles.at(i)->getRadius()));
     }
    unsigned short flags=0;
    do{
        ret.append(solveAppolloniusSingle(cs));
        flags++;
        unsigned short j=0;
        for(unsigned short i=1u;i<=4u;i<<=1){
            if(flags & i) {
                cs[j].setRadius( - fabs(cs[j].getRadius()));
            }else{
                cs[j].setRadius( fabs(cs[j].getRadius()));
            }
            j++;
        }

    }while(flags<8u);
//    std::cout<<__FILE__<<" : "<<__FUNCTION__<<" : line "<<__LINE__<<std::endl;
//    std::cout<<"before testing, ret.size()="<<ret.size()<<std::endl;
    for(int i=0;i<ret.size();){
        if(ret[i].testTan3(circles) == false) {
            ret.erase(ret.begin()+i);
        }else{
            i++;
        }
    }
//    std::cout<<"after testing, ret.size()="<<ret.size()<<std::endl;
    return ret;
}
Example #3
0
std::vector<RS_Circle> RS_Circle::createTan3(const std::vector<RS_AtomicEntity*>& circles)
{
	std::vector<RS_Circle> ret;
    if(circles.size()!=3) return ret;
	 std::vector<RS_Circle> cs;
	 for(auto c: circles){
		 cs.emplace_back(RS_Circle(nullptr, {c->getCenter(),c->getRadius()}));
	 }
    unsigned short flags=0;
    do{
        for(unsigned short j=0u;j<3u;++j){
            if(flags & (1u<<j)) {
                cs[j].setRadius( - fabs(cs[j].getRadius()));
            }else{
                cs[j].setRadius( fabs(cs[j].getRadius()));
            }
        }
//        RS_DEBUG->print(RS_Debug::D_ERROR, "flags=%d\n",flags);
		auto list=solveAppolloniusSingle(cs);
        if(list.size()>=1){
            for(RS_Circle& c0: list){
                bool addNew=true;
                for(RS_Circle& c: ret){
                    if((c0.getCenter()-c.getCenter()).squared()<RS_TOLERANCE15 && fabs(c0.getRadius() - c.getRadius())<RS_TOLERANCE){
                        addNew=false;
                        break;
                    }
                }
				if(addNew) ret.push_back(c0);
            }
        }


    }while(++flags<8u);
//    std::cout<<__FILE__<<" : "<<__func__<<" : line "<<__LINE__<<std::endl;
//    std::cout<<"before testing, ret.size()="<<ret.size()<<std::endl;
	for(size_t i=0;i<ret.size();){
        if(ret[i].testTan3(circles) == false) {
            ret.erase(ret.begin()+i);
        }else{
            ++i;
        }
    }
//        DEBUG_HEADER
//    std::cout<<"after testing, ret.size()="<<ret.size()<<std::endl;
    return ret;
}
bool RS_ActionDrawCircleTan3::getData(){
    if(getStatus() != SetCircle3) return false;
    //find the nearest circle
    int i=0;
    for(i=0;i<circles.size();i++)
        if(circles[i]->rtti() == RS2::EntityLine) break;
    candidates.clear();
    if(i<circles.size() && circles[i]->rtti() == RS2::EntityLine){
        LC_Quadratic lc0(circles[i],circles[(i+1)%3]);
        LC_Quadratic lc1(circles[i],circles[(i+2)%3]);
        auto&& sol=LC_Quadratic::getIntersection(lc0,lc1);
        double d;

        //line passes circle center, need a second parabola as the image of the line
        for(int j=1;j<=2;j++){
            if(circles[(i+j)%3]->rtti() == RS2::EntityCircle){
                circles[i]->getNearestPointOnEntity(circles[(i+j)%3]->getCenter(),
                                                    false,&d);
                if(d<RS_TOLERANCE) {
                    LC_Quadratic lc2(circles[i],circles[(i+j)%3], true);
                    sol.appendTo(LC_Quadratic::getIntersection(lc2,lc1));
                }
            }
        }


        for(size_t j=0;j<sol.size();j++){
            circles[i]->getNearestPointOnEntity(sol[j],false,&d);
            RS_CircleData data(sol[j],d);
//            DEBUG_HEADER();
//            std::cout<<sol[j]<<" r="<<d<<std::endl;
            if(circles[(i+1)%3]->isTangent(data)==false) continue;
            if(circles[(i+2)%3]->isTangent(data)==false) continue;

            candidates<<RS_Circle(NULL,data);
        }
    }else{
        RS_Circle c(NULL,cData);
        candidates=c.createTan3(circles);
    }
    valid = ( candidates.size() >0);
    return valid;
}
bool RS_ActionDrawCircleTan3::getData(){
    if(getStatus() != SetCircle3) return false;
    //find the nearest circle
    int i=0;
    for(;i<circles.size();++i)
        if(circles[i]->rtti() == RS2::EntityLine) break;
    candidates.clear();
        const int i1=(i+1)%3;
        const int i2=(i+2)%3;
        if(i<circles.size() && circles[i]->rtti() == RS2::EntityLine){

            LC_Quadratic lc0(circles[i],circles[i1],false);
             LC_Quadratic lc01(circles[i],circles[i1],true);
            LC_Quadratic lc1;
            RS_VectorSolutions sol;
            //detect degenerate case two circles with the same radius
            if(circles[i1]->rtti()== RS2::EntityCircle &&
                    circles[i2]->rtti()== RS2::EntityCircle
                    ){
                RS_Circle* c1=static_cast<RS_Circle*>(circles[i1]);
                RS_Circle* c2=static_cast<RS_Circle*>(circles[i2]);
                if(fabs(fabs(c1->getRadius())-fabs(c2->getRadius()))<RS_TOLERANCE){
                    //degenerate
                    const RS_Vector p0=(c1->getCenter()+c2->getCenter())*0.5;
                    const RS_Vector p1=p0 + (c1->getCenter() - p0).rotate(0.5*M_PI);
                    lc1=RS_Line(NULL, RS_LineData(p0,p1 )).getQuadratic();
                    sol=LC_Quadratic::getIntersection(lc0,lc1);

                    sol.appendTo(LC_Quadratic::getIntersection(lc01,lc1));
                    lc1=RS_Line(NULL, RS_LineData(c1->getCenter(),c1->getCenter())).getQuadratic();
                    sol.appendTo(LC_Quadratic::getIntersection(lc0,lc1));
                    sol.appendTo(LC_Quadratic::getIntersection(lc01,lc1));
                }

            }
            if(sol.size()==0) {
                switch(circles[i2]->rtti()){
                case RS2::EntityCircle:
                    lc1=LC_Quadratic(circles[i],circles[i2], true);
                    sol.appendTo(LC_Quadratic::getIntersection(lc01,lc1));
                    if(circles[i1]->rtti()== RS2::EntityCircle )
                        sol.appendTo(LC_Quadratic::getIntersection(lc01,lc1));
                    //there's no break, because the default part would be run for circles as well
                default:
                    lc1=LC_Quadratic(circles[i],circles[i2]);
                    sol.appendTo(LC_Quadratic::getIntersection(lc01,lc1));
                    if(circles[i1]->rtti()== RS2::EntityCircle )
                        sol.appendTo(LC_Quadratic::getIntersection(lc01,lc1));
                }
            }
            double d;

        //line passes circle center, need a second parabola as the image of the line
        for(int j=1;j<=2;j++){
            if(circles[(i+j)%3]->rtti() == RS2::EntityCircle){
                circles[i]->getNearestPointOnEntity(circles[(i+j)%3]->getCenter(),
                                                    false,&d);
                if(d<RS_TOLERANCE) {
                    LC_Quadratic lc2(circles[i],circles[(i+j)%3], true);
                    sol.appendTo(LC_Quadratic::getIntersection(lc2,lc1));
                }
            }
        }

        //clean up duplicate and invalid
        RS_VectorSolutions sol1;
        for(size_t j=0; j<sol.size(); ++j){
            const RS_Vector&& vp=sol.at(j);
            if(vp.magnitude()>RS_MAXDOUBLE) continue;
            if(sol1.size())
                if(sol1.getClosestDistance(vp)<RS_TOLERANCE) continue;

            sol1.push_back(vp);
        }


        for(size_t j=0;j<sol1.size();j++){
            circles[i]->getNearestPointOnEntity(sol1[j],false,&d);
            RS_CircleData data(sol1[j],d);
            if(circles[(i+1)%3]->isTangent(data)==false) continue;
            if(circles[(i+2)%3]->isTangent(data)==false) continue;
            candidates<<RS_Circle(NULL,data);
        }
    }else{
        RS_Circle c(NULL,cData);
        candidates=c.createTan3(circles);
    }
    valid = ( candidates.size() >0);
    return valid;
}
Example #6
0
/** solve one of the eight Appollonius Equations
| Cx - Ci|^2=(Rx+Ri)^2
with Cx the center of the common tangent circle, Rx the radius. Ci and Ri are the Center and radius of the i-th existing circle
**/
QList<RS_Circle> RS_Circle::solveAppolloniusSingle(const QList<RS_Circle>& circles)
{
//          std::cout<<__FILE__<<" : "<<__FUNCTION__<<" : line "<<__LINE__<<std::endl;
//          for(int i=0;i<circles.size();i++){
//std::cout<<"i="<<i<<"\t center="<<circles[i].getCenter()<<"\tr="<<circles[i].getRadius()<<std::endl;
//          }
    QList<RS_Circle> ret;

    QList<RS_Vector> centers;
    QList<double> radii;

    for(size_t i=0;i<3;i++){
        if(circles[i].getCenter().valid==false) return ret;
        centers.push_back(circles[i].getCenter());
        radii.push_back(fabs(circles[i].getRadius()));
    }
/** form the linear equation to solve center in radius **/
    QVector<QVector<double> > mat(2,QVector<double>(3,0.));
    mat[0][0]=centers[2].x - centers[0].x;
    mat[0][1]=centers[2].y - centers[0].y;
    mat[1][0]=centers[2].x - centers[1].x;
    mat[1][1]=centers[2].y - centers[1].y;
    if(fabs(mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0])<RS_TOLERANCE*RS_TOLERANCE){
//        DEBUG_HEADER();
//        std::cout<<"The provided circles are in a line, not common tangent circle"<<std::endl;
        size_t i0=0;
        if( centers[0].distanceTo(centers[1]) <= RS_TOLERANCE ||  centers[0].distanceTo(centers[2]) <= RS_TOLERANCE) i0 = 1;
        LC_Quadratic lc0(& (circles[i0]), & (circles[(i0+1)%3]));
        LC_Quadratic lc1(& (circles[i0]), & (circles[(i0+2)%3]));
        auto&& c0 = LC_Quadratic::getIntersection(lc0, lc1);
//        qDebug()<<"c0.size()="<<c0.size();
        for(size_t i=0; i<c0.size(); i++){
            const double dc =  c0[i].distanceTo(centers[i0]);
            ret<<RS_Circle(NULL, RS_CircleData(c0[i], fabs(dc - radii[i0])));
            if( dc > radii[i0]) {
                ret<<RS_Circle(NULL, RS_CircleData(c0[i], dc + radii[i0]));
            }
        }
        return ret;
    }
    // r^0 term
    mat[0][2]=0.5*(centers[2].squared()-centers[0].squared()+radii[0]*radii[0]-radii[2]*radii[2]);
    mat[1][2]=0.5*(centers[2].squared()-centers[1].squared()+radii[1]*radii[1]-radii[2]*radii[2]);
    std::cout<<__FILE__<<" : "<<__FUNCTION__<<" : line "<<__LINE__<<std::endl;
    for(unsigned short i=0;i<=1;i++){
        std::cout<<"eqs P:"<<i<<" : "<<mat[i][0]<<"*x + "<<mat[i][1]<<"*y = "<<mat[i][2]<<std::endl;
    }
//    QVector<QVector<double> > sm(2,QVector<double>(2,0.));
    QVector<double> sm(2,0.);
    if(RS_Math::linearSolver(mat,sm)==false){
        return ret;
    }

    RS_Vector vp(sm[0],sm[1]);
//      std::cout<<__FILE__<<" : "<<__FUNCTION__<<" : line "<<__LINE__<<std::endl;
//      std::cout<<"vp="<<vp<<std::endl;

    // r term
    mat[0][2]= radii[0]-radii[2];
    mat[1][2]= radii[1]-radii[2];
//    for(unsigned short i=0;i<=1;i++){
//        std::cout<<"eqs Q:"<<i<<" : "<<mat[i][0]<<"*x + "<<mat[i][1]<<"*y = "<<mat[i][2]<<std::endl;
//    }
    if(RS_Math::linearSolver(mat,sm)==false){
        return ret;
    }
    RS_Vector vq(sm[0],sm[1]);
//      std::cout<<"vq="<<vq<<std::endl;
    //form quadratic equation for r
    RS_Vector dcp=vp-centers[0];
    double a=vq.squared()-1.;
    if(fabs(a)<RS_TOLERANCE*1e-4) {
        return ret;
    }
    std::vector<double> ce(0,0.);
    ce.push_back(2.*(dcp.dotP(vq)-radii[0])/a);
    ce.push_back((dcp.squared()-radii[0]*radii[0])/a);
    std::vector<double>&& vr=RS_Math::quadraticSolver(ce);
    for(size_t i=0; i < vr.size();i++){
        if(vr.at(i)<RS_TOLERANCE) continue;
        ret<<RS_Circle(NULL,RS_CircleData(vp+vq*vr.at(i),vr.at(i)));
    }
//    std::cout<<__FILE__<<" : "<<__FUNCTION__<<" : line "<<__LINE__<<std::endl;
//    std::cout<<"Found "<<ret.size()<<" solutions"<<std::endl;

    return ret;
}