[TD]fix #9471 - prevent impossible centerline

This commit is contained in:
wandererfan
2023-05-06 19:50:05 -04:00
committed by WandererFan
parent bd3f71b478
commit 970fd86705
5 changed files with 103 additions and 57 deletions

View File

@@ -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<Base::Vector3d, Base::Vector3d> 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
}

View File

@@ -283,6 +283,7 @@ std::vector<Base::Vector3d> 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;
}

View File

@@ -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;

View File

@@ -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<Base::Vector3d> 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<Base::Vector3d> 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,

View File

@@ -88,6 +88,9 @@ protected:
Qt::PenStyle getCenterStyle();
double getExtendBy();
int checkPathologicalEdges(int inMode);
void setUiOrientation(int orientation);
private:
std::unique_ptr<Ui_TaskCenterLine> ui;