bool RS_ActionDrawCircleTan1_2P::getCenters(){
	pPoints->centers.clear();
    if(getStatus() < SetPoint2) return false;

	LC_Quadratic lc0(circle, pPoints->points[0]);
//    LC_Quadratic lc1(circle, points[1]);
	LC_Quadratic lc1(pPoints->points[1], pPoints->points[0]);
	auto list=LC_Quadratic::getIntersection(lc0,lc1);
//    DEBUG_HEADER
//    std::cout<<"intersections : "<<list<<std::endl;

	for(const RS_Vector& vp: list){
        //when taking the path of center of tangent circle passing a given point,
        // the center is never closer to the circle center than the point, for internal and external tangent circles
		double ds0=vp.distanceTo(pPoints->points[0]);
//        double ds1=vp.distanceTo(points[1]);
//        if( fabs(ds0 - ds1)> RS_TOLERANCE) continue;
        if(circle->rtti()==RS2::EntityCircle||circle->rtti()==RS2::EntityArc){
            double ds=vp.distanceTo(circle->getCenter());
            //condition for tangential to the given circle
            if( fabs(ds - (ds0 + circle->getRadius())) > RS_TOLERANCE && fabs(ds - fabs(ds0 - circle->getRadius())) > RS_TOLERANCE ) continue;
        }else{
            double ds=0.;
            circle->getNearestPointOnEntity(vp, false,&ds);
            //condition for tangential to the given straight line
            if( fabs(ds - ds0)>RS_TOLERANCE) continue;
        }

        //avoid counting the same center
        bool existing=false;
		for(auto const& vq: pPoints->centers){
			if(vq.squaredTo(vp) < RS_TOLERANCE15 ){
                existing=true;
                break;
            }
        }
        if(existing) continue;
		pPoints->centers.push_back(vp);
    }
//    DEBUG_HEADER
//    std::cout<<"points: "<<points[0]<<" , "<<points[1]<<std::endl;
//    std::cout<<"centers.size()="<<centers.size()<<std::endl;
//    std::cout<<"centers: "<<centers<<std::endl;
	pPoints->valid= (pPoints->centers.size()>0);
	return pPoints->valid;
}
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_ActionDrawCircleTan2_1P::getCenters()
{
    if(circles.size()<2) return false;
    LC_Quadratic lc0(circles[0], point);
    LC_Quadratic lc1(circles[1], point);

	auto list=LC_Quadratic::getIntersection(lc0,lc1);
    centers.clean();
	for(const RS_Vector& vp: list){
		auto ds=vp.distanceTo(point)-RS_TOLERANCE;
        bool validBranch(true);
        for(int j=0;j<2;j++){
            if(circles[j]->rtti()==RS2::EntityCircle||circles[j]->rtti()==RS2::EntityArc){
                if( vp.distanceTo(circles[j]->getCenter()) <= ds) {
                    validBranch=false;
                    break;
                }
            }
        }
        if(validBranch)  centers.push_back(vp);
    }
    return centers.size()>0;
}
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;
}
/** 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;
}
bool RS_ActionDrawCircleTan3::getData(){
	if(getStatus() != SetCircle3) return false;
	//find the nearest circle
	size_t i=0;
	size_t const countLines=std::count_if(circles.begin(), circles.end(), [](RS_AtomicEntity* e)->bool
	{
			return e->rtti()==RS2::EntityLine;
});

	for(;i<circles.size();++i)
		if(circles[i]->rtti() == RS2::EntityLine) break;
	candidates.clear();
	size_t i1=(i+1)%3;
	size_t i2=(i+2)%3;
	if(i<circles.size() && circles[i]->rtti() == RS2::EntityLine){
		//one or more lines

		LC_Quadratic lc0(circles[i],circles[i1],false);
		LC_Quadratic lc1;
		RS_VectorSolutions sol;
		//detect degenerate case two circles with the same radius
		switch(countLines){
		default:
		case 0:
			//this should not happen
			assert(false);
		case 1:
			//1 line, two circles
		{
			for(unsigned k=0; k<4; ++k){
				//loop through all mirroring cases
				lc1=LC_Quadratic(circles[i],circles[i1], k & 1u);
				LC_Quadratic lc2=LC_Quadratic(circles[i],circles[i2], k & 2u);
				sol.appendTo(LC_Quadratic::getIntersection(lc1,lc2));
			}

		}
			break;
		case 2:
			//2 lines, one circle
		{
			if(circles[i2]->rtti()==RS2::EntityLine){
				std::swap(i1, i2);
			}
			//i2 is circle

			for(unsigned k=0; k<4; ++k){
				//loop through all mirroring cases
				lc1=LC_Quadratic(circles[i2],circles[i], k & 1u);
				LC_Quadratic lc2=LC_Quadratic(circles[i2],circles[i1], k & 2u);
				sol.appendTo(LC_Quadratic::getIntersection(lc1,lc2));
			}
		}
			break;
		case 3:
			//3 lines
		{
			lc0=circles[i]->getQuadratic();
			lc1=circles[i1]->getQuadratic();
			auto lc2=circles[i2]->getQuadratic();
			//attempt to have intersections (lc0, lc1), (lc0, lc2)
			auto sol1=LC_Quadratic::getIntersection(lc0,lc1);
			if(sol1.size()<1) {
				std::swap(lc0, lc2);
				std::swap(i, i2);
			}
			sol1=LC_Quadratic::getIntersection(lc0,lc2);
			if(sol1.size()<1) {
				std::swap(lc0, lc1);
				std::swap(i, i1);
			}

			RS_Line* line0=static_cast<RS_Line*>(circles[i]);
			RS_Line* line1=static_cast<RS_Line*>(circles[i1]);
			RS_Line* line2=static_cast<RS_Line*>(circles[i2]);
			lc0=line0->getQuadratic();
			lc1=line1->getQuadratic();
			lc2=line2->getQuadratic();
			//intersection 0, 1
			sol1=LC_Quadratic::getIntersection(lc0,lc1);
			if(!sol1.size()) {
				return false;
			}
			RS_Vector const v1=sol1.at(0);
			double angle1=0.5*(line0->getAngle1()+line1->getAngle1());

			//intersection 0, 2
			sol1=LC_Quadratic::getIntersection(lc0,lc2);
			double angle2;
			if(sol1.size()<1) {
				return false;
			}
			angle2=0.5*(line0->getAngle1()+line2->getAngle1());
			RS_Vector const& v2=sol1.at(0);
			//two bisector lines per intersection
			for(unsigned j=0; j<2; ++j){
				RS_Line l1{v1, v1+RS_Vector{angle1}};
				for(unsigned j1=0; j1<2; ++j1){
					RS_Line l2{v2, v2+RS_Vector{angle2}};
					sol.appendTo(RS_Information::getIntersectionLineLine(&l1, &l2));
					angle2 += M_PI_2;
				}
				angle1 += M_PI_2;
			}
		}
		}

		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(const RS_Vector& vp: sol){
			if(vp.magnitude()>RS_MAXDOUBLE) continue;
			if(sol1.size() && sol1.getClosestDistance(vp)<RS_TOLERANCE) continue;
			sol1.push_back(vp);
		}

		for(auto const& v: sol1){
			circles[i]->getNearestPointOnEntity(v,false,&d);
			std::shared_ptr<RS_CircleData> data(new RS_CircleData(v,d));
			if(circles[(i+1)%3]->isTangent(*data)==false) continue;
			if(circles[(i+2)%3]->isTangent(*data)==false) continue;
			candidates.push_back(data);
		}

	}else{
        RS_Circle c(nullptr,*cData);
		auto solutions=c.createTan3(circles);
		candidates.clear();
		for(const RS_Circle& s: solutions){
			candidates.push_back(std::make_shared<RS_CircleData>(s.getData()));
		}
	}
	valid = ( candidates.size() >0);
	return valid;
}