diff --git a/src/Mod/TechDraw/App/CenterLine.cpp b/src/Mod/TechDraw/App/CenterLine.cpp index f467f5a802..80b7c02d62 100644 --- a/src/Mod/TechDraw/App/CenterLine.cpp +++ b/src/Mod/TechDraw/App/CenterLine.cpp @@ -43,6 +43,7 @@ #include "CenterLinePy.h" using namespace TechDraw; +using DU = DrawUtil; TYPESYSTEM_SOURCE(TechDraw::CenterLine, Base::Persistence) @@ -108,8 +109,22 @@ CenterLine::CenterLine(Base::Vector3d pt1, double h, double v, double r, - double x) : CenterLine(BaseGeomPtrFromVectors(pt1, pt2), m, h, v, r, x) + double x) { + m_start = pt1; + m_end = pt2; + m_mode = m; + m_hShift = h; + m_vShift = v; + m_rotate = r; + m_extendBy = x; + m_type = CLTYPE::FACE; + m_flip2Line = false; + + m_geometry = BaseGeomPtrFromVectors(pt1, pt2); + + initialize(); + } CenterLine::~CenterLine() @@ -509,13 +524,28 @@ std::pair CenterLine::calcEndPoints2Lines(DrawVi Base::Vector3d p2 = (l1p2 + l2p2) / 2.0; Base::Vector3d mid = (p1 + p2) / 2.0; + // if the proposed end points prevent the creation of a vertical or horizontal centerline, we need + // to prevent the "orientation" code below from creating identical endpoints. This would create a + // zero length edge and cause problems later. + // this should probably be prevented in the creation task? + bool inhibitVertical = false; + bool inhibitHorizontal = false; + if (DU::fpCompare(p1.y, p2.y, EWTOLERANCE)) { + // proposed end points are aligned vertically, so we can't draw a vertical line to connect them + inhibitVertical = true; + } + if (DU::fpCompare(p1.x, p2.x, EWTOLERANCE)) { + // proposed end points are aligned horizontally, so we can't draw a horizontal line to connect them + inhibitHorizontal = true; + } + //orientation - if (mode == 0) { //Vertical - p1.x = mid.x; - p2.x = mid.x; - } else if (mode == 1) { //Horizontal - p1.y = mid.y; - p2.y = mid.y; + if (mode == 0 && !inhibitVertical) { //Vertical + p1.x = mid.x; + p2.x = mid.x; + } else if (mode == 1 && !inhibitHorizontal) { //Horizontal + p1.y = mid.y; + p2.y = mid.y; } else if (mode == 2) { //Aligned // no op } diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp index eb487f8aa8..9786f2245d 100644 --- a/src/Mod/TechDraw/App/Geometry.cpp +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -283,6 +283,7 @@ std::vector BaseGeom::findEndPoints() } else { //TODO: this should throw something Base::Console().Message("Geometry::findEndPoints - OCC edge not found\n"); + throw Base::RuntimeError("no OCC edge in Geometry::findEndPoints"); } return result; } diff --git a/src/Mod/TechDraw/App/GeometryMatcher.cpp b/src/Mod/TechDraw/App/GeometryMatcher.cpp index 6d1f68c018..45b2baea8a 100644 --- a/src/Mod/TechDraw/App/GeometryMatcher.cpp +++ b/src/Mod/TechDraw/App/GeometryMatcher.cpp @@ -272,7 +272,7 @@ bool GeometryMatcher::compareEllipseArcs(TopoDS_Edge &edge1, TopoDS_Edge &edge2) // not sure how successful this would be. For now, we just say it doesn't match bool GeometryMatcher::compareDifferent(TopoDS_Edge &edge1, TopoDS_Edge &edge2) { - Base::Console().Message("GM::compareDifferent()\n"); +// Base::Console().Message("GM::compareDifferent()\n"); BRepAdaptor_Curve adapt1(edge1); BRepAdaptor_Curve adapt2(edge2); return false; diff --git a/src/Mod/TechDraw/Gui/TaskCenterLine.cpp b/src/Mod/TechDraw/Gui/TaskCenterLine.cpp index 68110786de..94eae46cee 100644 --- a/src/Mod/TechDraw/Gui/TaskCenterLine.cpp +++ b/src/Mod/TechDraw/Gui/TaskCenterLine.cpp @@ -47,6 +47,7 @@ using namespace Gui; using namespace TechDraw; using namespace TechDrawGui; +using DU = DrawUtil; //ctor for edit TaskCenterLine::TaskCenterLine(TechDraw::DrawViewPart* partFeat, @@ -190,6 +191,9 @@ void TaskCenterLine::setUiPrimary() ui->qsbRotate->setValue(qAngle); int precision = Base::UnitsApi::getDecimals(); ui->qsbRotate->setDecimals(precision); + + int orientation = checkPathologicalEdges(m_mode); + setUiOrientation(orientation); } void TaskCenterLine::setUiEdit() @@ -292,26 +296,45 @@ void TaskCenterLine::onStyleChanged() m_partFeat->recomputeFeature(); } +// check that we are not trying to create an impossible centerline (ex a vertical centerline +// between 2 horizontal edges) +int TaskCenterLine::checkPathologicalEdges(int inMode) +{ + if (m_type != 1) { + // not an edge based centerline, this doesn't apply + return inMode; + } + + TechDraw::BaseGeomPtr edge1 = m_partFeat->getEdge(m_subNames.front()); + std::vector ends1 = edge1->findEndPoints(); + bool edge1Vertical = DU::fpCompare(ends1.front().x, ends1.back().x, EWTOLERANCE); + bool edge1Horizontal = DU::fpCompare(ends1.front().y, ends1.back().y, EWTOLERANCE); + + TechDraw::BaseGeomPtr edge2 = m_partFeat->getEdge(m_subNames.back()); + std::vector ends2 = edge2->findEndPoints(); + bool edge2Vertical = DU::fpCompare(ends2.front().x, ends2.back().x, EWTOLERANCE); + bool edge2Horizontal = DU::fpCompare(ends2.front().y, ends2.back().y, EWTOLERANCE); + + if (edge1Vertical && edge2Vertical) { + return CenterLine::CLMODE::VERTICAL; + } + if (edge1Horizontal && edge2Horizontal) { + return CenterLine::CLMODE::HORIZONTAL; + } + + // not pathological case, just return the input mode + return inMode; +} + //****************************************************************************** void TaskCenterLine::createCenterLine() { Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create CenterLine")); + m_mode = checkPathologicalEdges(m_mode); + CenterLine* cl = CenterLine::CenterLineBuilder(m_partFeat, m_subNames, m_mode, false); - // the centerline creation can fail if m_type is edge and both selected edges are horizontal - // because we attempt by default to create a vertical centerline - - if (!cl) { // try a horizontal line - cl = CenterLine::CenterLineBuilder(m_partFeat, m_subNames, CenterLine::CLMODE::HORIZONTAL, false); - if (cl) { - m_mode = CenterLine::CLMODE::HORIZONTAL; - ui->rbHorizontal->blockSignals(true); - ui->rbHorizontal->setChecked(true); - ui->rbHorizontal->blockSignals(false); - } - } - if (!cl) { Gui::Command::abortCommand(); return; @@ -344,52 +367,41 @@ void TaskCenterLine::createCenterLine() void TaskCenterLine::updateOrientation() { + if (!m_cl) { + return; + } // When the orientation was changed, it can be that the centerline becomes invalid // this can lead to a crash, see e.g. // https://forum.freecad.org/viewtopic.php?f=35&t=44255&start=20#p503220 // The centerline creation can fail if m_type is edge and both selected edges are vertical or horizontal. - // To test the validity before an existing centerline is changed, we create a new one with the desired parameters. int orientation = m_cl->m_mode; - if (!m_edgeName.empty()) { // we have an existing centerline, not a freshly created one - // since m_subNames is then empty, fill it with two times the centerline - // because the result of CenterLineBuilder will then in case of success again be the centerline - m_subNames.resize(2); - m_subNames[0] = m_edgeName; - m_subNames[1] = m_edgeName; + if (!m_edgeName.empty() && !m_cl->m_edges.empty()) { + // we have an existing centerline, not a freshly created one, and it is a centerline between edges + m_subNames = m_cl->m_edges; + orientation = checkPathologicalEdges(orientation); } - CenterLine* cl = CenterLine::CenterLineBuilder(m_partFeat, m_subNames, orientation, m_cl->m_flip2Line); + setUiOrientation(orientation); - if (!cl) { // try another orientation - if (orientation == CenterLine::CLMODE::VERTICAL) - orientation = CenterLine::CLMODE::HORIZONTAL; - else if (orientation == CenterLine::CLMODE::HORIZONTAL) - orientation = CenterLine::CLMODE::VERTICAL; - cl = CenterLine::CenterLineBuilder(m_partFeat, m_subNames, orientation, m_cl->m_flip2Line); - if (cl) { - if (orientation == CenterLine::CLMODE::VERTICAL) { - m_cl->m_mode = CenterLine::CLMODE::VERTICAL; - ui->rbVertical->blockSignals(true); - ui->rbVertical->setChecked(true); - // we know now that only vertical is possible - ui->rbHorizontal->setEnabled(false); - ui->rbVertical->blockSignals(false); - } - else if (orientation == CenterLine::CLMODE::HORIZONTAL) { - m_cl->m_mode = CenterLine::CLMODE::HORIZONTAL; - ui->rbHorizontal->blockSignals(true); - ui->rbHorizontal->setChecked(true); - ui->rbVertical->setEnabled(false); - ui->rbHorizontal->blockSignals(false); - } - } + m_partFeat->recomputeFeature(); +} + +void TaskCenterLine::setUiOrientation(int orientation) +{ + ui->rbVertical->blockSignals(true); + ui->rbVertical->blockSignals(true); + + if (orientation == CenterLine::CLMODE::VERTICAL) { + ui->rbVertical->setChecked(true); + ui->rbHorizontal->setChecked(false); + } else if (orientation == CenterLine::CLMODE::HORIZONTAL) { + ui->rbVertical->setChecked(false); + ui->rbHorizontal->setChecked(true); } - if (cl) { // we succeeded - // reset the flip for existing centerline that might use the flip feature (when created with FC 0.19) - m_cl->m_flip2Line = false; - m_partFeat->recomputeFeature(); - } + ui->rbVertical->blockSignals(false); + ui->rbVertical->blockSignals(false); + } void TaskCenterLine::saveButtons(QPushButton* btnOK, diff --git a/src/Mod/TechDraw/Gui/TaskCenterLine.h b/src/Mod/TechDraw/Gui/TaskCenterLine.h index cdd1a0cbff..b725d79b17 100644 --- a/src/Mod/TechDraw/Gui/TaskCenterLine.h +++ b/src/Mod/TechDraw/Gui/TaskCenterLine.h @@ -88,6 +88,9 @@ protected: Qt::PenStyle getCenterStyle(); double getExtendBy(); + int checkPathologicalEdges(int inMode); + void setUiOrientation(int orientation); + private: std::unique_ptr ui;