void RS_ActionDrawCircleCR::trigger() { RS_PreviewActionInterface::trigger(); RS_Circle* circle = new RS_Circle(container, *data); circle->setLayerToActive(); circle->setPenToActive(); switch(getStatus()) { case SetCenter: container->addEntity(circle); graphicView->moveRelativeZero(circle->getCenter()); break; case SetRadius: break; } // upd. undo list: if (document) { document->startUndoCycle(); document->addUndoable(circle); document->endUndoCycle(); } graphicView->redraw(RS2::RedrawDrawing); setStatus(SetCenter); RS_DEBUG->print("RS_ActionDrawCircleCR::trigger(): circle added: %d", circle->getId()); }
void RS_ActionDimDiametric::preparePreview() { if (entity) { double radius{0.}; RS_Vector center{false}; if (entity->rtti()==RS2::EntityArc) { RS_Arc* p = static_cast<RS_Arc*>(entity); radius = p->getRadius(); center = p->getCenter(); } else if (entity->rtti()==RS2::EntityCircle) { RS_Circle* p = static_cast<RS_Circle*>(entity); radius = p->getRadius(); center = p->getCenter(); } double angle = center.angleTo(*pos); data->definitionPoint.setPolar(radius, angle + M_PI); data->definitionPoint += center; edata->definitionPoint.setPolar(radius, angle); edata->definitionPoint += center; } }
/** * Calculates the intersection point(s) between two entities. * * @param onEntities true: only return intersection points which are * on both entities. * false: return all intersection points. * * @todo support more entities * * @return All intersections of the two entities. The tangent flag in * RS_VectorSolutions is set if one intersection is a tangent point. */ RS_VectorSolutions RS_Information::getIntersection(RS_Entity* e1, RS_Entity* e2, bool onEntities) { RS_VectorSolutions ret; double tol = 1.0e-4; if (e1==NULL || e2==NULL ) { RS_DEBUG->print("RS_Information::getIntersection() for NULL entities"); return ret; } if (e1->getId() == e2->getId()) { RS_DEBUG->print("RS_Information::getIntersection() of the same entity"); return ret; } // unsupported entities / entity combinations: if ( e1->rtti()==RS2::EntityText || e2->rtti()==RS2::EntityText || isDimension(e1->rtti()) || isDimension(e2->rtti())) { return ret; } // a little check to avoid doing unneeded intersections, an attempt to avoid O(N^2) increasing of checking two-entity information if (onEntities && ( e1 -> getMin().x > e2 -> getMax().x || e1 -> getMax().x < e2 -> getMin().x || e1 -> getMin().y > e2 -> getMax().y || e1 -> getMax().y < e2 -> getMin().y ) ) { return ret; } // one entity is an ellipse: if (e1->rtti()==RS2::EntityEllipse || e2->rtti()==RS2::EntityEllipse) { if (e2->rtti()==RS2::EntityEllipse) std::swap( e1, e2); if (e2->rtti()==RS2::EntityEllipse) { ret = getIntersectionEllipseEllipse((RS_Ellipse*)e1, (RS_Ellipse *) e2); } if (e2->rtti()==RS2::EntityCircle) { ret = getIntersectionCircleEllipse((RS_Circle *)e2, (RS_Ellipse *) e1); } if (e2->rtti()==RS2::EntityArc) { ret = getIntersectionArcEllipse((RS_Arc *)e2, (RS_Ellipse *) e1); } if (e2->rtti()==RS2::EntityLine) { ret = getIntersectionLineEllipse((RS_Line*)e2, (RS_Ellipse*) e1); tol = 1.0e-1; } // not supported: else { return ret; } } else { RS_Entity* te1 = e1; RS_Entity* te2 = e2; // entity copies - so we only have to deal with lines and arcs RS_Line l1(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Line l2(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Arc a1(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); RS_Arc a2(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); // convert construction lines to lines: if (e1->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e1; l1.setStartpoint(cl->getPoint1()); l1.setEndpoint(cl->getPoint2()); te1 = &l1; } if (e2->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e2; l2.setStartpoint(cl->getPoint1()); l2.setEndpoint(cl->getPoint2()); te2 = &l2; } // convert circles to arcs: if (e1->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e1; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a1.setData(data); te1 = &a1; } if (e2->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e2; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a2.setData(data); te2 = &a2; } // line / line: // //else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityLine) { RS_Line * line1=(RS_Line*) te1; RS_Line * line2=(RS_Line*) te2; /* ToDo: 24 Aug 2011, Dongxu Li, if rtti() is not defined for the parent, the following check for splines may still cause segfault */ if ( line1->getParent() != NULL && line1->getParent() == line2->getParent()) { if ( line1->getParent()->rtti()==RS2::EntitySpline ) { //do not calculate intersections from neighboring lines of a spline if ( abs(line1->getParent()->findEntity(line1) - line1->getParent()->findEntity(line2)) <= 1 ) { return ret; } } } ret = getIntersectionLineLine(line1, line2); } // line / arc: // else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityArc) { RS_Line* line = (RS_Line*)te1; RS_Arc* arc = (RS_Arc*)te2; ret = getIntersectionLineArc(line, arc); } // arc / line: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityLine) { RS_Arc* arc = (RS_Arc*)te1; RS_Line* line = (RS_Line*)te2; ret = getIntersectionLineArc(line, arc); } // arc / arc: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityArc) { RS_Arc* arc1 = (RS_Arc*)te1; RS_Arc* arc2 = (RS_Arc*)te2; ret = getIntersectionArcArc(arc1, arc2); // ellipse / ellipse // } else { RS_DEBUG->print("RS_Information::getIntersection:: Unsupported entity type."); } } // Check all intersection points for being on entities: // if (onEntities==true) { if (!e1->isPointOnEntity(ret.get(0), tol) || !e2->isPointOnEntity(ret.get(0), tol)) { ret.set(0, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(1), tol) || !e2->isPointOnEntity(ret.get(1), tol)) { ret.set(1, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(2), tol) || !e2->isPointOnEntity(ret.get(2), tol)) { ret.set(2, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(3), tol) || !e2->isPointOnEntity(ret.get(3), tol)) { ret.set(3, RS_Vector(false)); } } int k=0; for (int i=0; i<4; ++i) { if (ret.get(i).valid) { ret.set(k, ret.get(i)); k++; } } for (int i=k; i<4; ++i) { ret.set(i, RS_Vector(false)); } return ret; }
/** * 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(auto se: entities){ view->drawEntity(painter,se); } return; } //area of solid fill. Use polygon approximation, except trivial cases QPainterPath path; QList<QPolygon> paClosed; QPolygon pa; // QPolygon jp; // jump points // loops: if (needOptimization==true) { for(auto l: entities){ if (l->rtti()==RS2::EntityContainer) { RS_EntityContainer* loop = (RS_EntityContainer*)l; loop->optimizeContours(); } } needOptimization = false; } // loops: for(auto l: entities){ l->setLayer(getLayer()); if (l->rtti()==RS2::EntityContainer) { RS_EntityContainer* loop = (RS_EntityContainer*)l; // edges: for(auto e: *loop){ 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; // } if(pa.size() && (pa.last()-pt1).manhattanLength()>=1) pa<<pt1; pa<<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()); if(pa.size() &&pa2.size()&&(pa.last()-pa2.first()).manhattanLength()<1) pa2.remove(0,1); 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() ); // qDebug()<<"ellipse: "<<ellipse->getCenter().x<<","<<ellipse->getCenter().y; // qDebug()<<"ellipse: pa2.size()="<<pa2.size(); // qDebug()<<"ellipse: pa2="<<pa2; if(pa.size() && pa2.size()&&(pa.last()-pa2.first()).manhattanLength()<1) pa2.remove(0,1); 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; } // qDebug()<<"pa="<<pa; if( pa.size()>2 && pa.first() == pa.last()) { paClosed<<pa; pa.clear(); } } } } if(pa.size()>2){ pa<<pa.first(); paClosed<<pa; } for(auto& p:paClosed){ path.addPolygon(p); } //bug#474, restore brush after solid fill const QBrush brush(painter->brush()); const RS_Pen pen=painter->getPen(); painter->setBrush(pen.getColor()); painter->disablePen(); painter->drawPath(path); painter->setBrush(brush); painter->setPen(pen); }
/** * 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"); }
/** * 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__); }
void Plugin_Entity::updateData(QHash<int, QVariant> *data){ if (entity == NULL) return; QHash<int, QVariant> hash = *data; QString str; RS_Vector vec; RS_Pen epen = entity->getPen(); // double num; if (hash.contains(DPI::LAYER)) { str = (hash.take(DPI::LAYER)).toString(); entity->setLayer(str); } if (hash.contains(DPI::LTYPE)) { str = (hash.take(DPI::LTYPE)).toString(); epen.setLineType( Converter.str2lt(str) ); } if (hash.contains(DPI::LWIDTH)) { str = (hash.take(DPI::LWIDTH)).toString(); epen.setWidth( Converter.str2lw(str) ); } if (hash.contains(DPI::COLOR)) { QColor color = hash.take(DPI::COLOR).value<QColor>(); epen.setColor(color); } entity->setPen(epen); RS2::EntityType et = entity->rtti(); switch (et) { //atomicEntity case RS2::EntityLine: { vec = static_cast<RS_Line*>(entity)->getStartpoint(); if (hash.contains(DPI::STARTX)) { vec.x = (hash.take(DPI::STARTX)).toDouble(); } if (hash.contains(DPI::STARTY)) { vec.y = (hash.take(DPI::STARTY)).toDouble(); } static_cast<RS_Line*>(entity)->setStartpoint(vec); vec = static_cast<RS_Line*>(entity)->getEndpoint(); if (hash.contains(DPI::ENDX)) { vec.x = (hash.take(DPI::ENDX)).toDouble(); } if (hash.contains(DPI::ENDY)) { vec.y = (hash.take(DPI::ENDY)).toDouble(); } static_cast<RS_Line*>(entity)->setEndpoint(vec); break;} case RS2::EntityPoint: { vec = static_cast<RS_Point*>(entity)->getPos(); if (hash.contains(DPI::STARTX)) { vec.x = (hash.take(DPI::STARTX)).toDouble(); } if (hash.contains(DPI::STARTY)) { vec.y = (hash.take(DPI::STARTY)).toDouble(); } static_cast<RS_Point*>(entity)->setPos(vec); break; } case RS2::EntityArc: { RS_Arc *arc = static_cast<RS_Arc*>(entity); vec = arc->getCenter(); if (hash.contains(DPI::STARTX)) { vec.x = (hash.take(DPI::STARTX)).toDouble(); } if (hash.contains(DPI::STARTY)) { vec.y = (hash.take(DPI::STARTY)).toDouble(); } arc->setCenter(vec); if (hash.contains(DPI::RADIUS)) { arc->setRadius( (hash.take(DPI::RADIUS)).toDouble() ); } if (hash.contains(DPI::STARTANGLE)) { arc->setAngle1( (hash.take(DPI::STARTANGLE)).toDouble() ); vec.y = (hash.take(DPI::STARTANGLE)).toDouble(); } if (hash.contains(DPI::ENDANGLE)) { arc->setAngle2( (hash.take(DPI::ENDANGLE)).toDouble() ); } break;} case RS2::EntityCircle: { RS_Circle *cir = static_cast<RS_Circle*>(entity); vec = cir->getCenter(); if (hash.contains(DPI::STARTX)) { vec.x = (hash.take(DPI::STARTX)).toDouble(); } if (hash.contains(DPI::STARTY)) { vec.y = (hash.take(DPI::STARTY)).toDouble(); } cir->setCenter(vec); if (hash.contains(DPI::RADIUS)) { cir->setRadius( (hash.take(DPI::RADIUS)).toDouble() ); } break;} case RS2::EntityEllipse: { RS_Ellipse *ellipse = static_cast<RS_Ellipse*>(entity); vec = ellipse->getCenter(); if (hash.contains(DPI::STARTX)) { vec.x = (hash.take(DPI::STARTX)).toDouble(); } if (hash.contains(DPI::STARTY)) { vec.y = (hash.take(DPI::STARTY)).toDouble(); } ellipse->setCenter(vec); vec = ellipse->getMajorP(); if (hash.contains(DPI::ENDX)) { vec.x = (hash.take(DPI::ENDX)).toDouble(); } if (hash.contains(DPI::ENDY)) { vec.y = (hash.take(DPI::ENDY)).toDouble(); } ellipse->setMajorP(vec); if (hash.contains(DPI::STARTANGLE)) { ellipse->setAngle1((hash.take(DPI::STARTANGLE)).toDouble()); } if (hash.contains(DPI::ENDANGLE)) { ellipse->setAngle2((hash.take(DPI::ENDANGLE)).toDouble()); } if (hash.contains(DPI::HEIGHT)) { ellipse->setRatio((hash.take(DPI::HEIGHT)).toDouble()); } if (hash.contains(DPI::REVERSED)) { ellipse->setReversed( (hash.take(DPI::REVERSED)).toBool()); } break;} case RS2::EntitySolid: //TODO //Only used in dimensions ? break; case RS2::EntityConstructionLine: //Unused ? break; case RS2::EntityImage: { break;} case RS2::EntityOverlayBox: //Unused ? break; //EntityContainer case RS2::EntityInsert: { break;} case RS2::EntityText: { RS_Text *txt = static_cast<RS_Text*>(entity); bool move = false; vec = txt->getInsertionPoint(); if (hash.contains(DPI::STARTX)) { vec.x = (hash.take(DPI::STARTX)).toDouble() - vec.x; move = true; } else vec.x = 0; if (hash.contains(DPI::STARTY)) { vec.y = (hash.take(DPI::STARTY)).toDouble() - vec.y; move = true; } else vec.y = 0; if (move) txt->move(vec); if (hash.contains(DPI::TEXTCONTENT)) { txt->setText( (hash.take(DPI::TEXTCONTENT)).toString() ); } if (hash.contains(DPI::STARTANGLE)) { txt->setAngle( (hash.take(DPI::STARTANGLE)).toDouble() ); } if (hash.contains(DPI::HEIGHT)) { txt->setHeight( (hash.take(DPI::HEIGHT)).toDouble() ); } break;} case RS2::EntityHatch: break; case RS2::EntitySpline: break; case RS2::EntityPolyline: { RS_Polyline *pl = static_cast<RS_Polyline*>(entity); if (hash.take(DPI::CLOSEPOLY).toBool()) { pl->setClosed(true); }else{ pl->setClosed(false); } break;} case RS2::EntityVertex: break; case RS2::EntityDimAligned: break; case RS2::EntityDimLinear: break; case RS2::EntityDimRadial: break; case RS2::EntityDimDiametric: break; case RS2::EntityDimAngular: break; case RS2::EntityDimLeader: break; case RS2::EntityUnknown: default: break; } entity->update(); }
/** * 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); }
/** * Calculates the intersection point(s) between two entities. * * @param onEntities true: only return intersection points which are * on both entities. * false: return all intersection points. * * @todo support more entities * * @return All intersections of the two entities. The tangent flag in * RS_VectorSolutions is set if one intersection is a tangent point. */ RS_VectorSolutions RS_Information::getIntersection(RS_Entity* e1, RS_Entity* e2, bool onEntities) { RS_VectorSolutions ret; double tol = 1.0e-4; if (e1==NULL || e2==NULL) { return ret; } // unsupported entities / entity combinations: if ((e1->rtti()==RS2::EntityEllipse && e2->rtti()==RS2::EntityEllipse) || e1->rtti()==RS2::EntityText || e2->rtti()==RS2::EntityText || isDimension(e1->rtti()) || isDimension(e2->rtti())) { return ret; } // (only) one entity is an ellipse: if (e1->rtti()==RS2::EntityEllipse || e2->rtti()==RS2::EntityEllipse) { if (e2->rtti()==RS2::EntityEllipse) { RS_Entity* tmp = e1; e1 = e2; e2 = tmp; } if (e2->rtti()==RS2::EntityLine) { RS_Ellipse* ellipse = (RS_Ellipse*)e1; ret = getIntersectionLineEllipse((RS_Line*)e2, ellipse); tol = 1.0e-1; } // ellipse / arc, ellipse / ellipse: not supported: else { return ret; } } else { RS_Entity* te1 = e1; RS_Entity* te2 = e2; // entity copies - so we only have to deal with lines and arcs RS_Line l1(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Line l2(NULL, RS_LineData(RS_Vector(0.0, 0.0), RS_Vector(0.0,0.0))); RS_Arc a1(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); RS_Arc a2(NULL, RS_ArcData(RS_Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false)); // convert construction lines to lines: if (e1->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e1; l1.setStartpoint(cl->getPoint1()); l1.setEndpoint(cl->getPoint2()); te1 = &l1; } if (e2->rtti()==RS2::EntityConstructionLine) { RS_ConstructionLine* cl = (RS_ConstructionLine*)e2; l2.setStartpoint(cl->getPoint1()); l2.setEndpoint(cl->getPoint2()); te2 = &l2; } // convert circles to arcs: if (e1->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e1; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a1.setData(data); te1 = &a1; } if (e2->rtti()==RS2::EntityCircle) { RS_Circle* c = (RS_Circle*)e2; RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false); a2.setData(data); te2 = &a2; } // line / line: // //else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityLine) { RS_Line* line1 = (RS_Line*)te1; RS_Line* line2 = (RS_Line*)te2; ret = getIntersectionLineLine(line1, line2); } // line / arc: // else if (te1->rtti()==RS2::EntityLine && te2->rtti()==RS2::EntityArc) { RS_Line* line = (RS_Line*)te1; RS_Arc* arc = (RS_Arc*)te2; ret = getIntersectionLineArc(line, arc); } // arc / line: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityLine) { RS_Arc* arc = (RS_Arc*)te1; RS_Line* line = (RS_Line*)te2; ret = getIntersectionLineArc(line, arc); } // arc / arc: // else if (te1->rtti()==RS2::EntityArc && te2->rtti()==RS2::EntityArc) { RS_Arc* arc1 = (RS_Arc*)te1; RS_Arc* arc2 = (RS_Arc*)te2; ret = getIntersectionArcArc(arc1, arc2); } else { RS_DEBUG->print("RS_Information::getIntersection:: Unsupported entity type."); } } // Check all intersection points for being on entities: // if (onEntities==true) { if (!e1->isPointOnEntity(ret.get(0), tol) || !e2->isPointOnEntity(ret.get(0), tol)) { ret.set(0, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(1), tol) || !e2->isPointOnEntity(ret.get(1), tol)) { ret.set(1, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(2), tol) || !e2->isPointOnEntity(ret.get(2), tol)) { ret.set(2, RS_Vector(false)); } if (!e1->isPointOnEntity(ret.get(3), tol) || !e2->isPointOnEntity(ret.get(3), tol)) { ret.set(3, RS_Vector(false)); } } int k=0; for (int i=0; i<4; ++i) { if (ret.get(i).valid) { ret.set(k, ret.get(i)); k++; } } for (int i=k; i<4; ++i) { ret.set(i, RS_Vector(false)); } return ret; }
/** * 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"); }