[TD]fix #9471 - prevent impossible centerline
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user