RS_Vector RS_Image::getNearestPointOnEntity(const RS_Vector& coord, bool onEntity, double* dist, RS_Entity** entity) const{ if (entity!=NULL) { *entity = const_cast<RS_Image*>(this); } RS_VectorSolutions corners =getCorners(); //allow selecting image by clicking within images, bug#3464626 if(containsPoint(coord)){ //if coord is within image if(dist!=NULL) *dist=0.; return coord; } RS_VectorSolutions points(4); RS_Line l[] = { RS_Line(NULL, RS_LineData(corners.get(0), corners.get(1))), RS_Line(NULL, RS_LineData(corners.get(1), corners.get(2))), RS_Line(NULL, RS_LineData(corners.get(2), corners.get(3))), RS_Line(NULL, RS_LineData(corners.get(3), corners.get(0))) }; for (int i=0; i<4; ++i) { points.set(i, l[i].getNearestPointOnEntity(coord, onEntity)); } return points.getClosest(coord, dist); }
/** //create Ellipse with axes in x-/y- directions from 4 points * * *@Author Dongxu Li */ bool RS_Ellipse::createFrom4P(const RS_VectorSolutions& sol) { if (sol.getNumber() != 4 ) return (false); //only do 4 points QVector<QVector<double> > mt; QVector<double> dn; int mSize(4); mt.resize(mSize); for(int i=0;i<mSize;i++) {//form the linear equation, c0 x^2 + c1 x + c2 y^2 + c3 y = 1 mt[i].resize(mSize+1); mt[i][0]=sol.get(i).x * sol.get(i).x; mt[i][1]=sol.get(i).x ; mt[i][2]=sol.get(i).y * sol.get(i).y; mt[i][3]=sol.get(i).y ; mt[i][4]=1.; } if ( ! RS_Math::linearSolver(mt,dn)) return false; double d(1.+0.25*(dn[1]*dn[1]/dn[0]+dn[3]*dn[3]/dn[2])); if(fabs(dn[0])<RS_TOLERANCE*RS_TOLERANCE ||fabs(dn[2])<RS_TOLERANCE*RS_TOLERANCE ||d/dn[0]<RS_TOLERANCE*RS_TOLERANCE ||d/dn[2]<RS_TOLERANCE*RS_TOLERANCE ) { //ellipse not defined return false; } data.center.set(-0.5*dn[1]/dn[0],-0.5*dn[3]/dn[2]); // center d=sqrt(d/dn[0]); data.majorP.set(d,0.); data.ratio=sqrt(dn[0]/dn[2]); data.angle1=0.; data.angle2=0.; return true; }
void RS_Image::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) { if (!(painter && view) || !img.get() || img->isNull()) return; // erase image: //if (painter->getPen().getColor()==view->getBackground()) { // RS_VectorSolutions sol = getCorners(); // //} RS_Vector scale{view->toGuiDX(data.uVector.magnitude()), view->toGuiDY(data.vVector.magnitude())}; double angle = data.uVector.angle(); painter->drawImg(*img, view->toGui(data.insertionPoint), angle, scale); if (isSelected()) { RS_VectorSolutions sol = getCorners(); for (size_t i = 0; i < sol.size(); ++i){ size_t const j = (i+1)%sol.size(); painter->drawLine(view->toGui(sol.get(i)), view->toGui(sol.get(j))); } } }
double RS_Image::getDistanceToPoint(const RS_Vector& coord, RS_Entity** entity, RS2::ResolveLevel /*level*/, double /*solidDist*/) const{ if (entity) { *entity = const_cast<RS_Image*>(this); } RS_VectorSolutions corners = getCorners(); //allow selecting image by clicking within images, bug#3464626 if(containsPoint(coord)){ //if coord is on image RS_SETTINGS->beginGroup("/Appearance"); bool draftMode = (bool)RS_SETTINGS->readNumEntry("/DraftMode", 0); RS_SETTINGS->endGroup(); if(!draftMode) return double(0.); } //continue to allow selecting by image edges double minDist = RS_MAXDOUBLE; 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)}; double const dist = l.getDistanceToPoint(coord, nullptr); minDist = std::min(minDist, dist); } return minDist; }
void RS_Image::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) { if (painter==NULL || view==NULL || !img.get() || img->isNull()) { return; } // erase image: //if (painter->getPen().getColor()==view->getBackground()) { // RS_VectorSolutions sol = getCorners(); // //} RS_Vector scale = RS_Vector(view->toGuiDX(data.uVector.magnitude()), view->toGuiDY(data.vVector.magnitude())); double angle = data.uVector.angle(); painter->drawImg(*img, view->toGui(data.insertionPoint), angle, scale); if (isSelected()) { RS_VectorSolutions sol = getCorners(); painter->drawLine(view->toGui(sol.get(0)), view->toGui(sol.get(1))); painter->drawLine(view->toGui(sol.get(1)), view->toGui(sol.get(2))); painter->drawLine(view->toGui(sol.get(2)), view->toGui(sol.get(3))); painter->drawLine(view->toGui(sol.get(3)), view->toGui(sol.get(0))); } }
void RS_Image::calculateBorders() { RS_VectorSolutions sol = getCorners(); minV = RS_Vector::minimum( RS_Vector::minimum(sol.get(0), sol.get(1)), RS_Vector::minimum(sol.get(2), sol.get(3)) ); maxV = RS_Vector::maximum( RS_Vector::maximum(sol.get(0), sol.get(1)), RS_Vector::maximum(sol.get(2), sol.get(3)) ); }
/** * Helper function for makeContour * Calculate the intersection point of first and last entities * The first vertex is not added and the last is returned instead of added * * @retval RS_Vector nearest to startpoint of last and endpoint of first or RS_Vector(false) if not * * @author Rallaz */ RS_Vector RS_ActionPolylineEquidistant::calculateIntersection(RS_Entity* first,RS_Entity* last) { RS_VectorSolutions vsol; RS_Vector v(false); vsol = RS_Information::getIntersection(first, last, false); if (vsol.getNumber()==0) { //Parallel entities return RS_Vector(false); } else if (vsol.getNumber()>1 && vsol.get(0).distanceTo(last->getStartpoint()) > vsol.get(1).distanceTo(last->getStartpoint())) { return vsol.get(1); } return vsol.get(0); }
/** * Creates this arc from 3 given points which define the arc line. * * @param p1 1st point. * @param p2 2nd point. * @param p3 3rd point. */ bool RS_Arc::createFrom3P(const RS_Vector& p1, const RS_Vector& p2, const RS_Vector& p3) { if (p1.distanceTo(p2)>RS_TOLERANCE && p2.distanceTo(p3)>RS_TOLERANCE && p3.distanceTo(p1)>RS_TOLERANCE) { // middle points between 3 points: RS_Vector mp1, mp2; RS_Vector dir1, dir2; double a1, a2; // intersection of two middle lines mp1 = (p1 + p2)/2.0; a1 = p1.angleTo(p2) + M_PI/2.0; dir1.setPolar(100.0, a1); mp2 = (p2 + p3)/2.0; a2 = p2.angleTo(p3) + M_PI/2.0; dir2.setPolar(100.0, a2); RS_ConstructionLineData d1(mp1, mp1 + dir1); RS_ConstructionLineData d2(mp2, mp2 + dir2); RS_ConstructionLine midLine1(NULL, d1); RS_ConstructionLine midLine2(NULL, d2); RS_VectorSolutions sol = RS_Information::getIntersection(&midLine1, &midLine2); data.center = sol.get(0); data.radius = data.center.distanceTo(p3); data.angle1 = data.center.angleTo(p1); data.angle2 = data.center.angleTo(p3); data.reversed = RS_Math::isAngleBetween(data.center.angleTo(p2), data.angle1, data.angle2, true); if (sol.get(0).valid && data.radius<1.0e14 && data.radius>RS_TOLERANCE) { calculateEndpoints(); calculateBorders(); return true; } else { RS_DEBUG->print("RS_Arc::createFrom3P(): " "Cannot create an arc with inf radius."); return false; } } else { RS_DEBUG->print("RS_Arc::createFrom3P(): " "Cannot create an arc with radius 0.0."); return false; } }
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")); } } }
/** * @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; }
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")); } } }
/** * @return Center of the measured dimension. */ RS_Vector RS_DimAngular::getCenter() { RS_ConstructionLine l1(NULL, RS_ConstructionLineData(edata.definitionPoint1, edata.definitionPoint2)); RS_ConstructionLine l2(NULL, RS_ConstructionLineData(edata.definitionPoint3, data.definitionPoint)); RS_VectorSolutions vs = RS_Information::getIntersection(&l1, &l2, false); return vs.get(0); }
/** * Creates a bisecting line of the angle between the entities * e1 and e2. Out of the 4 possible bisectors, the one closest to * the given coordinate is returned. * * @param coord Coordinate to define which bisector we want (typically a * mouse coordinate). * @param length Length of the bisecting line. * @param num Number of bisectors * @param l1 First line. * @param l2 Second line. * * @return Pointer to the first bisector created or nullptr if no bisectors * were created. */ RS_Line* RS_Creation::createBisector(const RS_Vector& coord1, const RS_Vector& coord2, double length, int num, RS_Line* l1, RS_Line* l2) { RS_VectorSolutions sol; // check given entities: if( ! (l1 && l2)) return nullptr; if(! (l1->rtti()==RS2::EntityLine && l1->rtti()==RS2::EntityLine)) return nullptr; // intersection between entities: sol = RS_Information::getIntersection(l1, l2, false); RS_Vector inters = sol.get(0); if (inters.valid==false) { return nullptr; } double angle1 = inters.angleTo(l1->getNearestPointOnEntity(coord1)); double angle2 = inters.angleTo(l2->getNearestPointOnEntity(coord2)); double angleDiff = RS_Math::getAngleDifference(angle1, angle2); if (angleDiff>M_PI) { angleDiff = angleDiff - 2.*M_PI; } RS_Line* ret = nullptr; if (document && handleUndo) { document->startUndoCycle(); } for (int n=1; n<=num; ++n) { double angle = angle1 + (angleDiff / (num+1) * n); RS_LineData d; RS_Vector v; v.setPolar(length, angle); d = RS_LineData(inters, inters + v); RS_Line* newLine = new RS_Line(container, d); if (ret==nullptr) { ret = newLine; } setEntity(newLine); } if (document && handleUndo) { document->endUndoCycle(); } return ret; }
RS_Vector RS_Image::getNearestDist(double distance, const RS_Vector& coord, double* dist) { RS_VectorSolutions corners = getCorners(); RS_VectorSolutions points(4); RS_Line l[] = { RS_Line(NULL, RS_LineData(corners.get(0), corners.get(1))), RS_Line(NULL, RS_LineData(corners.get(1), corners.get(2))), RS_Line(NULL, RS_LineData(corners.get(2), corners.get(3))), RS_Line(NULL, RS_LineData(corners.get(3), corners.get(0))) }; for (int i=0; i<4; ++i) { points.set(i, l[i].getNearestDist(distance, coord, dist)); } return points.getClosest(coord, dist); }
double RS_Image::getDistanceToPoint(const RS_Vector& coord, RS_Entity** entity, RS2::ResolveLevel /*level*/, double /*solidDist*/) const{ if (entity!=NULL) { *entity = const_cast<RS_Image*>(this); } RS_VectorSolutions corners = getCorners(); //allow selecting image by clicking within images, bug#3464626 if(containsPoint(coord)){ //if coord is on image RS_SETTINGS->beginGroup("/Appearance"); bool draftMode = (bool)RS_SETTINGS->readNumEntry("/DraftMode", 0); RS_SETTINGS->endGroup(); if(!draftMode) return double(0.); } //continue to allow selecting by image edges double dist; double minDist = RS_MAXDOUBLE; RS_Line l[] = { RS_Line(NULL, RS_LineData(corners.get(0), corners.get(1))), RS_Line(NULL, RS_LineData(corners.get(1), corners.get(2))), RS_Line(NULL, RS_LineData(corners.get(2), corners.get(3))), RS_Line(NULL, RS_LineData(corners.get(3), corners.get(0))) }; for (int i=0; i<4; ++i) { dist = l[i].getDistanceToPoint(coord, NULL); if (dist<minDist) { minDist = dist; } } return minDist; }
//*create Circle from 3 points //Author: Dongxu Li bool RS_Circle::createFrom3P(const RS_VectorSolutions& sol) { if(sol.getNumber() < 2) return false; if(sol.getNumber() == 2) return createFrom2P(sol.get(0),sol.get(1)); if((sol.get(1)-sol.get(2)).squared() < RS_TOLERANCE*RS_TOLERANCE) return createFrom2P(sol.get(0),sol.get(1)); RS_Vector vra(sol.get(1) - sol.get(0)); RS_Vector vrb(sol.get(2) - sol.get(0)); double ra2=vra.squared()*0.5; double rb2=vrb.squared()*0.5; double crossp=vra.x * vrb.y - vra.y * vrb.x; if (fabs(crossp)< RS_TOLERANCE*RS_TOLERANCE) { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): " "Cannot create a circle with radius 0.0."); return false; } crossp=1./crossp; data.center.set((ra2*vrb.y - rb2*vra.y)*crossp,(rb2*vra.x - ra2*vrb.x)*crossp); data.radius=data.center.magnitude(); data.center += sol.get(0); return true; }
/** //create Ellipse with center and 3 points * * *@Author Dongxu Li */ bool RS_Ellipse::createFromCenter3Points(const RS_VectorSolutions& sol) { if(sol.getNumber()<3) return false; //need one center and 3 points on ellipse QVector<QVector<double> > mt; int mSize(sol.getNumber() -1); if( (sol.get(mSize) - sol.get(mSize-1)).squared() < RS_TOLERANCE*RS_TOLERANCE ) { //remove the last point mSize--; } mt.resize(mSize); QVector<double> dn(mSize); switch(mSize){ case 2: for(int i=0;i<mSize;i++){//form the linear equation mt[i].resize(mSize+1); RS_Vector vp(sol.get(i+1)-sol.get(0)); //the first vector is center mt[i][0]=vp.x*vp.x; mt[i][1]=vp.y*vp.y; mt[i][2]=1.; } if ( ! RS_Math::linearSolver(mt,dn) ) return false; if( dn[0]<RS_TOLERANCE*RS_TOLERANCE || dn[1]<RS_TOLERANCE*RS_TOLERANCE) return false; setMajorP(RS_Vector(1./sqrt(dn[0]),0.)); setRatio(sqrt(dn[0]/dn[1])); setAngle1(0.); setAngle2(0.); setCenter(sol.get(0)); return true; break; case 3: for(int i=0;i<mSize;i++){//form the linear equation mt[i].resize(mSize+1); RS_Vector vp(sol.get(i+1)-sol.get(0)); //the first vector is center mt[i][0]=vp.x*vp.x; mt[i][1]=vp.x*vp.y; mt[i][2]=vp.y*vp.y; mt[i][3]=1.; } if ( ! RS_Math::linearSolver(mt,dn) ) return false; setCenter(sol.get(0)); return createFromQuadratic(dn); default: return false; } }
/** * @return The intersection which is closest to 'coord' */ RS_Vector RS_EntityContainer::getNearestIntersection(const RS_Vector& coord, double* dist) { double minDist = RS_MAXDOUBLE; // minimum measured distance double curDist; // currently measured distance RS_Vector closestPoint(false); // closest found endpoint RS_Vector point; // endpoint found RS_VectorSolutions sol; RS_Entity* closestEntity; closestEntity = getNearestEntity(coord, NULL, RS2::ResolveAll); if (closestEntity!=NULL) { for (RS_Entity* en = firstEntity(RS2::ResolveAll); en != NULL; en = nextEntity(RS2::ResolveAll)) { if (en->isVisible() && en!=closestEntity) { sol = RS_Information::getIntersection(closestEntity, en, true); for (int i=0; i<4; i++) { point = sol.get(i); if (point.valid) { curDist = coord.distanceTo(point); if (curDist<minDist) { closestPoint = point; minDist = curDist; if (dist!=NULL) { *dist = curDist; } } } } } } //} } return closestPoint; }
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); }
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; }
bool RS_ActionPolylineEquidistant::makeContour() { if (container==NULL) { RS_DEBUG->print("RS_ActionPolylineEquidistant::makeContour: no valid container", RS_Debug::D_WARNING); return false; } RS_Vector offset(false); QList<RS_Entity*> addList; if (document!=NULL) { document->startUndoCycle(); } double neg = 1.0; if(bRightSide) neg = -1.0; // Create new entites RS_Line line1(NULL, RS_LineData(RS_Vector(true), RS_Vector(true))); RS_Line line2(NULL, RS_LineData(RS_Vector(true), RS_Vector(true))); for (int num=1; num<=number || (number==0 && num<=1); num++) { RS_Polyline* newPolyline = new RS_Polyline(container); newPolyline->setClosed(((RS_Polyline*)originalEntity)->isClosed()); // newPolyline->setSelected((RS_Polyline*)originalEntity)->isSelected()); newPolyline->setLayer(((RS_Polyline*)originalEntity)->getLayer()); newPolyline->setPen(((RS_Polyline*)originalEntity)->getPen()); bool first = true; RS_Entity* lastEntity = ((RS_Polyline*)originalEntity)->lastEntity(); for (RS_Entity* en=((RS_Polyline*)originalEntity)->firstEntity(); en!=NULL; en=((RS_Polyline*)originalEntity)->nextEntity()) { double bulge = 0.0; if (en->rtti()==RS2::EntityArc) { double r0 = ((RS_Arc*)en)->getRadius(); double r = r0 - dist*neg; if(r < 0) break; ((RS_Arc*)en)->setRadius(r); bulge = ((RS_Arc*)en)->getBulge(); ((RS_Arc*)en)->setRadius(r0); } else { bulge = 0.0; } RS_Vector v1 = ((RS_AtomicEntity*)en)->getStartpoint(); RS_Vector v2 = ((RS_AtomicEntity*)en)->getEndpoint(); offset.set(dist * cos(v1.angleTo(v2)+M_PI*0.5*neg), dist * sin(v1.angleTo(v2)+M_PI*0.5*neg)); v1.move(offset*num); v2.move(offset*num); if (first) { line1.setStartpoint(v1); line1.setEndpoint(v2); if(newPolyline->isClosed()){ RS_Vector v01 = ((RS_AtomicEntity*)lastEntity)->getStartpoint(); RS_Vector v02 = ((RS_AtomicEntity*)en)->getStartpoint(); offset.set(dist * cos(v01.angleTo(v02)+M_PI*0.5*neg), dist * sin(v01.angleTo(v02)+M_PI*0.5*neg)); v01.move(offset*num); v02.move(offset*num); line2.setStartpoint(v01); line2.setEndpoint(v02); RS_VectorSolutions vsol = RS_Information::getIntersection(&line1, &line2, false); v1 = vsol.get(0); } newPolyline->setStartpoint(v1); newPolyline->addVertex(v1, bulge); first = false; }else{ line2.setStartpoint(v1); line2.setEndpoint(v2); RS_VectorSolutions vsol = RS_Information::getIntersection(&line1, &line2, false); RS_Vector v = vsol.get(0); newPolyline->addVertex(v, bulge); newPolyline->setEndpoint(v); line1.setStartpoint(v1); line1.setEndpoint(v2); if (en==lastEntity/* && newPolyline->isClosed()==false*/){ newPolyline->addVertex(v2, bulge); } } } double bulge = lastEntity->rtti() == RS2::EntityArc? ((RS_Arc*)lastEntity)->getBulge():0.0; // newPolyline->setNextBulge(bulge); newPolyline->endPolyline(); container->addEntity(newPolyline); document->addUndoable(newPolyline); } if (document!=NULL) { document->endUndoCycle(); } if (graphicView!=NULL) { graphicView->redraw(); } return true; }
/** * Checks if the given coordinate is inside the given contour. * * @param point Coordinate to check. * @param contour One or more entities which shape a contour. * If the given contour is not closed, the result is undefined. * The entities don't need to be in a specific order. * @param onContour Will be set to true if the given point it exactly * on the contour. */ bool RS_Information::isPointInsideContour(const RS_Vector& point, RS_EntityContainer* contour, bool* onContour) { if (contour==NULL) { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Information::isPointInsideContour: contour is NULL"); return false; } if (point.x < contour->getMin().x || point.x > contour->getMax().x || point.y < contour->getMin().y || point.y > contour->getMax().y) { return false; } double width = contour->getSize().x+1.0; bool sure; int counter; int tries = 0; double rayAngle = 0.0; do { sure = true; // create ray: RS_Vector v; v.setPolar(width*10.0, rayAngle); RS_Line ray(NULL, RS_LineData(point, point+v)); counter = 0; RS_VectorSolutions sol; if (onContour!=NULL) { *onContour = false; } for (RS_Entity* e = contour->firstEntity(RS2::ResolveAll); e!=NULL; e = contour->nextEntity(RS2::ResolveAll)) { // intersection(s) from ray with contour entity: sol = RS_Information::getIntersection(&ray, e, true); for (int i=0; i<=1; ++i) { RS_Vector p = sol.get(i); if (p.valid) { // point is on the contour itself if (p.distanceTo(point)<1.0e-5) { if (onContour!=NULL) { *onContour = true; } } else { if (e->rtti()==RS2::EntityLine) { RS_Line* line = (RS_Line*)e; // ray goes through startpoint of line: if (p.distanceTo(line->getStartpoint())<1.0e-4) { if (RS_Math::correctAngle(line->getAngle1())<M_PI) { counter++; sure = false; } } // ray goes through endpoint of line: else if (p.distanceTo(line->getEndpoint())<1.0e-4) { if (RS_Math::correctAngle(line->getAngle2())<M_PI) { counter++; sure = false; } } // ray goes through the line: else { counter++; } } else if (e->rtti()==RS2::EntityArc) { RS_Arc* arc = (RS_Arc*)e; if (p.distanceTo(arc->getStartpoint())<1.0e-4) { double dir = arc->getDirection1(); if ((dir<M_PI && dir>=1.0e-5) || ((dir>2*M_PI-1.0e-5 || dir<1.0e-5) && arc->getCenter().y>p.y)) { counter++; sure = false; } } else if (p.distanceTo(arc->getEndpoint())<1.0e-4) { double dir = arc->getDirection2(); if ((dir<M_PI && dir>=1.0e-5) || ((dir>2*M_PI-1.0e-5 || dir<1.0e-5) && arc->getCenter().y>p.y)) { counter++; sure = false; } } else { counter++; } } else if (e->rtti()==RS2::EntityCircle) { // tangent: if (i==0 && sol.get(1).valid==false) { if (!sol.isTangent()) { counter++; } else { sure = false; } } else if (i==1 || sol.get(1).valid==true) { counter++; } } } } } } rayAngle+=0.02; tries++; } while (!sure && rayAngle<2*M_PI && tries<6); // remove double intersections: /* QList<RS_Vector> is2; bool done; RS_Vector* av; do { done = true; double minDist = RS_MAXDOUBLE; double dist; av = NULL; for (RS_Vector* v = is.first(); v!=NULL; v = is.next()) { dist = point.distanceTo(*v); if (dist<minDist) { minDist = dist; done = false; av = v; } } if (!done && av!=NULL) { is2.append(*av); } } while (!done); */ return ((counter%2)==1); }
/** * @return One or two intersection points between given entities. */ RS_VectorSolutions RS_Information::getIntersectionLineEllipse(RS_Line* line, RS_Ellipse* ellipse) { RS_VectorSolutions ret; if (line==NULL || ellipse==NULL) { return ret; } // rotate into normal position: double ang = ellipse->getAngle(); double rx = ellipse->getMajorRadius(); double ry = ellipse->getMinorRadius(); RS_Vector center = ellipse->getCenter(); RS_Vector a1 = line->getStartpoint().rotate(center, -ang); RS_Vector a2 = line->getEndpoint().rotate(center, -ang); RS_Vector origin = a1; RS_Vector dir = a2-a1; RS_Vector diff = origin - 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; if (d < 0) { RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: outside 0"); } else if ( d > 0 ) { double root = sqrt(d); double t_a = (-b - root) / a; double t_b = (-b + root) / a; /*if ( (t_a < 0 || 1 < t_a) && (t_b < 0 || 1 < t_b) ) { if ( (t_a < 0 && t_b < 0) || (t_a > 1 && t_b > 1) ) { RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: outside 1"); } else { RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: inside 1"); } } else {*/ RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: intersection 1"); RS_Vector ret1(false); RS_Vector ret2(false); //if ( 0 <= t_a && t_a <= 1 ) { //RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: 0<=t_a<=1"); ret1 = a1.lerp(a2, t_a); RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: ret1: %f/%f", ret1.x, ret1.y); //} //if ( 0 <= t_b && t_b <= 1 ) { //RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: 0<=t_b<=1"); ret2 = a1.lerp(a2, t_b); RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: ret2: %f/%f", ret2.x, ret2.y); //} if (ret1.valid && ret2.valid) { ret = RS_VectorSolutions(ret1, ret2); } else { if (ret1.valid) { ret = RS_VectorSolutions(ret1); } if (ret2.valid) { ret = RS_VectorSolutions(ret2); } } //} } else { double t = -b/a; if ( 0 <= t && t <= 1 ) { RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: 0<=t<=1"); RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: intersection 2"); ret = RS_VectorSolutions(a1.lerp(a2, t)); RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: ret1: %f/%f", ret.get(0).x, ret.get(0).y); } else { RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: outside 2"); } } ret.rotate(center, ang); return ret; /* RS_Arc* arc = new RS_Arc(NULL, RS_ArcData(ellipse->getCenter(), ellipse->getMajorRadius(), ellipse->getAngle1(), ellipse->getAngle2(), false)); RS_Line* other = (RS_Line*)line->clone(); double angle = ellipse->getAngle(); //double ratio = ellipse->getRatio(); // rotate entities: other->rotate(ellipse->getCenter(), -angle); other->scale(ellipse->getCenter(), RS_Vector(1.0, 1.0/ellipse->getRatio())); ret = getIntersectionLineArc(other, arc); ret.scale(ellipse->getCenter(), RS_Vector(1.0, ellipse->getRatio())); ret.rotate(ellipse->getCenter(), angle); delete arc; delete other; return ret; */ }
/** * Calculates the intersection point(s) between two entities. * * @param onEntities true: only return intersection points which are * on both entities. * false: return all intersection points. * * @todo support more entities * * @return All intersections of the two entities. The tangent flag in * RS_VectorSolutions is set if one intersection is a tangent point. */ RS_VectorSolutions RS_Information::getIntersection(RS_Entity* e1, RS_Entity* e2, bool onEntities) { RS_VectorSolutions ret; double tol = 1.0e-4; if (e1==NULL || e2==NULL ) { RS_DEBUG->print("RS_Information::getIntersection() for NULL entities"); return ret; } if (e1->getId() == e2->getId()) { RS_DEBUG->print("RS_Information::getIntersection() of the same entity"); return ret; } // unsupported entities / entity combinations: if ( e1->rtti()==RS2::EntityText || e2->rtti()==RS2::EntityText || isDimension(e1->rtti()) || isDimension(e2->rtti())) { return ret; } // a little check to avoid doing unneeded intersections, an attempt to avoid O(N^2) increasing of checking two-entity information if (onEntities && ( e1 -> getMin().x > e2 -> getMax().x || e1 -> getMax().x < e2 -> getMin().x || e1 -> getMin().y > e2 -> getMax().y || e1 -> getMax().y < e2 -> getMin().y ) ) { return ret; } // one entity is an ellipse: if (e1->rtti()==RS2::EntityEllipse || e2->rtti()==RS2::EntityEllipse) { if (e2->rtti()==RS2::EntityEllipse) std::swap( e1, e2); if (e2->rtti()==RS2::EntityEllipse) { ret = getIntersectionEllipseEllipse((RS_Ellipse*)e1, (RS_Ellipse *) e2); } if (e2->rtti()==RS2::EntityCircle) { ret = getIntersectionCircleEllipse((RS_Circle *)e2, (RS_Ellipse *) e1); } if (e2->rtti()==RS2::EntityArc) { ret = getIntersectionArcEllipse((RS_Arc *)e2, (RS_Ellipse *) e1); } if (e2->rtti()==RS2::EntityLine) { ret = getIntersectionLineEllipse((RS_Line*)e2, (RS_Ellipse*) e1); tol = 1.0e-1; } // not supported: else { return ret; } } else { RS_Entity* te1 = e1; RS_Entity* te2 = e2; // entity copies - so we only have to deal with lines and arcs RS_Line l1(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Line l2(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Arc a1(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); RS_Arc a2(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); // convert construction lines to lines: if (e1->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e1; l1.setStartpoint(cl->getPoint1()); l1.setEndpoint(cl->getPoint2()); te1 = &l1; } if (e2->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e2; l2.setStartpoint(cl->getPoint1()); l2.setEndpoint(cl->getPoint2()); te2 = &l2; } // convert circles to arcs: if (e1->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e1; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a1.setData(data); te1 = &a1; } if (e2->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e2; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a2.setData(data); te2 = &a2; } // line / line: // //else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityLine) { RS_Line * line1=(RS_Line*) te1; RS_Line * line2=(RS_Line*) te2; /* ToDo: 24 Aug 2011, Dongxu Li, if rtti() is not defined for the parent, the following check for splines may still cause segfault */ if ( line1->getParent() != NULL && line1->getParent() == line2->getParent()) { if ( line1->getParent()->rtti()==RS2::EntitySpline ) { //do not calculate intersections from neighboring lines of a spline if ( abs(line1->getParent()->findEntity(line1) - line1->getParent()->findEntity(line2)) <= 1 ) { return ret; } } } ret = getIntersectionLineLine(line1, line2); } // line / arc: // else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityArc) { RS_Line* line = (RS_Line*)te1; RS_Arc* arc = (RS_Arc*)te2; ret = getIntersectionLineArc(line, arc); } // arc / line: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityLine) { RS_Arc* arc = (RS_Arc*)te1; RS_Line* line = (RS_Line*)te2; ret = getIntersectionLineArc(line, arc); } // arc / arc: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityArc) { RS_Arc* arc1 = (RS_Arc*)te1; RS_Arc* arc2 = (RS_Arc*)te2; ret = getIntersectionArcArc(arc1, arc2); // ellipse / ellipse // } else { RS_DEBUG->print("RS_Information::getIntersection:: Unsupported entity type."); } } // Check all intersection points for being on entities: // if (onEntities==true) { if (!e1->isPointOnEntity(ret.get(0), tol) || !e2->isPointOnEntity(ret.get(0), tol)) { ret.set(0, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(1), tol) || !e2->isPointOnEntity(ret.get(1), tol)) { ret.set(1, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(2), tol) || !e2->isPointOnEntity(ret.get(2), tol)) { ret.set(2, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(3), tol) || !e2->isPointOnEntity(ret.get(3), tol)) { ret.set(3, RS_Vector(false)); } } int k=0; for (int i=0; i<4; ++i) { if (ret.get(i).valid) { ret.set(k, ret.get(i)); k++; } } for (int i=k; i<4; ++i) { ret.set(i, RS_Vector(false)); } return ret; }
void RS_ActionDimAngular::mouseReleaseEvent(QMouseEvent* e) { if (e->button()==Qt::LeftButton) { switch (getStatus()) { case SetLine1: { RS_Entity* en = catchEntity(e, RS2::ResolveAll); if (en!=NULL && en->rtti()==RS2::EntityLine) { line1 = (RS_Line*)en; setStatus(SetLine2); } } break; case SetLine2: { RS_Entity* en = catchEntity(e, RS2::ResolveAll); if (en!=NULL && en->rtti()==RS2::EntityLine) { line2 = (RS_Line*)en; RS_VectorSolutions sol = RS_Information::getIntersectionLineLine(line1, line2); if (sol.get(0).valid) { center = sol.get(0); if (center.distanceTo(line1->getStartpoint()) < center.distanceTo(line1->getEndpoint())) { edata->definitionPoint1 = line1->getStartpoint(); edata->definitionPoint2 = line1->getEndpoint(); } else { edata->definitionPoint1 = line1->getEndpoint(); edata->definitionPoint2 = line1->getStartpoint(); } if (center.distanceTo(line2->getStartpoint()) < center.distanceTo(line2->getEndpoint())) { edata->definitionPoint3 = line2->getStartpoint(); data->definitionPoint = line2->getEndpoint(); } else { edata->definitionPoint3 = line2->getEndpoint(); data->definitionPoint = line2->getStartpoint(); } graphicView->moveRelativeZero(center); setStatus(SetPos); } } } break; case SetPos: { RS_CoordinateEvent ce(snapPoint(e)); coordinateEvent(&ce); } break; } } else if (e->button()==Qt::RightButton) { deletePreview(); init(getStatus()-1); } }
/** * Updates the Hatch. Called when the * hatch or it's data, position, alignment, .. changes. */ void RS_Hatch::update() { RS_DEBUG->print("RS_Hatch::update"); RS_DEBUG->print("RS_Hatch::update: contour has %d loops", count()); updateError = HATCH_OK; if (updateRunning) { return; } if (updateEnabled==false) { return; } if (data.solid==true) { calculateBorders(); return; } RS_DEBUG->print("RS_Hatch::update"); updateRunning = true; // delete old hatch: if (hatch!=NULL) { removeEntity(hatch); hatch = NULL; } if (isUndone()) { updateRunning = false; return; } if (!validate()) { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Hatch::update: invalid contour in hatch found"); updateRunning = false; updateError = HATCH_INVALID_CONTOUR; return; } // search pattern: RS_DEBUG->print("RS_Hatch::update: requesting pattern"); RS_Pattern* pat = RS_PATTERNLIST->requestPattern(data.pattern); if (pat==NULL) { updateRunning = false; RS_DEBUG->print("RS_Hatch::update: requesting pattern: not found"); updateError = HATCH_PATTERN_NOT_FOUND; return; } RS_DEBUG->print("RS_Hatch::update: requesting pattern: OK"); RS_DEBUG->print("RS_Hatch::update: cloning pattern"); pat = (RS_Pattern*)pat->clone(); RS_DEBUG->print("RS_Hatch::update: cloning pattern: OK"); // scale pattern RS_DEBUG->print("RS_Hatch::update: scaling pattern"); pat->scale(RS_Vector(0.0,0.0), RS_Vector(data.scale, data.scale)); pat->calculateBorders(); forcedCalculateBorders(); RS_DEBUG->print("RS_Hatch::update: scaling pattern: OK"); // find out how many pattern-instances we need in x/y: int px1, py1, px2, py2; double f; RS_Hatch* copy = (RS_Hatch*)this->clone(); copy->rotate(RS_Vector(0.0,0.0), -data.angle); copy->forcedCalculateBorders(); // create a pattern over the whole contour. RS_Vector pSize = pat->getSize(); RS_Vector rot_center=pat->getMin(); // RS_Vector cPos = getMin(); RS_Vector cSize = getSize(); RS_DEBUG->print("RS_Hatch::update: pattern size: %f/%f", pSize.x, pSize.y); RS_DEBUG->print("RS_Hatch::update: contour size: %f/%f", cSize.x, cSize.y); if (cSize.x<1.0e-6 || cSize.y<1.0e-6 || pSize.x<1.0e-6 || pSize.y<1.0e-6 || cSize.x>RS_MAXDOUBLE-1 || cSize.y>RS_MAXDOUBLE-1 || pSize.x>RS_MAXDOUBLE-1 || pSize.y>RS_MAXDOUBLE-1) { delete pat; delete copy; updateRunning = false; RS_DEBUG->print("RS_Hatch::update: contour size or pattern size too small"); updateError = HATCH_TOO_SMALL; return; } // avoid huge memory consumption: else if ( cSize.x* cSize.y/(pSize.x*pSize.y)>1e4) { RS_DEBUG->print("RS_Hatch::update: contour size too large or pattern size too small"); updateError = HATCH_AREA_TOO_BIG; return; } f = copy->getMin().x/pat->getSize().x; px1 = (int)floor(f); f = copy->getMin().y/pat->getSize().y; py1 = (int)floor(f); f = copy->getMax().x/pat->getSize().x; px2 = (int)ceil(f); f = copy->getMax().y/pat->getSize().y; py2 = (int)ceil(f); RS_Vector dvx=RS_Vector(data.angle)*pSize.x; RS_Vector dvy=RS_Vector(data.angle+M_PI*0.5)*pSize.y; pat->rotate(rot_center, data.angle); pat->move(-rot_center); RS_EntityContainer tmp; // container for untrimmed lines // adding array of patterns to tmp: RS_DEBUG->print("RS_Hatch::update: creating pattern carpet"); for (int px=px1; px<=px2; px++) { for (int py=py1; py<=py2; py++) { for (RS_Entity* e=pat->firstEntity(); e!=NULL; e=pat->nextEntity()) { RS_Entity* te=e->clone(); te->move(dvx*px + dvy*py); tmp.addEntity(te); } } } delete pat; pat = NULL; RS_DEBUG->print("RS_Hatch::update: creating pattern carpet: OK"); RS_DEBUG->print("RS_Hatch::update: cutting pattern carpet"); // cut pattern to contour shape: RS_EntityContainer tmp2; // container for small cut lines RS_Line* line = NULL; RS_Arc* arc = NULL; RS_Circle* circle = NULL; RS_Ellipse* ellipse = NULL; for (RS_Entity* e=tmp.firstEntity(); e!=NULL; e=tmp.nextEntity()) { RS_Vector startPoint; RS_Vector endPoint; RS_Vector center = RS_Vector(false); bool reversed=false; switch(e->rtti()){ case RS2::EntityLine: line=static_cast<RS_Line*>(e); startPoint = line->getStartpoint(); endPoint = line->getEndpoint(); break; case RS2::EntityArc: arc=static_cast<RS_Arc*>(e); startPoint = arc->getStartpoint(); endPoint = arc->getEndpoint(); center = arc->getCenter(); reversed = arc->isReversed(); break; case RS2::EntityCircle: circle=static_cast<RS_Circle*>(e); startPoint = circle->getCenter() + RS_Vector(circle->getRadius(), 0.0); endPoint = startPoint; center = circle->getCenter(); break; case RS2::EntityEllipse: ellipse = static_cast<RS_Ellipse*>(e); startPoint = ellipse->getStartpoint(); endPoint = ellipse->getEndpoint(); center = ellipse->getCenter(); reversed = ellipse->isReversed(); break; default: continue; } // getting all intersections of this pattern line with the contour: QList<std::shared_ptr<RS_Vector> > is; is.append(std::shared_ptr<RS_Vector>(new RS_Vector(startPoint))); for (RS_Entity* loop=firstEntity(); loop!=NULL; loop=nextEntity()) { if (loop->isContainer()) { for (RS_Entity* p=((RS_EntityContainer*)loop)->firstEntity(); p!=NULL; p=((RS_EntityContainer*)loop)->nextEntity()) { RS_VectorSolutions sol = RS_Information::getIntersection(e, p, true); for (int i=0; i<=1; ++i) { if (sol.get(i).valid) { is.append(std::shared_ptr<RS_Vector>( new RS_Vector(sol.get(i)) )); RS_DEBUG->print(" pattern line intersection: %f/%f", sol.get(i).x, sol.get(i).y); } } } } } is.append(std::shared_ptr<RS_Vector>(new RS_Vector(endPoint))); // sort the intersection points into is2: RS_Vector sp = startPoint; double sa = center.angleTo(sp); if(ellipse != NULL) sa=ellipse->getEllipseAngle(sp); QList<std::shared_ptr<RS_Vector> > is2; bool done; double minDist; double dist = 0.0; std::shared_ptr<RS_Vector> av; std::shared_ptr<RS_Vector> v; RS_Vector last = RS_Vector(false); do { done = true; minDist = RS_MAXDOUBLE; av.reset(); for (int i = 0; i < is.size(); ++i) { v = is.at(i); double a; switch(e->rtti()){ case RS2::EntityLine: dist = sp.distanceTo(*v); break; case RS2::EntityArc: case RS2::EntityCircle: a = center.angleTo(*v); dist = reversed? fmod(sa - a + 2.*M_PI,2.*M_PI): fmod(a - sa + 2.*M_PI,2.*M_PI); break; case RS2::EntityEllipse: a = ellipse->getEllipseAngle(*v); dist = reversed? fmod(sa - a + 2.*M_PI,2.*M_PI): fmod(a - sa + 2.*M_PI,2.*M_PI); break; default: break; } if (dist<minDist) { minDist = dist; done = false; av = v; } } // copy to sorted list, removing double points if (!done && av.get()!=NULL) { if (last.valid==false || last.distanceTo(*av)>RS_TOLERANCE) { is2.append(std::shared_ptr<RS_Vector>(new RS_Vector(*av))); last = *av; } #if QT_VERSION < 0x040400 emu_qt44_removeOne(is, av); #else is.removeOne(av); #endif av.reset(); } } while(!done); // add small cut lines / arcs to tmp2: for (int i = 1; i < is2.size(); ++i) { auto v1 = is2.at(i-1); auto v2 = is2.at(i); if (line!=NULL) { tmp2.addEntity(new RS_Line(&tmp2, RS_LineData(*v1, *v2))); } else if (arc!=NULL || circle!=NULL) { tmp2.addEntity(new RS_Arc(&tmp2, RS_ArcData(center, center.distanceTo(*v1), center.angleTo(*v1), center.angleTo(*v2), reversed))); } } } // updating hatch / adding entities that are inside RS_DEBUG->print("RS_Hatch::update: cutting pattern carpet: OK"); //RS_EntityContainer* rubbish = new RS_EntityContainer(getGraphic()); // the hatch pattern entities: hatch = new RS_EntityContainer(this); hatch->setPen(RS_Pen(RS2::FlagInvalid)); hatch->setLayer(NULL); hatch->setFlag(RS2::FlagTemp); //calculateBorders(); for (RS_Entity* e=tmp2.firstEntity(); e!=NULL; e=tmp2.nextEntity()) { RS_Vector middlePoint; RS_Vector middlePoint2; if (e->rtti()==RS2::EntityLine) { RS_Line* line = (RS_Line*)e; middlePoint = line->getMiddlePoint(); middlePoint2 = line->getNearestDist(line->getLength()/2.1, line->getStartpoint()); } else if (e->rtti()==RS2::EntityArc) { RS_Arc* arc = (RS_Arc*)e; middlePoint = arc->getMiddlePoint(); middlePoint2 = arc->getNearestDist(arc->getLength()/2.1, arc->getStartpoint()); } else { middlePoint = RS_Vector(false); middlePoint2 = RS_Vector(false); } if (middlePoint.valid) { bool onContour=false; if (RS_Information::isPointInsideContour( middlePoint, this, &onContour) || RS_Information::isPointInsideContour(middlePoint2, this)) { RS_Entity* te = e->clone(); te->setPen(RS_Pen(RS2::FlagInvalid)); te->setLayer(NULL); te->reparent(hatch); hatch->addEntity(te); } } } addEntity(hatch); //getGraphic()->addEntity(rubbish); forcedCalculateBorders(); // deactivate contour: activateContour(false); updateRunning = false; RS_DEBUG->print("RS_Hatch::update: OK"); }
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; }