/** * Selects all entities within the given area. * * @param select True to select, False to deselect the entities. */ void RS_EntityContainer::selectWindow(RS_Vector v1, RS_Vector v2, bool select, bool cross) { bool included; for (RS_Entity* e=firstEntity(RS2::ResolveNone); e!=NULL; e=nextEntity(RS2::ResolveNone)) { included = false; if (e->isVisible()) { if (e->isInWindow(v1, v2)) { //e->setSelected(select); included = true; } else if (cross==true) { RS_Line l[] = { RS_Line(NULL, RS_LineData(v1, RS_Vector(v2.x, v1.y))), RS_Line(NULL, RS_LineData(RS_Vector(v2.x, v1.y), v2)), RS_Line(NULL, RS_LineData(v2, RS_Vector(v1.x, v2.y))), RS_Line(NULL, RS_LineData(RS_Vector(v1.x, v2.y), v1)) }; RS_VectorSolutions sol; if (e->isContainer()) { RS_EntityContainer* ec = (RS_EntityContainer*)e; for (RS_Entity* se=ec->firstEntity(RS2::ResolveAll); se!=NULL && included==false; se=ec->nextEntity(RS2::ResolveAll)) { for (int i=0; i<4; ++i) { sol = RS_Information::getIntersection( se, &l[i], true); if (sol.hasValid()) { included = true; break; } } } } else { for (int i=0; i<4; ++i) { sol = RS_Information::getIntersection(e, &l[i], true); if (sol.hasValid()) { included = true; break; } } } } } if (included) { e->setSelected(select); } } }
/** * Selects all entities within the given area. * * @param select True to select, False to deselect the entities. */ void RS_EntityContainer::selectWindow(RS_Vector v1, RS_Vector v2, bool select, bool cross) { bool included; for(auto e: entities){ included = false; if (e->isVisible()) { if (e->isInWindow(v1, v2)) { //e->setSelected(select); included = true; } else if (cross) { RS_EntityContainer l; l.addRectangle(v1, v2); RS_VectorSolutions sol; if (e->isContainer()) { RS_EntityContainer* ec = (RS_EntityContainer*)e; for (RS_Entity* se=ec->firstEntity(RS2::ResolveAll); se && included==false; se=ec->nextEntity(RS2::ResolveAll)) { if (se->rtti() == RS2::EntitySolid){ included = static_cast<RS_Solid*>(se)->isInCrossWindow(v1,v2); } else { for (auto line: l) { sol = RS_Information::getIntersection( se, line, true); if (sol.hasValid()) { included = true; break; } } } } } else if (e->rtti() == RS2::EntitySolid){ included = static_cast<RS_Solid*>(e)->isInCrossWindow(v1,v2); } else { for (auto line: l) { sol = RS_Information::getIntersection(e, line, true); if (sol.hasValid()) { included = true; break; } } } } } if (included) { e->setSelected(select); } } }
/** * Selects all entities that are intersected by the given line. * * @param v1 Startpoint of line. * @param v2 Endpoint of line. * @param select true: select, false: deselect */ void RS_Selection::selectIntersected(const RS_Vector& v1, const RS_Vector& v2, bool select) { RS_Line line(NULL, RS_LineData(v1, v2)); bool inters; for (RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity()) { //for (uint i=0; i<container->count(); ++i) { //RS_Entity* e = container->entityAt(i); if (e!=NULL && e->isVisible()) { inters = false; // select containers / groups: if (e->isContainer()) { RS_EntityContainer* ec = (RS_EntityContainer*)e; for (RS_Entity* e2=ec->firstEntity(RS2::ResolveAll); e2!=NULL; e2=ec->nextEntity(RS2::ResolveAll)) { RS_VectorSolutions sol = RS_Information::getIntersection(&line, e2, true); if (sol.hasValid()) { inters = true; } } } else { RS_VectorSolutions sol = RS_Information::getIntersection(&line, e, true); if (sol.hasValid()) { inters = true; } } if (inters) { if (graphicView!=NULL) { graphicView->deleteEntity(e); } e->setSelected(select); if (graphicView!=NULL) { graphicView->drawEntity(e); } } } } }
RS_Vector RS_Line::prepareTrim(const RS_Vector& trimCoord, const RS_VectorSolutions& trimSol) { //prepare trimming for multiple intersections if ( ! trimSol.hasValid()) return(RS_Vector(false)); if ( trimSol.getNumber() == 1 ) return(trimSol.get(0)); auto&& vp0=trimSol.getClosest(trimCoord,NULL,0); double dr2=trimCoord.squaredTo(vp0); //the trim point found is closer to mouse location (trimCoord) than both end points, return this trim point if(dr2 < trimCoord.squaredTo(getStartpoint()) && dr2 < trimCoord.squaredTo(getEndpoint())) return vp0; //the closer endpoint to trimCoord RS_Vector vp1=(trimCoord.squaredTo(getStartpoint()) <= trimCoord.squaredTo(getEndpoint()))?getStartpoint():getEndpoint(); //searching for intersection in the direction of the closer end point auto&& dvp1=vp1 - trimCoord; RS_VectorSolutions sol1; for(size_t i=0; i<trimSol.size(); i++){ auto&& dvp2=trimSol.at(i) - trimCoord; if( RS_Vector::dotP(dvp1, dvp2) > RS_TOLERANCE) sol1.push_back(trimSol.at(i)); } //if found intersection in direction, return the closest to trimCoord from it if(sol1.size()) return sol1.getClosest(trimCoord,NULL,0); //no intersection by direction, return previously found closest intersection return vp0; }
void RS_ActionInfoAngle::trigger() { RS_DEBUG->print("RS_ActionInfoAngle::trigger()"); if (entity1!=NULL && entity2!=NULL) { RS_VectorSolutions sol = RS_Information::getIntersection(entity1, entity2, false); if (sol.hasValid()) { intersection = sol.get(0); if (intersection.valid && point1.valid && point2.valid) { double angle1 = intersection.angleTo(point1); double angle2 = intersection.angleTo(point2); double angle = RS_Math::rad2deg(remainder(angle2-angle1,2.*M_PI)); QString str; str.setNum(angle); str += QChar(0xB0); if(angle<0.) { QString str2; str2.setNum(angle+360.); //positive value str += QString(" or %1%2").arg(str2).arg(QChar(0xB0)); } RS_DIALOGFACTORY->commandMessage(tr("Angle: %1").arg(str)); } } else { RS_DIALOGFACTORY->commandMessage(tr("Lines are parallel")); } } }
RS_Vector RS_Line::prepareTrim(const RS_Vector& trimCoord, const RS_VectorSolutions& trimSol) { //prepare trimming for multiple intersections if ( ! trimSol.hasValid()) return(RS_Vector(false)); if ( trimSol.getNumber() == 1 ) return(trimSol.get(0)); return trimSol.getClosest(trimCoord,NULL,0); }
void RS_ActionInfoAngle::trigger() { RS_DEBUG->print("RS_ActionInfoAngle::trigger()"); if (entity1 && entity2) { RS_VectorSolutions sol = RS_Information::getIntersection(entity1, entity2, false); if (sol.hasValid()) { intersection = sol.get(0); if (intersection.valid && point1.valid && point2.valid) { double angle1 = intersection.angleTo(point1); double angle2 = intersection.angleTo(point2); double angle = remainder(angle2-angle1,2.*M_PI); QString str = RS_Units::formatAngle(angle, graphic->getAngleFormat(), graphic->getAnglePrecision()); if(angle<0.){ str += " or "; str += RS_Units::formatAngle(angle + 2.*M_PI, graphic->getAngleFormat(), graphic->getAnglePrecision()); } RS_DIALOGFACTORY->commandMessage(tr("Angle: %1").arg(str)); } } else { RS_DIALOGFACTORY->commandMessage(tr("Lines are parallel")); } } }
void RS_ActionInfoAngle::trigger() { RS_DEBUG->print("RS_ActionInfoAngle::trigger()"); if (entity1!=NULL && entity2!=NULL) { RS_VectorSolutions sol = RS_Information::getIntersection(entity1, entity2, false); if (sol.hasValid()) { intersection = sol.get(0); if (intersection.valid && point1.valid && point2.valid) { double angle1 = intersection.angleTo(point1); double angle2 = intersection.angleTo(point2); double angle = fabs(angle2-angle1); QString str; str.sprintf("%.6f", RS_Math::rad2deg(angle)); RS_DIALOGFACTORY->commandMessage(tr("Angle: %1%2") .arg(str).arg(QChar(0xB0))); } } else { RS_DIALOGFACTORY->commandMessage(tr("Lines are parallel")); } } }
RS_Vector RS_Ellipse::prepareTrim(const RS_Vector& trimCoord, const RS_VectorSolutions& trimSol) { //special trimming for ellipse arc RS_DEBUG->print("RS_Ellipse::prepareTrim()"); if( ! trimSol.hasValid() ) return (RS_Vector(false)); if( trimSol.getNumber() == 1 ) return (trimSol.get(0)); double am=getEllipseAngle(trimCoord); QList<double> ias; double ia(0.),ia2(0.); RS_Vector is,is2; for(int ii=0; ii<trimSol.getNumber(); ii++) { //find closest according ellipse angle ias.append(getEllipseAngle(trimSol.get(ii))); if( !ii || fabs( remainder( ias[ii] - am, 2*M_PI)) < fabs( remainder( ia -am, 2*M_PI)) ) { ia = ias[ii]; is = trimSol.get(ii); } } qSort(ias.begin(),ias.end()); for(int ii=0; ii<trimSol.getNumber(); ii++) { //find segment to enclude trimCoord if ( ! RS_Math::isSameDirection(ia,ias[ii],RS_TOLERANCE)) continue; if( RS_Math::isAngleBetween(am,ias[(ii+trimSol.getNumber()-1)% trimSol.getNumber()],ia,false)) { ia2=ias[(ii+trimSol.getNumber()-1)% trimSol.getNumber()]; } else { ia2=ias[(ii+1)% trimSol.getNumber()]; } break; } for(int ii=0; ii<trimSol.getNumber(); ii++) { //find segment to enclude trimCoord if ( ! RS_Math::isSameDirection(ia2,getEllipseAngle(trimSol.get(ii)),RS_TOLERANCE)) continue; is2=trimSol.get(ii); break; } if(RS_Math::isSameDirection(getAngle1(),getAngle2(),RS_TOLERANCE_ANGLE) || RS_Math::isSameDirection(ia2,ia,RS_TOLERANCE) ) { //whole ellipse if( !RS_Math::isAngleBetween(am,ia,ia2,isReversed())) { std::swap(ia,ia2); std::swap(is,is2); } setAngle1(ia); setAngle2(ia2); double da1=fabs(remainder(getAngle1()-am,2*M_PI)); double da2=fabs(remainder(getAngle2()-am,2*M_PI)); if(da2<da1) { std::swap(is,is2); } } else { double dia=fabs(remainder(ia-am,2*M_PI)); double dia2=fabs(remainder(ia2-am,2*M_PI)); double ai_min=std::min(dia,dia2); double da1=fabs(remainder(getAngle1()-am,2*M_PI)); double da2=fabs(remainder(getAngle2()-am,2*M_PI)); double da_min=std::min(da1,da2); if( da_min < ai_min ) { //trimming one end of arc bool irev= RS_Math::isAngleBetween(am,ia2,ia, isReversed()) ; if ( RS_Math::isAngleBetween(ia,getAngle1(),getAngle2(), isReversed()) && RS_Math::isAngleBetween(ia2,getAngle1(),getAngle2(), isReversed()) ) { // if(irev) { setAngle2(ia); setAngle1(ia2); } else { setAngle1(ia); setAngle2(ia2); } da1=fabs(remainder(getAngle1()-am,2*M_PI)); da2=fabs(remainder(getAngle2()-am,2*M_PI)); } if( ((da1 < da2) && (RS_Math::isAngleBetween(ia2,ia,getAngle1(),isReversed()))) || ((da1 > da2) && (RS_Math::isAngleBetween(ia2,getAngle2(),ia,isReversed()))) ) { std::swap(is,is2); //std::cout<<"reset: angle1="<<getAngle1()<<" angle2="<<getAngle2()<<" am="<< am<<" is="<<getEllipseAngle(is)<<" ia2="<<ia2<<std::endl; } } else { //choose intersection as new end if( dia > dia2) { std::swap(is,is2); std::swap(ia,ia2); } if(RS_Math::isAngleBetween(ia,getAngle1(),getAngle2(),isReversed())) { if(RS_Math::isAngleBetween(am,getAngle1(),ia,isReversed())) { setAngle2(ia); } else { setAngle1(ia); } } } } return is; }
bool RS_Solid::isInCrossWindow(const RS_Vector& v1,const RS_Vector& v2)const { // bool sol = false; RS_Vector vBL, vTR; RS_VectorSolutions sol; //sort imput vectors to BottomLeft & TopRight if (v1.x<v2.x) { vBL.x = v1.x; vTR.x = v2.x; } else { vBL.x = v2.x; vTR.x = v1.x; } if (v1.y<v2.y) { vBL.y = v1.y; vTR.y = v2.y; } else { vBL.y = v2.y; vTR.y = v1.y; } //Check if is out of window if ( getMin().x > vTR.x || getMax().x < vBL.x || getMin().y > vTR.y || getMax().y < vBL.y) { return false; } std::vector<RS_Line> l; l.push_back(RS_Line(nullptr, RS_LineData(data.corner[0], data.corner[1]))); l.push_back(RS_Line(nullptr, RS_LineData(data.corner[1], data.corner[2]))); if (data.corner[3].valid) { l.push_back(RS_Line(nullptr, RS_LineData(data.corner[2], data.corner[3]))); l.push_back(RS_Line(nullptr, RS_LineData(data.corner[3], data.corner[0]))); } else { l.push_back(RS_Line(nullptr, RS_LineData(data.corner[2], data.corner[0]))); } //Find crossing edge if (getMax().x > vBL.x && getMin().x < vBL.x) {//left RS_Line edge = RS_Line(nullptr, RS_LineData(vBL, RS_Vector(vBL.x, vTR.y))); for(auto const& l0: l) { sol = RS_Information::getIntersection(&edge, &l0, true); if (sol.hasValid()) { return true; } } } if (getMax().x > vTR.x && getMin().x < vTR.x) {//right RS_Line edge = RS_Line(nullptr, RS_LineData(RS_Vector(vTR.x, vBL.y), vTR)); for(auto const& l0: l) { sol = RS_Information::getIntersection(&edge, &l0, true); if (sol.hasValid()) { return true; } } } if (getMax().y > vBL.y && getMin().y < vBL.y) {//bottom RS_Line edge = RS_Line(nullptr, RS_LineData(vBL, RS_Vector(vTR.x, vBL.y))); for(auto const& l0: l) { sol = RS_Information::getIntersection(&edge, &l0, true); if (sol.hasValid()) { return true; } } } if(getMax().y > vTR.y && getMin().y < vTR.y) {//top RS_Line edge = RS_Line(nullptr, RS_LineData(RS_Vector(vBL.x, vTR.y), vTR)); for(auto const& l0: l) { sol = RS_Information::getIntersection(&edge, &l0, true); if (sol.hasValid()) { return true; } } } return false; }
/** * Selects all circles (and arcs min. 3/4 circle) with same diameter and same layer, * in a window (v1, v2) * mosty used with CAM bores * * @param e Must be an circle or arc (min. 3/4 circle) */ void RS_Selection::selectCircles(RS_Entity* e, RS_Vector v1, RS_Vector v2 /*, bool inside=true */ ) { if (e==NULL) return; if (!e->isAtomic()) return; e->toggleSelected(); // bool cross = v2.y > v1.y; bool cross = v1.x > v2.x; bool select = !e->isSelected(); RS_AtomicEntity* ae = (RS_AtomicEntity*)e; double r_clicked = 0; RS_Layer* layer_clicked = 0; if (graphicView!=NULL) graphicView->drawEntity(e); if (ae->rtti()==RS2::EntityArc || ae->rtti()==RS2::EntityCircle) { r_clicked = ae->getRadius(); if (ae->rtti()==RS2::EntityArc) if(ae->getAngleLength() < 4.66) /* ca. 267 grad (knapp 3/4 kreis) */ { r_clicked = 0; RS_DIALOGFACTORY->commandMessage("selected arc has AngleLength < 4.66"); } layer_clicked = ae->getLayer(); } for (RS_Entity* en=container->firstEntity(); en!=NULL; en=container->nextEntity()) { int included = 0; if (en!=NULL && en->isVisible() && en->isAtomic() && en->isSelected()!=select && (en->rtti()==RS2::EntityArc || en->rtti()==RS2::EntityCircle) && (en->getLayer()==NULL || en->getLayer()->isLocked()==false)) { ae = (RS_AtomicEntity*)en; if(en->isInWindow(v1, v2)) included++; if (cross == true) { RS_Line l[] = { RS_Line(NULL, RS_LineData(v1, RS_Vector(v2.x, v1.y))), RS_Line(NULL, RS_LineData(RS_Vector(v2.x, v1.y), v2)), RS_Line(NULL, RS_LineData(v2, RS_Vector(v1.x, v2.y))), RS_Line(NULL, RS_LineData(RS_Vector(v1.x, v2.y), v1)) }; RS_VectorSolutions sol; if (ae->isContainer()) continue; else { for (int i=0; i<4; ++i) { sol = RS_Information::getIntersection(ae, &l[i], true); if (sol.hasValid()) { included++; break; } } } } // ----------------------- if(included) { double rc = ae->getRadius(); double rdiff = fabs (rc - r_clicked); if ((r_clicked > 0.000003) && (0.000003 > rdiff) && (ae->getLayer() == layer_clicked)) { if (graphicView!=NULL) { graphicView->deleteEntity(ae); } ae->setSelected(select); if (graphicView!=NULL) { graphicView->drawEntity(ae); } } } } } //std::cerr << "ende in rs_selection.cpp \n"; }
bool RS_Solid::isInCrossWindow(const RS_Vector& v1, const RS_Vector& v2) const { RS_Vector vBL; RS_Vector vTR; RS_VectorSolutions sol; //sort input vectors to BottomLeft & TopRight if (v1.x < v2.x) { vBL.x = v1.x; vTR.x = v2.x; } else { vBL.x = v2.x; vTR.x = v1.x; } if (v1.y < v2.y) { vBL.y = v1.y; vTR.y = v2.y; } else { vBL.y = v2.y; vTR.y = v1.y; } //Check if entity is out of window if (getMin().x > vTR.x || getMax().x < vBL.x || getMin().y > vTR.y || getMax().y < vBL.y) { return false; } std::vector<RS_Line> border; border.emplace_back( data.corner[0], data.corner[1]); border.emplace_back( data.corner[1], data.corner[2]); if (isTriangle()) { border.emplace_back( data.corner[2], data.corner[0]); } else { border.emplace_back( data.corner[2], data.corner[3]); border.emplace_back( data.corner[3], data.corner[0]); } //Find crossing edge if (getMax().x > vBL.x && getMin().x < vBL.x) { //left RS_Line edge {vBL, {vBL.x, vTR.y}}; for (auto const& line: border) { sol = RS_Information::getIntersection(&edge, &line, true); if (sol.hasValid()) { return true; } } } if (getMax().x > vTR.x && getMin().x < vTR.x) { //right RS_Line edge {{vTR.x, vBL.y}, vTR}; for (auto const& line: border) { sol = RS_Information::getIntersection(&edge, &line, true); if (sol.hasValid()) { return true; } } } if (getMax().y > vBL.y && getMin().y < vBL.y) { //bottom RS_Line edge {vBL, {vTR.x, vBL.y}}; for(auto const& line: border) { sol = RS_Information::getIntersection(&edge, &line, true); if (sol.hasValid()) { return true; } } } if(getMax().y > vTR.y && getMin().y < vTR.y) { //top RS_Line edge {{vBL.x, vTR.y}, vTR}; for(auto const& line: border) { sol = RS_Information::getIntersection(&edge, &line, true); if (sol.hasValid()) { return true; } } } return false; }