/** * Adds all entities in the given range and those which have endpoints * in the given range to the preview. */ void RS_Preview::addStretchablesFrom(RS_EntityContainer& container, const RS_Vector& v1, const RS_Vector& v2) { int c=0; for (RS_Entity* e=container.firstEntity(); e!=NULL; e=container.nextEntity()) { if (e->isVisible() && e->rtti()!=RS2::EntityHatch && ((e->isInWindow(v1, v2)) || e->hasEndpointsWithinWindow(v1, v2)) && c<maxEntities) { RS_Entity* clone = e->clone(); //clone->setSelected(false); clone->reparent(this); c+=clone->countDeep(); addEntity(clone); // clone might be NULL after this point } } }
/** * Selects all entities within the given area. * * @param select True to select, False to deselect the entities. */ void RS_EntityContainer::selectWindow(RS_Vector v1, RS_Vector v2, bool select, bool cross) { bool included; for (RS_Entity* e=firstEntity(RS2::ResolveNone); e!=NULL; e=nextEntity(RS2::ResolveNone)) { included = false; if (e->isVisible()) { if (e->isInWindow(v1, v2)) { //e->setSelected(select); included = true; } else if (cross==true) { RS_Line l[] = { RS_Line(NULL, RS_LineData(v1, RS_Vector(v2.x, v1.y))), RS_Line(NULL, RS_LineData(RS_Vector(v2.x, v1.y), v2)), RS_Line(NULL, RS_LineData(v2, RS_Vector(v1.x, v2.y))), RS_Line(NULL, RS_LineData(RS_Vector(v1.x, v2.y), v1)) }; RS_VectorSolutions sol; if (e->isContainer()) { RS_EntityContainer* ec = (RS_EntityContainer*)e; for (RS_Entity* se=ec->firstEntity(RS2::ResolveAll); se!=NULL && included==false; se=ec->nextEntity(RS2::ResolveAll)) { for (int i=0; i<4; ++i) { sol = RS_Information::getIntersection( se, &l[i], true); if (sol.hasValid()) { included = true; break; } } } } else { for (int i=0; i<4; ++i) { sol = RS_Information::getIntersection(e, &l[i], true); if (sol.hasValid()) { included = true; break; } } } } } if (included) { e->setSelected(select); } } }
/** * Selects all entities within the given area. * * @param select True to select, False to deselect the entities. */ void RS_EntityContainer::selectWindow(RS_Vector v1, RS_Vector v2, bool select, bool cross) { bool included; for(auto e: entities){ included = false; if (e->isVisible()) { if (e->isInWindow(v1, v2)) { //e->setSelected(select); included = true; } else if (cross) { RS_EntityContainer l; l.addRectangle(v1, v2); RS_VectorSolutions sol; if (e->isContainer()) { RS_EntityContainer* ec = (RS_EntityContainer*)e; for (RS_Entity* se=ec->firstEntity(RS2::ResolveAll); se && included==false; se=ec->nextEntity(RS2::ResolveAll)) { if (se->rtti() == RS2::EntitySolid){ included = static_cast<RS_Solid*>(se)->isInCrossWindow(v1,v2); } else { for (auto line: l) { sol = RS_Information::getIntersection( se, line, true); if (sol.hasValid()) { included = true; break; } } } } } else if (e->rtti() == RS2::EntitySolid){ included = static_cast<RS_Solid*>(e)->isInCrossWindow(v1,v2); } else { for (auto line: l) { sol = RS_Information::getIntersection(e, line, true); if (sol.hasValid()) { included = true; break; } } } } } if (included) { e->setSelected(select); } } }
void RS_ActionBlocksRemove::trigger() { RS_DEBUG->print("RS_ActionBlocksRemove::trigger"); if (graphic!=NULL) { RS_Block* block = RS_DIALOGFACTORY->requestBlockRemovalDialog(graphic->getBlockList()); // list of containers that might refer to the block via inserts: RS_PtrList<RS_EntityContainer> containerList; containerList.append(graphic); RS_BlockList* blkLst = graphic->getBlockList(); for (uint bi=0; bi<blkLst->count(); bi++) { containerList.append(blkLst->at(bi)); } if (block!=NULL) { for (RS_EntityContainer* cont = containerList.first(); cont!=NULL; cont=containerList.next()) { // remove all inserts from the graphic: bool done; do { done = true; for (RS_Entity* e=cont->firstEntity(RS2::ResolveNone); e!=NULL; e=cont->nextEntity(RS2::ResolveNone)) { if (e->rtti()==RS2::EntityInsert) { RS_Insert* ins = (RS_Insert*)e; if (ins->getName()==block->getName()) { cont->removeEntity(ins); done = false; break; } } } } while (!done); } // close all windows that are editing this block: if (RS_DIALOGFACTORY!=NULL) { RS_DIALOGFACTORY->closeEditBlockWindow(block); } // Now remove the block from the block list: graphic->removeBlock(block); graphic->updateInserts(); graphicView->redraw(); } } finish(); RS_DIALOGFACTORY->updateSelectionWidget(container->countSelected()); }
/** * Selects all entities that are intersected by the given line. * * @param v1 Startpoint of line. * @param v2 Endpoint of line. * @param select true: select, false: deselect */ void RS_Selection::selectIntersected(const RS_Vector& v1, const RS_Vector& v2, bool select) { RS_Line line(NULL, RS_LineData(v1, v2)); bool inters; for (RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity()) { //for (uint i=0; i<container->count(); ++i) { //RS_Entity* e = container->entityAt(i); if (e!=NULL && e->isVisible()) { inters = false; // select containers / groups: if (e->isContainer()) { RS_EntityContainer* ec = (RS_EntityContainer*)e; for (RS_Entity* e2=ec->firstEntity(RS2::ResolveAll); e2!=NULL; e2=ec->nextEntity(RS2::ResolveAll)) { RS_VectorSolutions sol = RS_Information::getIntersection(&line, e2, true); if (sol.hasValid()) { inters = true; } } } else { RS_VectorSolutions sol = RS_Information::getIntersection(&line, e, true); if (sol.hasValid()) { inters = true; } } if (inters) { if (graphicView!=NULL) { graphicView->deleteEntity(e); } e->setSelected(select); if (graphicView!=NULL) { graphicView->drawEntity(e); } } } } }
RS_ActionInfoInside::RS_ActionInfoInside(RS_EntityContainer& container, RS_GraphicView& graphicView) :RS_ActionInterface("Info Inside", container, graphicView) { contour = new RS_EntityContainer(NULL, false); for (RS_Entity* e=container.firstEntity(); e!=NULL; e=container.nextEntity()) { if (e->isSelected()) { contour->addEntity(e); } } }
void QG_GraphicView::layerActivated(RS_Layer *layer) { if(m_bUpdateLayer==false) return; RS_EntityContainer *container = this->getContainer(); RS_Entity *entity = container->firstEntity(); while (entity != NULL) { if (entity->isSelected()) { entity->setLayer(layer); } entity = container->nextEntity(); } container->setSelected(false); redraw(RS2::RedrawDrawing); }
/** * Adds all selected entities from 'container' to the preview (unselected). */ void RS_Preview::addSelectionFrom(RS_EntityContainer& container) { int c=0; for (RS_Entity* e=container.firstEntity(); e!=NULL; e=container.nextEntity()) { if (e->isSelected() && c<maxEntities) { RS_Entity* clone = e->clone(); clone->setSelected(false); clone->reparent(this); c+=clone->countDeep(); addEntity(clone); // clone might be NULL after this point } } }
/** * Overrides drawing of subentities. This is only ever called for solid fills. */ void RS_Hatch::draw(RS_Painter* painter, RS_GraphicView* view, double& /*patternOffset*/) { if (!data.solid) { for (RS_Entity* se=firstEntity(); se!=NULL; se = nextEntity()) { view->drawEntity(painter,se); } return; } QPainterPath path; QList<QPolygon> paClosed; QPolygon pa; // QPolygon jp; // jump points // loops: if (needOptimization==true) { for (RS_Entity* l=firstEntity(RS2::ResolveNone); l!=NULL; l=nextEntity(RS2::ResolveNone)) { if (l->rtti()==RS2::EntityContainer) { RS_EntityContainer* loop = (RS_EntityContainer*)l; loop->optimizeContours(); } } needOptimization = false; } // loops: for (RS_Entity* l=firstEntity(RS2::ResolveNone); l!=NULL; l=nextEntity(RS2::ResolveNone)) { l->setLayer(getLayer()); if (l->rtti()==RS2::EntityContainer) { RS_EntityContainer* loop = (RS_EntityContainer*)l; // edges: for (RS_Entity* e=loop->firstEntity(RS2::ResolveNone); e!=NULL; e=loop->nextEntity(RS2::ResolveNone)) { e->setLayer(getLayer()); switch (e->rtti()) { case RS2::EntityLine: { QPoint pt1(RS_Math::round(view->toGuiX(e->getStartpoint().x)), RS_Math::round(view->toGuiY(e->getStartpoint().y))); QPoint pt2(RS_Math::round(view->toGuiX(e->getEndpoint().x)), RS_Math::round(view->toGuiY(e->getEndpoint().y))); // if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) { // jp<<pt1; // } pa<<pt1<<pt2; } break; case RS2::EntityArc: { // QPoint pt1(RS_Math::round(view->toGuiX(e->getStartpoint().x)), // RS_Math::round(view->toGuiY(e->getStartpoint().y))); // if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) { // jp<<pt1; // } QPolygon pa2; RS_Arc* arc=static_cast<RS_Arc*>(e); painter->createArc(pa2, view->toGui(arc->getCenter()), view->toGuiDX(arc->getRadius()), arc->getAngle1(), arc->getAngle2(), arc->isReversed()); pa<<pa2; } break; case RS2::EntityCircle: { RS_Circle* circle = static_cast<RS_Circle*>(e); // QPoint pt1(RS_Math::round(view->toGuiX(circle->getCenter().x+circle->getRadius())), // RS_Math::round(view->toGuiY(circle->getCenter().y))); // if (! (pa.size()>0 && (pa.last() - pt1).manhattanLength()<=2)) { // jp<<pt1; // } RS_Vector c=view->toGui(circle->getCenter()); double r=view->toGuiDX(circle->getRadius()); #if QT_VERSION >= 0x040400 path.addEllipse(QPoint(c.x,c.y),r,r); #else path.addEllipse(c.x - r, c.y + r, 2.*r, 2.*r); // QPolygon pa2; // painter->createArc(pa2, view->toGui(circle->getCenter()), // view->toGuiDX(circle->getRadius()), // 0.0, // 2*M_PI, // false); // pa<<pa2; #endif } break; case RS2::EntityEllipse: if(static_cast<RS_Ellipse*>(e)->isArc()) { QPolygon pa2; auto ellipse=static_cast<RS_Ellipse*>(e); painter->createEllipse(pa2, view->toGui(ellipse->getCenter()), view->toGuiDX(ellipse->getMajorRadius()), view->toGuiDX(ellipse->getMinorRadius()), ellipse->getAngle(), ellipse->getAngle1(), ellipse->getAngle2(), ellipse->isReversed() ); pa<<pa2; }else{ QPolygon pa2; auto ellipse=static_cast<RS_Ellipse*>(e); painter->createEllipse(pa2, view->toGui(ellipse->getCenter()), view->toGuiDX(ellipse->getMajorRadius()), view->toGuiDX(ellipse->getMinorRadius()), ellipse->getAngle(), ellipse->getAngle1(), ellipse->getAngle2(), ellipse->isReversed() ); path.addPolygon(pa2); } break; default: break; } if( pa.size()>2 && pa.first() == pa.last()) { paClosed<<pa; pa.clear(); } } } } if(pa.size()>2){ pa<<pa.first(); paClosed<<pa; } for(int i=0;i<paClosed.size();i++){ path.addPolygon(paClosed.at(i)); } painter->setBrush(painter->getPen().getColor()); painter->disablePen(); painter->drawPath(path); // pa<<jp; // painter->setBrush(painter->getPen().getColor()); // painter->disablePen(); // painter->drawPolygon(pa); }
/** * Updates the Hatch. Called when the * hatch or it's data, position, alignment, .. changes. */ void RS_Hatch::update() { RS_DEBUG->print("RS_Hatch::update"); RS_DEBUG->print("RS_Hatch::update: contour has %d loops", count()); updateError = HATCH_OK; if (updateRunning) { return; } if (updateEnabled==false) { return; } if (data.solid==true) { calculateBorders(); return; } RS_DEBUG->print("RS_Hatch::update"); updateRunning = true; // delete old hatch: if (hatch!=NULL) { removeEntity(hatch); hatch = NULL; } if (isUndone()) { updateRunning = false; return; } if (!validate()) { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Hatch::update: invalid contour in hatch found"); updateRunning = false; updateError = HATCH_INVALID_CONTOUR; return; } // search pattern: RS_DEBUG->print("RS_Hatch::update: requesting pattern"); RS_Pattern* pat = RS_PATTERNLIST->requestPattern(data.pattern); if (pat==NULL) { updateRunning = false; RS_DEBUG->print("RS_Hatch::update: requesting pattern: not found"); updateError = HATCH_PATTERN_NOT_FOUND; return; } RS_DEBUG->print("RS_Hatch::update: requesting pattern: OK"); RS_DEBUG->print("RS_Hatch::update: cloning pattern"); pat = (RS_Pattern*)pat->clone(); RS_DEBUG->print("RS_Hatch::update: cloning pattern: OK"); // scale pattern RS_DEBUG->print("RS_Hatch::update: scaling pattern"); pat->scale(RS_Vector(0.0,0.0), RS_Vector(data.scale, data.scale)); pat->calculateBorders(); forcedCalculateBorders(); RS_DEBUG->print("RS_Hatch::update: scaling pattern: OK"); // find out how many pattern-instances we need in x/y: int px1, py1, px2, py2; double f; RS_Hatch* copy = (RS_Hatch*)this->clone(); copy->rotate(RS_Vector(0.0,0.0), -data.angle); copy->forcedCalculateBorders(); // create a pattern over the whole contour. RS_Vector pSize = pat->getSize(); RS_Vector rot_center=pat->getMin(); // RS_Vector cPos = getMin(); RS_Vector cSize = getSize(); RS_DEBUG->print("RS_Hatch::update: pattern size: %f/%f", pSize.x, pSize.y); RS_DEBUG->print("RS_Hatch::update: contour size: %f/%f", cSize.x, cSize.y); if (cSize.x<1.0e-6 || cSize.y<1.0e-6 || pSize.x<1.0e-6 || pSize.y<1.0e-6 || cSize.x>RS_MAXDOUBLE-1 || cSize.y>RS_MAXDOUBLE-1 || pSize.x>RS_MAXDOUBLE-1 || pSize.y>RS_MAXDOUBLE-1) { delete pat; delete copy; updateRunning = false; RS_DEBUG->print("RS_Hatch::update: contour size or pattern size too small"); updateError = HATCH_TOO_SMALL; return; } // avoid huge memory consumption: else if ( cSize.x* cSize.y/(pSize.x*pSize.y)>1e4) { RS_DEBUG->print("RS_Hatch::update: contour size too large or pattern size too small"); updateError = HATCH_AREA_TOO_BIG; return; } f = copy->getMin().x/pat->getSize().x; px1 = (int)floor(f); f = copy->getMin().y/pat->getSize().y; py1 = (int)floor(f); f = copy->getMax().x/pat->getSize().x; px2 = (int)ceil(f); f = copy->getMax().y/pat->getSize().y; py2 = (int)ceil(f); RS_Vector dvx=RS_Vector(data.angle)*pSize.x; RS_Vector dvy=RS_Vector(data.angle+M_PI*0.5)*pSize.y; pat->rotate(rot_center, data.angle); pat->move(-rot_center); RS_EntityContainer tmp; // container for untrimmed lines // adding array of patterns to tmp: RS_DEBUG->print("RS_Hatch::update: creating pattern carpet"); for (int px=px1; px<=px2; px++) { for (int py=py1; py<=py2; py++) { for (RS_Entity* e=pat->firstEntity(); e!=NULL; e=pat->nextEntity()) { RS_Entity* te=e->clone(); te->move(dvx*px + dvy*py); tmp.addEntity(te); } } } delete pat; pat = NULL; RS_DEBUG->print("RS_Hatch::update: creating pattern carpet: OK"); RS_DEBUG->print("RS_Hatch::update: cutting pattern carpet"); // cut pattern to contour shape: RS_EntityContainer tmp2; // container for small cut lines RS_Line* line = NULL; RS_Arc* arc = NULL; RS_Circle* circle = NULL; RS_Ellipse* ellipse = NULL; for (RS_Entity* e=tmp.firstEntity(); e!=NULL; e=tmp.nextEntity()) { RS_Vector startPoint; RS_Vector endPoint; RS_Vector center = RS_Vector(false); bool reversed=false; switch(e->rtti()){ case RS2::EntityLine: line=static_cast<RS_Line*>(e); startPoint = line->getStartpoint(); endPoint = line->getEndpoint(); break; case RS2::EntityArc: arc=static_cast<RS_Arc*>(e); startPoint = arc->getStartpoint(); endPoint = arc->getEndpoint(); center = arc->getCenter(); reversed = arc->isReversed(); break; case RS2::EntityCircle: circle=static_cast<RS_Circle*>(e); startPoint = circle->getCenter() + RS_Vector(circle->getRadius(), 0.0); endPoint = startPoint; center = circle->getCenter(); break; case RS2::EntityEllipse: ellipse = static_cast<RS_Ellipse*>(e); startPoint = ellipse->getStartpoint(); endPoint = ellipse->getEndpoint(); center = ellipse->getCenter(); reversed = ellipse->isReversed(); break; default: continue; } // getting all intersections of this pattern line with the contour: QList<std::shared_ptr<RS_Vector> > is; is.append(std::shared_ptr<RS_Vector>(new RS_Vector(startPoint))); for (RS_Entity* loop=firstEntity(); loop!=NULL; loop=nextEntity()) { if (loop->isContainer()) { for (RS_Entity* p=((RS_EntityContainer*)loop)->firstEntity(); p!=NULL; p=((RS_EntityContainer*)loop)->nextEntity()) { RS_VectorSolutions sol = RS_Information::getIntersection(e, p, true); for (int i=0; i<=1; ++i) { if (sol.get(i).valid) { is.append(std::shared_ptr<RS_Vector>( new RS_Vector(sol.get(i)) )); RS_DEBUG->print(" pattern line intersection: %f/%f", sol.get(i).x, sol.get(i).y); } } } } } is.append(std::shared_ptr<RS_Vector>(new RS_Vector(endPoint))); // sort the intersection points into is2: RS_Vector sp = startPoint; double sa = center.angleTo(sp); if(ellipse != NULL) sa=ellipse->getEllipseAngle(sp); QList<std::shared_ptr<RS_Vector> > is2; bool done; double minDist; double dist = 0.0; std::shared_ptr<RS_Vector> av; std::shared_ptr<RS_Vector> v; RS_Vector last = RS_Vector(false); do { done = true; minDist = RS_MAXDOUBLE; av.reset(); for (int i = 0; i < is.size(); ++i) { v = is.at(i); double a; switch(e->rtti()){ case RS2::EntityLine: dist = sp.distanceTo(*v); break; case RS2::EntityArc: case RS2::EntityCircle: a = center.angleTo(*v); dist = reversed? fmod(sa - a + 2.*M_PI,2.*M_PI): fmod(a - sa + 2.*M_PI,2.*M_PI); break; case RS2::EntityEllipse: a = ellipse->getEllipseAngle(*v); dist = reversed? fmod(sa - a + 2.*M_PI,2.*M_PI): fmod(a - sa + 2.*M_PI,2.*M_PI); break; default: break; } if (dist<minDist) { minDist = dist; done = false; av = v; } } // copy to sorted list, removing double points if (!done && av.get()!=NULL) { if (last.valid==false || last.distanceTo(*av)>RS_TOLERANCE) { is2.append(std::shared_ptr<RS_Vector>(new RS_Vector(*av))); last = *av; } #if QT_VERSION < 0x040400 emu_qt44_removeOne(is, av); #else is.removeOne(av); #endif av.reset(); } } while(!done); // add small cut lines / arcs to tmp2: for (int i = 1; i < is2.size(); ++i) { auto v1 = is2.at(i-1); auto v2 = is2.at(i); if (line!=NULL) { tmp2.addEntity(new RS_Line(&tmp2, RS_LineData(*v1, *v2))); } else if (arc!=NULL || circle!=NULL) { tmp2.addEntity(new RS_Arc(&tmp2, RS_ArcData(center, center.distanceTo(*v1), center.angleTo(*v1), center.angleTo(*v2), reversed))); } } } // updating hatch / adding entities that are inside RS_DEBUG->print("RS_Hatch::update: cutting pattern carpet: OK"); //RS_EntityContainer* rubbish = new RS_EntityContainer(getGraphic()); // the hatch pattern entities: hatch = new RS_EntityContainer(this); hatch->setPen(RS_Pen(RS2::FlagInvalid)); hatch->setLayer(NULL); hatch->setFlag(RS2::FlagTemp); //calculateBorders(); for (RS_Entity* e=tmp2.firstEntity(); e!=NULL; e=tmp2.nextEntity()) { RS_Vector middlePoint; RS_Vector middlePoint2; if (e->rtti()==RS2::EntityLine) { RS_Line* line = (RS_Line*)e; middlePoint = line->getMiddlePoint(); middlePoint2 = line->getNearestDist(line->getLength()/2.1, line->getStartpoint()); } else if (e->rtti()==RS2::EntityArc) { RS_Arc* arc = (RS_Arc*)e; middlePoint = arc->getMiddlePoint(); middlePoint2 = arc->getNearestDist(arc->getLength()/2.1, arc->getStartpoint()); } else { middlePoint = RS_Vector(false); middlePoint2 = RS_Vector(false); } if (middlePoint.valid) { bool onContour=false; if (RS_Information::isPointInsideContour( middlePoint, this, &onContour) || RS_Information::isPointInsideContour(middlePoint2, this)) { RS_Entity* te = e->clone(); te->setPen(RS_Pen(RS2::FlagInvalid)); te->setLayer(NULL); te->reparent(hatch); hatch->addEntity(te); } } } addEntity(hatch); //getGraphic()->addEntity(rubbish); forcedCalculateBorders(); // deactivate contour: activateContour(false); updateRunning = false; RS_DEBUG->print("RS_Hatch::update: OK"); }
/** * Rearranges the atomic entities in this container in a way that connected * entities are stored in the right order and direction. * Non-recoursive. Only affects atomic entities in this container. * * @retval true all contours were closed * @retval false at least one contour is not closed */ bool RS_ActionPolylineSegment::convertPolyline(RS_Entity* selectedEntity) { RS_DEBUG->print("RS_ActionPolylineSegment::convertPolyline"); RS_Vector current(false); RS_Vector start(false); RS_Vector end(false); RS_EntityContainer tmp; bool closed = true; int pos = container->findEntity(selectedEntity); RS_Entity* e1=container->entityAt(pos); if (!e1) return false; if (document!=NULL) { document->startUndoCycle(); } if (document!=NULL) { if (e1!=NULL && e1->isEdge() && !e1->isContainer() && !e1->isProcessed()) { RS_AtomicEntity* ce = (RS_AtomicEntity*)e1; /////////////////////////////////////////////////// ce->setUndoState(true); document->addUndoable(ce); /////////////////////////////////////////////////// // next contour start: ce->setProcessed(true); tmp.addEntity(ce->clone()); current = ce->getStartpoint(); end = ce->getEndpoint(); // find first connected entities: for (int ei=pos-1; ei>=0; --ei) { RS_Entity* e2=container->entityAt(ei); if (e2!=NULL && e2->isEdge() && !e2->isContainer() && !e2->isProcessed()) { RS_AtomicEntity* e = (RS_AtomicEntity*)e2; /////////////////////////////////////////////////// e->setUndoState(true); document->addUndoable(e); /////////////////////////////////////////////////// if (e->getEndpoint().distanceTo(current) < 1.0e-4) { e->setProcessed(true); tmp.insertEntity(0,e->clone()); current = e->getStartpoint(); } else if (e->getStartpoint().distanceTo(current) < 1.0e-4) { e->setProcessed(true); RS_AtomicEntity* cl = (RS_AtomicEntity*)e->clone(); cl->reverse(); tmp.insertEntity(0,cl); current = cl->getStartpoint(); }else break; } } if (current.distanceTo(end)>1.0e-4) { closed = false; } current = ce->getEndpoint(); start = ce->getStartpoint(); // find last connected entities: for (uint ei=pos+1; ei<container->count(); ++ei) { RS_Entity* e2=container->entityAt(ei); /////////////////////////////////////////////////// e2->setUndoState(true); document->addUndoable(e2); /////////////////////////////////////////////////// if (e2!=NULL && e2->isEdge() && !e2->isContainer() && !e2->isProcessed()) { RS_AtomicEntity* e = (RS_AtomicEntity*)e2; if (e->getStartpoint().distanceTo(current) < 1.0e-4) { e->setProcessed(true); tmp.addEntity(e->clone()); current = e->getEndpoint(); } else if (e->getEndpoint().distanceTo(current) < 1.0e-4) { e->setProcessed(true); RS_AtomicEntity* cl = (RS_AtomicEntity*)e->clone(); cl->reverse(); tmp.addEntity(cl); current = cl->getEndpoint(); }else break; } } if (current.distanceTo(start)>1.0e-4) { closed = false; } } } if (document!=NULL) { document->endUndoCycle(); } RS_Polyline* newPolyline = new RS_Polyline(container, RS_PolylineData(RS_Vector(false), RS_Vector(false), closed)); newPolyline->setLayerToActive(); newPolyline->setPenToActive(); // add new polyline: bool first = true; RS_Entity* lastEntity = tmp.lastEntity(); for (RS_Entity* en=tmp.firstEntity(); en!=NULL; en=tmp.nextEntity()) { en->setProcessed(false); double bulge = 0.0; if (en->rtti()==RS2::EntityArc) { bulge = ((RS_Arc*)en)->getBulge(); } else { bulge = 0.0; } if (first) { newPolyline->setNextBulge(bulge); newPolyline->addVertex(((RS_AtomicEntity*)en)->getStartpoint()); first = false; } if (en!=lastEntity || closed==false){ newPolyline->setNextBulge(bulge); newPolyline->addVertex(((RS_AtomicEntity*)en)->getEndpoint()); } } double bulge = lastEntity->rtti() == RS2::EntityArc? ((RS_Arc*)lastEntity)->getBulge():0.0; newPolyline->setNextBulge(bulge); newPolyline->endPolyline(); container->addEntity(newPolyline); if (graphicView!=NULL) { graphicView->drawEntity(newPolyline); } if (document!=NULL) { document->startUndoCycle(); document->addUndoable(newPolyline); document->endUndoCycle(); } RS_DEBUG->print("RS_ActionPolylineSegment::convertPolyline: OK"); return closed; }
/** * Rearranges the atomic entities in this container in a way that connected * entities are stored in the right order and direction. * Non-recoursive. Only affects atomic entities in this container. * * @retval true all contours were closed * @retval false at least one contour is not closed */ bool RS_EntityContainer::optimizeContours() { RS_DEBUG->print("RS_EntityContainer::optimizeContours"); RS_Vector current(false); RS_Vector start(false); RS_EntityContainer tmp; bool changed = false; bool closed = true; for (uint ci=0; ci<count(); ++ci) { RS_Entity* e1=entityAt(ci); if (e1!=NULL && e1->isEdge() && !e1->isContainer() && !e1->isProcessed()) { RS_AtomicEntity* ce = (RS_AtomicEntity*)e1; // next contour start: ce->setProcessed(true); tmp.addEntity(ce->clone()); current = ce->getEndpoint(); start = ce->getStartpoint(); // find all connected entities: bool done; do { done = true; for (uint ei=0; ei<count(); ++ei) { RS_Entity* e2=entityAt(ei); if (e2!=NULL && e2->isEdge() && !e2->isContainer() && !e2->isProcessed()) { RS_AtomicEntity* e = (RS_AtomicEntity*)e2; if (e->getStartpoint().distanceTo(current) < 1.0e-4) { e->setProcessed(true); tmp.addEntity(e->clone()); current = e->getEndpoint(); done=false; } else if (e->getEndpoint().distanceTo(current) < 1.0e-4) { e->setProcessed(true); RS_AtomicEntity* cl = (RS_AtomicEntity*)e->clone(); cl->reverse(); tmp.addEntity(cl); current = cl->getEndpoint(); changed = true; done=false; } } } if (!done) { changed = true; } } while (!done); if (current.distanceTo(start)>1.0e-4) { closed = false; } } } // remove all atomic entities: bool done; do { done = true; for (RS_Entity* en=firstEntity(); en!=NULL; en=nextEntity()) { if (!en->isContainer()) { removeEntity(en); done = false; break; } } } while (!done); // add new sorted entities: for (RS_Entity* en=tmp.firstEntity(); en!=NULL; en=tmp.nextEntity()) { en->setProcessed(false); addEntity(en->clone()); } RS_DEBUG->print("RS_EntityContainer::optimizeContours: OK"); return closed; }