| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <cmath> |
| | #include <iostream> |
| | #include <set> |
| |
|
| | #include <QList> |
| | #include <QObject> |
| |
|
| | #include "lc_containertraverser.h" |
| | #include "lc_looputils.h" |
| | #include "qg_dialogfactory.h" |
| | #include "rs_constructionline.h" |
| | #include "rs_debug.h" |
| | #include "rs_dialogfactory.h" |
| | #include "rs_dimension.h" |
| | #include "rs_ellipse.h" |
| | #include "rs_entitycontainer.h" |
| | #include "rs_information.h" |
| | #include "rs_insert.h" |
| | #include "rs_layer.h" |
| | #include "rs_line.h" |
| | #include "rs_painter.h" |
| | #include "rs_solid.h" |
| | #include "rs_vector.h" |
| |
|
| | class RS_Dimension; |
| |
|
| | namespace { |
| |
|
| | |
| | constexpr double contourTolerance = 1e-8; |
| |
|
| | |
| | |
| | bool isClosedLoop(RS_Entity &entity) { |
| | switch (entity.rtti()) { |
| | case RS2::EntityCircle: |
| | |
| | case RS2::EntityContainer: |
| | return true; |
| | case RS2::EntityEllipse: |
| | return !static_cast<RS_Ellipse *>(&entity)->isArc(); |
| | default: |
| | return false; |
| | } |
| | } |
| |
|
| | |
| | double endPointDistance(const RS_Vector &point, const RS_Entity &entity) { |
| | double distance = RS_MAXDOUBLE; |
| | entity.getNearestEndpoint(point, &distance); |
| | return distance; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | RS_EntityContainer::RS_EntityContainer(RS_EntityContainer *parent, bool owner): |
| | RS_Entity(parent){ |
| | autoDelete = owner; |
| | |
| | |
| | subContainer = nullptr; |
| | |
| | entIdx = -1; |
| | } |
| | |
| | |
| | |
| |
|
| | RS_EntityContainer::RS_EntityContainer(const RS_EntityContainer& other): |
| | RS_Entity{other} |
| | , subContainer{other.subContainer} |
| | , m_entities{other.m_entities} |
| | , m_autoUpdateBorders{other.m_autoUpdateBorders} |
| | , entIdx{other.entIdx} |
| | , autoDelete{other.autoDelete}{ |
| | if (autoDelete) { |
| | for(auto it = begin(); it != end(); ++it) { |
| | if ((*it)->isContainer()) { |
| | *it = (*it)->clone(); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | RS_EntityContainer::RS_EntityContainer(const RS_EntityContainer& other, bool copyChildren) : |
| | RS_Entity{other}{ |
| | subContainer = nullptr; |
| | m_autoUpdateBorders = other.m_autoUpdateBorders; |
| | entIdx = other.entIdx; |
| | autoDelete = other.autoDelete; |
| | if (copyChildren) { |
| | m_entities = other.m_entities; |
| | if (autoDelete) { |
| | for(auto it = begin(); it != end(); ++it) { |
| | if ((*it)->isContainer()) { |
| | *it = (*it)->clone(); |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| |
|
| |
|
| | RS_EntityContainer& RS_EntityContainer::operator = (const RS_EntityContainer& other){ |
| | this->RS_Entity::operator = (other); |
| | subContainer=other.subContainer; |
| | m_entities = other.m_entities; |
| | m_autoUpdateBorders = other.m_autoUpdateBorders; |
| | entIdx = other.entIdx; |
| | autoDelete = other.autoDelete; |
| | if (autoDelete) { |
| | for(auto it = begin(); it != end(); ++it) { |
| | if ((*it)->isContainer()) { |
| | *it = (*it)->clone(); |
| | } |
| | } |
| | } |
| | return *this; |
| | } |
| |
|
| | RS_EntityContainer::RS_EntityContainer(RS_EntityContainer&& other): |
| | RS_Entity{other} |
| | , subContainer{other.subContainer} |
| | , m_entities{std::move(other.m_entities)} |
| | , m_autoUpdateBorders{other.m_autoUpdateBorders} |
| | , entIdx{other.entIdx} |
| | , autoDelete{other.autoDelete}{ |
| | } |
| |
|
| | RS_EntityContainer& RS_EntityContainer::operator = (RS_EntityContainer&& other){ |
| | this->RS_Entity::operator = (other); |
| | subContainer=other.subContainer; |
| | m_entities = std::move(other.m_entities); |
| | m_autoUpdateBorders = other.m_autoUpdateBorders; |
| | entIdx = other.entIdx; |
| | autoDelete = other.autoDelete; |
| | return *this; |
| | } |
| |
|
| | |
| | |
| | |
| | RS_EntityContainer::~RS_EntityContainer() { |
| | if (autoDelete) { |
| | while (!m_entities.isEmpty()) |
| | delete m_entities.takeFirst(); |
| | } else { |
| | m_entities.clear(); |
| | } |
| | } |
| |
|
| | RS_Entity *RS_EntityContainer::clone() const { |
| | RS_DEBUG->print("RS_EntityContainer::clone: ori autoDel: %d",autoDelete); |
| |
|
| | auto *ec = new RS_EntityContainer(getParent(), isOwner()); |
| | if (isOwner()) { |
| | for (const RS_Entity *entity: std::as_const(m_entities)) { |
| | if (entity != nullptr) { |
| | ec->m_entities.push_back(entity->clone()); |
| | } |
| | } |
| | } else { |
| | ec->m_entities = m_entities; |
| | } |
| |
|
| | RS_DEBUG->print("RS_EntityContainer::clone: clone autoDel: %d",ec->isOwner()); |
| |
|
| | ec->detach(); |
| | return ec; |
| | } |
| |
|
| | RS_Entity *RS_EntityContainer::cloneProxy() const { |
| | RS_DEBUG->print("RS_EntityContainer::cloneproxy: ori autoDel: %d", autoDelete); |
| |
|
| | auto *ec = new RS_EntityContainer(getParent(), isOwner()); |
| | if (isOwner()) { |
| | for (const RS_Entity *entity: std::as_const(m_entities)) { |
| | if (entity != nullptr) { |
| | ec->m_entities.push_back(entity->cloneProxy()); |
| | } |
| | } |
| | } else { |
| | ec->m_entities = m_entities; |
| | } |
| |
|
| | RS_DEBUG->print("RS_EntityContainer::cloneproxy: clone autoDel: %d", ec->isOwner()); |
| |
|
| | ec->detach(); |
| | return ec; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::detach() { |
| | QList<RS_Entity *> tmp; |
| | bool autoDel = isOwner(); |
| | RS_DEBUG->print("RS_EntityContainer::detach: autoDel: %d",(int) autoDel); |
| | setOwner(false); |
| |
|
| | |
| | for(RS_Entity* e: *this) { |
| | if (!e->getFlag(RS2::FlagTemp)) { |
| | tmp.append(e->clone()); |
| | } |
| | } |
| |
|
| | |
| | clear(); |
| | setOwner(autoDel); |
| |
|
| | |
| | for(RS_Entity* e: tmp) { |
| | push_back(e); |
| | e->reparent(this); |
| | } |
| | } |
| |
|
| | void RS_EntityContainer::reparent(RS_EntityContainer *parent) { |
| | RS_Entity::reparent(parent); |
| |
|
| | |
| | for (RS_Entity* e: *this) { |
| | e->reparent(parent); |
| | } |
| | } |
| |
|
| | void RS_EntityContainer::setVisible(bool v) { |
| | |
| | RS_Entity::setVisible(v); |
| |
|
| | |
| | for (auto e: std::as_const(m_entities)) { |
| | |
| | e->setVisible(v); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_EntityContainer::getLength() const { |
| | double ret = 0.0; |
| |
|
| | for (RS_Entity* e: *this) { |
| | if (e->isVisible()) { |
| | double length = e->getLength(); |
| | if (std::signbit(length)) { |
| | ret = -1.0; |
| | break; |
| | } else { |
| | ret += length; |
| | } |
| | } |
| | } |
| |
|
| | return ret; |
| | } |
| |
|
| | |
| | |
| | |
| | bool RS_EntityContainer::setSelected(bool select) { |
| | |
| | if (RS_Entity::setSelected(select)) { |
| | |
| | for (RS_Entity* e: *this) { |
| | if (e->isVisible()) { |
| | e->setSelected(select); |
| | } |
| | } |
| | return true; |
| | } |
| | return false; |
| | } |
| |
|
| | |
| | |
| | |
| | bool RS_EntityContainer::toggleSelected() { |
| | |
| | return RS_Entity::toggleSelected(); |
| | } |
| |
|
| | void RS_EntityContainer::setHighlighted(bool on){ |
| | for (RS_Entity* e: *this) { |
| | e->setHighlighted(on); |
| | } |
| | RS_Entity::setHighlighted(on); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::selectWindow( |
| | enum RS2::EntityType typeToSelect, RS_Vector v1, RS_Vector v2, |
| | bool select, bool cross){ |
| | for (RS_Entity* e: *this) { |
| | bool included = false; |
| | if (e->isVisible()) { |
| | if (e->isInWindow(v1, v2)) { |
| | |
| | included = true; |
| | } else if (cross) { |
| | RS_EntityContainer l; |
| | l.addRectangle(v1, v2); |
| | RS_VectorSolutions sol; |
| |
|
| | if (e->isContainer()) { |
| | auto *ec = (RS_EntityContainer *) e; |
| | lc::LC_ContainerTraverser traverser{*ec, RS2::ResolveAll}; |
| | for (RS_Entity *se = traverser.first(); se != nullptr && !included; se = traverser.next()){ |
| | if (se->rtti() == RS2::EntitySolid) { |
| | included = static_cast<RS_Solid *>(se)->isInCrossWindow(v1, v2); |
| | } else { |
| | for (RS_Entity* 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 (RS_Entity* line: l) { |
| | sol = RS_Information::getIntersection(e, line, true); |
| | if (sol.hasValid()) { |
| | included = true; |
| | break; |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | if (included) { |
| | if (typeToSelect != RS2::EntityType::EntityUnknown) { |
| | if (typeToSelect == e->rtti()) { |
| | e->setSelected(select); |
| | } else { |
| | |
| | } |
| | } else { |
| | e->setSelected(select); |
| | } |
| | } |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::selectWindow( |
| | const QList<RS2::EntityType> &typesToSelect, RS_Vector v1, RS_Vector v2, |
| | bool select, bool cross){ |
| | for (RS_Entity* e: *this) { |
| | if (!typesToSelect.contains(e->rtti())){ |
| | continue; |
| | } |
| | bool included = false; |
| | if (e->isVisible()) { |
| | if (e->isInWindow(v1, v2)) { |
| | |
| | included = true; |
| | } else if (cross) { |
| | RS_EntityContainer l; |
| | l.addRectangle(v1, v2); |
| | RS_VectorSolutions sol; |
| |
|
| | if (e->isContainer()) { |
| | auto *ec = (RS_EntityContainer *) e; |
| | lc::LC_ContainerTraverser traverser{*ec, RS2::ResolveAll}; |
| | for (RS_Entity* se = traverser.first(); se != nullptr && !included; se = traverser.next()) { |
| | if (se->rtti() == RS2::EntitySolid) { |
| | included = dynamic_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 = dynamic_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_EntityContainer::addEntity(RS_Entity *entity) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if (entity == nullptr) { |
| | return; |
| | } |
| | if (entity->rtti() == RS2::EntityImage || entity->rtti() == RS2::EntityHatch) { |
| | m_entities.prepend(entity); |
| | } else { |
| | m_entities.append(entity); |
| | } |
| | adjustBordersIfNeeded(entity); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::appendEntity(RS_Entity *entity) { |
| | if (entity == nullptr) { |
| | return; |
| | } |
| | m_entities.append(entity); |
| | adjustBordersIfNeeded(entity); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::prependEntity(RS_Entity *entity) { |
| | if (entity == nullptr) { |
| | return; |
| | } |
| | m_entities.prepend(entity); |
| | adjustBordersIfNeeded(entity); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::moveEntity(int index, QList<RS_Entity *> &entList) { |
| | if (entList.isEmpty()) { |
| | return; |
| | } |
| | int ci = 0; |
| | bool into = false; |
| | RS_Entity *mid = nullptr; |
| | if (index < 1) { |
| | ci = 0; |
| | } else if (index >= m_entities.size()) { |
| | ci = m_entities.size() - entList.size(); |
| | } else { |
| | into = true; |
| | mid = m_entities.at(index); |
| | } |
| |
|
| | for (int i = 0; i < entList.size(); ++i) { |
| | RS_Entity *e = entList.at(i); |
| | bool ret = m_entities.removeOne(e); |
| | |
| | if (!ret) { |
| | entList.removeAt(i); |
| | } |
| | } |
| | if (into) { |
| | ci = m_entities.indexOf(mid); |
| | } |
| |
|
| | for (auto e: entList) { |
| | m_entities.insert(ci++, e); |
| | } |
| | } |
| |
|
| | void RS_EntityContainer::adjustBordersIfNeeded(RS_Entity* entity) { |
| | if (m_autoUpdateBorders) { |
| | adjustBorders(entity); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::insertEntity(int index, RS_Entity *entity) { |
| | if (entity == nullptr) { |
| | return; |
| | } |
| |
|
| | m_entities.insert(index, entity); |
| | adjustBordersIfNeeded(entity); |
| | } |
| | |
| | |
| | |
| | |
| | bool RS_EntityContainer::removeEntity(RS_Entity *entity) { |
| | |
| | |
| | |
| | bool ret = m_entities.removeOne(entity); |
| |
|
| | if (autoDelete && ret) { |
| | delete entity; |
| | } |
| | calculateBordersIfNeeded(); |
| | return ret; |
| | } |
| |
|
| | |
| | |
| | |
| | void RS_EntityContainer::clear() { |
| | if (autoDelete) { |
| | while (!m_entities.isEmpty()) { |
| | RS_Entity * en = m_entities.takeFirst(); |
| | delete en; |
| | } |
| | } else { |
| | m_entities.clear(); |
| | } |
| | resetBorders(); |
| | } |
| |
|
| | unsigned int RS_EntityContainer::count() const { |
| | return m_entities.size(); |
| | } |
| |
|
| | |
| | |
| | |
| | unsigned int RS_EntityContainer::countDeep() const { |
| | unsigned int c = 0; |
| | for (auto t: *this) { |
| | c += t->countDeep(); |
| | } |
| | return c; |
| | } |
| |
|
| | |
| | |
| | |
| | unsigned RS_EntityContainer::countSelected(bool deep, QList<RS2::EntityType> const &types) { |
| | unsigned count = 0; |
| | std::set<RS2::EntityType> type{types.cbegin(), types.cend()}; |
| |
|
| | for (RS_Entity *entity: *this) { |
| | if (entity->isSelected()) { |
| | if (!types.size() || type.count(entity->rtti())) { |
| | count++; |
| | } |
| | } |
| | if (entity->isContainer()) { |
| | count += dynamic_cast<RS_EntityContainer *>(entity)->countSelected(deep); |
| | } |
| | } |
| | return count; |
| | } |
| |
|
| | void RS_EntityContainer::collectSelected(std::vector<RS_Entity*> &collect, bool deep, QList<RS2::EntityType> const &types) { |
| | std::set<RS2::EntityType> type{types.cbegin(), types.cend()}; |
| | for (RS_Entity *e: std::as_const(m_entities)) { |
| | if (e != nullptr) { |
| | if (e->isSelected()) { |
| | if (types.empty() || type.count(e->rtti())) { |
| | collect.push_back(e); |
| | } |
| | if (deep && e->isContainer()) { |
| | auto *container = dynamic_cast<RS_EntityContainer *>(e); |
| | container->collectSelected(collect, false); |
| | } |
| | } |
| | } |
| | } |
| | } |
| | |
| | RS_EntityContainer::LC_SelectionInfo RS_EntityContainer::getSelectionInfo(const QList<RS2::EntityType> &types) { |
| | LC_SelectionInfo result; |
| | std::set<RS2::EntityType> type{types.cbegin(), types.cend()}; |
| | for (RS_Entity *e: *this) { |
| | if (e != nullptr) { |
| | if (e->isSelected()) { |
| | if (types.empty() || type.count(e->rtti())) { |
| | result.count ++; |
| | double entityLength = e->getLength(); |
| | if (entityLength >= 0.) { |
| | result.length += entityLength; |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | return result; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | double RS_EntityContainer::totalSelectedLength() { |
| | double ret(0.0); |
| | for (RS_Entity *e: *this) { |
| | if (e->isVisible() && e->isSelected()) { |
| | double l = e->getLength(); |
| | if (l >= 0.) { |
| | ret += l; |
| | } |
| | } |
| | } |
| | return ret; |
| | } |
| |
|
| | |
| | |
| | |
| | void RS_EntityContainer::adjustBorders(RS_Entity *entity) { |
| | |
| | |
| |
|
| | if (entity) { |
| | |
| | |
| | if (!entity->isContainer() || entity->count() > 0) { |
| | minV = RS_Vector::minimum(entity->getMin(), minV); |
| | maxV = RS_Vector::maximum(entity->getMax(), maxV); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | void RS_EntityContainer::calculateBorders() { |
| | RS_DEBUG->print("RS_EntityContainer::calculateBorders"); |
| |
|
| | resetBorders(); |
| | for (RS_Entity *e: *this) { |
| | |
| | |
| |
|
| | if (e != nullptr && e->isVisible()) { |
| | e->calculateBorders(); |
| | adjustBorders(e); |
| | } |
| | } |
| |
|
| | RS_DEBUG->print("RS_EntityContainer::calculateBorders: size 1: %f,%f", |
| | getSize().x, getSize().y); |
| |
|
| | |
| | if (minV.x > maxV.x || minV.x > RS_MAXDOUBLE || maxV.x > RS_MAXDOUBLE |
| | || minV.x < RS_MINDOUBLE || maxV.x < RS_MINDOUBLE) { |
| | minV.x = 0.0; |
| | maxV.x = 0.0; |
| | } |
| | if (minV.y > maxV.y || minV.y > RS_MAXDOUBLE || maxV.y > RS_MAXDOUBLE |
| | || minV.y < RS_MINDOUBLE || maxV.y < RS_MINDOUBLE) { |
| | minV.y = 0.0; |
| | maxV.y = 0.0; |
| | } |
| |
|
| | RS_DEBUG->print("RS_EntityContainer::calculateBorders: size: %f,%f", |
| | getSize().x, getSize().y); |
| |
|
| | |
| |
|
| | |
| | |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::forcedCalculateBorders() { |
| | |
| | resetBorders(); |
| | for (RS_Entity* e : *this) { |
| | if (e->isContainer()) { |
| | auto container = static_cast<RS_EntityContainer*>(e); |
| | container->forcedCalculateBorders(); |
| | } |
| | else { |
| | e->calculateBorders(); |
| | } |
| | adjustBorders(e); |
| | } |
| |
|
| | |
| | if (minV.x > maxV.x || minV.x > RS_MAXDOUBLE || maxV.x > RS_MAXDOUBLE |
| | || minV.x < RS_MINDOUBLE || maxV.x < RS_MINDOUBLE) { |
| |
|
| | minV.x = 0.0; |
| | maxV.x = 0.0; |
| | } |
| | if (minV.y > maxV.y || minV.y > RS_MAXDOUBLE || maxV.y > RS_MAXDOUBLE |
| | || minV.y < RS_MINDOUBLE || maxV.y < RS_MINDOUBLE) { |
| |
|
| | minV.y = 0.0; |
| | maxV.y = 0.0; |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | int RS_EntityContainer::updateDimensions(bool autoText) { |
| | RS_DEBUG->print("RS_EntityContainer::updateDimensions()"); |
| | int updatedDimsCount = 0; |
| |
|
| | for (RS_Entity *e: *this) { |
| | if (e->isUndone()) { |
| | continue; |
| | } |
| | if (e->rtti() == RS2::EntityDimLeader) { |
| | updatedDimsCount ++; |
| | e->update(); |
| | } |
| | if (RS_Information::isDimension(e->rtti())) { |
| | auto dimension = static_cast<RS_Dimension*>(e); |
| | |
| | |
| | dimension->update(); |
| | updatedDimsCount ++; |
| | } |
| | else if (e->isContainer()) { |
| | auto container = static_cast<RS_EntityContainer*>(e); |
| | updatedDimsCount += container->updateDimensions(autoText); |
| | } |
| | } |
| |
|
| | RS_DEBUG->print("RS_EntityContainer::updateDimensions() OK"); |
| | return updatedDimsCount; |
| | } |
| |
|
| | int RS_EntityContainer::updateVisibleDimensions(bool autoText) { |
| | RS_DEBUG->print("RS_EntityContainer::updateVisibleDimensions()"); |
| | int updatedDimsCount = 0; |
| | for (RS_Entity *e: *this) { |
| | if (e->isVisible()) { |
| | if (e->rtti() == RS2::EntityDimLeader) { |
| | e->update(); |
| | updatedDimsCount ++; |
| | } |
| | else if (RS_Information::isDimension(e->rtti())) { |
| | auto dimension = static_cast<RS_Dimension*>(e); |
| | |
| | dimension->updateDim(autoText); |
| | updatedDimsCount ++; |
| | } |
| | else if (e->isContainer()) { |
| | auto container = static_cast<RS_EntityContainer*>(e); |
| | updatedDimsCount += container->updateVisibleDimensions(autoText); |
| | } |
| | } |
| | } |
| |
|
| | RS_DEBUG->print("RS_EntityContainer::updateVisibleDimensions() OK"); |
| | return updatedDimsCount; |
| | } |
| |
|
| | |
| | |
| | |
| | void RS_EntityContainer::updateInserts() { |
| | std::string idTypeId = std::to_string(getId()) + "/" + std::to_string(rtti()); |
| | RS_DEBUG->print("RS_EntityContainer::updateInserts() ID/type: %s", idTypeId.c_str()); |
| |
|
| | for (RS_Entity *e: std::as_const(*this)) { |
| | |
| | if (e != nullptr && e->getId() != 0 && e->rtti() == RS2::EntityInsert ) { |
| | static_cast<RS_Insert*>(e)->update(); |
| |
|
| | RS_DEBUG->print("RS_EntityContainer::updateInserts: updated ID/type: %s", idTypeId.c_str()); |
| | } else if (e != nullptr && e->isContainer()) { |
| | if (e->rtti() == RS2::EntityHatch) { |
| | RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_EntityContainer::updateInserts: skip hatch ID/type: %s", |
| | idTypeId.c_str()); |
| | } else { |
| | RS_DEBUG->print("RS_EntityContainer::updateInserts: update container ID/type: %s", idTypeId.c_str()); |
| |
|
| | static_cast<RS_EntityContainer*>(e)->updateInserts(); |
| | } |
| | } else { |
| | RS_DEBUG->print(RS_Debug::D_DEBUGGING, "RS_EntityContainer::updateInserts: skip entity ID/type: %s", |
| | idTypeId.c_str()); |
| | } |
| | } |
| | RS_DEBUG->print("RS_EntityContainer::updateInserts() ID/type: %s", idTypeId.c_str()); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::renameInserts(const QString &oldName,const QString &newName) { |
| | RS_DEBUG->print("RS_EntityContainer::renameInserts()"); |
| | for (RS_Entity *e: std::as_const(m_entities)) { |
| | if (e->rtti() == RS2::EntityInsert) { |
| | auto *i = static_cast<RS_Insert*>(e); |
| | if (i->getName() == oldName) { |
| | i->setName(newName); |
| | } |
| | } |
| | if (e->isContainer()) { |
| | auto container = static_cast<RS_EntityContainer*>(e); |
| | container->renameInserts(oldName, newName); |
| | } |
| | } |
| | RS_DEBUG->print("RS_EntityContainer::renameInserts() OK"); |
| | } |
| |
|
| | |
| | |
| | |
| | void RS_EntityContainer::updateSplines() { |
| | RS_DEBUG->print("RS_EntityContainer::updateSplines()"); |
| | for (RS_Entity *e: *this) { |
| | |
| | if (e->rtti() == RS2::EntitySpline ) { |
| | e->update(); |
| | } else if (e->isContainer() && e->rtti() != RS2::EntityHatch) { |
| | static_cast<RS_EntityContainer *>(e)->updateSplines(); |
| | } |
| | } |
| | RS_DEBUG->print("RS_EntityContainer::updateSplines() OK"); |
| | } |
| |
|
| | |
| | |
| | |
| | void RS_EntityContainer::update() { |
| | for (RS_Entity *e: *this) { |
| | e->update(); |
| | } |
| | } |
| |
|
| | void RS_EntityContainer::addRectangle(RS_Vector const &v0, RS_Vector const &v1) { |
| | addEntity(new RS_Line{this, v0, {v1.x, v0.y}}); |
| | addEntity(new RS_Line{this, {v1.x, v0.y}, v1}); |
| | addEntity(new RS_Line{this, v1, {v0.x, v1.y}}); |
| | addEntity(new RS_Line{this, {v0.x, v1.y}, v0}); |
| | } |
| |
|
| | void RS_EntityContainer::addRectangle(RS_Vector const& v0, RS_Vector const& v1,RS_Vector const& v2, RS_Vector const& v3){ |
| | addEntity(new RS_Line(this, v0, v1)); |
| | addEntity(new RS_Line(this, v1, v2)); |
| | addEntity(new RS_Line(this, v2, v3)); |
| | addEntity(new RS_Line(this, v3, v0)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | RS_Entity *RS_EntityContainer::firstEntity(RS2::ResolveLevel level) const { |
| | RS_Entity *e = nullptr; |
| | entIdx = -1; |
| | switch (level) { |
| | case RS2::ResolveNone: { |
| | if (!m_entities.isEmpty()) { |
| | entIdx = 0; |
| | return m_entities.first(); |
| | } |
| | break; |
| | } |
| | case RS2::ResolveAllButInserts: { |
| | subContainer = nullptr; |
| | if (!m_entities.isEmpty()) { |
| | entIdx = 0; |
| | e = m_entities.first(); |
| | } |
| | if (e && e->isContainer() && e->rtti() != RS2::EntityInsert) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->firstEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = nextEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | case RS2::ResolveAllButTextImage: |
| | case RS2::ResolveAllButTexts: { |
| | subContainer = nullptr; |
| | if (!m_entities.isEmpty()) { |
| | entIdx = 0; |
| | e = m_entities.first(); |
| | } |
| | if (e != nullptr && e->isContainer() && e->rtti() != RS2::EntityText && e->rtti() != RS2::EntityMText) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->firstEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = nextEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | case RS2::ResolveAll: { |
| | subContainer = nullptr; |
| | if (!m_entities.isEmpty()) { |
| | entIdx = 0; |
| | e = m_entities.first(); |
| | } |
| | if (e != nullptr && e->isContainer()) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->firstEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = nextEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | } |
| | return nullptr; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | RS_Entity *RS_EntityContainer::lastEntity(RS2::ResolveLevel level) const { |
| | RS_Entity *e = nullptr; |
| | if (m_entities.empty()) { |
| | return nullptr; |
| | } |
| | entIdx = m_entities.size() - 1; |
| | switch (level) { |
| | case RS2::ResolveNone: { |
| | if (!m_entities.isEmpty()) { |
| | return m_entities.last(); |
| | } |
| | break; |
| | } |
| | case RS2::ResolveAllButInserts: { |
| | if (!m_entities.isEmpty()) { |
| | e = m_entities.last(); |
| | } |
| | subContainer = nullptr; |
| | if (e != nullptr && e->isContainer() && e->rtti() != RS2::EntityInsert) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->lastEntity(level); |
| | } |
| | return e; |
| | } |
| | case RS2::ResolveAllButTextImage: |
| | case RS2::ResolveAllButTexts: { |
| | if (!m_entities.isEmpty()) { |
| | e = m_entities.last(); |
| | } |
| | subContainer = nullptr; |
| | if (e != nullptr && e->isContainer() && e->rtti() != RS2::EntityText && e->rtti() != RS2::EntityMText) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->lastEntity(level); |
| | } |
| | return e; |
| | } |
| | case RS2::ResolveAll: { |
| | if (!m_entities.isEmpty()) { |
| | e = m_entities.last(); |
| | } |
| | subContainer = nullptr; |
| | if (e != nullptr && e->isContainer()) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->lastEntity(level); |
| | } |
| | return e; |
| | } |
| | } |
| | return nullptr; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | RS_Entity *RS_EntityContainer::nextEntity(RS2::ResolveLevel level) const { |
| | |
| | ++entIdx; |
| | switch (level) { |
| | case RS2::ResolveNone: { |
| | if (entIdx < m_entities.size()) { |
| | return m_entities.at(entIdx); |
| | } |
| | break; |
| | } |
| | case RS2::ResolveAllButInserts: { |
| | RS_Entity *e = nullptr; |
| | if (subContainer) { |
| | e = subContainer->nextEntity(level); |
| | if (e != nullptr) { |
| | --entIdx; |
| | return e; |
| | } else { |
| | if (entIdx < m_entities.size()) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | } else { |
| | if (entIdx < m_entities.size()) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | if (e != nullptr && e->isContainer() && e->rtti() != RS2::EntityInsert) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->firstEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = nextEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | break; |
| |
|
| | case RS2::ResolveAllButTextImage: |
| | case RS2::ResolveAllButTexts: { |
| | RS_Entity *e = nullptr; |
| | if (subContainer) { |
| | e = subContainer->nextEntity(level); |
| | if (e != nullptr) { |
| | --entIdx; |
| | return e; |
| | } else { |
| | if (entIdx < m_entities.size()) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | } else { |
| | if (entIdx < m_entities.size()) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | if (e != nullptr && e->isContainer() && e->rtti() != RS2::EntityText && e->rtti() != RS2::EntityMText) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->firstEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = nextEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | case RS2::ResolveAll: { |
| | RS_Entity *e = nullptr; |
| | if (subContainer) { |
| | e = subContainer->nextEntity(level); |
| | if (e != nullptr) { |
| | --entIdx; |
| | return e; |
| | } else { |
| | if (entIdx < m_entities.size()) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | } else { |
| | if (entIdx < m_entities.size()) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | if (e != nullptr && e->isContainer()) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->firstEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = nextEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | } |
| | return nullptr; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | RS_Entity *RS_EntityContainer::prevEntity(RS2::ResolveLevel level) const { |
| | |
| | --entIdx; |
| | switch (level) { |
| | case RS2::ResolveNone: { |
| | if (entIdx >= 0) { |
| | return m_entities.at(entIdx); |
| | } |
| | break; |
| | } |
| | case RS2::ResolveAllButInserts: { |
| | RS_Entity *e = nullptr; |
| | if (subContainer) { |
| | e = subContainer->prevEntity(level); |
| | if (e != nullptr) { |
| | return e; |
| | } |
| | else { |
| | if (entIdx >= 0) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | } |
| | else { |
| | if (entIdx >= 0) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | if (e != nullptr && e->isContainer() && e->rtti() != RS2::EntityInsert) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->lastEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = prevEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | case RS2::ResolveAllButTextImage: |
| | case RS2::ResolveAllButTexts: { |
| | RS_Entity *e = nullptr; |
| | if (subContainer != nullptr) { |
| | e = subContainer->prevEntity(level); |
| | if (e != nullptr) { |
| | return e; |
| | } else { |
| | if (entIdx >= 0) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | } else { |
| | if (entIdx >= 0) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | if (e != nullptr && e->isContainer() && e->rtti() != RS2::EntityText && e->rtti() != RS2::EntityMText) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->lastEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = prevEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | case RS2::ResolveAll: { |
| | RS_Entity *e = nullptr; |
| | if (subContainer != nullptr) { |
| | e = subContainer->prevEntity(level); |
| | if (e != nullptr) { |
| | ++entIdx; |
| | return e; |
| | } else { |
| | if (entIdx >= 0) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | } else { |
| | if (entIdx >= 0) { |
| | e = m_entities.at(entIdx); |
| | } |
| | } |
| | if (e != nullptr && e->isContainer()) { |
| | subContainer = static_cast<RS_EntityContainer*>(e); |
| | e = subContainer->lastEntity(level); |
| | |
| | if (e == nullptr) { |
| | subContainer = nullptr; |
| | e = prevEntity(level); |
| | } |
| | } |
| | return e; |
| | } |
| | } |
| | return nullptr; |
| | } |
| |
|
| | |
| | |
| | |
| | RS_Entity *RS_EntityContainer::entityAt(int index) const{ |
| | if (m_entities.size() > index && index >= 0) { |
| | return m_entities.at(index); |
| | } |
| | else { |
| | return nullptr; |
| | } |
| | } |
| |
|
| | void RS_EntityContainer::setEntityAt(int index, RS_Entity *en) { |
| | if (autoDelete && m_entities.at(index)) { |
| | delete m_entities.at(index); |
| | } |
| | m_entities[index] = en; |
| | } |
| |
|
| | |
| | |
| | |
| | int RS_EntityContainer::findEntity(RS_Entity const *const entity) { |
| | entIdx = m_entities.indexOf(const_cast<RS_Entity *>(entity)); |
| | return entIdx; |
| | } |
| |
|
| | int RS_EntityContainer::findEntityIndex(RS_Entity const *const entity) { |
| | return m_entities.indexOf(const_cast<RS_Entity *>(entity)); |
| | } |
| |
|
| | bool RS_EntityContainer::areNeighborsEntities(RS_Entity const *const e1, RS_Entity const *const e2) { |
| | return abs(m_entities.indexOf(e1) - m_entities.indexOf(e2)) <= 1; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | RS_Vector RS_EntityContainer::getNearestEndpoint(const RS_Vector &coord,double *dist) const{ |
| | double minDist = RS_MAXDOUBLE; |
| | double curDist = 0.; |
| | RS_Vector closestPoint(false); |
| | RS_Vector point; |
| |
|
| | for(RS_Entity* en : *this) { |
| | if (en != nullptr && en->getId() != 0 && en->isVisible()){ |
| | auto parent = en->getParent(); |
| | bool checkForEndpoint = true; |
| | if (parent != nullptr){ |
| | checkForEndpoint = !parent->ignoredOnModification(); |
| | } |
| | if (checkForEndpoint) { |
| | point = en->getNearestEndpoint(coord, &curDist); |
| | if (point.valid && curDist < minDist) { |
| | closestPoint = point; |
| | minDist = curDist; |
| | if (dist) { |
| | *dist = minDist; |
| | } |
| | } |
| | } |
| | } |
| | } |
| | return closestPoint; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | RS_Vector RS_EntityContainer::getNearestEndpoint(const RS_Vector &coord,double *dist, RS_Entity **pEntity) const { |
| | double minDist = RS_MAXDOUBLE; |
| | double curDist; |
| | RS_Vector closestPoint(false); |
| | RS_Vector point; |
| |
|
| | for (auto en: m_entities) { |
| | if (en->getParent() == nullptr || !en->getParent()->ignoredOnModification()) { |
| | |
| | point = en->getNearestEndpoint(coord, &curDist); |
| | if (point.valid && curDist < minDist) { |
| | closestPoint = point; |
| | minDist = curDist; |
| | if (dist) { |
| | *dist = minDist; |
| | } |
| | if (pEntity) { |
| | *pEntity = en; |
| | } |
| | } |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | return closestPoint; |
| | } |
| |
|
| | RS_Vector RS_EntityContainer::getNearestPointOnEntity(const RS_Vector &coord,bool onEntity, double *dist, RS_Entity **entity) const { |
| | RS_Vector point(false); |
| | RS_Entity *en = getNearestEntity(coord, dist, RS2::ResolveNone); |
| | if (en && en->isVisible() && !en->getParent()->ignoredSnap() ) { |
| | point = en->getNearestPointOnEntity(coord, onEntity, dist, entity); |
| | } |
| | return point; |
| | } |
| |
|
| | RS_Vector RS_EntityContainer::getNearestCenter(const RS_Vector &coord,double *dist) const { |
| | double minDist = RS_MAXDOUBLE; |
| | double curDist = RS_MAXDOUBLE; |
| | RS_Vector closestPoint(false); |
| | RS_Vector point; |
| |
|
| | for (auto en: m_entities) { |
| | if (en != nullptr && en->getId() != 0 && en->isVisible() && !en->getParent()->ignoredSnap() ) { |
| | point = en->getNearestCenter(coord, &curDist); |
| | if (point.valid && curDist < minDist) { |
| | closestPoint = point; |
| | minDist = curDist; |
| | } |
| | } |
| | } |
| | if (dist) { |
| | *dist = minDist; |
| | } |
| | return closestPoint; |
| | } |
| |
|
| | |
| |
|
| | RS_Vector RS_EntityContainer::getNearestMiddle(const RS_Vector &coord,double *dist,int middlePoints ) const { |
| | double minDist = RS_MAXDOUBLE; |
| | double curDist = RS_MAXDOUBLE; |
| | RS_Vector closestPoint(false); |
| | RS_Vector point; |
| |
|
| | for (auto en: m_entities) { |
| | if (en->isVisible() && !en->getParent()->ignoredSnap() ) { |
| | point = en->getNearestMiddle(coord, &curDist, middlePoints); |
| | if (point.valid && curDist < minDist) { |
| | closestPoint = point; |
| | minDist = curDist; |
| | } |
| | } |
| | } |
| | if (dist) { |
| | *dist = minDist; |
| | } |
| | return closestPoint; |
| | } |
| |
|
| | RS_Vector RS_EntityContainer::getNearestDist(double distance,const RS_Vector &coord, double *dist) const { |
| | RS_Entity *closestEntity = getNearestEntity(coord, nullptr, RS2::ResolveNone); |
| | return (closestEntity != nullptr) ? closestEntity->getNearestDist(distance, coord, dist) |
| | : RS_Vector{false}; |
| | } |
| |
|
| | |
| | |
| | |
| | RS_Vector RS_EntityContainer::getNearestIntersection(const RS_Vector &coord, double *dist){ |
| | double minDist = RS_MAXDOUBLE; |
| | RS_Vector closestPoint(false); |
| | RS_Entity* closestEntity = getNearestEntity(coord, nullptr, RS2::ResolveAllButTextImage); |
| |
|
| | if (closestEntity) { |
| | |
| | for (RS_Entity *en = firstEntity(RS2::ResolveAllButTextImage);en;en = nextEntity(RS2::ResolveAllButTextImage)) { |
| | auto parent = en->getParent(); |
| | bool ignoredSnap = false; |
| | if (parent != nullptr) { |
| | ignoredSnap = parent->ignoredSnap(); |
| | } |
| | if (!en->isVisible() || ignoredSnap) { |
| | continue; |
| | } |
| |
|
| | RS_VectorSolutions sol = RS_Information::getIntersection(closestEntity, en, true); |
| | double curDist = RS_MAXDOUBLE; |
| | RS_Vector point = sol.getClosest(coord, &curDist, nullptr); |
| | if (sol.getNumber() > 0 && curDist < minDist) { |
| | closestPoint = point; |
| | minDist = curDist; |
| | } |
| | } |
| | } |
| | if (dist && closestPoint.valid) { |
| | *dist = minDist; |
| | } |
| | return closestPoint; |
| | } |
| |
|
| | RS_Vector RS_EntityContainer::getNearestVirtualIntersection(const RS_Vector &coord, const double &angle, double *dist) { |
| | RS_Entity* closestEntity = getNearestEntity(coord, nullptr, RS2::ResolveAllButTextImage); |
| | if (closestEntity != nullptr) { |
| | RS_Vector second_coord{angle}; |
| | RS_ConstructionLineData data(coord, coord + second_coord); |
| | auto line = RS_ConstructionLine(nullptr, data); |
| |
|
| | RS_VectorSolutions sol = RS_Information::getIntersection(closestEntity, &line, true); |
| | if (sol.getVector().empty()) { |
| | return coord; |
| | } else { |
| | return sol.getClosest(coord, dist, nullptr); |
| | } |
| | } else { |
| | return coord; |
| | } |
| | } |
| |
|
| | RS_Vector RS_EntityContainer::getNearestRef(const RS_Vector &coord, double *dist) const { |
| | double minDist = RS_MAXDOUBLE; |
| | double curDist; |
| | RS_Vector closestPoint(false); |
| | RS_Vector point; |
| |
|
| | for (RS_Entity* en: *this) { |
| | if (en->isVisible()) { |
| | point = en->getNearestRef(coord, &curDist); |
| | if (point.valid && curDist < minDist) { |
| | closestPoint = point; |
| | minDist = curDist; |
| | if (dist) { |
| | *dist = minDist; |
| | } |
| | } |
| | } |
| | } |
| | return closestPoint; |
| | } |
| |
|
| | RS_Vector RS_EntityContainer::getNearestSelectedRef(const RS_Vector &coord, double *dist) const{ |
| | RefInfo info = getNearestSelectedRefInfo(coord, dist); |
| | return info.ref; |
| | } |
| |
|
| | RS_EntityContainer::RefInfo RS_EntityContainer::getNearestSelectedRefInfo(const RS_Vector &coord, double *dist) const { |
| | double minDist = RS_MAXDOUBLE; |
| | RS_Vector closestPoint(false); |
| | RS_Entity *closestPointEntity = nullptr; |
| |
|
| | for (RS_Entity* en: *this) { |
| | if (en->isVisible() && en->isSelected() && !en->isParentSelected()) { |
| | double curDist = 0.; |
| | RS_Vector point = en->getNearestSelectedRef(coord, &curDist); |
| | if (point.valid && curDist < minDist) { |
| | closestPoint = point; |
| | closestPointEntity = en; |
| | minDist = curDist; |
| | if (dist) { |
| | *dist = minDist; |
| | } |
| | } |
| | } |
| | } |
| | RefInfo result {closestPoint, closestPointEntity}; |
| | return result; |
| | } |
| |
|
| | double RS_EntityContainer::getDistanceToPoint(const RS_Vector &coord,RS_Entity **entity,RS2::ResolveLevel level,double solidDist) const{ |
| | RS_DEBUG->print("RS_EntityContainer::getDistanceToPoint"); |
| | double minDist = RS_MAXDOUBLE; |
| | double curDist = 0.; |
| | RS_Entity *closestEntity = nullptr; |
| | RS_Entity *subEntity = nullptr; |
| |
|
| | for (RS_Entity* e: *this) { |
| | auto entityLayer = e->getLayer(); |
| | if (e->isVisible() && (entityLayer == nullptr || !entityLayer->isLocked())) { |
| | RS_DEBUG->print("entity: getDistanceToPoint"); |
| | RS_DEBUG->print("entity: %d", e->rtti()); |
| | |
| | if (level == RS2::ResolveAllButTextImage && e->rtti() == RS2::EntityImage) continue; |
| | curDist = e->getDistanceToPoint(coord, &subEntity, level, solidDist); |
| |
|
| | RS_DEBUG->print("entity: getDistanceToPoint: OK"); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if (curDist <= minDist) { |
| | switch (level) { |
| | case RS2::ResolveAll: |
| | case RS2::ResolveAllButTextImage: |
| | closestEntity = subEntity; |
| | break; |
| | default: |
| | closestEntity = e; |
| | } |
| | minDist = curDist; |
| | } |
| | } |
| | } |
| |
|
| | if (entity != nullptr) { |
| | *entity = closestEntity; |
| | } |
| | RS_DEBUG->print("RS_EntityContainer::getDistanceToPoint: OK"); |
| |
|
| | return minDist; |
| | } |
| |
|
| | RS_Entity* RS_EntityContainer::getNearestEntity(const RS_Vector& coord,double* dist,RS2::ResolveLevel level) const { |
| | RS_DEBUG->print("RS_EntityContainer::getNearestEntity"); |
| |
|
| | RS_Entity *e = nullptr; |
| |
|
| | |
| | double solidDist = RS_MAXDOUBLE; |
| | if (dist) { |
| | solidDist = *dist; |
| | } |
| |
|
| | double d = getDistanceToPoint(coord, &e, level, solidDist); |
| | if (e != nullptr && e->isVisible() == false) { |
| | e = nullptr; |
| | } |
| |
|
| | |
| | if (dist != nullptr) { |
| | *dist = d; |
| | } |
| | RS_DEBUG->print("RS_EntityContainer::getNearestEntity: OK"); |
| | return e; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | bool RS_EntityContainer::optimizeContours() { |
| | |
| | |
| | |
| | RS_DEBUG->print("RS_EntityContainer::optimizeContours"); |
| |
|
| | RS_EntityContainer tmp; |
| | tmp.setAutoUpdateBorders(false); |
| | bool closed = true; |
| |
|
| | |
| | QList<RS_Entity *> enList; |
| | for(RS_Entity* e1: *this) { |
| | if (!e1->isEdge() || e1->isContainer()) { |
| | enList << e1; |
| | continue; |
| | } |
| |
|
| | |
| | switch (e1->rtti()) { |
| | case RS2::EntityEllipse: { |
| | if (dynamic_cast<RS_Ellipse *>(e1)->isEllipticArc()) { |
| | continue; |
| | } |
| | |
| | [[fallthrough]]; |
| | } |
| | case RS2::EntityCircle: { |
| | |
| | tmp.addEntity(e1->clone()); |
| | enList << e1; |
| | |
| | [[fallthrough]]; |
| | } |
| | default: |
| | continue; |
| | } |
| | } |
| | |
| |
|
| | |
| | for (RS_Entity *it: std::as_const(enList)) { |
| | removeEntity(it); |
| | } |
| |
|
| | |
| | |
| | |
| | RS_Entity* current(nullptr); |
| | if (count() > 0) { |
| | current = entityAt(0)->clone(); |
| | tmp.addEntity(current); |
| | removeEntity(entityAt(0)); |
| | } |
| | else { |
| | if (tmp.count() == 0) { |
| | return false; |
| | } |
| | } |
| | |
| | RS_Vector vpStart; |
| | RS_Vector vpEnd; |
| | if (current) { |
| | vpStart = current->getStartpoint(); |
| | vpEnd = current->getEndpoint(); |
| | } |
| | RS_Entity *next = nullptr; |
| | |
| | |
| | const auto errMsg = QObject::tr("Hatch failed due to a gap=%1 between (%2, %3) and (%4, %5)"); |
| |
|
| | while (count() > 0) { |
| | double dist = 0.; |
| | RS_Vector vpTmp = getNearestEndpoint(vpEnd, &dist, &next); |
| | if (dist > contourTolerance) { |
| | if (vpEnd.squaredTo(vpStart) < contourTolerance) { |
| | RS_Entity *e2 = entityAt(0); |
| | tmp.addEntity(e2->clone()); |
| | vpStart = e2->getStartpoint(); |
| | vpEnd = e2->getEndpoint(); |
| | removeEntity(e2); |
| | continue; |
| | } else { |
| | |
| | QG_DIALOGFACTORY->commandMessage(errMsg.arg(dist).arg(vpTmp.x).arg(vpTmp.y).arg(vpEnd.x).arg(vpEnd.y)); |
| | RS_DEBUG->print(RS_Debug::D_ERROR, "RS_EntityContainer::optimizeContours: hatch failed due to a gap"); |
| | closed = false; |
| | break; |
| | } |
| | } |
| | if (!next) { |
| | |
| | RS_DEBUG->print("RS_EntityContainer::optimizeContours: next is nullptr"); |
| | |
| | break; |
| | } |
| | if (closed) { |
| | next->setProcessed(true); |
| | RS_Entity *eTmp = next->clone(); |
| | if (vpEnd.squaredTo(eTmp->getStartpoint()) > vpEnd.squaredTo(eTmp->getEndpoint())) { |
| | eTmp->revertDirection(); |
| | } |
| | vpEnd = eTmp->getEndpoint(); |
| | tmp.addEntity(eTmp); |
| | removeEntity(next); |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | |
| | for (RS_Entity* en: tmp) { |
| | en->setProcessed(false); |
| | addEntity(en->clone()); |
| | en->reparent(this); |
| | } |
| | |
| |
|
| | if (closed) { |
| | RS_DEBUG->print("RS_EntityContainer::optimizeContours: OK"); |
| | } else { |
| | RS_DEBUG->print("RS_EntityContainer::optimizeContours: bad"); |
| | } |
| | |
| | |
| | return closed; |
| | } |
| |
|
| | bool RS_EntityContainer::hasEndpointsWithinWindow(const RS_Vector &v1, const RS_Vector &v2) const{ |
| | return std::any_of(cbegin(), cend(), [&v1, &v2](const RS_Entity* entity) { |
| | return entity->hasEndpointsWithinWindow(v1, v2); |
| | }); |
| | } |
| |
|
| | void RS_EntityContainer::move(const RS_Vector &offset) { |
| | moveBorders(offset); |
| | for (RS_Entity *e: *this) { |
| | e->move(offset); |
| | adjustBorders(e); |
| | } |
| | calculateBordersIfNeeded(); |
| | } |
| |
|
| | void RS_EntityContainer::rotate(const RS_Vector ¢er, double angle) { |
| | RS_EntityContainer::rotate(center, RS_Vector{angle}); |
| | } |
| |
|
| | void RS_EntityContainer::rotate(const RS_Vector ¢er, const RS_Vector &angleVector) { |
| | resetBorders(); |
| | for (RS_Entity *e: *this) { |
| | e->rotate(center, angleVector); |
| | adjustBorders(e); |
| | } |
| | calculateBordersIfNeeded(); |
| | } |
| |
|
| | void RS_EntityContainer::scale(const RS_Vector ¢er, const RS_Vector &factor) { |
| | if (std::abs(factor.x) > RS_TOLERANCE && std::abs(factor.y) > RS_TOLERANCE) { |
| | scaleBorders(center, factor); |
| | for (RS_Entity* e: *this) { |
| | e->scale(center, factor); |
| | adjustBorders(e); |
| | } |
| | calculateBordersIfNeeded(); |
| | } |
| | } |
| |
|
| | void RS_EntityContainer::mirror(const RS_Vector &axisPoint1, const RS_Vector &axisPoint2) { |
| | if (axisPoint1.distanceTo(axisPoint2) > RS_TOLERANCE) { |
| | resetBorders(); |
| | for (RS_Entity *e: *this) { |
| | e->mirror(axisPoint1, axisPoint2); |
| | adjustBorders(e); |
| | } |
| | } |
| | } |
| |
|
| | RS_Entity &RS_EntityContainer::shear(double k) { |
| | for (RS_Entity *e: *this) { |
| | e->shear(k); |
| | } |
| | calculateBorders(); |
| | return *this; |
| | } |
| |
|
| | void RS_EntityContainer::stretch(const RS_Vector &firstCorner,const RS_Vector &secondCorner,const RS_Vector &offset) { |
| | if (getMin().isInWindow(firstCorner, secondCorner) && getMax().isInWindow(firstCorner, secondCorner)) { |
| | move(offset); |
| | } else { |
| | for (RS_Entity *e: *this) { |
| | e->stretch(firstCorner, secondCorner, offset); |
| | } |
| | } |
| | |
| | update(); |
| | } |
| |
|
| | void RS_EntityContainer::calculateBordersIfNeeded() { |
| | if (m_autoUpdateBorders) { |
| | calculateBorders(); |
| | } |
| | } |
| |
|
| | void RS_EntityContainer::moveRef(const RS_Vector &ref,const RS_Vector &offset) { |
| | resetBorders(); |
| | for (RS_Entity *e: *this) { |
| | e->moveRef(ref, offset); |
| | adjustBorders(e); |
| | } |
| | calculateBordersIfNeeded(); |
| | } |
| |
|
| | void RS_EntityContainer::moveSelectedRef(const RS_Vector &ref,const RS_Vector &offset) { |
| | resetBorders(); |
| | for (RS_Entity *e: *this) { |
| | e->moveSelectedRef(ref, offset); |
| | adjustBorders(e); |
| | } |
| | calculateBordersIfNeeded(); |
| | } |
| |
|
| | void RS_EntityContainer::revertDirection() { |
| | |
| | for (int k = 0; k < m_entities.size() / 2; ++k) { |
| | #if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) |
| | m_entities.swapItemsAt(k, m_entities.size() - 1 - k); |
| | #else |
| | entities.swap(k, entities.size() - 1 - k); |
| | #endif |
| | } |
| |
|
| | |
| | for (RS_Entity *entity: std::as_const(m_entities)) { |
| | entity->revertDirection(); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void RS_EntityContainer::draw(RS_Painter *painter) { |
| | for(RS_Entity *e: *this){ |
| | if (e!=nullptr && e->getId() != 0) { |
| | painter->drawEntity(e); |
| | } |
| | } |
| | } |
| |
|
| | void RS_EntityContainer::drawAsChild(RS_Painter *painter) { |
| | for(RS_Entity *e: *this){ |
| | if (e!=nullptr && e->getId() != 0) { |
| | painter->drawAsChild(e); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | double RS_EntityContainer::areaLineIntegral() const { |
| | |
| | double contourArea = 0.; |
| | |
| | double closedArea = 0.; |
| | double subArea = 0.; |
| |
|
| | |
| | RS_Vector previousPoint(false); |
| | for (unsigned i = 0; i < count(); ++i) { |
| | RS_Entity *e = m_entities.at(i); |
| | if (isClosedLoop(*e)) { |
| | if (e->isContainer()) { |
| | subArea += e->areaLineIntegral(); |
| | } |
| | else { |
| | closedArea += e->areaLineIntegral(); |
| | } |
| | continue; |
| | } |
| | e->setLayer(getLayer()); |
| | double lineIntegral = e->areaLineIntegral(); |
| | RS_Vector startPoint = e->getStartpoint(); |
| | RS_Vector endPoint = e->getEndpoint(); |
| | |
| |
|
| | |
| | if (previousPoint.valid) { |
| | double distance = endPointDistance(previousPoint, *e); |
| | if (distance > contourTolerance) |
| | RS_DEBUG->print(RS_Debug::D_ERROR, |
| | "%s(): contour area calculation maybe incorrect: gap of %lg found at (%lg, %lg)", |
| | __func__, distance, previousPoint.x, previousPoint.y); |
| | } |
| | |
| | if (previousPoint.valid && endPoint.squaredTo(previousPoint) <= RS_TOLERANCE15) { |
| | contourArea -= lineIntegral; |
| | previousPoint = startPoint; |
| | } else { |
| | bool useEndPoint = true; |
| | if (!previousPoint.valid && i + 1 < count()) { |
| | auto currEntity = m_entities.at(i + 1); |
| | useEndPoint = endPointDistance(endPoint, *currEntity) < endPointDistance(startPoint, *currEntity); |
| | } |
| | contourArea += useEndPoint ? lineIntegral : -lineIntegral; |
| | previousPoint = useEndPoint ? endPoint : startPoint; |
| | } |
| | } |
| | return std::abs(contourArea) + closedArea - subArea; |
| | } |
| |
|
| | bool RS_EntityContainer::ignoredOnModification() const { |
| | RS2::EntityType ownType = rtti(); |
| | if (RS2::isDimensionalEntity(ownType) || RS2::isTextEntity(ownType) || ownType == RS2::EntityHatch){ |
| | return true; |
| | } |
| | else { |
| | return isParentIgnoredOnModifications(); |
| | } |
| | } |
| |
|
| | bool RS_EntityContainer::ignoredSnap() const{ |
| | |
| | |
| | if (getParent() && getParent()->rtti() == RS2::EntityHatch) { |
| | return true; |
| | } |
| | return ignoredOnModification(); |
| | } |
| |
|
| | QList<RS_Entity *>::const_iterator RS_EntityContainer::begin() const{ |
| | return m_entities.begin(); |
| | } |
| |
|
| | QList<RS_Entity *>::const_iterator RS_EntityContainer::end() const{ |
| | return m_entities.end(); |
| | } |
| |
|
| | QList<RS_Entity *>::const_iterator RS_EntityContainer::cbegin() const{ |
| | return m_entities.cbegin(); |
| | } |
| |
|
| | QList<RS_Entity *>::const_iterator RS_EntityContainer::cend() const{ |
| | return m_entities.cend(); |
| | } |
| |
|
| | QList<RS_Entity *>::iterator RS_EntityContainer::begin(){ |
| | return m_entities.begin(); |
| | } |
| |
|
| | QList<RS_Entity *>::iterator RS_EntityContainer::end() { |
| | return m_entities.end(); |
| | } |
| |
|
| | |
| | |
| | |
| | std::ostream &operator<<(std::ostream &os, RS_EntityContainer &ec) { |
| | static int indent = 0; |
| | std::string tab(indent * 2, ' '); |
| | ++indent; |
| | unsigned long int id = ec.getId(); |
| | os << tab << "EntityContainer[" << id << "]: \n"; |
| | os << tab << "Borders[" << id << "]: " |
| | << ec.minV << " - " << ec.maxV << "\n"; |
| | |
| | |
| | if (ec.getLayer()) { |
| | os << tab << "Layer[" << id << "]: " |
| | << ec.getLayer()->getName().toLatin1().data() << "\n"; |
| | } else { |
| | os << tab << "Layer[" << id << "]: <nullptr>\n"; |
| | } |
| | |
| |
|
| | os << tab << " Flags[" << id << "]: " |
| | << (ec.getFlag(RS2::FlagVisible) ? "RS2::FlagVisible" : ""); |
| | os << (ec.getFlag(RS2::FlagUndone) ? " RS2::FlagUndone" : ""); |
| | os << (ec.getFlag(RS2::FlagSelected) ? " RS2::FlagSelected" : ""); |
| | os << "\n"; |
| |
|
| | os << tab << "Entities[" << id << "]: \n"; |
| | for(auto t: ec){ |
| | switch (t->rtti()) { |
| | case RS2::EntityInsert: |
| | os << tab << *static_cast<RS_Insert*>(t); |
| | os << tab << *t; |
| | os << tab << *static_cast<RS_EntityContainer*>(t); |
| | break; |
| | default: |
| | if (t->isContainer()) { |
| | os << tab << *static_cast<RS_EntityContainer*>(t); |
| | } |
| | else { |
| | os << tab << *t; |
| | } |
| | break; |
| | } |
| | } |
| | os << tab << "\n\n"; |
| | --indent; |
| | return os; |
| | } |
| |
|
| | RS_Entity *RS_EntityContainer::first() const { |
| | return m_entities.first(); |
| | } |
| |
|
| | RS_Entity *RS_EntityContainer::last() const { |
| | return m_entities.last(); |
| | } |
| |
|
| | const QList<RS_Entity *> &RS_EntityContainer::getEntityList() { |
| | return m_entities; |
| | } |
| |
|
| | std::vector<std::unique_ptr<RS_EntityContainer>> RS_EntityContainer::getLoops() const { |
| | if (m_entities.empty()) { |
| | return {}; |
| | } |
| | std::vector<std::unique_ptr<RS_EntityContainer>> loops; |
| | RS_EntityContainer edges(nullptr, false); |
| | for(RS_Entity* en: *this){ |
| | if (en != nullptr && en->isContainer()){ |
| | if (en->isContainer()){ |
| | auto subLoops = static_cast<RS_EntityContainer*>(en)->getLoops(); |
| | for (auto& subLoop: subLoops) { |
| | loops.push_back(std::move(subLoop)); |
| | } |
| | } |
| | continue; |
| | } |
| |
|
| | if (en == nullptr || !en->isEdge()) { |
| | continue; |
| | } |
| |
|
| | |
| | switch (en->rtti()) { |
| | case RS2::EntityEllipse: |
| | if (static_cast<RS_Ellipse*>(en)->isEllipticArc()) { |
| | edges.addEntity(en); |
| | break; |
| | } |
| | [[fallthrough]]; |
| | case RS2::EntityCircle: { |
| | auto ec = std::make_unique<RS_EntityContainer>(nullptr, false); |
| | ec->addEntity(en); |
| | loops.push_back(std::move(ec)); |
| | break; |
| | } |
| | default: |
| | edges.addEntity(en); |
| | } |
| | } |
| | |
| | while (!edges.isEmpty()){ |
| | LC_LoopUtils::LoopExtractor extractor{edges}; |
| | auto subLoops = extractor.extract(); |
| | for (auto& loop: subLoops) { |
| | loops.push_back(std::move(loop)); |
| | } |
| | } |
| | return loops; |
| | } |
| |
|