RemoveLaneCommand::~RemoveLaneCommand() { if (!isUndone()) { delete oldLane_; } }
InsertLaneWidthCommand::~InsertLaneWidthCommand() { if (isUndone()) { delete newLaneWidth_; } }
InsertLaneCommand::~InsertLaneCommand() { if (isUndone()) { delete newLane_; } }
/** * Implementation of update. Updates the arrow. */ void RS_Leader::update() { // find and delete arrow: for(auto e: entities){ if (e->rtti()==RS2::EntitySolid) { removeEntity(e); break; } } if (isUndone()) { return; } RS_Entity* fe = firstEntity(); if (fe && fe->isAtomic()) { RS_Vector p1 = ((RS_AtomicEntity*)fe)->getStartpoint(); RS_Vector p2 = ((RS_AtomicEntity*)fe)->getEndpoint(); // first entity must be the line which gets the arrow: if (hasArrowHead()) { RS_Solid* s = new RS_Solid(this, RS_SolidData()); s->shapeArrow(p1, p2.angleTo(p1), getGraphicVariableDouble("$DIMASZ", 2.5)* getGraphicVariableDouble("$DIMSCALE", 1.0)); s->setPen(RS_Pen(RS2::FlagInvalid)); s->setLayer(nullptr); RS_EntityContainer::addEntity(s); } } calculateBorders(); }
/** * Implementation of update. Updates the arrow. */ void RS_Leader::update() { // find and delete arrow: for (RS_Entity* e=firstEntity(); e!=NULL; e=nextEntity()) { if (e->rtti()==RS2::EntitySolid) { removeEntity(e); break; } } if (isUndone()) { setVisible(false); return; } RS_Entity* fe = firstEntity(); if (fe!=NULL && fe->isAtomic()) { RS_Vector p1 = ((RS_AtomicEntity*)fe)->getStartpoint(); RS_Vector p2 = ((RS_AtomicEntity*)fe)->getEndpoint(); // first entity must be the line which gets the arrow: if (hasArrowHead()) { RS_Solid* s = new RS_Solid(this, RS_SolidData()); s->shapeArrow(p1, p2.angleTo(p1), getGraphicVariableDouble("$DIMASZ", 2.5)); s->setPen(RS_Pen(RS2::FlagInvalid)); s->setLayer(NULL); RS_EntityContainer::addEntity(s); } } }
/** * Undoes or redoes an undoable. */ void RS_Undoable::setUndoState(bool undone) { if (undone) { setFlag(RS2::FlagUndone); } else { delFlag(RS2::FlagUndone); } undoStateChanged(isUndone()); }
/** * 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)); } } 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> h(npts+1, 1.); std::vector<RS_Vector> p(p1, {0., 0.}); if (data.closed) { rbsplinu(npts,k,p1,tControlPoints,h,p); } else { rbspline(npts,k,p1,tControlPoints,h,p); } RS_Vector prev{}; for (auto const& vp: p) { if (prev.valid) { RS_Line* line = new RS_Line{this, prev, vp}; line->setLayer(nullptr); line->setPen(RS2::FlagInvalid); addEntity(line); } prev = vp; minV = RS_Vector::minimum(prev, minV); maxV = RS_Vector::maximum(prev, maxV); } }
/*! \brief Does nothing. */ SetTypeTypeSectionCommand::~SetTypeTypeSectionCommand() { // Clean up // // if (isUndone()) { // nothing to be done } else { // nothing to be done } }
/*! \brief Deletes the TypeSection if the command has been undone. * * Otherwise the RSystemElementRoad now ownes the TypeSection * and takes care of it. */ AddTypeSectionCommand::~AddTypeSectionCommand() { // Clean up // // if (isUndone()) { delete newTypeSection_; } else { // nothing to be done // the typeSection is now owned by the road } }
/*! \brief Does nothing. */ SetSpeedTypeSectionCommand::~SetSpeedTypeSectionCommand() { // Clean up // // if (isUndone()) { // nothing to be done } else { delete oldSpeedRecord; // nothing to be done } }
/** * 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_DimDiametric::updateDim(bool autoText) { RS_DEBUG->print("RS_DimDiametric::update"); clear(); if (isUndone()) { return; } // dimension line: updateCreateDimensionLine(data.definitionPoint, edata.definitionPoint, true, true, autoText); calculateBorders(); }
/*! \brief Deletes the TypeSection if the command has not been undone. * * Otherwise the RSystemElementRoad now ownes the TypeSection * and takes care of it. */ DeleteTypeSectionCommand::~DeleteTypeSectionCommand() { if (isValid()) // do not delete anything if this command hasn't been run. { // Clean up // // if (isUndone()) { // nothing to be done // the typeSection is now again owned by the road } else { delete deletedTypeSection_; } } }
/** * Updates the entity buffer of this insert entity. This method * needs to be called whenever the block this insert is based on changes. */ void RS_Insert::update() { RS_DEBUG->print("RS_Insert::update"); RS_DEBUG->print("RS_Insert::update: name: %s", data.name.toLatin1().data()); // RS_DEBUG->print("RS_Insert::update: insertionPoint: %f/%f", // data.insertionPoint.x, data.insertionPoint.y); if (updateEnabled==false) { return; } clear(); RS_Block* blk = getBlockForInsert(); if (blk==nullptr) { //return nullptr; RS_DEBUG->print("RS_Insert::update: Block is nullptr"); return; } if (isUndone()) { RS_DEBUG->print("RS_Insert::update: Insert is in undo list"); return; } if (fabs(data.scaleFactor.x)<1.0e-6 || fabs(data.scaleFactor.y)<1.0e-6) { RS_DEBUG->print("RS_Insert::update: scale factor is 0"); return; } RS_Pen tmpPen; /*QListIterator<RS_Entity> it = createIterator(); RS_Entity* e; while ( (e = it.current()) != nullptr ) { ++it;*/ RS_DEBUG->print("RS_Insert::update: cols: %d, rows: %d", data.cols, data.rows); RS_DEBUG->print("RS_Insert::update: block has %d entities", blk->count()); //int i_en_counts=0; for(auto e: *blk){ for (int c=0; c<data.cols; ++c) { // RS_DEBUG->print("RS_Insert::update: col %d", c); for (int r=0; r<data.rows; ++r) { // i_en_counts++; // RS_DEBUG->print("RS_Insert::update: row %d", r); if (e->rtti()==RS2::EntityInsert && data.updateMode!=RS2::PreviewUpdate) { // RS_DEBUG->print("RS_Insert::update: updating sub-insert"); ((RS_Insert*)e)->update(); } // RS_DEBUG->print("RS_Insert::update: cloning entity"); RS_Entity* ne; if ( (data.scaleFactor.x - data.scaleFactor.y)>1.0e-6) { if (e->rtti()== RS2::EntityArc) { RS_Arc* a= (RS_Arc*)e; ne = new RS_Ellipse(this, RS_EllipseData(a->getCenter(), RS_Vector(a->getRadius(), 0), 1, a->getAngle1(), a->getAngle2(), a->isReversed() )); ne->setLayer(e->getLayer()); ne->setPen(e->getPen(false)); } else if (e->rtti()== RS2::EntityCircle) { RS_Circle* a= (RS_Circle*)e; ne = new RS_Ellipse(this, RS_EllipseData(a->getCenter(), RS_Vector(a->getRadius(), 0), 1, 0.0,2.0*M_PI, false)); ne->setLayer(e->getLayer()); ne->setPen(e->getPen(false)); } else ne = e->clone(); } else ne = e->clone(); ne->initId(); ne->setUpdateEnabled(false); // if entity layer are 0 set to insert layer to allow "1 layer control" bug ID #3602152 RS_Layer *l= ne->getLayer();//special fontchar block don't have if (l != nullptr && ne->getLayer()->getName() == "0") ne->setLayer(this->getLayer()); ne->setParent(this); ne->setVisible(getFlag(RS2::FlagVisible)); // RS_DEBUG->print("RS_Insert::update: transforming entity"); // Move: // RS_DEBUG->print("RS_Insert::update: move 1"); if (fabs(data.scaleFactor.x)>1.0e-6 && fabs(data.scaleFactor.y)>1.0e-6) { ne->move(data.insertionPoint + RS_Vector(data.spacing.x/data.scaleFactor.x*c, data.spacing.y/data.scaleFactor.y*r)); } else { ne->move(data.insertionPoint); } // Move because of block base point: // RS_DEBUG->print("RS_Insert::update: move 2"); ne->move(blk->getBasePoint()*-1); // Scale: // RS_DEBUG->print("RS_Insert::update: scale"); ne->scale(data.insertionPoint, data.scaleFactor); // Rotate: // RS_DEBUG->print("RS_Insert::update: rotate"); ne->rotate(data.insertionPoint, data.angle); // Select: ne->setSelected(isSelected()); // individual entities can be on indiv. layers tmpPen = ne->getPen(false); // color from block (free floating): if (tmpPen.getColor()==RS_Color(RS2::FlagByBlock)) { tmpPen.setColor(getPen().getColor()); } // line width from block (free floating): if (tmpPen.getWidth()==RS2::WidthByBlock) { tmpPen.setWidth(getPen().getWidth()); } // line type from block (free floating): if (tmpPen.getLineType()==RS2::LineByBlock) { tmpPen.setLineType(getPen().getLineType()); } // now that we've evaluated all flags, let's strip them: // TODO: strip all flags (width, line type) //tmpPen.setColor(tmpPen.getColor().stripFlags()); ne->setPen(tmpPen); ne->setUpdateEnabled(true); if (data.updateMode!=RS2::PreviewUpdate) { // RS_DEBUG->print("RS_Insert::update: updating new entity"); ne->update(); } // RS_DEBUG->print("RS_Insert::update: adding new entity"); appendEntity(ne); // std::cout<<"done # of entity: "<<i_en_counts<<std::endl; } } } calculateBorders(); RS_DEBUG->print("RS_Insert::update: OK"); }
/** * 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::updateDim(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; // direction of dimension line RS_Vector dirDim = RS_Vector::polar(100.0, edata.angle); // construction line for dimension line RS_ConstructionLine dimLine( nullptr, 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); */ double extAngle1, extAngle2; if ((edata.extensionPoint1-dimP1).magnitude()<1e-6) { if ((edata.extensionPoint2-dimP2).magnitude()<1e-6) { //boot extension points are in dimension line only rotate 90 extAngle2 = edata.angle + (M_PI_2); } else { //first extension point are in dimension line use second extAngle2 = edata.extensionPoint2.angleTo(dimP2); } extAngle1 = extAngle2; } else { //first extension point not are in dimension line use it extAngle1 = edata.extensionPoint1.angleTo(dimP1); if ((edata.extensionPoint2-dimP2).magnitude()<1e-6) extAngle2 = extAngle1; else extAngle2 = edata.extensionPoint2.angleTo(dimP2); } RS_Vector vDimexe1 = RS_Vector::polar(dimexe, extAngle1); RS_Vector vDimexe2 = RS_Vector::polar(dimexe, extAngle2); RS_Vector vDimexo1, vDimexo2; if (getFixedLengthOn()){ double dimfxl = getFixedLength(); double extLength = (edata.extensionPoint1-dimP1).magnitude(); if (extLength-dimexo > dimfxl) vDimexo1.setPolar(extLength - dimfxl, extAngle1); extLength = (edata.extensionPoint2-dimP2).magnitude(); if (extLength-dimexo > dimfxl) vDimexo2.setPolar(extLength - dimfxl, extAngle2); } else { vDimexo1.setPolar(dimexo, extAngle1); vDimexo2.setPolar(dimexo, extAngle2); } RS_Pen pen(getExtensionLineColor(), getExtensionLineWidth(), RS2::LineByBlock); // extension lines: RS_Line* line = new RS_Line{this, edata.extensionPoint1+vDimexo1, dimP1+vDimexe1}; line->setPen(pen); // line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(nullptr); addEntity(line); //data.definitionPoint+vDimexe2); line = new RS_Line{this, edata.extensionPoint2+vDimexo2, dimP2+vDimexe2}; line->setPen(pen); // line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(nullptr); addEntity(line); calculateBorders(); }
/** * Is this entity visible? * * @return true Only if the entity and the layer it is on are visible. * The Layer might also be NULL. In that case the layer visiblity * is ignored. */ bool RS_Entity::isVisible() { if (!getFlag(RS2::FlagVisible)) { return false; } if (isUndone()) { return false; } /*RS_EntityCotnainer* parent = getParent(); if (parent!=NULL && parent->isUndone()) { return false; }*/ if (getLayer()==NULL) { return true; } // inserts are usually visible - the entities in them have their own // layers which might be frozen // upd: i'm not sure if that is the best behaviour //if (rtti()==RS2::EntityInsert) { // return true; //} if (layer!=NULL /*&& layer->getName()!="ByBlock"*/) { if (!layer->isFrozen()) { return true; } else { return false; } } if (layer==NULL /*&& getLayer()->getName()!="ByBlock"*/) { if (getLayer()==NULL) { return true; } else { if (!getLayer()->isFrozen()) { return true; } else { return false; } } } if (getBlockOrInsert()==NULL) { return true; } if (getBlockOrInsert()->rtti()==RS2::EntityBlock) { if (getLayer(false)==NULL || !getLayer(false)->isFrozen()) { return true; } else { return false; } } if (getBlockOrInsert()->getLayer()==NULL) { return true; } if(!getBlockOrInsert()->getLayer()->isFrozen()) { return true; } return false; }
/** * 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 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); } }
ListInsert::~ListInsert() { if ( isUndone() && newNode ) SAFE_DELETE(newNode); }
/** * Updates the entity buffer of this insert entity. This method * needs to be called whenever the block this insert is based on changes. */ void RS_Insert::update() { RS_DEBUG->print("RS_Insert::update"); RS_DEBUG->print("RS_Insert::update: name: %s", data.name.latin1()); RS_DEBUG->print("RS_Insert::update: insertionPoint: %f/%f", data.insertionPoint.x, data.insertionPoint.y); if (updateEnabled==false) { return; } clear(); RS_Block* blk = getBlockForInsert(); if (blk==NULL) { //return NULL; RS_DEBUG->print("RS_Insert::update: Block is NULL"); return; } if (isUndone()) { RS_DEBUG->print("RS_Insert::update: Insert is in undo list"); return; } if (fabs(data.scaleFactor.x)<1.0e-6 || fabs(data.scaleFactor.y)<1.0e-6) { RS_DEBUG->print("RS_Insert::update: scale factor is 0"); return; } RS_Pen tmpPen; /*RS_PtrListIterator<RS_Entity> it = createIterator(); RS_Entity* e; while ( (e = it.current()) != NULL ) { ++it;*/ RS_DEBUG->print("RS_Insert::update: cols: %d, rows: %d", data.cols, data.rows); RS_DEBUG->print("RS_Insert::update: block has %d entities", blk->count()); for (RS_Entity* e=blk->firstEntity(); e!=NULL; e=blk->nextEntity()) { for (int c=0; c<data.cols; ++c) { RS_DEBUG->print("RS_Insert::update: col %d", c); for (int r=0; r<data.rows; ++r) { RS_DEBUG->print("RS_Insert::update: row %d", r); if (e->rtti()==RS2::EntityInsert && data.updateMode!=RS2::PreviewUpdate) { RS_DEBUG->print("RS_Insert::update: updating sub-insert"); ((RS_Insert*)e)->update(); } RS_DEBUG->print("RS_Insert::update: cloning entity"); RS_Entity* ne = e->clone(); ne->initId(); ne->setUpdateEnabled(false); ne->setParent(this); ne->setVisible(getFlag(RS2::FlagVisible)); RS_DEBUG->print("RS_Insert::update: transforming entity"); // Move: RS_DEBUG->print("RS_Insert::update: move 1"); if (fabs(data.scaleFactor.x)>1.0e-6 && fabs(data.scaleFactor.y)>1.0e-6) { ne->move(data.insertionPoint + RS_Vector(data.spacing.x/data.scaleFactor.x*c, data.spacing.y/data.scaleFactor.y*r)); } else { ne->move(data.insertionPoint); } // Move because of block base point: RS_DEBUG->print("RS_Insert::update: move 2"); ne->move(blk->getBasePoint()*-1); // Scale: RS_DEBUG->print("RS_Insert::update: scale"); ne->scale(data.insertionPoint, data.scaleFactor); // Rotate: RS_DEBUG->print("RS_Insert::update: rotate"); ne->rotate(data.insertionPoint, data.angle); // Select: ne->setSelected(isSelected()); // individual entities can be on indiv. layers tmpPen = ne->getPen(false); // color from block (free floating): if (tmpPen.getColor()==RS_Color(RS2::FlagByBlock)) { tmpPen.setColor(getPen().getColor()); } // line width from block (free floating): if (tmpPen.getWidth()==RS2::WidthByBlock) { tmpPen.setWidth(getPen().getWidth()); } // line type from block (free floating): if (tmpPen.getLineType()==RS2::LineByBlock) { tmpPen.setLineType(getPen().getLineType()); } // now that we've evaluated all flags, let's strip them: // TODO: strip all flags (width, line type) //tmpPen.setColor(tmpPen.getColor().stripFlags()); ne->setPen(tmpPen); ne->setUpdateEnabled(true); if (data.updateMode!=RS2::PreviewUpdate) { RS_DEBUG->print("RS_Insert::update: updating new entity"); ne->update(); } RS_DEBUG->print("RS_Insert::update: adding new entity"); addEntity(ne); } } } calculateBorders(); RS_DEBUG->print("RS_Insert::update: OK"); }
/** * 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"); }
/** * The undoable thing gets activated if it was undone and * deactivated otherwise. */ void RS_Undoable::changeUndoState() { toggleFlag(RS2::FlagUndone); undoStateChanged(isUndone()); }
/** * 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_DimAligned::update(bool autoText) { RS_DEBUG->print("RS_DimAligned::update"); clear(); if (isUndone()) { return; } // general scale (DIMSCALE) double dimscale = getGeneralScale(); // distance from entities (DIMEXO) double dimexo = getExtensionLineOffset()*dimscale; // definition line definition (DIMEXE) double dimexe = getExtensionLineExtension()*dimscale; // text height (DIMTXT) //double dimtxt = getTextHeight(); // text distance to line (DIMGAP) //double dimgap = getDimensionLineGap(); // Angle from extension endpoints towards dimension line double extAngle = edata.extensionPoint2.angleTo(data.definitionPoint); // extension lines length double extLength = edata.extensionPoint2.distanceTo(data.definitionPoint); RS_Vector v1, v2, e1; RS_LineData ld; RS_Line* line; v1.setPolar(dimexo, extAngle); v2.setPolar(dimexe, extAngle); e1.setPolar(1.0, extAngle); // Extension line 1: ld = RS_LineData(edata.extensionPoint1 + v1, edata.extensionPoint1 + e1*extLength + v2); line = new RS_Line(this, ld); //line->setLayerToActive(); //line->setPenToActive(); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); // Extension line 2: ld = RS_LineData(edata.extensionPoint2 + v1, edata.extensionPoint2 + e1*extLength + v2); line = new RS_Line(this, ld); //line->setLayerToActive(); //line->setPenToActive(); line->setPen(RS_Pen(RS2::FlagInvalid)); line->setLayer(NULL); addEntity(line); // Dimension line: updateCreateDimensionLine(edata.extensionPoint1 + e1*extLength, edata.extensionPoint2 + e1*extLength, true, true, autoText); 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()); 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"); }
/** * 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_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(); }
/** * 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_DimAligned::updateDim(bool autoText) { RS_DEBUG->print("RS_DimAligned::update"); clear(); if (isUndone()) { return; } // general scale (DIMSCALE) double dimscale = getGeneralScale(); // distance from entities (DIMEXO) double dimexo = getExtensionLineOffset()*dimscale; // definition line definition (DIMEXE) double dimexe = getExtensionLineExtension()*dimscale; // text height (DIMTXT) //double dimtxt = getTextHeight(); // text distance to line (DIMGAP) //double dimgap = getDimensionLineGap(); // Angle from extension endpoints towards dimension line double extAngle = edata.extensionPoint2.angleTo(data.definitionPoint); // extension lines length double extLength = edata.extensionPoint2.distanceTo(data.definitionPoint); if (getFixedLengthOn()){ double dimfxl = getFixedLength(); if (extLength-dimexo > dimfxl) dimexo = extLength - dimfxl; } RS_Vector v1 = RS_Vector::polar(dimexo, extAngle); RS_Vector v2 = RS_Vector::polar(dimexe, extAngle); RS_Vector e1 = RS_Vector::polar(1.0, extAngle); RS_Pen pen(getExtensionLineColor(), getExtensionLineWidth(), RS2::LineByBlock); // Extension line 1: RS_Line* line = new RS_Line{this, edata.extensionPoint1 + v1, edata.extensionPoint1 + e1*extLength + v2}; //line->setLayerToActive(); //line->setPenToActive(); // line->setPen(RS_Pen(RS2::FlagInvalid)); line->setPen(pen); line->setLayer(nullptr); addEntity(line); // Extension line 2: line = new RS_Line{this, edata.extensionPoint2 + v1, edata.extensionPoint2 + e1*extLength + v2}; //line->setLayerToActive(); //line->setPenToActive(); // line->setPen(RS_Pen(RS2::FlagInvalid)); line->setPen(pen); line->setLayer(nullptr); addEntity(line); // Dimension line: updateCreateDimensionLine(edata.extensionPoint1 + e1*extLength, edata.extensionPoint2 + e1*extLength, true, true, autoText); calculateBorders(); }
/** * Updates the Inserts (letters) of this text. Called when the * text or it's data, position, alignment, .. changes. * This method also updates the usedTextWidth / usedTextHeight property. */ void RS_MText::update() { RS_DEBUG->print("RS_Text::update"); clear(); if (isUndone()) { return; } usedTextWidth = 0.0; usedTextHeight = 0.0; RS_Font* font = RS_FONTLIST->requestFont(data.style); if (font==NULL) { return; } RS_Vector letterPos = RS_Vector(0.0, -9.0); RS_Vector letterSpace = RS_Vector(font->getLetterSpacing(), 0.0); RS_Vector space = RS_Vector(font->getWordSpacing(), 0.0); int lineCounter = 0; // Every single text line gets stored in this entity container // so we can move the whole line around easely: RS_EntityContainer* oneLine = new RS_EntityContainer(this); // First every text line is created with // alignement: top left // angle: 0 // height: 9.0 // Rotation, scaling and centering is done later // For every letter: for (int i=0; i<(int)data.text.length(); ++i) { bool handled = false; switch (data.text.at(i).unicode()) { case 0x0A: // line feed: updateAddLine(oneLine, lineCounter++); oneLine = new RS_EntityContainer(this); letterPos = RS_Vector(0.0, -9.0); break; case 0x20: // Space: letterPos+=space; break; case 0x5C: { // code (e.g. \S, \P, ..) i++; int ch = data.text.at(i).unicode(); switch (ch) { case 'P': updateAddLine(oneLine, lineCounter++); oneLine = new RS_EntityContainer(this); letterPos = RS_Vector(0.0, -9.0); handled = true; break; case 'f': case 'F': //font change // \f{symbol} changes font to symbol // \f{} sets font to standard { i++; if(data.text.at(i).unicode()!='{') { i--; continue; } int j=data.text.indexOf('}',i); if(j>i){ // QString fontName; if(j==i+1) fontName="standard"; else fontName=data.text.mid(i+1,j-i-1); RS_Font* fontNew = RS_FONTLIST->requestFont( fontName ); if(fontNew != NULL) { font=fontNew; } if(font==NULL) font = RS_FONTLIST->requestFont("standard"); i=j; } } continue; case 'S': { QString up; QString dw; //letterPos += letterSpace; // get upper string: i++; while (data.text.at(i).unicode()!='^' && //data.text.at(i).unicode()!='/' && data.text.at(i).unicode()!='\\' && //data.text.at(i).unicode()!='#' && i<(int)data.text.length()) { up += data.text.at(i); i++; } i++; if (data.text.at(i-1).unicode()=='^' && data.text.at(i).unicode()==' ') { i++; } // get lower string: while (data.text.at(i).unicode()!=';' && i<(int)data.text.length()) { dw += data.text.at(i); i++; } // add texts: RS_MText* upper = new RS_MText( oneLine, RS_MTextData(letterPos + RS_Vector(0.0,9.0), 4.0, 100.0, RS_MTextData::VATop, RS_MTextData::HALeft, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, up, data.style, 0.0, RS2::Update)); upper->setLayer(NULL); upper->setPen(RS_Pen(RS2::FlagInvalid)); oneLine->addEntity(upper); RS_MText* lower = new RS_MText( oneLine, RS_MTextData(letterPos+RS_Vector(0.0,4.0), 4.0, 100.0, RS_MTextData::VATop, RS_MTextData::HALeft, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, dw, data.style, 0.0, RS2::Update)); lower->setLayer(NULL); lower->setPen(RS_Pen(RS2::FlagInvalid)); oneLine->addEntity(lower); // move cursor: upper->calculateBorders(); lower->calculateBorders(); double w1 = upper->getSize().x; double w2 = lower->getSize().x; if (w1>w2) { letterPos += RS_Vector(w1, 0.0); } else { letterPos += RS_Vector(w2, 0.0); } letterPos += letterSpace; } handled = true; break; default: i--; break; } } //if char is not handled continue in default: statement if (handled) break; default: { // One Letter: QString letterText = QString(data.text.at(i)); if (font->findLetter(letterText) == NULL) { RS_DEBUG->print("RS_Text::update: missing font for letter( %s ), replaced it with QChar(0xfffd)",qPrintable(letterText)); letterText = QChar(0xfffd); } // if (font->findLetter(QString(data.text.at(i))) != NULL) { RS_DEBUG->print("RS_Text::update: insert a " "letter at pos: %f/%f", letterPos.x, letterPos.y); RS_InsertData d(letterText, letterPos, RS_Vector(1.0, 1.0), 0.0, 1,1, RS_Vector(0.0,0.0), font->getLetterList(), RS2::NoUpdate); RS_Insert* letter = new RS_Insert(this, d); RS_Vector letterWidth; letter->setPen(RS_Pen(RS2::FlagInvalid)); letter->setLayer(NULL); letter->update(); letter->forcedCalculateBorders(); // until 2.0.4.5: //letterWidth = RS_Vector(letter->getSize().x, 0.0); // from 2.0.4.6: letterWidth = RS_Vector(letter->getMax().x-letterPos.x, 0.0); if (letterWidth.x < 0) letterWidth.x = -letterSpace.x; oneLine->addEntity(letter); // next letter position: letterPos += letterWidth; letterPos += letterSpace; // } } break; } } double tt = updateAddLine(oneLine, lineCounter); if (data.valign == RS_MTextData::VABottom) { RS_Vector ot = RS_Vector(0.0,-tt).rotate(data.angle); RS_EntityContainer::move(ot); } usedTextHeight -= data.height*data.lineSpacingFactor*5.0/3.0 - data.height; forcedCalculateBorders(); RS_DEBUG->print("RS_Text::update: OK"); }
/** * 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 Inserts (letters) of this text. Called when the * text or it's data, position, alignment, .. changes. * This method also updates the usedTextWidth / usedTextHeight property. */ void RS_Text::update() { RS_DEBUG->print("RS_Text::update"); clear(); if (isUndone()) { return; } usedTextWidth = 0.0; usedTextHeight = 0.0; RS_Font* font = RS_FONTLIST->requestFont(data.style); if (font==NULL) { return; } RS_Vector letterPos = RS_Vector(0.0, -9.0); RS_Vector letterSpace = RS_Vector(font->getLetterSpacing(), 0.0); RS_Vector space = RS_Vector(font->getWordSpacing(), 0.0); // First every text line is created with // alignement: top left // angle: 0 // height: 9.0 // Rotation, scaling and centering is done later // For every letter: for (int i=0; i<(int)data.text.length(); ++i) { // Space: if (data.text.at(i).unicode() == 0x20) { letterPos+=space; } else { // One Letter: QString letterText = QString(data.text.at(i)); if (font->findLetter(letterText) == NULL) { RS_DEBUG->print("RS_Text::update: missing font for letter( %s ), replaced it with QChar(0xfffd)",qPrintable(letterText)); letterText = QChar(0xfffd); } RS_DEBUG->print("RS_Text::update: insert a " "letter at pos: %f/%f", letterPos.x, letterPos.y); RS_InsertData d(letterText, letterPos, RS_Vector(1.0, 1.0), 0.0, 1,1, RS_Vector(0.0,0.0), font->getLetterList(), RS2::NoUpdate); RS_Insert* letter = new RS_Insert(this, d); RS_Vector letterWidth; letter->setPen(RS_Pen(RS2::FlagInvalid)); letter->setLayer(NULL); letter->update(); letter->forcedCalculateBorders(); letterWidth = RS_Vector(letter->getMax().x-letterPos.x, 0.0); if (letterWidth.x < 0) letterWidth.x = -letterSpace.x; // oneLine->addEntity(letter); addEntity(letter); // next letter position: letterPos += letterWidth; letterPos += letterSpace; } } if( ! RS_EntityContainer::autoUpdateBorders) { //only update borders when needed forcedCalculateBorders(); } RS_Vector textSize = getSize(); RS_DEBUG->print("RS_Text::updateAddLine: width 2: %f", textSize.x); // Vertical Align: double vSize = 9.0; //HAAligned, HAFit, HAMiddle require VABaseline if (data.halign == RS_TextData::HAAligned || data.halign == RS_TextData::HAFit || data.halign == RS_TextData::HAMiddle) { data.valign = RS_TextData::VABaseline; } RS_Vector offset(0.0, 0.0); switch (data.valign) { case RS_TextData::VAMiddle: offset.move(RS_Vector(0.0, vSize/2.0)); break; case RS_TextData::VABottom: offset.move(RS_Vector(0.0, vSize+3)); break; case RS_TextData::VABaseline: offset.move(RS_Vector(0.0, vSize)); break; default: break; } // Horizontal Align: switch (data.halign) { case RS_TextData::HAMiddle:{ offset.move(RS_Vector(-textSize.x/2.0, -(vSize + textSize.y/2.0 + getMin().y) )); break;} case RS_TextData::HACenter: RS_DEBUG->print("RS_Text::updateAddLine: move by: %f", -textSize.x/2.0); offset.move(RS_Vector(-textSize.x/2.0, 0.0)); break; case RS_TextData::HARight: offset.move(RS_Vector(-textSize.x, 0.0)); break; default: break; } if (data.halign!=RS_TextData::HAAligned && data.halign!=RS_TextData::HAFit){ data.secondPoint = RS_Vector(offset.x, offset.y - vSize); } RS_EntityContainer::move(offset); // Scale: if (data.halign==RS_TextData::HAAligned){ double dist = data.insertionPoint.distanceTo(data.secondPoint)/textSize.x; data.height = vSize*dist; RS_EntityContainer::scale(RS_Vector(0.0,0.0), RS_Vector(dist, dist)); } else if (data.halign==RS_TextData::HAFit){ double dist = data.insertionPoint.distanceTo(data.secondPoint)/textSize.x; RS_EntityContainer::scale(RS_Vector(0.0,0.0), RS_Vector(dist, data.height/9.0)); } else { RS_EntityContainer::scale(RS_Vector(0.0,0.0), RS_Vector(data.height*data.widthRel/9.0, data.height/9.0)); data.secondPoint.scale(RS_Vector(0.0,0.0), RS_Vector(data.height*data.widthRel/9.0, data.height/9.0)); } forcedCalculateBorders(); // Update actual text size (before rotating, after scaling!): usedTextWidth = getSize().x; usedTextHeight = data.height; // Rotate: if (data.halign==RS_TextData::HAAligned || data.halign==RS_TextData::HAFit){ double angle = data.insertionPoint.angleTo(data.secondPoint); data.angle = angle; } else { data.secondPoint.rotate(RS_Vector(0.0,0.0), data.angle); data.secondPoint.move(data.insertionPoint); } RS_EntityContainer::rotate(RS_Vector(0.0,0.0), data.angle); // Move to insertion point: RS_EntityContainer::move(data.insertionPoint); forcedCalculateBorders(); RS_DEBUG->print("RS_Text::update: OK"); }
/** * Is this entity visible? * * @return true Only if the entity and the layer it is on are visible. * The Layer might also be nullptr. In that case the layer visiblity * is ignored. */ bool RS_Entity::isVisible() const{ if (!getFlag(RS2::FlagVisible)) { return false; } if (isUndone()) { return false; } /*RS_EntityCotnainer* parent = getParent(); if (parent && parent->isUndone()) { return false; }*/ if (!getLayer()) { return true; } // inserts are usually visible - the entities in them have their own // layers which might be frozen // upd: i'm not sure if that is the best behaviour //if (rtti()==RS2::EntityInsert) { // return true; //} // blocks are visible in editting window, issue#253 if( isDocument() && (rtti()==RS2::EntityBlock || rtti()==RS2::EntityInsert)) { return true; } if (layer /*&& layer->getName()!="ByBlock"*/) { if (!layer->isFrozen()) { return true; } else { return false; } } if (!layer /*&& getLayer()->getName()!="ByBlock"*/) { if (!getLayer()) { return true; } else { if (!getLayer()->isFrozen()) { return true; } else { return false; } } } if (!getBlockOrInsert()) { return true; } if (getBlockOrInsert()->rtti()==RS2::EntityBlock) { return !(getLayer(false) && getLayer(false)->isFrozen()); } if (!getBlockOrInsert()->getLayer()) { return true; } if (!getBlockOrInsert()->getLayer()->isFrozen()) { return true; } return false; }