1
/***************************************************************************
2
* Copyright (c) 2019 WandererFan <wandererfan@gmail.com> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
25
#include <Base/Console.h>
26
#include <Base/Tools.h>
27
#include <Base/UnitsApi.h>
28
#include <Gui/Application.h>
29
#include <Gui/BitmapFactory.h>
30
#include <Gui/Command.h>
31
#include <Gui/Document.h>
32
#include <Gui/ViewProvider.h>
33
#include <Mod/TechDraw/App/Cosmetic.h>
34
#include <Mod/TechDraw/App/DrawPage.h>
35
#include <Mod/TechDraw/App/DrawUtil.h>
36
#include <Mod/TechDraw/App/DrawViewPart.h>
37
#include <Mod/TechDraw/App/Geometry.h>
38
#include <Mod/TechDraw/App/LineGroup.h>
40
#include "TaskCenterLine.h"
41
#include "ui_TaskCenterLine.h"
42
#include "PreferencesGui.h"
44
#include "ViewProviderViewPart.h"
45
#include "DrawGuiUtil.h"
49
using namespace TechDraw;
50
using namespace TechDrawGui;
54
TaskCenterLine::TaskCenterLine(TechDraw::DrawViewPart* partFeat,
55
TechDraw::DrawPage* page,
58
ui(new Ui_TaskCenterLine),
65
m_type(CenterLine::FACE),
66
m_mode(CenterLine::VERTICAL),
71
m_geomIndex = DrawUtil::getIndexFromName(m_edgeName);
72
const TechDraw::BaseGeomPtrVector &geoms = partFeat->getEdgeGeometry();
73
BaseGeomPtr bg = geoms.at(m_geomIndex);
74
std::string tag = bg->getCosmeticTag();
75
m_cl = partFeat->getCenterLine(tag);
76
//existence of m_cl is checked in CommandAnnotate
77
m_type = m_cl->m_type;
78
m_mode = m_cl->m_mode;
81
// connect the dialog objects
83
// save the existing centerline to restore in case the user rejects the changes
88
TaskCenterLine::TaskCenterLine(TechDraw::DrawViewPart* partFeat,
89
TechDraw::DrawPage* page,
90
std::vector<std::string> subNames,
92
ui(new Ui_TaskCenterLine),
101
m_type(CenterLine::FACE),
102
m_mode(CenterLine::VERTICAL),
105
//existence of page and feature are checked by isActive method of calling command
108
std::string check = subNames.front();
109
std::string geomType = TechDraw::DrawUtil::getGeomTypeFromName(check);
110
if (geomType == "Face") {
111
m_type = CenterLine::FACE;
112
} else if (geomType == "Edge") {
113
m_type = CenterLine::EDGE;
114
} else if (geomType == "Vertex") {
115
m_type = CenterLine::VERTEX;
117
Base::Console().Error("TaskCenterLine - unknown geometry type: %s. Can not proceed.\n", geomType.c_str());
121
// setup the Ui using (user-defined) default values
123
// connect the dialog objects
125
// now create the centerline
129
TaskCenterLine::~TaskCenterLine()
133
void TaskCenterLine::updateTask()
137
void TaskCenterLine::changeEvent(QEvent *event)
139
if (event->type() == QEvent::LanguageChange) {
140
ui->retranslateUi(this);
144
void TaskCenterLine::setUiConnect()
146
// first enabling/disabling
147
if (m_type == CenterLine::FACE) // if face, then aligned is not possible
148
ui->rbAligned->setEnabled(false);
150
ui->rbAligned->setEnabled(true);
153
connect(ui->cpLineColor, &ColorButton::changed, this, &TaskCenterLine::onColorChanged);
154
connect(ui->dsbWeight, qOverload<double>(&QuantitySpinBox::valueChanged), this, &TaskCenterLine::onWeightChanged);
155
connect(ui->cboxStyle, qOverload<int>(&QComboBox::currentIndexChanged), this, &TaskCenterLine::onStyleChanged);
156
connect(ui->qsbVertShift, qOverload<double>(&QuantitySpinBox::valueChanged), this, &TaskCenterLine::onShiftVertChanged);
157
connect(ui->qsbHorizShift, qOverload<double>(&QuantitySpinBox::valueChanged), this, &TaskCenterLine::onShiftHorizChanged);
158
connect(ui->qsbExtend, qOverload<double>(&QuantitySpinBox::valueChanged), this, &TaskCenterLine::onExtendChanged);
159
connect(ui->qsbRotate, qOverload<double>(&QuantitySpinBox::valueChanged), this, &TaskCenterLine::onRotationChanged);
160
#if QT_VERSION < QT_VERSION_CHECK(5,15,0)
161
connect(ui->bgOrientation, qOverload<int>(&QButtonGroup::buttonClicked), this, &TaskCenterLine::onOrientationChanged);
163
connect(ui->bgOrientation, &QButtonGroup::idClicked, this, &TaskCenterLine::onOrientationChanged);
167
void TaskCenterLine::setUiPrimary()
169
setWindowTitle(QObject::tr("Create Center Line"));
172
std::string baseName = m_partFeat->getNameInDocument();
173
ui->leBaseView->setText(Base::Tools::fromStdString(baseName));
174
for (auto& s: m_subNames) {
175
QString listItem = Base::Tools::fromStdString(s);
176
ui->lstSubList->addItem(listItem);
179
ui->cpLineColor->setColor(getCenterColor());
180
ui->dsbWeight->setValue(getCenterWidth());
182
DrawGuiUtil::loadLineStyleChoices(ui->cboxStyle);
183
if (ui->cboxStyle->count() >= Preferences::CenterLineStyle() ) {
184
ui->cboxStyle->setCurrentIndex(Preferences::CenterLineStyle() - 1);
187
ui->qsbVertShift->setUnit(Base::Unit::Length);
188
ui->qsbHorizShift->setUnit(Base::Unit::Length);
190
qVal.setUnit(Base::Unit::Length);
191
qVal.setValue(getExtendBy());
192
ui->qsbExtend->setValue(qVal);
194
Base::Quantity qAngle;
195
qAngle.setUnit(Base::Unit::Angle);
196
ui->qsbRotate->setValue(qAngle);
197
int precision = Base::UnitsApi::getDecimals();
198
ui->qsbRotate->setDecimals(precision);
200
if (m_type == CenterLine::EDGE) {
201
int orientation = checkPathologicalEdges(m_mode);
202
setUiOrientation(orientation);
204
if (m_type == CenterLine::VERTEX) {
205
int orientation = checkPathologicalVertices(m_mode);
206
setUiOrientation(orientation);
210
void TaskCenterLine::setUiEdit()
212
setWindowTitle(QObject::tr("Edit Center Line"));
214
std::string baseName = m_partFeat->getNameInDocument();
215
ui->leBaseView->setText(Base::Tools::fromStdString(baseName));
216
QString listItem = Base::Tools::fromStdString(m_edgeName);
217
ui->lstSubList->addItem(listItem);
219
ui->cpLineColor->setColor(m_cl->m_format.m_color.asValue<QColor>());
220
ui->dsbWeight->setValue(m_cl->m_format.m_weight);
222
DrawGuiUtil::loadLineStyleChoices(ui->cboxStyle);
223
if (ui->cboxStyle->count() >= m_cl->m_format.m_style ) {
224
ui->cboxStyle->setCurrentIndex(m_cl->m_format.m_style - 1);
227
ui->rbVertical->setChecked(false);
228
ui->rbHorizontal->setChecked(false);
229
ui->rbAligned->setChecked(false);
230
if (m_cl->m_mode == CenterLine::VERTICAL)
231
ui->rbVertical->setChecked(true);
232
else if (m_cl->m_mode == CenterLine::HORIZONTAL)
233
ui->rbHorizontal->setChecked(true);
234
else if (m_cl->m_mode == CenterLine::ALIGNED)
235
ui->rbAligned->setChecked(true);
238
qVal.setUnit(Base::Unit::Length);
239
qVal.setValue(m_cl->m_vShift);
240
ui->qsbVertShift->setValue(qVal);
241
qVal.setValue(m_cl->m_hShift);
242
ui->qsbHorizShift->setValue(qVal);
243
qVal.setValue(m_cl->m_extendBy);
244
ui->qsbExtend->setValue(qVal);
246
Base::Quantity qAngle;
247
qAngle.setUnit(Base::Unit::Angle);
248
ui->qsbRotate->setValue(qAngle);
249
int precision = Base::UnitsApi::getDecimals();
250
ui->qsbRotate->setDecimals(precision);
251
ui->qsbRotate->setValue(m_cl->m_rotate);
254
void TaskCenterLine::onOrientationChanged()
259
if (ui->rbVertical->isChecked())
260
m_cl->m_mode = CenterLine::CLMODE::VERTICAL;
261
else if (ui->rbHorizontal->isChecked())
262
m_cl->m_mode = CenterLine::CLMODE::HORIZONTAL;
263
else if (ui->rbAligned->isChecked())
264
m_cl->m_mode = CenterLine::CLMODE::ALIGNED;
265
// for centerlines between 2 lines we cannot just recompute
266
// because the new orientation might lead to an invalid centerline
267
if (m_type == CenterLine::EDGE)
270
m_partFeat->recomputeFeature();
273
void TaskCenterLine::onShiftHorizChanged()
279
m_cl->m_hShift = ui->qsbHorizShift->rawValue();
280
m_partFeat->recomputeFeature();
283
void TaskCenterLine::onShiftVertChanged()
289
m_cl->m_vShift = ui->qsbVertShift->rawValue();
290
m_partFeat->recomputeFeature();
293
void TaskCenterLine::onRotationChanged()
299
m_cl->m_rotate = ui->qsbRotate->rawValue();
300
m_partFeat->recomputeFeature();
303
void TaskCenterLine::onExtendChanged()
309
m_cl->m_extendBy = ui->qsbExtend->rawValue();
310
m_partFeat->recomputeFeature();
313
void TaskCenterLine::onColorChanged()
320
ac.setValue<QColor>(ui->cpLineColor->color());
321
m_cl->m_format.m_color.setValue<QColor>(ui->cpLineColor->color());
322
m_partFeat->recomputeFeature();
325
void TaskCenterLine::onWeightChanged()
331
m_cl->m_format.m_weight = ui->dsbWeight->value().getValue();
332
m_partFeat->recomputeFeature();
335
void TaskCenterLine::onStyleChanged()
341
m_cl->m_format.setLineNumber(ui->cboxStyle->currentIndex() + 1);
342
m_partFeat->recomputeFeature();
345
// check that we are not trying to create an impossible centerline (ex a vertical centerline
346
// between 2 horizontal edges)
347
int TaskCenterLine::checkPathologicalEdges(int inMode)
349
if (m_type != CenterLine::EDGE) {
350
// not an edge based centerline, this doesn't apply
354
TechDraw::BaseGeomPtr edge1 = m_partFeat->getEdge(m_subNames.front());
355
std::vector<Base::Vector3d> ends1 = edge1->findEndPoints();
356
bool edge1Vertical = DU::fpCompare(ends1.front().x, ends1.back().x, EWTOLERANCE);
357
bool edge1Horizontal = DU::fpCompare(ends1.front().y, ends1.back().y, EWTOLERANCE);
359
TechDraw::BaseGeomPtr edge2 = m_partFeat->getEdge(m_subNames.back());
360
std::vector<Base::Vector3d> ends2 = edge2->findEndPoints();
361
bool edge2Vertical = DU::fpCompare(ends2.front().x, ends2.back().x, EWTOLERANCE);
362
bool edge2Horizontal = DU::fpCompare(ends2.front().y, ends2.back().y, EWTOLERANCE);
364
if (edge1Vertical && edge2Vertical) {
365
return CenterLine::CLMODE::VERTICAL;
367
if (edge1Horizontal && edge2Horizontal) {
368
return CenterLine::CLMODE::HORIZONTAL;
371
// not pathological case, just return the input mode
375
// check that we are not trying to create an impossible centerline (ex a vertical centerline
376
// between 2 vertices aligned vertically)
377
int TaskCenterLine::checkPathologicalVertices(int inMode)
379
if (m_type != CenterLine::VERTEX) {
380
// not a vertex based centerline, this doesn't apply
384
TechDraw::VertexPtr vert1 = m_partFeat->getVertex(m_subNames.front());
385
Base::Vector3d point1 = vert1->point();
386
TechDraw::VertexPtr vert2 = m_partFeat->getVertex(m_subNames.back());
387
Base::Vector3d point2 = vert2->point();
389
if (DU::fpCompare(point1.x, point2.x, EWTOLERANCE)) {
390
// points are aligned vertically, CL must be horizontal
391
return CenterLine::CLMODE::HORIZONTAL;
394
if (DU::fpCompare(point1.y, point2.y, EWTOLERANCE)) {
395
// points are aligned horizontally, CL must be vertical
396
return CenterLine::CLMODE::VERTICAL;
399
// not pathological case, just return the input mode
403
//******************************************************************************
404
void TaskCenterLine::createCenterLine()
406
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create CenterLine"));
408
// check for illogical parameters
409
if (m_type == CenterLine::EDGE) {
411
m_mode = checkPathologicalEdges(m_mode);
412
} else if (m_type == CenterLine::VERTEX) {
414
m_mode = checkPathologicalVertices(m_mode);
417
CenterLine* cl = CenterLine::CenterLineBuilder(m_partFeat, m_subNames, m_mode, false);
420
Gui::Command::abortCommand();
424
double hShift = ui->qsbHorizShift->rawValue();
425
double vShift = ui->qsbVertShift->rawValue();
426
double rotate = ui->qsbRotate->rawValue();
427
double extendBy = ui->qsbExtend->rawValue();
428
cl->setShifts(hShift, vShift);
429
cl->setExtend(extendBy);
430
cl->setRotate(rotate);
431
cl->m_flip2Line = false;
433
ac.setValue<QColor>(ui->cpLineColor->color());
434
cl->m_format.m_color = ac;
435
cl->m_format.m_weight = ui->dsbWeight->value().getValue();
436
cl->m_format.setLineNumber(ui->cboxStyle->currentIndex() + 1);
437
cl->m_format.m_visible = true;
438
m_partFeat->addCenterLine(cl);
440
m_partFeat->recomputeFeature();
441
Gui::Command::updateActive();
442
Gui::Command::commitCommand();
444
// entering the edit mode
449
void TaskCenterLine::updateOrientation()
451
// Base::Console().Message("TCL::updateOrientation()\n");
455
// When the orientation was changed, it can be that the centerline becomes invalid
456
// this can lead to a crash, see e.g.
457
// https://forum.freecad.org/viewtopic.php?f=35&t=44255&start=20#p503220
458
// The centerline creation can fail if m_type is edge and both selected edges are vertical or horizontal.
459
int orientation = m_cl->m_mode;
460
if (m_type == CenterLine::EDGE) {
462
if (!m_edgeName.empty() && !m_cl->m_edges.empty()) {
463
// we have an existing centerline, not a freshly created one, and it is a centerline between edges
464
m_subNames = m_cl->m_edges;
465
orientation = checkPathologicalEdges(orientation);
467
} else if (m_type == CenterLine::VERTEX) {
469
if (!m_edgeName.empty() && !m_cl->m_verts.empty()) {
470
// we have an existing centerline, not a freshly created one, and it is a centerline between points
471
m_subNames = m_cl->m_verts;
472
orientation = checkPathologicalVertices(orientation);
476
setUiOrientation(orientation);
478
m_partFeat->recomputeFeature();
481
void TaskCenterLine::setUiOrientation(int orientation)
483
ui->rbVertical->blockSignals(true);
484
ui->rbVertical->blockSignals(true);
486
if (orientation == CenterLine::CLMODE::VERTICAL) {
487
ui->rbVertical->setChecked(true);
488
ui->rbHorizontal->setChecked(false);
489
} else if (orientation == CenterLine::CLMODE::HORIZONTAL) {
490
ui->rbVertical->setChecked(false);
491
ui->rbHorizontal->setChecked(true);
494
ui->rbVertical->blockSignals(false);
495
ui->rbVertical->blockSignals(false);
499
void TaskCenterLine::saveButtons(QPushButton* btnOK,
500
QPushButton* btnCancel)
503
m_btnCancel = btnCancel;
506
void TaskCenterLine::enableTaskButtons(bool isEnabled)
508
m_btnOK->setEnabled(isEnabled);
509
m_btnCancel->setEnabled(isEnabled);
512
double TaskCenterLine::getCenterWidth()
514
Gui::ViewProvider* vp = QGIView::getViewProvider(m_partFeat);
515
auto partVP = dynamic_cast<ViewProviderViewPart*>(vp);
517
return TechDraw::LineGroup::getDefaultWidth("Graphic");
519
return partVP->IsoWidth.getValue();
522
QColor TaskCenterLine::getCenterColor()
524
return PreferencesGui::centerQColor();
527
double TaskCenterLine::getExtendBy()
529
return Preferences::getPreferenceGroup("Decorations")->GetFloat("CosmoCLExtend", 3.0);
532
//******************************************************************************
534
bool TaskCenterLine::accept()
536
Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument());
540
Gui::Command::updateActive();
541
Gui::Command::commitCommand();
547
bool TaskCenterLine::reject()
549
Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument());
553
if (getCreateMode() && m_partFeat) {
554
// undo the centerline creation
557
else if (!getCreateMode() && m_partFeat) {
558
// restore the initial centerline
559
m_cl->m_format.m_color = (&orig_cl)->m_format.m_color;
560
m_cl->m_format.m_weight = (&orig_cl)->m_format.m_weight;
561
m_cl->m_format.setLineNumber((&orig_cl)->m_format.getLineNumber());
562
m_cl->m_format.m_visible = (&orig_cl)->m_format.m_visible;
563
m_cl->m_mode = (&orig_cl)->m_mode;
564
m_cl->m_rotate = (&orig_cl)->m_rotate;
565
m_cl->m_vShift = (&orig_cl)->m_vShift;
566
m_cl->m_hShift = (&orig_cl)->m_hShift;
567
m_cl->m_extendBy = (&orig_cl)->m_extendBy;
568
m_cl->m_type = (&orig_cl)->m_type;
572
m_partFeat->recomputeFeature();
573
Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().recompute()");
580
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
581
TaskDlgCenterLine::TaskDlgCenterLine(TechDraw::DrawViewPart* partFeat,
582
TechDraw::DrawPage* page,
583
std::vector<std::string> subNames,
587
widget = new TaskCenterLine(partFeat, page, subNames, editMode);
588
taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/TechDraw_FaceCenterLine"),
589
widget->windowTitle(), true, nullptr);
590
taskbox->groupLayout()->addWidget(widget);
591
Content.push_back(taskbox);
592
setAutoCloseOnTransactionChange(true);
595
TaskDlgCenterLine::TaskDlgCenterLine(TechDraw::DrawViewPart* partFeat,
596
TechDraw::DrawPage* page,
597
std::string edgeName,
601
widget = new TaskCenterLine(partFeat, page, edgeName, editMode);
602
taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/TechDraw_FaceCenterLine"),
603
widget->windowTitle(), true, nullptr);
604
taskbox->groupLayout()->addWidget(widget);
605
Content.push_back(taskbox);
606
setAutoCloseOnTransactionChange(true);
609
TaskDlgCenterLine::~TaskDlgCenterLine()
613
void TaskDlgCenterLine::update()
615
// widget->updateTask();
618
void TaskDlgCenterLine::modifyStandardButtons(QDialogButtonBox* box)
620
QPushButton* btnOK = box->button(QDialogButtonBox::Ok);
621
QPushButton* btnCancel = box->button(QDialogButtonBox::Cancel);
622
widget->saveButtons(btnOK, btnCancel);
625
//==== calls from the TaskView ===============================================================
626
void TaskDlgCenterLine::open()
630
void TaskDlgCenterLine::clicked(int)
634
bool TaskDlgCenterLine::accept()
640
bool TaskDlgCenterLine::reject()
646
#include <Mod/TechDraw/Gui/moc_TaskCenterLine.cpp>