/** * Creates a polygon with 'number' edges. * * @param center Center of the polygon. * @param corner The first corner of the polygon * @param number Number of edges / corners. */ RS_Line* RS_Creation::createPolygon(const RS_Vector& center, const RS_Vector& corner, int number) { // check given coords / number: if (!center.valid || !corner.valid || number<3) { return NULL; } RS_Line* ret = NULL; if (document!=NULL && handleUndo) { document->startUndoCycle(); } RS_Vector c1(false); RS_Vector c2 = corner; RS_Line* line; for (int n=1; n<=number; ++n) { c1 = c2; c2 = c2.rotate(center, (M_PI*2)/number); line = new RS_Line(container, RS_LineData(c1, c2)); line->setLayerToActive(); line->setPenToActive(); if (ret==NULL) { ret = line; } if (container!=NULL) { container->addEntity(line); } if (document!=NULL && handleUndo) { document->addUndoable(line); } if (graphicView!=NULL) { graphicView->drawEntity(line); } } if (document!=NULL && handleUndo) { document->endUndoCycle(); } return ret; }
RS_Vector RS_Image::getNearestDist(double distance, const RS_Vector& coord, double* dist) const{ RS_VectorSolutions const& corners = getCorners(); RS_VectorSolutions points; 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)}; RS_Vector const& vp = l.getNearestDist(distance, coord, dist); points.push_back(vp); } return points.getClosest(coord, dist); }
RS_Vector RS_Arc::getNearestOrthTan(const RS_Vector& coord, const RS_Line& normal, bool onEntity ) const { if ( !coord.valid ) { return RS_Vector(false); } double angle=normal.getAngle1(); RS_Vector vp; vp.setPolar(getRadius(),angle); std::vector<RS_Vector> sol; for(int i=0;i <= 1;i++){ if(!onEntity || RS_Math::isAngleBetween(angle,getAngle1(),getAngle2(),isReversed())) { if(i){ sol.push_back(- vp); }else { sol.push_back(vp); } } angle=RS_Math::correctAngle(angle+M_PI); } switch(sol.size()) { case 0: return RS_Vector(false); case 2: if( RS_Vector::dotP(sol[1],coord-getCenter())>0.) { vp=sol[1]; break; } default: vp=sol[0]; } return getCenter()+vp; }
RS_Vector RS_Ellipse::getNearestOrthTan(const RS_Vector& coord, const RS_Line& normal, bool onEntity ) { if ( !coord.valid ) { return RS_Vector(false); } RS_Vector direction=normal.getEndpoint() - normal.getStartpoint(); if (direction.squared()< RS_TOLERANCE*RS_TOLERANCE) { //undefined direction return RS_Vector(false); } //scale to ellipse angle RS_Vector aV(-getAngle()); direction.rotate(aV); double angle=direction.scale(RS_Vector(1.,getRatio())).angle(); double ra(getMajorRadius()); direction.set(ra*cos(angle),getRatio()*ra*sin(angle));//relative to center QList<RS_Vector> sol; for(int i=0;i<2;i++){ if(!onEntity || RS_Math::isAngleBetween(angle,getAngle1(),getAngle2(),isReversed())) { if(i){ sol.append(- direction); }else{ sol.append(direction); } } angle=RS_Math::correctAngle(angle+M_PI); } if(sol.size()<1) return RS_Vector(false); aV.y*=-1.; for(int i=0;i<sol.size();i++) sol[i].rotate(aV); RS_Vector vp; switch(sol.count()) { case 0: return RS_Vector(false); case 2: if( RS_Vector::dotP(sol[1],coord-getCenter())>0.) { vp=sol[1]; break; } default: vp=sol[0]; } return getCenter() + vp; }
void RS_GraphicView::zoomAutoY(bool axis) { if (container) { double visibleHeight = 0.0; double minY = RS_MAXDOUBLE; double maxY = RS_MINDOUBLE; bool noChange = false; for(auto e: *container){ if (e->rtti()==RS2::EntityLine) { RS_Line* l = (RS_Line*)e; double x1, x2; x1 = toGuiX(l->getStartpoint().x); x2 = toGuiX(l->getEndpoint().x); if ( ((x1 > 0.0) && (x1 < (double) getWidth())) || ((x2 > 0.0) && (x2 < (double) getWidth()))) { minY = std::min(minY, l->getStartpoint().y); minY = std::min(minY, l->getEndpoint().y); maxY = std::max(maxY, l->getStartpoint().y); maxY = std::max(maxY, l->getEndpoint().y); } } } if (axis) { visibleHeight = std::max(maxY, 0.0) - std::min(minY, 0.0); } else { visibleHeight = maxY-minY; } if (visibleHeight<1.0) { noChange = true; } double fy = 1.0; if (visibleHeight>1.0e-6) { fy = (getHeight()-borderTop-borderBottom) / visibleHeight; if (factor.y<0.000001) { noChange = true; } } if (noChange==false) { setFactorY(fy); //centerOffsetY(); offsetY = (int)((getHeight()-borderTop-borderBottom - (visibleHeight*factor.y))/2.0 - (minY*factor.y)) + borderBottom; adjustOffsetControls(); adjustZoomControls(); // updateGrid(); } RS_DEBUG->print("Auto zoom y ok"); } }
/** * create a tangent line which is orthogonal to the given RS_Line(normal) * @coord, the tangent line closest to this point * @normal, the line orthogonal to the tangent line * @circle, arc/circle/ellipse for tangent line * * Author: Dongxu Li */ RS_Line* RS_Creation::createLineOrthTan(const RS_Vector& coord, RS_Line* normal, RS_Entity* circle) { RS_Line* ret = NULL; // check given entities: if (circle==NULL||normal==NULL ||!coord.valid || ( circle->rtti()!=RS2::EntityArc && circle->rtti()!=RS2::EntityCircle && circle->rtti()!=RS2::EntityEllipse)) { return ret; } //if( normal->getLength()<RS_TOLERANCE) return ret;//line too short RS_Vector t0; // calculate tangent points for arcs / circles: t0= circle->getNearestOrthTan(coord,*normal,false); if(!t0.valid) return ret; RS_Vector vp(normal->getStartpoint()); RS_Vector direction(normal->getEndpoint() - vp); RS_Vector vpt(t0 - vp); double a=direction.squared(); if( a <RS_TOLERANCE*RS_TOLERANCE) { return NULL;//undefined direction } else { //find projection on the normal line vp += direction*( RS_Vector::dotP(direction,vpt)/a); if( fabs(vp.x - t0.x) <=RS_TOLERANCE || fabs(vp.y-t0.y)<=RS_TOLERANCE) { //t0 already on the given line, need to extend in the normal direction vp += RS_Vector(-direction.y,direction.x); } } if (document!=NULL && handleUndo) { document->startUndoCycle(); } ret = new RS_Line(container, RS_LineData(vp,t0)); ret->setLayerToActive(); ret->setPenToActive(); return ret; }
/** * create a tangent line which is orthogonal to the given RS_Line(normal) * @coord, the tangent line closest to this point * @normal, the line orthogonal to the tangent line * @circle, arc/circle/ellipse for tangent line * * Author: Dongxu Li */ RS_Line* RS_Creation::createLineOrthTan(const RS_Vector& coord, RS_Line* normal, RS_Entity* circle) { RS_Line* ret = nullptr; // check given entities: if(! (circle && normal)) return ret; if(! circle->isArc()) return ret; //if( normal->getLength()<RS_TOLERANCE) return ret;//line too short RS_Vector t0 = circle->getNearestOrthTan(coord,*normal,false); if(!t0.valid) return ret; RS_Vector vp=normal->getNearestPointOnEntity(t0, false); if (document && handleUndo) { document->startUndoCycle(); } ret = new RS_Line(container, RS_LineData(vp,t0)); ret->setLayerToActive(); ret->setPenToActive(); return ret; }
void RS_ActionDrawLineAngle::trigger() { RS_PreviewActionInterface::trigger(); preparePreview(); RS_Line* line = new RS_Line{container, *data}; line->setLayerToActive(); line->setPenToActive(); container->addEntity(line); // upd. undo list: if (document) { document->startUndoCycle(); document->addUndoable(line); document->endUndoCycle(); } graphicView->moveRelativeZero(data->startpoint); graphicView->redraw(RS2::RedrawDrawing); RS_DEBUG->print("RS_ActionDrawLineAngle::trigger(): line added: %d", line->getId()); }
void RS_ActionDrawLine::trigger() { RS_PreviewActionInterface::trigger(); RS_Line* line = new RS_Line(container, pPoints->data); line->setLayerToActive(); line->setPenToActive(); container->addEntity(line); // upd. undo list: if (document) { document->startUndoCycle(); document->addUndoable(line); document->endUndoCycle(); } graphicView->redraw(RS2::RedrawDrawing); graphicView->moveRelativeZero(pPoints->history.at(pPoints->historyIndex)); // graphicView->moveRelativeZero(line->getEndpoint()); RS_DEBUG->print("RS_ActionDrawLine::trigger(): line added: %d", line->getId()); }
void RS_ActionDrawLineHorVert::trigger() { RS_PreviewActionInterface::trigger(); RS_Line* line = new RS_Line(container, data); line->setLayerToActive(); line->setPenToActive(); container->addEntity(line); // upd. undo list: if (document!=NULL) { document->startUndoCycle(); document->addUndoable(line); document->endUndoCycle(); } graphicView->redraw(RS2::RedrawDrawing); graphicView->moveRelativeZero(line->getMiddlePoint()); RS_DEBUG->print("RS_ActionDrawLineHorVert::trigger():" " line added: %d", line->getId()); }
void QC_ActionGetPoint::mouseMoveEvent(QMouseEvent* e) { RS_DEBUG->print("QC_ActionGetPoint::mouseMoveEvent begin"); RS_Vector mouse = snapPoint(e); if(setTargetPoint){ if (referencePoint.valid) { targetPoint = mouse; deletePreview(); RS_Line *line =new RS_Line(preview, RS_LineData(referencePoint, mouse)); line->setPen(RS_Pen(RS_Color(0,0,0), RS2::Width00, RS2::DotLine )); preview->addEntity(line); RS_DEBUG->print("QC_ActionGetPoint::mouseMoveEvent: draw preview"); drawPreview(); preview->addSelectionFrom(*container); } } else { targetPoint = mouse; } RS_DEBUG->print("QC_ActionGetPoint::mouseMoveEvent end"); }
/** * create a tangent line which is orthogonal to the given RS_Line(normal) * @coord, the tangent line closest to this point * @normal, the line orthogonal to the tangent line * @circle, arc/circle/ellipse for tangent line * * Author: Dongxu Li */ RS_Line* RS_Creation::createLineOrthTan(const RS_Vector& coord, RS_Line* normal, RS_Entity* circle) { RS_Line* ret = NULL; // check given entities: if (circle==NULL||normal==NULL ||!coord.valid || ( circle->rtti()!=RS2::EntityArc && circle->rtti()!=RS2::EntityCircle && circle->rtti()!=RS2::EntityEllipse)) { return ret; } //if( normal->getLength()<RS_TOLERANCE) return ret;//line too short RS_Vector t0; // calculate tangent points for arcs / circles: t0= circle->getNearestOrthTan(coord,*normal,false); if(!t0.valid) return ret; RS_Vector vp(normal->getStartpoint()); RS_Vector direction(normal->getEndpoint() - vp); RS_Vector vpt(t0 - vp); if (document!=NULL && handleUndo) { document->startUndoCycle(); } double a=RS_Vector::dotP(vpt,vpt); if( a <RS_TOLERANCE*RS_TOLERANCE) { vp = t0 + direction;//selected line already a tangent } else { //find projection on the normal line vp += direction*( RS_Vector::dotP(direction,vpt)/RS_Vector::dotP(direction,direction)); } ret = new RS_Line(container, RS_LineData(vp,t0)); ret->setLayerToActive(); ret->setPenToActive(); return ret; }
RS_Vector RS_Image::getNearestPointOnEntity(const RS_Vector& coord, bool onEntity, double* dist, RS_Entity** entity) const{ if (entity) { *entity = const_cast<RS_Image*>(this); } RS_VectorSolutions const& corners =getCorners(); //allow selecting image by clicking within images, bug#3464626 if(containsPoint(coord)){ //if coord is within image if(dist) *dist=0.; return coord; } RS_VectorSolutions points; for (size_t i=0; i < corners.size(); ++i){ size_t const j = (i+1)%corners.size(); RS_Line const l{corners.at(i), corners.at(j)}; RS_Vector const vp = l.getNearestPointOnEntity(coord, onEntity); points.push_back(vp); } return points.getClosest(coord, dist); }
RS_Vector RS_Circle::getNearestOrthTan(const RS_Vector& coord, const RS_Line& normal, bool /*onEntity = false*/) { if ( !coord.valid) { return RS_Vector(false); } RS_Vector vp0(coord-getCenter()); RS_Vector vp1(normal.getAngle1()); double d=RS_Vector::dotP(vp0,vp1); if(d >= 0. ) { return getCenter() + vp1*getRadius(); }else{ return getCenter() - vp1*getRadius(); } }
void DL_Jww::CreateSen(DL_CreationInterface* creationInterface, CDataSen& DSen) { string lName = HEX[DSen.m_nGLayer > ArraySize(HEX)-1 ? ArraySize(HEX)-1: DSen.m_nGLayer] + "-" + HEX[DSen.m_nLayer > ArraySize(HEX)-1 ? ArraySize(HEX)-1: DSen.m_nLayer]; // add layer creationInterface->addLayer(DL_LayerData(lName,0)); //#ifdef DEBUG if(DSen.m_nPenStyle > ArraySize(lTable)-1) std::cout << "線種番号 " << (jwWORD)DSen.m_nPenStyle << std::endl; //線種番号 if(DSen.m_nPenColor > ArraySize(colTable)-1) std::cout << "線色番号 " << (jwWORD)DSen.m_nPenColor << std::endl; //線色番号 if(DSen.m_nPenWidth > 26) std::cout << "線色幅 " << (jwWORD)DSen.m_nPenWidth << std::endl;//線色幅 //#endif int width; if(DSen.m_nPenWidth > 26) width = 0; else width = DSen.m_nPenWidth; int color = colTable[DSen.m_nPenColor > ArraySize(colTable)-1 ? ArraySize(colTable)-1 : DSen.m_nPenColor]; attrib = DL_Attributes(values[8], // layer color, // color width, // width lTable[DSen.m_nPenStyle > ArraySize(lTable)-1 ? ArraySize(lTable)-1 : DSen.m_nPenStyle]); // linetype creationInterface->setAttributes(attrib); creationInterface->setExtrusion(0.0, 0.0, 1.0, 0.0 ); // correct some impossible attributes for layers: /* attrib = creationInterface->getAttributes(); if (attrib.getColor()==256 || attrib.getColor()==0) { attrib.setColor(7); } if (attrib.getWidth()<0) { attrib.setWidth(1); } if (!strcasecmp(attrib.getLineType().c_str(), "BYLAYER") || !strcasecmp(attrib.getLineType().c_str(), "BYBLOCK")) { attrib.setLineType("CONTINUOUS"); } */ DL_LineData d(DSen.m_start.x, DSen.m_start.y, 0.0, DSen.m_end.x, DSen.m_end.y, 0.0); creationInterface->addLine(d); #ifdef FINISHED RS_LineData data(RS_Vector(0.0, 0.0), RS_Vector(0.0, 0.0)); RS_Line* line; data.startpoint = RS_Vector(DSen.m_start.x, DSen.m_start.y); data.endpoint = RS_Vector(DSen.m_end.x, DSen.m_end.y); line = new RS_Line(graphic, data); RS2::LineType ltype = lTable[DSen.m_nPenStyle]; RS_Color col = colTable[DSen.m_nPenColor]; RS2::LineWidth lw = lWidth[DSen.m_nPenWidth>26 ? 0 : DSen.m_nPenWidth]; line->setPen(RS_Pen(col, lw, ltype)); //画層設定 //画層 // m_nGLayer-m_nLayer //_0-0_ から_0-F_ // ... //_F-0_ から_F-F_ RS_String lName = HEX[DSen.m_nGLayer > 0x0f ? 0: DSen.m_nGLayer] + "-" + HEX[DSen.m_nLayer > 0x0f ? 0: DSen.m_nLayer]; if( graphic->findLayer(lName) == (RS_Layer*)NULL ){ #ifdef DEBUG cout << jwdoc->vSen[i].m_nGLayer << " " << jwdoc->vSen[i].m_nLayer << endl; std::cout << lName.ascii() << std::endl; #endif RS_Layer* layer = new RS_Layer(lName); graphic->addLayer(layer); } line->setLayer(lName); #ifdef DEBUG std::cout << "線種番号 " << (jwWORD)DSen.m_nPenStyle << std::endl; //線種番号 std::cout << "線色番号 " << (jwWORD)DSen.m_nPenColor << std::endl; //線色番号 std::cout << "線色幅 " << (jwWORD)DSen.m_nPenWidth << std::endl;//線色幅 #endif // add the line to the graphic graphic->addEntity(line); std::cout << *line; #endif }
/** * 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); }
/** * 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) { removeEntity(hatch); hatch = nullptr; } 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) { 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"); delete pat; delete copy; updateError = HATCH_AREA_TOO_BIG; return; } f = copy->getMin().x/pSize.x; px1 = (int)floor(f); f = copy->getMin().y/pSize.y; py1 = (int)floor(f); f = copy->getMax().x/pSize.x; px2 = (int)ceil(f); f = copy->getMax().y/pSize.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(auto e: *pat){ RS_Entity* te=e->clone(); te->move(dvx*px + dvy*py); tmp.addEntity(te); } } } delete pat; pat = nullptr; delete copy; copy = nullptr; 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 = nullptr; RS_Arc* arc = nullptr; RS_Circle* circle = nullptr; RS_Ellipse* ellipse = nullptr; for(auto e: tmp){ line = nullptr; arc = nullptr; circle = nullptr; ellipse = nullptr; 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; for(auto loop: entities){ if (loop->isContainer()) { for(auto p: * static_cast<RS_EntityContainer*>(loop)){ RS_VectorSolutions sol = RS_Information::getIntersection(e, p, true); for (const RS_Vector& vp: sol){ if (vp.valid) { is.append(std::shared_ptr<RS_Vector>( new RS_Vector(vp) )); RS_DEBUG->print(" pattern line intersection: %f/%f", vp.x, vp.y); } } } } } QList<std::shared_ptr<RS_Vector> > is2;//to be filled with sorted intersections is2.append(std::shared_ptr<RS_Vector>(new RS_Vector(startPoint))); // sort the intersection points into is2 (only if there are intersections): if(is.size() == 1) {//only one intersection is2.append(is.first()); } else if(is.size() > 1) { RS_Vector sp = startPoint; double sa = center.angleTo(sp); if(ellipse ) sa=ellipse->getEllipseAngle(sp); 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()) { 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); } is2.append(std::shared_ptr<RS_Vector>(new RS_Vector(endPoint))); // 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) { tmp2.addEntity(new RS_Line{&tmp2, *v1, *v2}); } else if (arc || circle) { if(fabs(center.angleTo(*v2)-center.angleTo(*v1)) > RS_TOLERANCE_ANGLE) {//don't create an arc with a too small angle 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(nullptr); hatch->setFlag(RS2::FlagTemp); //calculateBorders(); for(auto e: tmp2){ RS_Vector middlePoint; RS_Vector middlePoint2; if (e->rtti()==RS2::EntityLine) { RS_Line* line = static_cast<RS_Line*>(e); middlePoint = line->getMiddlePoint(); middlePoint2 = line->getNearestDist(line->getLength()/2.1, line->getStartpoint()); } else if (e->rtti()==RS2::EntityArc) { RS_Arc* arc = static_cast<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(RS2::FlagInvalid); te->setLayer(nullptr); 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"); }
/** * Creates a dimensioning line (line with one, two or no arrows and a text). * * @param forceAutoText Automatically reposition the text label. */ void RS_Dimension::updateCreateDimensionLine(const RS_Vector& p1, const RS_Vector& p2, bool arrow1, bool arrow2, bool forceAutoText) { // general scale (DIMSCALE) double dimscale = getGeneralScale(); // text height (DIMTXT) double dimtxt = getTextHeight()*dimscale; // text distance to line (DIMGAP) double dimgap = getDimensionLineGap()*dimscale; // length of dimension line: double distance = p1.distanceTo(p2); // arrow size: double arrowSize = getArrowSize()*dimscale; // do we have to put the arrows outside of the line? bool outsideArrows = (distance<arrowSize*2.5); // arrow angles: double arrowAngle1, arrowAngle2; // Create dimension line: RS_Line* dimensionLine = new RS_Line(this, RS_LineData(p1, p2)); dimensionLine->setPen(RS_Pen(RS2::FlagInvalid)); dimensionLine->setLayer(NULL); addEntity(dimensionLine); if (outsideArrows==false) { arrowAngle1 = dimensionLine->getAngle2(); arrowAngle2 = dimensionLine->getAngle1(); } else { arrowAngle1 = dimensionLine->getAngle1(); arrowAngle2 = dimensionLine->getAngle2(); // extend dimension line outside arrows RS_Vector dir; dir.setPolar(arrowSize*2, arrowAngle2); dimensionLine->setStartpoint(p1 + dir); dimensionLine->setEndpoint(p2 - dir); } double dimtsz=getTickSize()*dimscale; if(dimtsz < 0.01) { //display arrow // Arrows: RS_SolidData sd; RS_Solid* arrow; if (arrow1) { // arrow 1 arrow = new RS_Solid(this, sd); arrow->shapeArrow(p1, arrowAngle1, arrowSize); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); } if (arrow2) { // arrow 2: arrow = new RS_Solid(this, sd); arrow->shapeArrow(p2, arrowAngle2, arrowSize); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); } }else{ //display ticks // Arrows: RS_Line* tick; RS_Vector tickVector; tickVector.setPolar(dimtsz,arrowAngle1 + M_PI*0.25); //tick is 45 degree away if (arrow1) { // tick 1 tick = new RS_Line(this, p1-tickVector, p1+tickVector); tick->setPen(RS_Pen(RS2::FlagInvalid)); tick->setLayer(NULL); addEntity(tick); } if (arrow2) { // tick 2: tick = new RS_Line(this, p2-tickVector, p2+tickVector); tick->setPen(RS_Pen(RS2::FlagInvalid)); tick->setLayer(NULL); addEntity(tick); } } // Text label: RS_MTextData textData; RS_Vector textPos; double dimAngle1 = dimensionLine->getAngle1(); double textAngle; bool corrected=false; if (getAlignText()) textAngle =0.0; else textAngle = RS_Math::makeAngleReadable(dimAngle1, true, &corrected); if (data.middleOfText.valid && !forceAutoText) { textPos = data.middleOfText; } else { textPos = dimensionLine->getMiddlePoint(); if (!getAlignText()) { RS_Vector distV; // rotate text so it's readable from the bottom or right (ISO) // quadrant 1 & 4 if (corrected) { distV.setPolar(dimgap + dimtxt/2.0, dimAngle1-M_PI/2.0); } else { distV.setPolar(dimgap + dimtxt/2.0, dimAngle1+M_PI/2.0); } // move text away from dimension line: textPos+=distV; } //// the next update should still be able to adjust this //// auto text position. leave it invalid data.middleOfText = textPos; } textData = RS_MTextData(textPos, dimtxt, 30.0, RS_MTextData::VAMiddle, RS_MTextData::HACenter, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, getLabel(), "standard", textAngle); RS_MText* text = new RS_MText(this, textData); // move text to the side: RS_Vector distH; if (text->getUsedTextWidth()>distance) { distH.setPolar(text->getUsedTextWidth()/2.0 +distance/2.0+dimgap, textAngle); text->move(distH); } text->setPen(RS_Pen(RS2::FlagInvalid)); text->setLayer(NULL); //horizontal text, split dimensionLine if (getAlignText()) { double w =text->getUsedTextWidth()/2+dimgap; double h = text->getUsedTextHeight()/2+dimgap; RS_Vector v1 = textPos - RS_Vector(w, h); RS_Vector v2 = textPos + RS_Vector(w, h); 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 sol1, sol2; int inters= 0; do { sol1 = RS_Information::getIntersection(dimensionLine, &(l[inters++]), true); } while (!sol1.hasValid() && inters < 4); if (!sol1.hasValid()) { do { sol2 = RS_Information::getIntersection(dimensionLine, &(l[inters++]), true); } while (!sol2.hasValid() && inters < 4); } //are text intersecting dimensionLine? if (sol1.hasValid() && sol2.hasValid()) { //yes, split dimension line RS_Line* dimensionLine2 = (RS_Line*)dimensionLine->clone(); v1 = sol1.get(0); v2 = sol2.get(0); if (p1.distanceTo(v1) < p1.distanceTo(v2)) { dimensionLine->setEndpoint(v1); dimensionLine2->setStartpoint(v2); } else { dimensionLine->setEndpoint(v2); dimensionLine2->setStartpoint(v1); } addEntity(dimensionLine2); } } addEntity(text); }
/** * Updates the sub entities of this dimension. Called when the * dimension or the position, alignment, .. changes. * * @param autoText Automatically reposition the text label */ void RS_DimAngular::update(bool /*autoText*/) { RS_DEBUG->print("RS_DimAngular::update"); clear(); if (isUndone()) { return; } // distance from entities (DIMEXO) double dimexo = getExtensionLineOffset(); // extension line extension (DIMEXE) double dimexe = getExtensionLineExtension(); // text height (DIMTXT) double dimtxt = getTextHeight(); // text distance to line (DIMGAP) double dimgap = getDimensionLineGap(); // find out center: RS_Vector center = getCenter(); if (!center.valid) { return; } double ang1 = 0.0; double ang2 = 0.0; bool reversed = false; RS_Vector p1; RS_Vector p2; getAngles(ang1, ang2, reversed, p1, p2); double rad = edata.definitionPoint4.distanceTo(center); RS_Line* line; RS_Vector dir; double len; double dist; // 1st extension line: dist = center.distanceTo(p1); len = rad - dist + dimexe; dir.setPolar(1.0, ang1); line = new RS_Line(this, RS_LineData(center + dir*dist + dir*dimexo, center + dir*dist + dir*len)); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); // 2nd extension line: dist = center.distanceTo(p2); len = rad - dist + dimexe; dir.setPolar(1.0, ang2); line = new RS_Line(this, RS_LineData(center + dir*dist + dir*dimexo, center + dir*dist + dir*len)); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); // Create dimension line (arc): RS_Arc* arc = new RS_Arc(this, RS_ArcData(center, rad, ang1, ang2, reversed)); arc->setPen(RS_Pen(RS2::FlagInvalid)); arc->setLayer(NULL); addEntity(arc); // length of dimension arc: double distance = arc->getLength(); // do we have to put the arrows outside of the arc? bool outsideArrows = (distance<getArrowSize()*2); // arrow angles: double arrowAngle1, arrowAngle2; double arrowAng; if (rad>1.0e-6) { arrowAng = getArrowSize() / rad; } else { arrowAng = 0.0; } RS_Vector v1, v2; if (!arc->isReversed()) { v1.setPolar(rad, arc->getAngle1()+arrowAng); } else { v1.setPolar(rad, arc->getAngle1()-arrowAng); } v1+=arc->getCenter(); arrowAngle1 = arc->getStartpoint().angleTo(v1); if (!arc->isReversed()) { v2.setPolar(rad, arc->getAngle2()-arrowAng); } else { v2.setPolar(rad, arc->getAngle2()+arrowAng); } v2+=arc->getCenter(); arrowAngle2 = arc->getEndpoint().angleTo(v2); if (!outsideArrows) { arrowAngle1 = arrowAngle1+M_PI; arrowAngle2 = arrowAngle2+M_PI; } // Arrows: RS_SolidData sd; RS_Solid* arrow; // arrow 1 arrow = new RS_Solid(this, sd); arrow->shapeArrow(arc->getStartpoint(), arrowAngle1, getArrowSize()); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); // arrow 2: arrow = new RS_Solid(this, sd); arrow->shapeArrow(arc->getEndpoint(), arrowAngle2, getArrowSize()); arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setLayer(NULL); addEntity(arrow); // text label: RS_TextData textData; RS_Vector textPos = arc->getMiddlePoint(); RS_Vector distV; double textAngle; double dimAngle1 = textPos.angleTo(arc->getCenter())-M_PI/2.0; // rotate text so it's readable from the bottom or right (ISO) // quadrant 1 & 4 if (dimAngle1>M_PI/2.0*3.0+0.001 || dimAngle1<M_PI/2.0+0.001) { distV.setPolar(dimgap, dimAngle1+M_PI/2.0); textAngle = dimAngle1; } // quadrant 2 & 3 else { distV.setPolar(dimgap, dimAngle1-M_PI/2.0); textAngle = dimAngle1+M_PI; } // move text away from dimension line: textPos+=distV; textData = RS_TextData(textPos, dimtxt, 30.0, RS2::VAlignBottom, RS2::HAlignCenter, RS2::LeftToRight, RS2::Exact, 1.0, getLabel(), "standard", textAngle); RS_Text* text = new RS_Text(this, textData); // move text to the side: text->setPen(RS_Pen(RS2::FlagInvalid)); text->setLayer(NULL); addEntity(text); calculateBorders(); }
/** * Creates a dimensioning line (line with one, two or no arrows and a text). * * @param forceAutoText Automatically reposition the text label. */ void RS_Dimension::updateCreateDimensionLine(const RS_Vector& p1, const RS_Vector& p2, bool arrow1, bool arrow2, bool forceAutoText) { // general scale (DIMSCALE) double dimscale = getGeneralScale(); // text height (DIMTXT) double dimtxt = getTextHeight()*dimscale; // text distance to line (DIMGAP) double dimgap = getDimensionLineGap()*dimscale; // length of dimension line: double distance = p1.distanceTo(p2); // arrow size: double arrowSize = getArrowSize()*dimscale; // do we have to put the arrows outside of the line? bool outsideArrows = (distance<arrowSize*2.5); // arrow angles: double arrowAngle1, arrowAngle2; RS_Pen pen(getDimensionLineColor(), getDimensionLineWidth(), RS2::LineByBlock); // Create dimension line: RS_Line* dimensionLine = new RS_Line{this, p1, p2}; dimensionLine->setPen(pen); // dimensionLine->setPen(RS_Pen(RS2::FlagInvalid)); dimensionLine->setLayer(nullptr); addEntity(dimensionLine); if (outsideArrows==false) { arrowAngle1 = dimensionLine->getAngle2(); arrowAngle2 = dimensionLine->getAngle1(); } else { arrowAngle1 = dimensionLine->getAngle1(); arrowAngle2 = dimensionLine->getAngle2(); // extend dimension line outside arrows RS_Vector dir = RS_Vector::polar(arrowSize*2, arrowAngle2); dimensionLine->setStartpoint(p1 + dir); dimensionLine->setEndpoint(p2 - dir); } double dimtsz=getTickSize()*dimscale; if(dimtsz < 0.01) { //display arrow // Arrows: RS_SolidData sd; RS_Solid* arrow; if (arrow1) { // arrow 1 arrow = new RS_Solid(this, sd); arrow->shapeArrow(p1, arrowAngle1, arrowSize); // arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setPen(pen); arrow->setLayer(nullptr); addEntity(arrow); } if (arrow2) { // arrow 2: arrow = new RS_Solid(this, sd); arrow->shapeArrow(p2, arrowAngle2, arrowSize); // arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setPen(pen); arrow->setLayer(nullptr); addEntity(arrow); } }else{ //display ticks // Arrows: RS_Line* tick; RS_Vector tickVector = RS_Vector::polar(dimtsz,arrowAngle1 + M_PI*0.25); //tick is 45 degree away if (arrow1) { // tick 1 tick = new RS_Line(this, p1-tickVector, p1+tickVector); tick->setPen(pen); // tick->setPen(RS_Pen(RS2::FlagInvalid)); tick->setLayer(nullptr); addEntity(tick); } if (arrow2) { // tick 2: tick = new RS_Line(this, p2-tickVector, p2+tickVector); tick->setPen(pen); // tick->setPen(RS_Pen(RS2::FlagInvalid)); tick->setLayer(nullptr); addEntity(tick); } } // Text label: RS_MTextData textData; RS_Vector textPos; double dimAngle1 = dimensionLine->getAngle1(); double textAngle; bool corrected=false; if (getAlignText()) textAngle =0.0; else textAngle = RS_Math::makeAngleReadable(dimAngle1, true, &corrected); if (data.middleOfText.valid && !forceAutoText) { textPos = data.middleOfText; } else { textPos = dimensionLine->getMiddlePoint(); if (!getAlignText()) { // rotate text so it's readable from the bottom or right (ISO) // quadrant 1 & 4 double const a = corrected?-M_PI_2:M_PI_2; RS_Vector distV = RS_Vector::polar(dimgap + dimtxt/2.0, dimAngle1+a); // move text away from dimension line: textPos+=distV; } //// the next update should still be able to adjust this //// auto text position. leave it invalid data.middleOfText = textPos; } textData = RS_MTextData(textPos, dimtxt, 30.0, RS_MTextData::VAMiddle, RS_MTextData::HACenter, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, getLabel(), getTextStyle(), // "standard", textAngle); RS_MText* text = new RS_MText(this, textData); // move text to the side: RS_Vector distH; if (text->getUsedTextWidth()>distance) { distH.setPolar(text->getUsedTextWidth()/2.0 +distance/2.0+dimgap, textAngle); text->move(distH); } text->setPen(RS_Pen(getTextColor(), RS2::WidthByBlock, RS2::SolidLine)); // text->setPen(RS_Pen(RS2::FlagInvalid)); text->setLayer(nullptr); //horizontal text, split dimensionLine if (getAlignText()) { double w =text->getUsedTextWidth()/2+dimgap; double h = text->getUsedTextHeight()/2+dimgap; RS_Vector v1 = textPos - RS_Vector{w, h}; RS_Vector v2 = textPos + RS_Vector{w, h}; RS_EntityContainer c; c.addRectangle(v1, v2); RS_VectorSolutions sol1; for(RS_Entity* e: c) { sol1.push_back( RS_Information::getIntersection(dimensionLine, e, true) ); } //are text intersecting dimensionLine? if (sol1.size()>1) { //yes, split dimension line RS_Line* dimensionLine2 = static_cast<RS_Line*>(dimensionLine->clone()); v1 = sol1.get(0); v2 = sol1.get(1); if (p1.distanceTo(v1) < p1.distanceTo(v2)) { dimensionLine->setEndpoint(v1); dimensionLine2->setStartpoint(v2); } else { dimensionLine->setEndpoint(v2); dimensionLine2->setStartpoint(v1); } addEntity(dimensionLine2); } } addEntity(text); }
/** * Updates the internal polygon of this spline. Called when the * spline or it's data, position, .. changes. */ void RS_Spline::update() { RS_DEBUG->print("RS_Spline::update"); clear(); if (isUndone()) { return; } if (data.degree<1 || data.degree>3) { RS_DEBUG->print("RS_Spline::update: invalid degree: %d", data.degree); return; } if (data.controlPoints.size() < data.degree+1) { RS_DEBUG->print("RS_Spline::update: not enough control points"); return; } resetBorders(); std::vector<RS_Vector> tControlPoints = data.controlPoints; if (data.closed) { for (size_t i=0; i<data.degree; ++i) { tControlPoints.push_back(data.controlPoints.at(i)); } } size_t i; const size_t npts = tControlPoints.size(); // order: const size_t k = data.degree+1; // resolution: const size_t p1 = getGraphicVariableInt("$SPLINESEGS", 8) * npts; std::vector<double> b(npts*3+1, 0.); std::vector<double> h(npts+1, 1.); std::vector<double> p(3*p1, 0.); i = 1; for (size_t it = 0; it < tControlPoints.size(); ++it) { b[i] = tControlPoints.at(it).x; b[i+1] = tControlPoints.at(it).y; RS_DEBUG->print("RS_Spline::update: b[%d]: %f/%f", i, b[i], b[i+1]); i+=3; } if (data.closed) { rbsplinu(npts,k,p1,b,h,p); } else { rbspline(npts,k,p1,b,h,p); } RS_Vector prev(false); for (i = 1; i <= 3*p1; i += 3) { if (prev.valid) { RS_Line* line = new RS_Line(this, RS_LineData(prev, RS_Vector(p[i], p[i+1]))); line->setLayer(nullptr); line->setPen(RS_Pen(RS2::FlagInvalid)); addEntity(line); } prev = RS_Vector(p[i], p[i+1]); minV = RS_Vector::minimum(prev, minV); maxV = RS_Vector::maximum(prev, maxV); } }
/** * Testing function. */ void LC_SimpleTests::slotTestInsertEllipse() { RS_DEBUG->print("%s\n: begin\n", __func__); auto appWin=QC_ApplicationWindow::getAppWindow(); RS_Document* d = appWin->getDocument(); if (d) { RS_Graphic* graphic = (RS_Graphic*)d; if (!graphic) { return; } RS_Ellipse* ellipse; RS_Line* line; for (double a=0.; a<2.*M_PI; a+=0.1) { RS_Vector v = RS_Vector::polar(50., a); double xp = 1000.*a; ellipse = new RS_Ellipse(graphic, {xp,0.}, v, 0.5, 0., 2.*M_PI, false); ellipse->setPen(RS_Pen(RS_Color(255, 0, 255), RS2::Width01, RS2::SolidLine)); graphic->addEntity(ellipse); //graphic->addEntity(new RS_Point(graphic, ellipse->getMax())); //graphic->addEntity(new RS_Point(graphic, ellipse->getMin())); line = new RS_Line{graphic, {xp, 0.}, RS_Vector{xp, 0.}+v}; line->setPen(RS_Pen(RS_Color(128, 128, 128), RS2::Width01, RS2::SolidLine)); graphic->addEntity(line); /* for (double mx=-60.0; mx<60.0; mx+=1.0) { //for (double mx=0.0; mx<1.0; mx+=2.5) { RS_VectorSolutions sol = ellipse->mapX(xp + mx); //graphic->addEntity(new RS_Point(graphic, // sol.vector2 + RS_Vector(a*500.0, 0.0))); //graphic->addEntity(new RS_Point(graphic, // sol.vector3 + RS_Vector(a*500.0, 0.0))); //graphic->addEntity(new RS_Point(graphic, // sol.vector4 + RS_Vector(a*500.0, 0.0))); line = new RS_Line(graphic, RS_LineData(RS_Vector(xp+mx,-50.0), RS_Vector(xp+mx,50.0))); line->setPen(RS_Pen(RS_Color(60, 60, 60), RS2::Width01, RS2::SolidLine)); graphic->addEntity(line); graphic->addEntity(new RS_Point(graphic, sol.get(0))); } */ } // different minor/minor relations /* double x, y; for (y=-250.0; y<=250.0; y+=50.0) { for (x=-250.0; x<=250.0; x+=50.0) { RS_Vector v(x, y); ellipse = new RS_Ellipse(graphic, v, RS_Vector((x/5+50.0)/2.0, 0.0), fabs(x/y), 0.0, 2*M_PI, false); ellipse->setPen(RS_Pen(RS_Color(255, 255, 0), RS2::Width01, RS2::DashDotLine)); graphic->addEntity(ellipse); graphic->addEntity(new RS_Point(graphic, ellipse->getMax())); graphic->addEntity(new RS_Point(graphic, ellipse->getMin())); ellipse = new RS_Ellipse(graphic, v + RS_Vector(750.0, 0.0), RS_Vector((x/5+50.0)/2.0, 0.0), fabs(x/y), 2*M_PI, 0.0, true); graphic->addEntity(ellipse); graphic->addEntity(new RS_Point(graphic, ellipse->getMax())); graphic->addEntity(new RS_Point(graphic, ellipse->getMin())); } } */ /* // different rotation angles: double rot; for (rot=0.0; rot<=2*M_PI+0.1; rot+=(M_PI/8)) { ellipse = new RS_Ellipse(graphic, RS_Vector(rot*200, 500.0), RS_Vector(50.0, 0.0).rotate(rot), 0.3, 0.0, 2*M_PI, false); graphic->addEntity(ellipse); graphic->addEntity(new RS_Point(graphic, ellipse->getMax())); graphic->addEntity(new RS_Point(graphic, ellipse->getMin())); } // different arc angles: double a1, a2; for (rot=0.0; rot<=2*M_PI+0.1; rot+=(M_PI/8)) { for (a1=0.0; a1<=2*M_PI+0.1; a1+=(M_PI/8)) { for (a2=a1+M_PI/8; a2<=2*M_PI+a1+0.1; a2+=(M_PI/8)) { ellipse = new RS_Ellipse(graphic, RS_Vector(-500.0-a1*200.0-5000.0*rot, 500.0-a2*200.0), RS_Vector(50.0, 0.0).rotate(rot), 0.3, a1, a2, false); graphic->addEntity(ellipse); graphic->addEntity(new RS_Point(graphic, ellipse->getMax())); graphic->addEntity(new RS_Point(graphic, ellipse->getMin())); } } } */ RS_GraphicView* v = appWin->getGraphicView(); if (v) { v->redraw(); } } RS_DEBUG->print("%s\n: end\n", __func__); }
/** * Testing function. */ void LC_SimpleTests::slotTestInsertBlock() { RS_DEBUG->print("%s\n: begin\n", __func__); auto appWin=QC_ApplicationWindow::getAppWindow(); RS_Document* d = appWin->getDocument(); if (d && d->rtti()==RS2::EntityGraphic) { RS_Graphic* graphic = (RS_Graphic*)d; if (graphic==NULL) { return; } graphic->addLayer(new RS_Layer("default")); RS_Block* block = new RS_Block(graphic, RS_BlockData("debugblock", RS_Vector(0.0,0.0), true)); RS_Line* line; RS_Arc* arc; RS_Circle* circle; // Add one red line: line = new RS_Line{block, {0.,0.}, {50.,0.}}; line->setLayerToActive(); line->setPen(RS_Pen(RS_Color(255, 0, 0), RS2::Width01, RS2::SolidLine)); block->addEntity(line); // Add one line with attributes from block: line = new RS_Line{block, {50.,0.}, {50.,50.}}; line->setPen(RS_Pen(RS_Color(RS2::FlagByBlock), RS2::WidthByBlock, RS2::LineByBlock)); block->addEntity(line); // Add one arc with attributes from block: RS_ArcData d({50.,0.}, 50.0, M_PI_2, M_PI, false); arc = new RS_Arc(block, d); arc->setPen(RS_Pen(RS_Color(RS2::FlagByBlock), RS2::WidthByBlock, RS2::LineByBlock)); block->addEntity(arc); // Add one blue circle: RS_CircleData circleData(RS_Vector(20.0,15.0), 12.5); circle = new RS_Circle(block, circleData); circle->setLayerToActive(); circle->setPen(RS_Pen(RS_Color(0, 0, 255), RS2::Width01, RS2::SolidLine)); block->addEntity(circle); graphic->addBlock(block); RS_Insert* ins; RS_InsertData insData("debugblock", RS_Vector(0.0,0.0), RS_Vector(1.0,1.0), 0.0, 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); // insert one magenta instance of the block (original): ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(255, 0, 255), RS2::Width02, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); // insert one green instance of the block (rotate): insData = RS_InsertData("debugblock", RS_Vector(-50.0,20.0), RS_Vector(1.0,1.0), M_PI/6., 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(0, 255, 0), RS2::Width02, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); // insert one cyan instance of the block (move): insData = RS_InsertData("debugblock", RS_Vector(10.0,20.0), RS_Vector(1.0,1.0), 0.0, 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width02, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); // insert one blue instance of the block: for (double a=0.0; a<360.0; a+=45.0) { insData = RS_InsertData("debugblock", RS_Vector(60.0,0.0), RS_Vector(2.0/5,2.0/5), RS_Math::deg2rad(a), 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(0, 0, 255), RS2::Width05, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); } // insert an array of yellow instances of the block: insData = RS_InsertData("debugblock", RS_Vector(-100.0,-100.0), RS_Vector(0.2,0.2), M_PI/6.0, 6, 4, RS_Vector(100.0, 100.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(255, 255, 0), RS2::Width01, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); RS_GraphicView* v = appWin->getGraphicView(); if (v) { v->redraw(); } } RS_DEBUG->print("%s\n: end\n", __func__); }
/** * Testing function. */ void LC_SimpleTests::slotTestDumpEntities(RS_EntityContainer* d){ int level = 0; std::ofstream dumpFile; if (d) { dumpFile.open("debug_entities.html", std::ios::app); ++level; } else { d = QC_ApplicationWindow::getAppWindow()->getDocument(); dumpFile.open("debug_entities.html"); level = 0; } if (d) { if (level==0) { dumpFile << "<html>\n"; dumpFile << "<body>\n"; } for(auto e: *d){ dumpFile << "<table border=\"1\">\n"; dumpFile << "<tr><td>Entity: " << e->getId() << "</td></tr>\n"; dumpFile << "<tr><td><table><tr>" << "<td>VIS:" << e->isVisible() << "</td>" << "<td>UND:" << e->isUndone() << "</td>" << "<td>SEL:" << e->isSelected() << "</td>" << "<td>TMP:" << e->getFlag(RS2::FlagTemp) << "</td>"; QString lay = "NULL"; if (e->getLayer()) { lay = e->getLayer()->getName(); } dumpFile << "<td>Layer: " << lay.toLatin1().data() << "</td>" << "<td>Width: " << (int)e->getPen(false).getWidth() << "</td>" << "<td>Parent: " << e->getParent()->getId() << "</td>" << "</tr></table>"; dumpFile << "<tr><td>\n"; switch (e->rtti()) { case RS2::EntityPoint: { RS_Point* p = (RS_Point*)e; dumpFile << "<table><tr><td>" << "<b>Point:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>" << p->getPos() << "</td>" << "</tr></table>"; } break; case RS2::EntityLine: { RS_Line* l = (RS_Line*)e; dumpFile << "<table><tr><td>" << "<b>Line:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>" << l->getStartpoint() << "</td>" << "<td>" << l->getEndpoint() << "</td>" << "</tr></table>"; } break; case RS2::EntityArc: { RS_Arc* a = (RS_Arc*)e; dumpFile << "<table><tr><td>" << "<b>Arc:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>Center: " << a->getCenter() << "</td>" << "<td>Radius: " << a->getRadius() << "</td>" << "<td>Angle 1: " << a->getAngle1() << "</td>" << "<td>Angle 2: " << a->getAngle2() << "</td>" << "<td>Startpoint: " << a->getStartpoint() << "</td>" << "<td>Endpoint: " << a->getEndpoint() << "</td>" << "<td>reversed: " << (int)a->isReversed() << "</td>" << "</tr></table>"; } break; case RS2::EntityCircle: { RS_Circle* c = (RS_Circle*)e; dumpFile << "<table><tr><td>" << "<b>Circle:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>Center: " << c->getCenter() << "</td>" << "<td>Radius: " << c->getRadius() << "</td>" << "</tr></table>"; } break; case RS2::EntityDimAligned: { RS_DimAligned* d = (RS_DimAligned*)e; dumpFile << "<table><tr><td>" << "<b>Dimension / Aligned:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>" << d->getDefinitionPoint() << "</td>" << "<td>" << d->getExtensionPoint1() << "</td>" << "<td>" << d->getExtensionPoint2() << "</td>" << "<td>Text: " << d->getText().toLatin1().data() << "</td>" << "<td>Label: " << d->getLabel().toLatin1().data() << "</td>" << "</tr></table>"; } break; case RS2::EntityDimLinear: { RS_DimLinear* d = (RS_DimLinear*)e; dumpFile << "<table><tr><td>" << "<b>Dimension / Linear:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>" << d->getDefinitionPoint() << "</td>" << "<td>" << d->getExtensionPoint1() << "</td>" << "<td>" << d->getExtensionPoint2() << "</td>" << "<td>Text: " << d->getText().toLatin1().data() << "</td>" << "<td>Label: " << d->getLabel().toLatin1().data() << "</td>" << "</tr></table>"; } break; case RS2::EntityInsert: { RS_Insert* i = (RS_Insert*)e; dumpFile << "<table><tr><td>" << "<b>Insert:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>Insertion point:" << i->getInsertionPoint() << "</td>" << "</tr></table>"; } break; case RS2::EntityMText: { RS_MText* t = (RS_MText*)e; dumpFile << "<table><tr><td>" << "<b>Text:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>Text:" << t->getText().toLatin1().data() << "</td>" << "<td>Height:" << t->getHeight() << "</td>" << "</tr></table>"; } break; case RS2::EntityText: { RS_Text* t = (RS_Text*)e; dumpFile << "<table><tr><td>" << "<b>Text:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>Text:" << t->getText().toLatin1().data() << "</td>" << "<td>Height:" << t->getHeight() << "</td>" << "</tr></table>"; } break; case RS2::EntityHatch: { RS_Hatch* h = (RS_Hatch*)e; dumpFile << "<table><tr><td>" << "<b>Hatch:</b>" << "</td></tr>"; dumpFile << "<tr>" << "<td>Pattern:" << h->getPattern().toLatin1().data() << "</td>" << "<td>Scale:" << h->getScale() << "</td>" << "<td>Solid:" << (int)h->isSolid() << "</td>" << "</tr></table>"; } break; default: dumpFile << "<tr><td>" << "<b>Unknown Entity: " << e->rtti() << "</b>" << "</td></tr>"; break; } if (e->isContainer() || e->rtti()==RS2::EntityHatch) { RS_EntityContainer* ec = (RS_EntityContainer*)e; dumpFile << "<table><tr><td valign=\"top\"> Contents:</td><td>\n"; dumpFile.close(); slotTestDumpEntities(ec); dumpFile.open("debug_entities.html", std::ios::app); dumpFile << "</td></tr></table>\n"; } dumpFile << "</td></tr>" << "</table>\n" << "<br><br>"; } if (level==0) { dumpFile << "</body>\n"; dumpFile << "</html>\n"; } else { level--; } } RS_DEBUG->print("%s\n: end\n", __func__); }
/** * Updates the internal polygon of this spline. Called when the * spline or it's data, position, .. changes. */ void RS_Spline::update() { RS_DEBUG->print("RS_Spline::update"); clear(); if (isUndone()) { return; } if (data.degree<1 || data.degree>3) { RS_DEBUG->print("RS_Spline::update: invalid degree: %d", data.degree); return; } if (data.controlPoints.size() < data.degree+1) { RS_DEBUG->print("RS_Spline::update: not enough control points"); return; } resetBorders(); QList<RS_Vector> tControlPoints = data.controlPoints; if (data.closed) { for (int i=0; i<data.degree; ++i) { tControlPoints.append(data.controlPoints.at(i)); } } int i; int npts = tControlPoints.count(); // order: int k = data.degree+1; // resolution: int p1 = getGraphicVariableInt("$SPLINESEGS", 8) * npts; double* b = new double[npts*3+1]; double* h = new double[npts+1]; double* p = new double[p1*3+1]; i = 1; for (int it = 0; it < tControlPoints.size(); ++it) { b[i] = tControlPoints.at(it).x; b[i+1] = tControlPoints.at(it).y; b[i+2] = 0.0; RS_DEBUG->print("RS_Spline::update: b[%d]: %f/%f", i, b[i], b[i+1]); i+=3; } // set all homogeneous weighting factors to 1.0 for (i=1; i <= npts; i++) { h[i] = 1.0; } for (i = 1; i <= 3*p1; i++) { p[i] = 0.0; } if (data.closed) { rbsplinu(npts,k,p1,b,h,p); } else { rbspline(npts,k,p1,b,h,p); } RS_Vector prev(false); for (i = 1; i <= 3*p1; i=i+3) { if (prev.valid) { RS_Line* line = new RS_Line(this, RS_LineData(prev, RS_Vector(p[i], p[i+1]))); line->setLayer(NULL); line->setPen(RS_Pen(RS2::FlagInvalid)); addEntity(line); } prev = RS_Vector(p[i], p[i+1]); minV = RS_Vector::minimum(prev, minV); maxV = RS_Vector::maximum(prev, maxV); } delete[] b; delete[] h; delete[] p; }
/** * Updates the sub entities of this dimension. Called when the * dimension or the position, alignment, .. changes. * * @param autoText Automatically reposition the text label */ void RS_DimRadial::updateDim(bool autoText) { RS_DEBUG->print("RS_DimRadial::update"); clear(); if (isUndone()) { return; } // dimension line: //updateCreateDimensionLine(data.definitionPoint, edata.definitionPoint, //false, true); // general scale (DIMSCALE) double dimscale = getGeneralScale(); RS_Vector p1 = data.definitionPoint; RS_Vector p2 = edata.definitionPoint; double angle = p1.angleTo(p2); // text height (DIMTXT) double dimtxt = getTextHeight()*dimscale; // text distance to line (DIMGAP) double dimgap = getDimensionLineGap()*dimscale; // arrow size: double arrowSize = getArrowSize()*dimscale; // length of dimension line: double length = p1.distanceTo(p2); RS_Pen pen(getDimensionLineColor(), getDimensionLineWidth(), RS2::LineByBlock); RS_MTextData textData; textData = RS_MTextData(RS_Vector(0.0,0.0), dimtxt, 30.0, RS_MTextData::VAMiddle, RS_MTextData::HACenter, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, getLabel(), getTextStyle(), // "standard", 0.0); RS_MText* text = new RS_MText(this, textData); double textWidth = text->getSize().x; // do we have to put the arrow / text outside of the arc? bool outsideArrow = (length<arrowSize*2+textWidth); double arrowAngle; if (outsideArrow) { length += arrowSize*2 + textWidth; arrowAngle = angle+M_PI; } else { arrowAngle = angle; } // create arrow: RS_SolidData sd; RS_Solid* arrow; arrow = new RS_Solid(this, sd); arrow->shapeArrow(p2, arrowAngle, arrowSize); // arrow->setPen(RS_Pen(RS2::FlagInvalid)); arrow->setPen(pen); arrow->setLayer(NULL); addEntity(arrow); RS_Vector p3; p3.setPolar(length, angle); p3 += p1; // Create dimension line: RS_Line* dimensionLine = new RS_Line(this, RS_LineData(p1, p3)); dimensionLine->setPen(pen); // dimensionLine->setPen(RS_Pen(RS2::FlagInvalid)); dimensionLine->setLayer(NULL); addEntity(dimensionLine); RS_Vector distV; double textAngle; // rotate text so it's readable from the bottom or right (ISO) // quadrant 1 & 4 if (angle>M_PI_2*3.0+0.001 || angle<M_PI_2+0.001) { distV.setPolar(dimgap + dimtxt/2.0, angle+M_PI_2); textAngle = angle; } // quadrant 2 & 3 else { distV.setPolar(dimgap + dimtxt/2.0, angle-M_PI_2); textAngle = angle+M_PI; } // move text label: RS_Vector textPos; if (data.middleOfText.valid && !autoText) { textPos = data.middleOfText; } else { if (outsideArrow) { textPos.setPolar(length-textWidth/2.0-arrowSize, angle); } else { textPos.setPolar(length/2.0, angle); } textPos+=p1; // move text away from dimension line: textPos += distV; data.middleOfText = textPos; } text->rotate(RS_Vector(0.0,0.0), textAngle); text->move(textPos); text->setPen(RS_Pen(getTextColor(), RS2::WidthByBlock, RS2::SolidLine)); // text->setPen(RS_Pen(RS2::FlagInvalid)); text->setLayer(NULL); addEntity(text); calculateBorders(); }
/** * Updates the sub entities of this dimension. Called when the * text or the position, alignment, .. changes. * * @param autoText Automatically reposition the text label */ void RS_DimLinear::update(bool autoText) { RS_DEBUG->print("RS_DimLinear::update"); clear(); if (isUndone()) { return; } // general scale (DIMSCALE) double dimscale = getGeneralScale(); // distance from entities (DIMEXO) double dimexo = getExtensionLineOffset()*dimscale; // extension line extension (DIMEXE) double dimexe = getExtensionLineExtension()*dimscale; RS_LineData ld; double extAngle = edata.angle + (M_PI/2.0); // direction of dimension line RS_Vector dirDim; dirDim.setPolar(100.0, edata.angle); // direction of extension lines RS_Vector dirExt; dirExt.setPolar(100.0, extAngle); // construction line for dimension line RS_ConstructionLine dimLine( NULL, RS_ConstructionLineData(data.definitionPoint, data.definitionPoint + dirDim)); RS_Vector dimP1 = dimLine.getNearestPointOnEntity(edata.extensionPoint1); RS_Vector dimP2 = dimLine.getNearestPointOnEntity(edata.extensionPoint2); // Definitive dimension line: updateCreateDimensionLine(dimP1, dimP2, true, true, autoText); /* ld = RS_LineData(data.definitionPoint, dimP1); RS_Line* dimensionLine = new RS_Line(this, ld); addEntity(dimensionLine); */ RS_Vector vDimexo1, vDimexe1, vDimexo2, vDimexe2; vDimexe1.setPolar(dimexe, edata.extensionPoint1.angleTo(dimP1)); vDimexo1.setPolar(dimexo, edata.extensionPoint1.angleTo(dimP1)); vDimexe2.setPolar(dimexe, edata.extensionPoint2.angleTo(dimP2)); vDimexo2.setPolar(dimexo, edata.extensionPoint2.angleTo(dimP2)); if ((edata.extensionPoint1-dimP1).magnitude()<1e-6) { vDimexe1.setPolar(dimexe, data.definitionPoint.angleTo(dimP1)-M_PI/2.0); vDimexo1.setPolar(dimexo, data.definitionPoint.angleTo(dimP1)-M_PI/2.0); } if ((edata.extensionPoint2-dimP2).magnitude()<1e-6) { vDimexe2.setPolar(dimexe, data.definitionPoint.angleTo(dimP2)-M_PI/2.0); vDimexo2.setPolar(dimexo, data.definitionPoint.angleTo(dimP2)-M_PI/2.0); } // extension lines: ld = RS_LineData(edata.extensionPoint1+vDimexo1, dimP1+vDimexe1); RS_Line* line = new RS_Line(this, ld); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); ld = RS_LineData(edata.extensionPoint2+vDimexo2, dimP2+vDimexe2); //data.definitionPoint+vDimexe2); line = new RS_Line(this, ld); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); calculateBorders(); }
/** * 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()); 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; 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"); 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 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"); return; } // avoid huge memory consumption: else if (cSize.x/pSize.x>100 || cSize.y/pSize.y>100) { RS_DEBUG->print("RS_Hatch::update: contour size too large or pattern size too small"); 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) - 1; f = copy->getMax().y/pat->getSize().y; py2 = (int)ceil(f) - 1; 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->rotate(RS_Vector(0.0,0.0), data.angle); RS_Vector v1, v2; v1.setPolar(px*pSize.x, data.angle); v2.setPolar(py*pSize.y, data.angle+M_PI/2.0); te->move(v1+v2); 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; 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"); }
void RS_Font::readCXF(QString path) { QString line; QFile f(path); f.open(QIODevice::ReadOnly); QTextStream ts(&f); // Read line by line until we find a new letter: while (!ts.atEnd()) { line = ts.readLine(); if (line.isEmpty()) continue; // Read font settings: if (line.at(0)=='#') { QStringList lst = ( line.right(line.length()-1) ).split(':', QString::SkipEmptyParts); QStringList::Iterator it3 = lst.begin(); // RVT_PORT sometimes it happens that the size is < 2 if (lst.size()<2) continue; QString identifier = (*it3).trimmed(); it3++; QString value = (*it3).trimmed(); if (identifier.toLower()=="letterspacing") { letterSpacing = value.toDouble(); } else if (identifier.toLower()=="wordspacing") { wordSpacing = value.toDouble(); } else if (identifier.toLower()=="linespacingfactor") { lineSpacingFactor = value.toDouble(); } else if (identifier.toLower()=="author") { authors.append(value); } else if (identifier.toLower()=="name") { names.append(value); } else if (identifier.toLower()=="encoding") { ts.setCodec(QTextCodec::codecForName(value.toLatin1())); encoding = value; } } // Add another letter to this font: else if (line.at(0)=='[') { // uniode character: QChar ch; // read unicode: QRegExp regexp("[0-9A-Fa-f]{4,4}"); regexp.indexIn(line); QString cap = regexp.cap(); if (!cap.isNull()) { int uCode = cap.toInt(nullptr, 16); ch = QChar(uCode); } // read UTF8 (LibreCAD 1 compatibility) else if (line.indexOf(']')>=3) { int i = line.indexOf(']'); QString mid = line.mid(1, i-1); ch = QString::fromUtf8(mid.toLatin1()).at(0); } // read normal ascii character: else { ch = line.at(1); } // create new letter: RS_FontChar* letter = new RS_FontChar(nullptr, ch, RS_Vector(0.0, 0.0)); // Read entities of this letter: QString coordsStr; QStringList coords; QStringList::Iterator it2; do { line = ts.readLine(); if (line.isEmpty()) { continue; } coordsStr = line.right(line.length()-2); // coords = QStringList::split(',', coordsStr); coords = coordsStr.split(',', QString::SkipEmptyParts); it2 = coords.begin(); // Line: if (line.at(0)=='L') { double x1 = (*it2++).toDouble(); double y1 = (*it2++).toDouble(); double x2 = (*it2++).toDouble(); double y2 = (*it2).toDouble(); RS_Line* line = new RS_Line{letter, {{x1, y1}, {x2, y2}}}; line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(nullptr); letter->addEntity(line); } // Arc: else if (line.at(0)=='A') { double cx = (*it2++).toDouble(); double cy = (*it2++).toDouble(); double r = (*it2++).toDouble(); double a1 = RS_Math::deg2rad((*it2++).toDouble()); double a2 = RS_Math::deg2rad((*it2).toDouble()); bool reversed = (line.at(1)=='R'); RS_ArcData ad(RS_Vector(cx,cy), r, a1, a2, reversed); RS_Arc* arc = new RS_Arc(letter, ad); arc->setPen(RS_Pen(RS2::FlagInvalid)); arc->setLayer(nullptr); letter->addEntity(arc); } } while (!line.isEmpty()); if (letter->isEmpty()) { delete letter; } else { letter->calculateBorders(); letterList.add(letter); } } } f.close(); }
RS_Entity* RS_Line::clone() { RS_Line* l = new RS_Line(*this); l->initId(); return l; }