QVector<RS_Entity* > RS_Circle::offsetTwoSides(const double& distance) const { QVector<RS_Entity*> ret(0,NULL); ret<<new RS_Circle(NULL,RS_CircleData(getCenter(),getRadius()+distance)); if(getRadius()>distance) ret<<new RS_Circle(NULL,RS_CircleData(getCenter(),getRadius()-distance)); return ret; }
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; }
void RS_ActionSnapIntersectionManual::mouseMoveEvent(QMouseEvent* e) { RS_DEBUG->print("RS_ActionSnapIntersectionManual::mouseMoveEvent begin"); RS_Entity* se = catchEntity(e); RS_Vector mouse = graphicView->toGraph(e->x(), e->y()); switch (getStatus()) { case ChooseEntity1: entity1 = se; break; case ChooseEntity2: { entity2 = se; coord = mouse; RS_VectorSolutions sol = RS_Information::getIntersection(entity1, entity2, false); //for (int i=0; i<sol.getNumber(); i++) { // ip = sol.get(i); // break; //} RS_Vector ip = sol.getClosest(coord); if (ip.valid) { deletePreview(); preview->addEntity( new RS_Circle(preview.get(), RS_CircleData( ip, graphicView->toGraphDX(4)))); drawPreview(); RS_DIALOGFACTORY->updateCoordinateWidget(ip, ip - graphicView->getRelativeZero()); } } break; default: break; } RS_DEBUG->print("RS_ActionSnapIntersectionManual::mouseMoveEvent end"); }
void RS_ActionDrawCircleCR::reset() { data = RS_CircleData(RS_Vector(false), 0.0); }
void RS_ActionDrawArc::mouseMoveEvent(QMouseEvent* e) { RS_DEBUG->print("RS_ActionDrawArc::mouseMoveEvent begin"); RS_Vector mouse = snapPoint(e); switch (getStatus()) { case SetCenter: data.center = mouse; break; case SetRadius: if (data.center.valid) { data.radius = data.center.distanceTo(mouse); deletePreview(); preview->addEntity(new RS_Circle(preview, RS_CircleData(data.center, data.radius))); drawPreview(); } break; case SetAngle1: data.angle1 = data.center.angleTo(mouse); if (data.reversed) { data.angle2 = RS_Math::correctAngle(data.angle1-M_PI/3); } else { data.angle2 = RS_Math::correctAngle(data.angle1+M_PI/3); } deletePreview(); preview->addEntity(new RS_Arc(preview, data)); drawPreview(); break; case SetAngle2: data.angle2 = data.center.angleTo(mouse); deletePreview(); preview->addEntity(new RS_Arc(preview, data)); drawPreview(); break; case SetIncAngle: data.angle2 = data.angle1 + data.center.angleTo(mouse); deletePreview(); preview->addEntity(new RS_Arc(preview, data)); drawPreview(); break; case SetChordLength: { double x = data.center.distanceTo(mouse); if (fabs(x/(2*data.radius))<=1.0) { data.angle2 = data.angle1 + asin(x/(2*data.radius)) * 2; deletePreview(); preview->addEntity(new RS_Arc(preview, data)); drawPreview(); } } break; default: break; } RS_DEBUG->print("RS_ActionDrawArc::mouseMoveEvent end"); }
/** 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; }
/** * We could properly speed this up by calling the draw function of this snapper within the paint event * this will avoid creating/deletion of the lines */ void RS_Snapper::drawSnapper() { graphicView->getOverlayContainer(RS2::Snapper)->clear(); if (!finished && snapSpot.valid) { RS_EntityContainer *container=graphicView->getOverlayContainer(RS2::Snapper); RS_Pen crossHairPen(RS_Color(255,194,0), RS2::Width00, RS2::DashLine2); if (snapCoord.valid) { RS_DEBUG->print("RS_Snapper::Snapped draw start"); // Pen for snapper RS_Pen pen(RS_Color(255,194,0), RS2::Width00, RS2::SolidLine); pen.setScreenWidth(1); // Circle to show snap area RS_Circle *circle=new RS_Circle(NULL, RS_CircleData(snapCoord, 4/graphicView->getFactor().x)); circle->setPen(pen); container->addEntity(circle); // crosshairs: if (showCrosshairs==true) { if(graphicView->isGridIsometric()) {//isometric crosshair RS2::CrosshairType chType=graphicView->getCrosshairType(); RS_Vector direction1; RS_Vector direction2(0.,1.); double l=graphicView->getWidth()+graphicView->getHeight(); switch(chType){ case RS2::RightCrosshair: direction1=RS_Vector(M_PI*5./6.)*l; direction2*=l; break; case RS2::LeftCrosshair: direction1=RS_Vector(M_PI*1./6.)*l; direction2*=l; break; default: direction1=RS_Vector(M_PI*1./6.)*l; direction2=RS_Vector(M_PI*5./6.)*l; } RS_Vector center(graphicView->toGui(snapCoord)); RS_OverlayLine *line=new RS_OverlayLine(NULL,RS_LineData(center-direction1,center+direction1)); line->setPen(crossHairPen); container->addEntity(line); line=new RS_OverlayLine(NULL,RS_LineData(center-direction2,center+direction2)); line->setPen(crossHairPen); container->addEntity(line); }else{//orthogonal crosshair RS_OverlayLine *line=new RS_OverlayLine(NULL, RS_LineData(RS_Vector(0, graphicView->toGuiY(snapCoord.y)), RS_Vector(graphicView->getWidth(), graphicView->toGuiY(snapCoord.y)))); line->setPen(crossHairPen); container->addEntity(line); line=new RS_OverlayLine(NULL, RS_LineData(RS_Vector(graphicView->toGuiX(snapCoord.x),0), RS_Vector(graphicView->toGuiX(snapCoord.x), graphicView->getHeight()))); line->setPen(crossHairPen); container->addEntity(line); } } graphicView->redraw(RS2::RedrawOverlay); // redraw will happen in the mouse movement event RS_DEBUG->print("RS_Snapper::Snapped draw end"); } if (snapCoord.valid && snapCoord!=snapSpot) { RS_OverlayLine *line=new RS_OverlayLine(NULL, RS_LineData(graphicView->toGui(snapSpot)+RS_Vector(-5,0), graphicView->toGui(snapSpot)+RS_Vector(-1,4))); line->setPen(crossHairPen); container->addEntity(line); line=new RS_OverlayLine(NULL, RS_LineData(graphicView->toGui(snapSpot)+RS_Vector(0,5), graphicView->toGui(snapSpot)+RS_Vector(4,1))); line->setPen(crossHairPen); container->addEntity(line); line=new RS_OverlayLine(NULL, RS_LineData(graphicView->toGui(snapSpot)+RS_Vector(5,0), graphicView->toGui(snapSpot)+RS_Vector(1,-4))); line->setPen(crossHairPen); container->addEntity(line); line=new RS_OverlayLine(NULL, RS_LineData(graphicView->toGui(snapSpot)+RS_Vector(0,-5), graphicView->toGui(snapSpot)+RS_Vector(-4,-1))); line->setPen(crossHairPen); container->addEntity(line); graphicView->redraw(RS2::RedrawOverlay); // redraw will happen in the mouse movement event } } }
/*RS_EntityContainer* parent, const RS_LineData& d*/ Plugin_Entity::Plugin_Entity(RS_EntityContainer* parent, enum DPI::ETYPE type){ hasContainer = false; entity = NULL; switch (type) { case DPI::POINT: entity = new RS_Point(parent, RS_PointData(RS_Vector(0,0))); break; case DPI::LINE: entity = new RS_Line(parent, RS_LineData()); break; /* case DPI::CONSTRUCTIONLINE: entity = new RS_ConstructionLine(); break;*/ case DPI::CIRCLE: entity = new RS_Circle(parent, RS_CircleData()); break; case DPI::ARC: entity = new RS_Arc(parent, RS_ArcData()); break; case DPI::ELLIPSE: entity = new RS_Ellipse(parent, RS_EllipseData(RS_Vector(0,0), RS_Vector(0,0),0.0,0.0,0.0,false)); break; case DPI::IMAGE: entity = new RS_Image(parent, RS_ImageData()); break; /* case DPI::OVERLAYBOX: entity = new RS_OverlayBox(); break; case DPI::SOLID: entity = new RS_Solid(); break;*/ case DPI::TEXT: entity = new RS_Text(parent, RS_TextData()); break; /* case DPI::INSERT: entity = new RS_Insert(); break;*/ case DPI::POLYLINE: entity = new RS_Polyline(parent, RS_PolylineData()); break; /* case DPI::SPLINE: entity = new RS_Spline(); break; case DPI::HATCH: entity = new RS_Hatch(); break; case DPI::DIMLEADER: entity = new RS_Leader(); break; case DPI::DIMALIGNED: entity = new RS_DimAligned(); break; case DPI::DIMLINEAR: entity = new RS_DimLinear(); break; case DPI::DIMRADIAL: entity = new RS_DimRadial(); break; case DPI::DIMDIAMETRIC: entity = new RS_DimDiametric(); break; case DPI::DIMANGULAR: entity = new RS_DimAngular(); break;*/ default: break; } }
/** * 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; }