23
#include "PreCompiled.h"
28
# include <QHeaderView>
29
# include <QItemDelegate>
30
# include <QItemSelectionModel>
32
# include <QMessageBox>
34
# include <QVBoxLayout>
36
# include <BRep_Tool.hxx>
38
# include <TopoDS_Edge.hxx>
39
# include <TopoDS_Shape.hxx>
41
# include <TopTools_ListOfShape.hxx>
42
# include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
43
# include <TopTools_IndexedMapOfShape.hxx>
45
# include <Inventor/actions/SoSearchAction.h>
46
# include <Inventor/details/SoLineDetail.h>
49
#include <App/Application.h>
50
#include <App/Document.h>
51
#include <App/DocumentObject.h>
52
#include <Base/UnitsApi.h>
53
#include <Gui/Application.h>
54
#include <Gui/BitmapFactory.h>
55
#include <Gui/Command.h>
56
#include <Gui/QuantitySpinBox.h>
57
#include <Gui/Selection.h>
58
#include <Gui/SelectionFilter.h>
59
#include <Gui/SelectionObject.h>
60
#include <Gui/SoFCUnifiedSelection.h>
61
#include <Gui/ViewProvider.h>
62
#include <Gui/WaitCursor.h>
63
#include <Gui/Window.h>
64
#include <Mod/Part/App/FeatureChamfer.h>
65
#include <Mod/Part/App/FeatureFillet.h>
67
#include "DlgFilletEdges.h"
68
#include "ui_DlgFilletEdges.h"
69
#include "SoBrepEdgeSet.h"
70
#include "SoBrepFaceSet.h"
71
#include "SoBrepPointSet.h"
73
FC_LOG_LEVEL_INIT("Part", true, true)
75
using namespace PartGui;
76
namespace sp = std::placeholders;
78
FilletRadiusDelegate::FilletRadiusDelegate(QObject *parent) : QItemDelegate(parent)
82
QWidget *FilletRadiusDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &,
83
const QModelIndex & index) const
85
if (index.column() < 1)
88
Gui::QuantitySpinBox *editor = new Gui::QuantitySpinBox(parent);
89
editor->setUnit(Base::Unit::Length);
90
editor->setMinimum(0.0);
91
editor->setMaximum(INT_MAX);
92
editor->setSingleStep(0.1);
97
void FilletRadiusDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
99
Base::Quantity value = index.model()->data(index, Qt::EditRole).value<Base::Quantity>();
101
Gui::QuantitySpinBox *spinBox = static_cast<Gui::QuantitySpinBox*>(editor);
102
spinBox->setValue(value);
105
void FilletRadiusDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
106
const QModelIndex &index) const
108
Gui::QuantitySpinBox *spinBox = static_cast<Gui::QuantitySpinBox*>(editor);
109
spinBox->interpretText();
113
Base::Quantity value = spinBox->value();
115
model->setData(index, QVariant::fromValue<Base::Quantity>(value), Qt::EditRole);
118
void FilletRadiusDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
119
const QModelIndex &) const
121
editor->setGeometry(option.rect);
126
FilletRadiusModel::FilletRadiusModel(QObject * parent) : QStandardItemModel(parent)
130
void FilletRadiusModel::updateCheckStates()
133
Q_EMIT layoutChanged();
136
Qt::ItemFlags FilletRadiusModel::flags (const QModelIndex & index) const
138
Qt::ItemFlags fl = QStandardItemModel::flags(index);
139
if (index.column() == 0)
140
fl = fl | Qt::ItemIsUserCheckable;
144
bool FilletRadiusModel::setData (const QModelIndex & index, const QVariant & value, int role)
146
bool ok = QStandardItemModel::setData(index, value, role);
147
if (role == Qt::CheckStateRole) {
148
Q_EMIT toggleCheckState(index);
153
QVariant FilletRadiusModel::data(const QModelIndex& index, int role) const
155
QVariant value = QStandardItemModel::data(index, role);
156
if (role == Qt::DisplayRole && index.column() >= 1) {
157
Base::Quantity q = value.value<Base::Quantity>();
158
QString str = q.getUserString();
167
class EdgeFaceSelection : public Gui::SelectionFilterGate
169
bool allowEdge{true};
170
App::DocumentObject*& object;
172
explicit EdgeFaceSelection(App::DocumentObject*& obj)
173
: Gui::SelectionFilterGate(nullPointer())
185
bool allow(App::Document* , App::DocumentObject*pObj, const char*sSubName) override
187
if (pObj != this->object)
189
if (!sSubName || sSubName[0] == '\0')
191
std::string element(sSubName);
193
return element.substr(0,4) == "Edge";
195
return element.substr(0,4) == "Face";
198
class DlgFilletEdges::Private
201
App::DocumentObject* object;
202
EdgeFaceSelection* selection;
203
Part::FilletBase* fillet;
204
QTimer* highlighttimer;
205
FilletType filletType;
206
std::vector<int> edge_ids;
207
TopTools_IndexedMapOfShape all_edges;
208
TopTools_IndexedMapOfShape all_faces;
209
using Connection = boost::signals2::connection;
210
Connection connectApplicationDeletedObject;
211
Connection connectApplicationDeletedDocument;
213
class SelectionObjectCompare
216
App::DocumentObject* obj;
217
explicit SelectionObjectCompare(App::DocumentObject* obj) : obj(obj)
220
bool operator()(const Gui::SelectionObject& sel) const
222
return (sel.getObject() == obj);
230
DlgFilletEdges::DlgFilletEdges(FilletType type, Part::FilletBase* fillet, QWidget* parent, Qt::WindowFlags fl)
231
: QWidget(parent, fl), ui(new Ui_DlgFilletEdges()), d(new Private())
236
ui->filletStartRadius->setMaximum(INT_MAX);
237
ui->filletStartRadius->setMinimum(0);
238
ui->filletStartRadius->setUnit(Base::Unit::Length);
240
ui->filletEndRadius->setMaximum(INT_MAX);
241
ui->filletEndRadius->setMinimum(0);
242
ui->filletEndRadius->setUnit(Base::Unit::Length);
245
d->selection = new EdgeFaceSelection(d->object);
246
Gui::Selection().addSelectionGate(d->selection);
250
d->connectApplicationDeletedObject = App::GetApplication().signalDeletedObject
251
.connect(std::bind(&DlgFilletEdges::onDeleteObject, this, sp::_1));
252
d->connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument
253
.connect(std::bind(&DlgFilletEdges::onDeleteDocument, this, sp::_1));
256
FilletRadiusModel* model = new FilletRadiusModel(this);
257
connect(model, &FilletRadiusModel::toggleCheckState,
258
this, &DlgFilletEdges::toggleCheckState);
259
model->insertColumns(0,3);
262
d->highlighttimer = new QTimer(this);
263
d->highlighttimer->setSingleShot(true);
264
connect(d->highlighttimer, &QTimer::timeout,
265
this, &DlgFilletEdges::onHighlightEdges);
267
d->filletType = type;
268
if (d->filletType == DlgFilletEdges::CHAMFER) {
269
ui->parameterName->setTitle(tr("Chamfer Parameters"));
270
ui->labelfillet->setText(tr("Chamfer type"));
271
ui->labelRadius->setText(tr("Length:"));
272
ui->filletType->setItemText(0, tr("Equal distance"));
273
ui->filletType->setItemText(1, tr("Two distances"));
275
model->setHeaderData(0, Qt::Horizontal, tr("Edges to chamfer"), Qt::DisplayRole);
276
model->setHeaderData(1, Qt::Horizontal, tr("Size"), Qt::DisplayRole);
277
model->setHeaderData(2, Qt::Horizontal, tr("Size2"), Qt::DisplayRole);
280
ui->parameterName->setTitle(tr("Fillet Parameter"));
281
ui->labelfillet->setText(tr("Fillet type"));
282
model->setHeaderData(0, Qt::Horizontal, tr("Edges to fillet"), Qt::DisplayRole);
283
model->setHeaderData(1, Qt::Horizontal, tr("Start radius"), Qt::DisplayRole);
284
model->setHeaderData(2, Qt::Horizontal, tr("End radius"), Qt::DisplayRole);
286
ui->treeView->setRootIsDecorated(false);
287
ui->treeView->setItemDelegate(new FilletRadiusDelegate(this));
288
ui->treeView->setModel(model);
290
QHeaderView* header = ui->treeView->header();
291
header->setSectionResizeMode(0, QHeaderView::Stretch);
292
header->setDefaultAlignment(Qt::AlignLeft);
293
header->setSectionsMovable(false);
294
onFilletTypeActivated(0);
301
DlgFilletEdges::~DlgFilletEdges()
304
d->connectApplicationDeletedDocument.disconnect();
305
d->connectApplicationDeletedObject.disconnect();
306
Gui::Selection().rmvSelectionGate();
309
void DlgFilletEdges::setupConnections()
312
connect(ui->shapeObject, qOverload<int>(&QComboBox::activated),
313
this, &DlgFilletEdges::onShapeObjectActivated);
314
connect(ui->selectEdges, &QRadioButton::toggled,
315
this, &DlgFilletEdges::onSelectEdgesToggled);
316
connect(ui->selectFaces, &QRadioButton::toggled,
317
this, &DlgFilletEdges::onSelectFacesToggled);
318
connect(ui->selectAllButton, &QPushButton::clicked,
319
this, &DlgFilletEdges::onSelectAllButtonClicked);
320
connect(ui->selectNoneButton, &QPushButton::clicked,
321
this, &DlgFilletEdges::onSelectNoneButtonClicked);
322
connect(ui->filletType, qOverload<int>(&QComboBox::activated),
323
this, &DlgFilletEdges::onFilletTypeActivated);
324
connect(ui->filletStartRadius,
325
qOverload<const Base::Quantity&>(&Gui::QuantitySpinBox::valueChanged),
326
this, &DlgFilletEdges::onFilletStartRadiusValueChanged);
327
connect(ui->filletEndRadius,
328
qOverload<const Base::Quantity&>(&Gui::QuantitySpinBox::valueChanged),
329
this, &DlgFilletEdges::onFilletEndRadiusValueChanged);
333
void DlgFilletEdges::onSelectionChanged(const Gui::SelectionChanges& msg)
336
if (!d->object || !msg.pSubName)
338
if (msg.Type == Gui::SelectionChanges::AddSelection ||
339
msg.Type == Gui::SelectionChanges::RmvSelection) {
342
App::Document* doc = d->object->getDocument();
343
std::string docname = doc->getName();
344
std::string objname = d->object->getNameInDocument();
345
if (docname==msg.pDocName && objname==msg.pObjectName) {
346
QString subelement = QString::fromLatin1(msg.pSubName);
347
if (subelement.startsWith(QLatin1String("Edge"))) {
348
onSelectEdge(subelement, msg.Type);
350
else if (subelement.startsWith(QLatin1String("Face"))) {
351
d->selection->selectEdges();
352
onSelectEdgesOfFace(subelement, msg.Type);
353
d->selection->selectFaces();
358
if (msg.Type != Gui::SelectionChanges::SetPreselect &&
359
msg.Type != Gui::SelectionChanges::RmvPreselect)
360
d->highlighttimer->start(20);
363
void DlgFilletEdges::onHighlightEdges()
365
Gui::ViewProvider* view = Gui::Application::Instance->getViewProvider(d->object);
369
SoSearchAction searchAction;
370
searchAction.setType(PartGui::SoBrepFaceSet::getClassTypeId());
371
searchAction.setInterest(SoSearchAction::FIRST);
372
searchAction.apply(view->getRoot());
373
SoPath* selectionPath = searchAction.getPath();
375
Gui::SoSelectionElementAction action(Gui::SoSelectionElementAction::None);
376
action.apply(selectionPath);
381
SoSearchAction searchAction;
382
searchAction.setType(PartGui::SoBrepPointSet::getClassTypeId());
383
searchAction.setInterest(SoSearchAction::FIRST);
384
searchAction.apply(view->getRoot());
385
SoPath* selectionPath = searchAction.getPath();
387
Gui::SoSelectionElementAction action(Gui::SoSelectionElementAction::None);
388
action.apply(selectionPath);
393
SoSearchAction searchAction;
394
searchAction.setType(PartGui::SoBrepEdgeSet::getClassTypeId());
395
searchAction.setInterest(SoSearchAction::FIRST);
396
searchAction.apply(view->getRoot());
397
SoPath* selectionPath = searchAction.getPath();
399
ParameterGrp::handle hGrp = Gui::WindowParameter::getDefaultParameter()->GetGroup("View");
400
SbColor selectionColor(0.1f, 0.8f, 0.1f);
401
unsigned long selection = (unsigned long)(selectionColor.getPackedValue());
402
selection = hGrp->GetUnsigned("SelectionColor", selection);
404
selectionColor.setPackedValue((uint32_t)selection, transparency);
407
Gui::SoSelectionElementAction clear(Gui::SoSelectionElementAction::None);
408
clear.apply(selectionPath);
410
Gui::SoSelectionElementAction action(Gui::SoSelectionElementAction::Append);
411
action.setColor(selectionColor);
412
action.apply(selectionPath);
414
QAbstractItemModel* model = ui->treeView->model();
416
action.setElement(&detail);
417
for (int i=0; i<model->rowCount(); ++i) {
418
QVariant value = model->index(i,0).data(Qt::CheckStateRole);
419
Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
422
if (checkState & Qt::Checked) {
424
int id = model->index(i,0).data(Qt::UserRole).toInt();
425
detail.setLineIndex(id-1);
426
action.apply(selectionPath);
434
void DlgFilletEdges::onSelectEdge(const QString& subelement, int type)
436
Gui::SelectionChanges::MsgType msgType = Gui::SelectionChanges::MsgType(type);
437
QAbstractItemModel* model = ui->treeView->model();
438
for (int i=0; i<model->rowCount(); ++i) {
439
int id = model->data(model->index(i,0), Qt::UserRole).toInt();
440
QString name = QString::fromLatin1("Edge%1").arg(id);
441
if (name == subelement) {
443
Qt::CheckState checkState =
444
(msgType == Gui::SelectionChanges::AddSelection
445
? Qt::Checked : Qt::Unchecked);
446
QVariant value(static_cast<int>(checkState));
447
QModelIndex index = model->index(i,0);
448
model->setData(index, value, Qt::CheckStateRole);
450
ui->treeView->selectionModel()->setCurrentIndex(index,QItemSelectionModel::NoUpdate);
451
QItemSelection selection(index, model->index(i,1));
452
ui->treeView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
453
ui->treeView->update();
459
void DlgFilletEdges::onSelectEdgesOfFace(const QString& subelement, int type)
462
int index = subelement.mid(4).toInt(&ok);
465
const TopoDS_Shape& face = d->all_faces.FindKey(index);
466
TopTools_IndexedMapOfShape mapOfEdges;
467
TopExp::MapShapes(face, TopAbs_EDGE, mapOfEdges);
469
for(int j = 1; j <= mapOfEdges.Extent(); ++j) {
470
TopoDS_Edge edge = TopoDS::Edge(mapOfEdges.FindKey(j));
471
int id = d->all_edges.FindIndex(edge);
472
QString name = QString::fromLatin1("Edge%1").arg(id);
473
onSelectEdge(name, type);
474
Gui::SelectionChanges::MsgType msgType = Gui::SelectionChanges::MsgType(type);
475
if (msgType == Gui::SelectionChanges::AddSelection) {
476
Gui::Selection().addSelection(d->object->getDocument()->getName(),
477
d->object->getNameInDocument(), (const char*)name.toLatin1());
481
catch (Standard_Failure&) {
486
void DlgFilletEdges::onDeleteObject(const App::DocumentObject& obj)
488
if (d->fillet == &obj) {
491
else if (d->fillet && d->fillet->Base.getValue() == &obj) {
494
ui->shapeObject->setCurrentIndex(0);
495
onShapeObjectActivated(0);
497
else if (d->object == &obj) {
499
ui->shapeObject->removeItem(ui->shapeObject->currentIndex());
500
ui->shapeObject->setCurrentIndex(0);
501
onShapeObjectActivated(0);
504
QString shape = QString::fromLatin1(obj.getNameInDocument());
506
for (int i=1; i<ui->shapeObject->count(); i++) {
507
if (ui->shapeObject->itemData(i).toString() == shape) {
508
ui->shapeObject->removeItem(i);
515
void DlgFilletEdges::onDeleteDocument(const App::Document& doc)
518
if (d->object->getDocument() == &doc) {
519
ui->shapeObject->setCurrentIndex(0);
520
onShapeObjectActivated(0);
524
else if (App::GetApplication().getActiveDocument() == &doc) {
525
ui->shapeObject->setCurrentIndex(0);
526
onShapeObjectActivated(0);
531
void DlgFilletEdges::toggleCheckState(const QModelIndex& index)
535
QVariant check = index.data(Qt::CheckStateRole);
536
int id = index.data(Qt::UserRole).toInt();
537
QString name = QString::fromLatin1("Edge%1").arg(id);
538
Qt::CheckState checkState = static_cast<Qt::CheckState>(check.toInt());
540
bool block = this->blockSelection(true);
543
if (checkState & Qt::Checked) {
544
App::Document* doc = d->object->getDocument();
545
Gui::Selection().addSelection(doc->getName(),
546
d->object->getNameInDocument(),
547
(const char*)name.toLatin1());
550
App::Document* doc = d->object->getDocument();
551
Gui::Selection().rmvSelection(doc->getName(),
552
d->object->getNameInDocument(),
553
(const char*)name.toLatin1());
556
this->blockSelection(block);
559
void DlgFilletEdges::findShapes()
561
App::Document* activeDoc = App::GetApplication().getActiveDocument();
565
std::vector<App::DocumentObject*> objs = activeDoc->getObjectsOfType
566
(Part::Feature::getClassTypeId());
568
int current_index = 0;
569
for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it!=objs.end(); ++it, ++index) {
570
ui->shapeObject->addItem(QString::fromUtf8((*it)->Label.getValue()));
571
ui->shapeObject->setItemData(index, QString::fromLatin1((*it)->getNameInDocument()));
572
if (current_index == 0) {
573
if (Gui::Selection().isSelected(*it)) {
574
current_index = index;
580
if (objs.size() == 1)
583
if (current_index > 0) {
584
ui->shapeObject->setCurrentIndex(current_index);
585
onShapeObjectActivated(current_index);
594
void DlgFilletEdges::setupFillet(const std::vector<App::DocumentObject*>& objs)
596
App::DocumentObject* base = d->fillet->Base.getValue();
597
const std::vector<Part::FilletElement>& e = d->fillet->Edges.getValues();
598
const auto &subs = d->fillet->EdgeLinks.getShadowSubs();
599
if(subs.size()!=e.size()) {
600
FC_ERR("edge link size mismatch");
603
std::set<std::string> subSet;
604
for(auto &sub : subs)
605
subSet.insert(sub.newName.empty()?sub.oldName:sub.newName);
608
std::vector<App::DocumentObject*>::const_iterator it = std::find(objs.begin(), objs.end(), base);
609
if (it != objs.end()) {
611
Gui::ViewProvider* vp;
612
vp = Gui::Application::Instance->getViewProvider(d->fillet);
614
vp = Gui::Application::Instance->getViewProvider(base);
617
int current_index = (it - objs.begin()) + 1;
618
ui->shapeObject->setCurrentIndex(current_index);
619
onShapeObjectActivated(current_index);
620
ui->shapeObject->setEnabled(false);
622
double startRadius = 1;
623
double endRadius = 1;
624
bool twoRadii = false;
626
std::vector<std::string> subElements;
627
QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->treeView->model());
628
bool block = model->blockSignals(true);
629
auto baseShape = Part::Feature::getTopoShape(base);
630
std::set<Part::FilletElement> elements;
631
for(size_t i=0;i<e.size();++i) {
633
if(sub.newName.empty()) {
635
sscanf(sub.oldName.c_str(),"Edge%d",&idx);
637
FC_WARN("missing element reference: " << sub.oldName);
639
elements.insert(e[i]);
642
auto &ref = sub.newName;
643
Part::TopoShape edge;
645
edge = baseShape.getSubShape(ref.c_str());
648
elements.insert(e[i]);
651
FC_WARN("missing element reference: " << base->getFullName() << "." << ref);
653
for(auto &mapped : Part::Feature::getRelatedElements(base,ref.c_str())) {
655
if(!subSet.insert(mapped.index.appendToStringBuffer(tmp)).second
656
|| !subSet.insert(mapped.name.toString(0)).second)
658
FC_WARN("guess element reference: " << ref << " -> " << mapped.index);
659
elements.emplace(mapped.index.getIndex(),e[i].radius1,e[i].radius2);
663
for (const auto & et : e) {
664
std::vector<int>::iterator it = std::find(d->edge_ids.begin(), d->edge_ids.end(), et.edgeid);
665
if (it != d->edge_ids.end()) {
666
int index = it - d->edge_ids.begin();
667
model->setData(model->index(index, 0), Qt::Checked, Qt::CheckStateRole);
670
model->setData(model->index(index, 1), QVariant::fromValue<Base::Quantity>(Base::Quantity(et.radius1, Base::Unit::Length)));
671
model->setData(model->index(index, 2), QVariant::fromValue<Base::Quantity>(Base::Quantity(et.radius2, Base::Unit::Length)));
673
startRadius = et.radius1;
674
endRadius = et.radius2;
675
if (startRadius != endRadius)
678
int id = model->index(index, 0).data(Qt::UserRole).toInt();
679
std::stringstream str;
681
subElements.push_back(str.str());
684
model->blockSignals(block);
688
ui->filletType->setCurrentIndex(1);
689
onFilletTypeActivated(1);
693
ui->filletStartRadius->blockSignals(true);
694
ui->filletStartRadius->setValue(startRadius);
695
ui->filletStartRadius->blockSignals(false);
696
ui->filletEndRadius->blockSignals(true);
697
ui->filletEndRadius->setValue(endRadius);
698
ui->filletEndRadius->blockSignals(false);
700
App::Document* doc = d->object->getDocument();
726
Gui::Selection().clearSelection(doc->getName());
728
if (!subElements.empty()) {
729
Gui::Selection().addSelections(doc->getName(),
730
d->object->getNameInDocument(),
739
void DlgFilletEdges::changeEvent(QEvent *e)
741
if (e->type() == QEvent::LanguageChange) {
742
int index = ui->shapeObject->currentIndex();
744
int count = ui->shapeObject->count() - 1;
746
QList<QVariant> data;
747
for (int i=0; i<count; i++) {
748
text << ui->shapeObject->itemText(i+1);
749
data << ui->shapeObject->itemData(i+1);
752
ui->retranslateUi(this);
753
for (int i=0; i<count; i++) {
754
ui->shapeObject->addItem(text.at(i));
755
ui->shapeObject->setItemData(i+1, data.at(i));
758
ui->shapeObject->setCurrentIndex(index);
759
QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->treeView->model());
760
count = model->rowCount();
761
for (int i=0; i<count; i++) {
762
int id = model->data(model->index(i, 0), Qt::UserRole).toInt();
763
model->setData(model->index(i, 0), QVariant(tr("Edge%1").arg(id)));
767
QWidget::changeEvent(e);
771
void DlgFilletEdges::onShapeObjectActivated(int itemPos)
774
QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->treeView->model());
775
model->removeRows(0, model->rowCount());
777
QByteArray name = ui->shapeObject->itemData(itemPos).toByteArray();
778
App::Document* doc = App::GetApplication().getActiveDocument();
781
App::DocumentObject* part = doc->getObject((const char*)name);
782
if (part && part->isDerivedFrom<Part::Feature>()) {
784
TopoDS_Shape myShape = static_cast<Part::Feature*>(part)->Shape.getValue();
786
d->all_edges.Clear();
787
TopExp::MapShapes(myShape, TopAbs_EDGE, d->all_edges);
789
d->all_faces.Clear();
790
TopExp::MapShapes(myShape, TopAbs_FACE, d->all_faces);
793
TopTools_IndexedDataMapOfShapeListOfShape edge2Face;
794
TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, edge2Face);
795
TopTools_IndexedMapOfShape mapOfShape;
796
TopExp::MapShapes(myShape, TopAbs_EDGE, mapOfShape);
800
for (int i=1; i<= edge2Face.Extent(); ++i) {
802
const TopTools_ListOfShape& los = edge2Face.FindFromIndex(i);
803
if (los.Extent() == 2) {
805
const TopoDS_Shape& edge = edge2Face.FindKey(i);
808
const TopoDS_Shape& face1 = los.First();
809
const TopoDS_Shape& face2 = los.Last();
810
GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge),
812
TopoDS::Face(face2));
813
if (cont == GeomAbs_C0) {
814
int id = mapOfShape.FindIndex(edge);
815
d->edge_ids.push_back(id);
820
model->insertRows(0, d->edge_ids.size());
822
for (int id : d->edge_ids) {
823
model->setData(model->index(index, 0), QVariant(tr("Edge%1").arg(id)));
824
model->setData(model->index(index, 0), QVariant(id), Qt::UserRole);
827
model->setData(model->index(index, 1), QVariant::fromValue<Base::Quantity>(Base::Quantity(1.0,Base::Unit::Length)));
828
model->setData(model->index(index, 2), QVariant::fromValue<Base::Quantity>(Base::Quantity(1.0,Base::Unit::Length)));
829
std::stringstream element;
830
element << "Edge" << id;
831
if (Gui::Selection().isSelected(part, element.str().c_str()))
832
model->setData(model->index(index, 0), Qt::Checked, Qt::CheckStateRole);
834
model->setData(model->index(index, 0), Qt::Unchecked, Qt::CheckStateRole);
840
void DlgFilletEdges::onSelectEdgesToggled(bool on)
842
if (on) d->selection->selectEdges();
845
void DlgFilletEdges::onSelectFacesToggled(bool on)
847
if (on) d->selection->selectFaces();
850
void DlgFilletEdges::onSelectAllButtonClicked()
852
std::vector<std::string> subElements;
853
FilletRadiusModel* model = static_cast<FilletRadiusModel*>(ui->treeView->model());
854
bool block = model->blockSignals(true);
855
for (int i=0; i<model->rowCount(); ++i) {
856
QModelIndex index = model->index(i,0);
859
QVariant check = index.data(Qt::CheckStateRole);
860
Qt::CheckState state = static_cast<Qt::CheckState>(check.toInt());
861
if (state == Qt::Unchecked) {
862
int id = index.data(Qt::UserRole).toInt();
863
std::stringstream str;
865
subElements.push_back(str.str());
868
Qt::CheckState checkState = Qt::Checked;
869
QVariant value(static_cast<int>(checkState));
870
model->setData(index, value, Qt::CheckStateRole);
872
model->blockSignals(block);
873
model->updateCheckStates();
876
App::Document* doc = d->object->getDocument();
877
Gui::Selection().addSelections(doc->getName(),
878
d->object->getNameInDocument(),
883
void DlgFilletEdges::onSelectNoneButtonClicked()
885
FilletRadiusModel* model = static_cast<FilletRadiusModel*>(ui->treeView->model());
886
bool block = model->blockSignals(true);
887
for (int i=0; i<model->rowCount(); ++i) {
888
Qt::CheckState checkState = Qt::Unchecked;
889
QVariant value(static_cast<int>(checkState));
890
model->setData(model->index(i,0), value, Qt::CheckStateRole);
892
model->blockSignals(block);
893
model->updateCheckStates();
896
App::Document* doc = d->object->getDocument();
897
Gui::Selection().clearSelection(doc->getName());
901
void DlgFilletEdges::onFilletTypeActivated(int index)
903
QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->treeView->model());
905
if (d->filletType == DlgFilletEdges::CHAMFER)
906
model->setHeaderData(1, Qt::Horizontal, tr("Length"), Qt::DisplayRole);
908
model->setHeaderData(1, Qt::Horizontal, tr("Radius"), Qt::DisplayRole);
909
ui->treeView->hideColumn(2);
910
ui->filletEndRadius->hide();
913
if (d->filletType == DlgFilletEdges::CHAMFER)
914
model->setHeaderData(1, Qt::Horizontal, tr("Start length"), Qt::DisplayRole);
916
model->setHeaderData(1, Qt::Horizontal, tr("Start radius"), Qt::DisplayRole);
917
ui->treeView->showColumn(2);
918
ui->filletEndRadius->show();
921
ui->treeView->resizeColumnToContents(0);
922
ui->treeView->resizeColumnToContents(1);
923
ui->treeView->resizeColumnToContents(2);
926
void DlgFilletEdges::onFilletStartRadiusValueChanged(const Base::Quantity& radius)
928
QAbstractItemModel* model = ui->treeView->model();
929
for (int i=0; i<model->rowCount(); ++i) {
930
QVariant value = model->index(i,0).data(Qt::CheckStateRole);
931
Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
934
if (checkState & Qt::Checked) {
935
model->setData(model->index(i, 1), QVariant::fromValue<Base::Quantity>(radius));
940
void DlgFilletEdges::onFilletEndRadiusValueChanged(const Base::Quantity& radius)
942
QAbstractItemModel* model = ui->treeView->model();
943
for (int i=0; i<model->rowCount(); ++i) {
944
QVariant value = model->index(i,0).data(Qt::CheckStateRole);
945
Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
948
if (checkState & Qt::Checked) {
949
model->setData(model->index(i, 2), QVariant::fromValue<Base::Quantity>(radius));
954
const char* DlgFilletEdges::getFilletType() const
959
bool DlgFilletEdges::accept()
962
QMessageBox::warning(this, tr("No shape selected"),
963
tr("No valid shape is selected.\n"
964
"Please select a valid shape in the drop-down box first."));
967
App::Document* activeDoc = App::GetApplication().getActiveDocument();
968
QAbstractItemModel* model = ui->treeView->model();
969
bool end_radius = !ui->treeView->isColumnHidden(2);
972
QString shape, type, name;
973
std::string fillet = getFilletType();
974
int index = ui->shapeObject->currentIndex();
975
shape = ui->shapeObject->itemData(index).toString();
976
type = QString::fromLatin1("Part::%1").arg(QString::fromLatin1(fillet.c_str()));
979
name = QString::fromLatin1(d->fillet->getNameInDocument());
981
name = QString::fromLatin1(activeDoc->getUniqueObjectName(fillet.c_str()).c_str());
983
activeDoc->openTransaction(fillet.c_str());
986
code = QString::fromLatin1(
987
"FreeCAD.ActiveDocument.addObject(\"%1\",\"%2\")\n"
988
"FreeCAD.ActiveDocument.%2.Base = FreeCAD.ActiveDocument.%3\n")
989
.arg(type, name, shape);
991
code += QString::fromLatin1("__fillets__ = []\n");
992
for (int i=0; i<model->rowCount(); ++i) {
993
QVariant value = model->index(i,0).data(Qt::CheckStateRole);
994
Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
997
if (checkState & Qt::Checked) {
999
int id = model->index(i,0).data(Qt::UserRole).toInt();
1000
Base::Quantity r1 = model->index(i,1).data(Qt::EditRole).value<Base::Quantity>();
1001
Base::Quantity r2 = r1;
1003
r2 = model->index(i,2).data(Qt::EditRole).value<Base::Quantity>();
1004
code += QString::fromLatin1(
1005
"__fillets__.append((%1,%2,%3))\n")
1007
.arg(r1.getValue(),0,'f',Base::UnitsApi::getDecimals())
1008
.arg(r2.getValue(),0,'f',Base::UnitsApi::getDecimals());
1014
QMessageBox::warning(this, tr("No edge selected"),
1015
tr("No edge entity is checked to fillet.\n"
1016
"Please check one or more edge entities first."));
1021
code += QString::fromLatin1(
1022
"FreeCAD.ActiveDocument.%1.Edges = __fillets__\n"
1024
"FreeCADGui.ActiveDocument.%2.Visibility = False\n")
1026
Gui::Command::runCommand(Gui::Command::App, code.toLatin1());
1027
activeDoc->commitTransaction();
1028
activeDoc->recompute();
1030
Gui::ViewProvider* vp;
1031
vp = Gui::Application::Instance->getViewProvider(d->fillet);
1035
QByteArray to = name.toLatin1();
1036
QByteArray from = shape.toLatin1();
1037
Gui::Command::copyVisual(to, "LineColor", from);
1038
Gui::Command::copyVisual(to, "PointColor", from);
1044
FilletEdgesDialog::FilletEdgesDialog(DlgFilletEdges::FilletType type, Part::FilletBase* fillet, QWidget* parent, Qt::WindowFlags fl)
1045
: QDialog(parent, fl)
1047
widget = new DlgFilletEdges(type, fillet, this);
1048
this->setWindowTitle(widget->windowTitle());
1050
QVBoxLayout* hboxLayout = new QVBoxLayout(this);
1051
QDialogButtonBox* buttonBox = new QDialogButtonBox(this);
1052
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
1054
QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &FilletEdgesDialog::accept);
1055
QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &FilletEdgesDialog::reject);
1057
hboxLayout->addWidget(widget);
1058
hboxLayout->addWidget(buttonBox);
1061
FilletEdgesDialog::~FilletEdgesDialog() = default;
1063
void FilletEdgesDialog::accept()
1065
if (widget->accept())
1071
TaskFilletEdges::TaskFilletEdges(Part::Fillet* fillet)
1073
widget = new DlgFilletEdges(DlgFilletEdges::FILLET, fillet);
1074
addTaskBox(Gui::BitmapFactory().pixmap("Part_Fillet"), widget);
1077
TaskFilletEdges::~TaskFilletEdges()
1082
void TaskFilletEdges::open()
1086
void TaskFilletEdges::clicked(int)
1090
bool TaskFilletEdges::accept()
1092
bool ok = widget->accept();
1094
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
1098
bool TaskFilletEdges::reject()
1100
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
1108
DlgChamferEdges::DlgChamferEdges(Part::FilletBase* chamfer, QWidget* parent, Qt::WindowFlags fl)
1109
: DlgFilletEdges(DlgFilletEdges::CHAMFER, chamfer, parent, fl)
1111
this->setWindowTitle(tr("Chamfer Edges"));
1117
DlgChamferEdges::~DlgChamferEdges() = default;
1119
const char* DlgChamferEdges::getFilletType() const
1124
TaskChamferEdges::TaskChamferEdges(Part::Chamfer* chamfer)
1126
widget = new DlgChamferEdges(chamfer);
1127
addTaskBox(Gui::BitmapFactory().pixmap("Part_Chamfer"), widget);
1130
TaskChamferEdges::~TaskChamferEdges()
1135
void TaskChamferEdges::open()
1139
void TaskChamferEdges::clicked(int)
1143
bool TaskChamferEdges::accept()
1145
bool ok = widget->accept();
1147
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
1151
bool TaskChamferEdges::reject()
1153
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
1157
#include "moc_DlgFilletEdges.cpp"