FreeCAD

Форк
0
/
DlgProjectionOnSurface.cpp 
1600 строк · 54.1 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2019 Manuel Apeltauer, direkt cnc-systeme GmbH          *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
#include <BRep_Tool.hxx>
26
#include <BRepBuilderAPI_MakeEdge.hxx>
27
#include <BRepBuilderAPI_MakeFace.hxx>
28
#include <BRepBuilderAPI_Transform.hxx>
29
#include <BRepCheck_Analyzer.hxx>
30
#include <BRepExtrema_DistShapeShape.hxx>
31
#include <BRepPrimAPI_MakePrism.hxx>
32
#include <BRepProj_Projection.hxx>
33
#include <gp_Ax1.hxx>
34
#include <ShapeAnalysis.hxx>
35
#include <ShapeAnalysis_FreeBounds.hxx>
36
#include <ShapeFix_Face.hxx>
37
#include <ShapeFix_Wire.hxx>
38
#include <ShapeFix_Wireframe.hxx>
39
#include <TopExp.hxx>
40
#include <TopExp_Explorer.hxx>
41
#include <TopoDS_Builder.hxx>
42
#include <TopoDS_Edge.hxx>
43
#include <TopoDS_Face.hxx>
44
#endif
45

46
#include <App/Document.h>
47
#include <Gui/BitmapFactory.h>
48
#include <Gui/CommandT.h>
49
#include <Gui/MainWindow.h>
50
#include <Gui/View3DInventor.h>
51
#include <Gui/View3DInventorViewer.h>
52
#include <Gui/Application.h>
53
#include <Gui/SelectionObject.h>
54
#include <Inventor/SbVec3d.h>
55

56
#include "DlgProjectionOnSurface.h"
57
#include "ui_DlgProjectionOnSurface.h"
58
#include "ViewProviderExt.h"
59

60

61
using namespace PartGui;
62

63
namespace {
64
//////////////////////////////////////////////////////////////////////////
65
class EdgeSelection: public Gui::SelectionFilterGate
66
{
67
public:
68
    bool canSelect = false;
69

70
    EdgeSelection()
71
        : Gui::SelectionFilterGate(nullPointer())
72
    {}
73

74
    bool allow(App::Document* /*pDoc*/, App::DocumentObject* iPObj, const char* sSubName) override
75
    {
76
        auto aPart = dynamic_cast<Part::Feature*>(iPObj);
77
        if (!aPart) {
78
            return false;
79
        }
80
        if (!sSubName) {
81
            return false;
82
        }
83
        std::string subName(sSubName);
84
        if (subName.empty()) {
85
            return false;
86
        }
87

88
        auto subShape = aPart->Shape.getShape().getSubShape(sSubName);
89
        if (subShape.IsNull()) {
90
            return false;
91
        }
92
        auto type = subShape.ShapeType();
93
        return (type == TopAbs_EDGE);
94
    }
95
};
96
//////////////////////////////////////////////////////////////////////////
97
//////////////////////////////////////////////////////////////////////////
98
class FaceSelection: public Gui::SelectionFilterGate
99
{
100
public:
101
    bool canSelect = false;
102

103
    FaceSelection()
104
        : Gui::SelectionFilterGate(nullPointer())
105
    {}
106

107
    bool allow(App::Document* /*pDoc*/, App::DocumentObject* iPObj, const char* sSubName) override
108
    {
109
        auto aPart = dynamic_cast<Part::Feature*>(iPObj);
110
        if (!aPart) {
111
            return false;
112
        }
113
        if (!sSubName) {
114
            return false;
115
        }
116
        std::string subName(sSubName);
117
        if (subName.empty()) {
118
            return false;
119
        }
120

121
        auto subShape = aPart->Shape.getShape().getSubShape(sSubName, true);
122
        if (subShape.IsNull()) {
123
            return false;
124
        }
125
        auto type = subShape.ShapeType();
126
        return (type == TopAbs_FACE);
127
    }
128
};
129
//////////////////////////////////////////////////////////////////////////
130
}
131

132
DlgProjectionOnSurface::DlgProjectionOnSurface(QWidget* parent)
133
    : QWidget(parent)
134
    , ui(new Ui::DlgProjectionOnSurface)
135
    , m_projectionObjectName(tr("Projection Object"))
136
    , filterEdge(nullptr)
137
    , filterFace(nullptr)
138
{
139
    ui->setupUi(this);
140
    setupConnections();
141

142
    ui->pushButtonAddEdge->setCheckable(true);
143
    ui->pushButtonAddFace->setCheckable(true);
144
    ui->pushButtonAddProjFace->setCheckable(true);
145
    ui->pushButtonAddWire->setCheckable(true);
146

147
    m_guiObjectVec.push_back(ui->pushButtonAddEdge);
148
    m_guiObjectVec.push_back(ui->pushButtonAddFace);
149
    m_guiObjectVec.push_back(ui->pushButtonAddProjFace);
150
    m_guiObjectVec.push_back(ui->pushButtonDirX);
151
    m_guiObjectVec.push_back(ui->pushButtonDirY);
152
    m_guiObjectVec.push_back(ui->pushButtonDirZ);
153
    m_guiObjectVec.push_back(ui->pushButtonGetCurrentCamDir);
154
    m_guiObjectVec.push_back(ui->radioButtonShowAll);
155
    m_guiObjectVec.push_back(ui->radioButtonFaces);
156
    m_guiObjectVec.push_back(ui->radioButtonEdges);
157
    m_guiObjectVec.push_back(ui->pushButtonAddWire);
158

159
    get_camera_direction();
160
    disable_ui_elements(m_guiObjectVec, ui->pushButtonAddProjFace);
161

162
    m_partDocument = App::GetApplication().getActiveDocument();
163
    if (!m_partDocument) {
164
        throw Base::ValueError(QString(tr("Have no active document!!!")).toUtf8());
165
    }
166
    this->attachDocument(m_partDocument);
167
    m_partDocument->openTransaction("Project on surface");
168
    m_projectionObject = dynamic_cast<Part::Feature*>(
169
        m_partDocument->addObject("Part::Feature", "Projection Object"));
170
    if (!m_projectionObject) {
171
        throw Base::ValueError(QString(tr("Can not create a projection object!!!")).toUtf8());
172
    }
173
    m_projectionObject->Label.setValue(std::string(m_projectionObjectName.toUtf8()).c_str());
174
    onRadioButtonShowAllClicked();
175
    m_lastDepthVal = ui->doubleSpinBoxSolidDepth->value();
176
}
177

178
DlgProjectionOnSurface::~DlgProjectionOnSurface()
179
{
180
    delete ui;
181
    for (const auto& it : m_projectionSurfaceVec) {
182
        try {
183
            higlight_object(it.partFeature, it.partName, false, 0);
184
        }
185
        catch (Standard_NoSuchObject& e) {
186
            Base::Console().Warning("DlgProjectionOnSurface::~DlgProjectionOnSurface: %s",
187
                                    e.GetMessageString());
188
        }
189
        auto vp = dynamic_cast<PartGui::ViewProviderPartExt*>(
190
            Gui::Application::Instance->getViewProvider(it.partFeature));
191
        if (vp) {
192
            vp->Selectable.setValue(it.is_selectable);
193
            vp->Transparency.setValue(it.transparency);
194
        }
195
    }
196
    for (const auto& it : m_shapeVec) {
197
        try {
198
            higlight_object(it.partFeature, it.partName, false, 0);
199
        }
200
        catch (Standard_NoSuchObject& e) {
201
            Base::Console().Warning("DlgProjectionOnSurface::~DlgProjectionOnSurface: %s",
202
                                    e.GetMessageString());
203
        }
204
    }
205
    Gui::Selection().rmvSelectionGate();
206
}
207

208
void PartGui::DlgProjectionOnSurface::setupConnections()
209
{
210
    // clang-format off
211
    connect(ui->pushButtonAddFace,
212
            &QPushButton::clicked,
213
            this,
214
            &DlgProjectionOnSurface::onPushButtonAddFaceClicked);
215
    connect(ui->pushButtonAddEdge,
216
            &QPushButton::clicked,
217
            this,
218
            &DlgProjectionOnSurface::onPushButtonAddEdgeClicked);
219
    connect(ui->pushButtonGetCurrentCamDir,
220
            &QPushButton::clicked,
221
            this,
222
            &DlgProjectionOnSurface::onPushButtonGetCurrentCamDirClicked);
223
    connect(ui->pushButtonDirX,
224
            &QPushButton::clicked,
225
            this,
226
            &DlgProjectionOnSurface::onPushButtonDirXClicked);
227
    connect(ui->pushButtonDirY,
228
            &QPushButton::clicked,
229
            this,
230
            &DlgProjectionOnSurface::onPushButtonDirYClicked);
231
    connect(ui->pushButtonDirZ,
232
            &QPushButton::clicked,
233
            this,
234
            &DlgProjectionOnSurface::onPushButtonDirZClicked);
235
    connect(ui->pushButtonAddProjFace,
236
            &QPushButton::clicked,
237
            this,
238
            &DlgProjectionOnSurface::onPushButtonAddProjFaceClicked);
239
    connect(ui->radioButtonShowAll,
240
            &QRadioButton::clicked,
241
            this,
242
            &DlgProjectionOnSurface::onRadioButtonShowAllClicked);
243
    connect(ui->radioButtonFaces,
244
            &QRadioButton::clicked,
245
            this,
246
            &DlgProjectionOnSurface::onRadioButtonFacesClicked);
247
    connect(ui->radioButtonEdges,
248
            &QRadioButton::clicked,
249
            this,
250
            &DlgProjectionOnSurface::onRadioButtonEdgesClicked);
251
    connect(ui->doubleSpinBoxExtrudeHeight,
252
            qOverload<double>(&QDoubleSpinBox::valueChanged),
253
            this,
254
            &DlgProjectionOnSurface::onDoubleSpinBoxExtrudeHeightValueChanged);
255
    connect(ui->pushButtonAddWire,
256
            &QPushButton::clicked,
257
            this,
258
            &DlgProjectionOnSurface::onPushButtonAddWireClicked);
259
    connect(ui->doubleSpinBoxSolidDepth,
260
            qOverload<double>(&QDoubleSpinBox::valueChanged),
261
            this,
262
            &DlgProjectionOnSurface::onDoubleSpinBoxSolidDepthValueChanged);
263
    // clang-format on
264
}
265

266
void PartGui::DlgProjectionOnSurface::slotDeletedDocument(const App::Document& Doc)
267
{
268
    if (m_partDocument == &Doc) {
269
        m_partDocument = nullptr;
270
        m_projectionObject = nullptr;
271
    }
272
}
273

274
void PartGui::DlgProjectionOnSurface::slotDeletedObject(const App::DocumentObject& Obj)
275
{
276
    if (m_projectionObject == &Obj) {
277
        m_projectionObject = nullptr;
278
    }
279
}
280

281
void PartGui::DlgProjectionOnSurface::apply()
282
{
283
    if (m_partDocument) {
284
        m_partDocument->commitTransaction();
285
    }
286
}
287

288
void PartGui::DlgProjectionOnSurface::reject()
289
{
290
    if (m_partDocument) {
291
        m_partDocument->abortTransaction();
292
    }
293
}
294

295
void PartGui::DlgProjectionOnSurface::onPushButtonAddFaceClicked()
296
{
297
    if (ui->pushButtonAddFace->isChecked()) {
298
        m_currentSelection = "add_face";
299
        disable_ui_elements(m_guiObjectVec, ui->pushButtonAddFace);
300
        if (!filterFace) {
301
            filterFace = new FaceSelection();
302
            Gui::Selection().addSelectionGate(filterFace);
303
        }
304
    }
305
    else {
306
        m_currentSelection = "";
307
        enable_ui_elements(m_guiObjectVec, nullptr);
308
        Gui::Selection().rmvSelectionGate();
309
        filterFace = nullptr;
310
    }
311
}
312

313
void PartGui::DlgProjectionOnSurface::onPushButtonAddEdgeClicked()
314
{
315
    if (ui->pushButtonAddEdge->isChecked()) {
316
        m_currentSelection = "add_edge";
317
        disable_ui_elements(m_guiObjectVec, ui->pushButtonAddEdge);
318
        if (!filterEdge) {
319
            filterEdge = new EdgeSelection();
320
            Gui::Selection().addSelectionGate(filterEdge);
321
        }
322
        ui->radioButtonEdges->setChecked(true);
323
        onRadioButtonEdgesClicked();
324
    }
325
    else {
326
        m_currentSelection = "";
327
        enable_ui_elements(m_guiObjectVec, nullptr);
328
        Gui::Selection().rmvSelectionGate();
329
        filterEdge = nullptr;
330
    }
331
}
332

333
void PartGui::DlgProjectionOnSurface::onPushButtonGetCurrentCamDirClicked()
334
{
335
    get_camera_direction();
336
}
337

338
void PartGui::DlgProjectionOnSurface::onPushButtonDirXClicked()
339
{
340
    set_xyz_dir_spinbox(ui->doubleSpinBoxDirX);
341
}
342

343
void PartGui::DlgProjectionOnSurface::onPushButtonDirYClicked()
344
{
345
    set_xyz_dir_spinbox(ui->doubleSpinBoxDirY);
346
}
347

348
void PartGui::DlgProjectionOnSurface::onPushButtonDirZClicked()
349
{
350
    set_xyz_dir_spinbox(ui->doubleSpinBoxDirZ);
351
}
352

353
void PartGui::DlgProjectionOnSurface::onSelectionChanged(const Gui::SelectionChanges& msg)
354
{
355
    if (msg.Type == Gui::SelectionChanges::AddSelection) {
356
        if (m_currentSelection == "add_face" || m_currentSelection == "add_edge"
357
            || m_currentSelection == "add_wire") {
358
            store_current_selected_parts(m_shapeVec, 0xff00ff00);
359
            create_projection_wire(m_shapeVec);
360
            create_projection_face_from_wire(m_shapeVec);
361
            create_face_extrude(m_shapeVec);
362
            show_projected_shapes(m_shapeVec);
363
        }
364
        else if (m_currentSelection == "add_projection_surface") {
365
            m_projectionSurfaceVec.clear();
366
            store_current_selected_parts(m_projectionSurfaceVec, 0xffff0000);
367
            if (!m_projectionSurfaceVec.empty()) {
368
                auto vp = dynamic_cast<PartGui::ViewProviderPartExt*>(
369
                    Gui::Application::Instance->getViewProvider(
370
                        m_projectionSurfaceVec.back().partFeature));
371
                if (vp) {
372
                    vp->Selectable.setValue(false);
373
                    vp->Transparency.setValue(90);
374
                }
375
            }
376

377
            ui->pushButtonAddProjFace->setChecked(false);
378
            onPushButtonAddProjFaceClicked();
379
        }
380
    }
381
}
382

383
void PartGui::DlgProjectionOnSurface::get_camera_direction()
384
{
385
    auto mainWindow = Gui::getMainWindow();
386

387
    auto mdiObject = dynamic_cast<Gui::View3DInventor*>(mainWindow->activeWindow());
388
    if (!mdiObject) {
389
        return;
390
    }
391
    auto camerRotation = mdiObject->getViewer()->getCameraOrientation();
392

393
    SbVec3f lookAt(0, 0, -1);
394
    camerRotation.multVec(lookAt, lookAt);
395

396
    float valX {};
397
    float valY {};
398
    float valZ {};
399
    lookAt.getValue(valX, valY, valZ);
400

401
    ui->doubleSpinBoxDirX->setValue(valX);
402
    ui->doubleSpinBoxDirY->setValue(valY);
403
    ui->doubleSpinBoxDirZ->setValue(valZ);
404
}
405

406
void PartGui::DlgProjectionOnSurface::store_current_selected_parts(
407
    std::vector<SShapeStore>& iStoreVec,
408
    unsigned int iColor)
409
{
410
    if (!m_partDocument) {
411
        return;
412
    }
413
    std::vector<Gui::SelectionObject> selObj = Gui::Selection().getSelectionEx();
414
    if (!selObj.empty()) {
415
        for (auto it = selObj.begin(); it != selObj.end(); ++it) {
416
            auto aPart = dynamic_cast<Part::Feature*>(it->getObject());
417
            if (!aPart) {
418
                continue;
419
            }
420

421
            if (aPart) {
422
                SShapeStore currentShapeStore;
423
                currentShapeStore.inputShape = aPart->Shape.getShape().getShape();
424
                currentShapeStore.partFeature = aPart;
425
                currentShapeStore.partName = aPart->getNameInDocument();
426

427
                auto vp = dynamic_cast<PartGui::ViewProviderPartExt*>(
428
                    Gui::Application::Instance->getViewProvider(aPart));
429
                if (vp) {
430
                    currentShapeStore.is_selectable = vp->Selectable.getValue();
431
                    currentShapeStore.transparency = vp->Transparency.getValue();
432
                }
433
                if (!it->getSubNames().empty()) {
434
                    auto parentShape = currentShapeStore.inputShape;
435
                    for (const auto& itName : selObj.front().getSubNames()) {
436
                        auto currentShape = aPart->Shape.getShape().getSubShape(itName.c_str());
437

438
                        transform_shape_to_global_position(currentShape, aPart);
439

440
                        currentShapeStore.inputShape = currentShape;
441
                        currentShapeStore.partName = itName;
442
                        auto store = store_part_in_vector(currentShapeStore, iStoreVec);
443
                        higlight_object(aPart, itName, store, iColor);
444
                        store_wire_in_vector(currentShapeStore, parentShape, iStoreVec, iColor);
445
                    }
446
                }
447
                else {
448
                    transform_shape_to_global_position(currentShapeStore.inputShape,
449
                                                       currentShapeStore.partFeature);
450
                    auto store = store_part_in_vector(currentShapeStore, iStoreVec);
451
                    higlight_object(aPart, aPart->Shape.getName(), store, iColor);
452
                }
453
                Gui::Selection().clearSelection(m_partDocument->getName());
454
                Gui::Selection().rmvPreselect();
455
            }
456
        }
457
    }
458
}
459

460
bool PartGui::DlgProjectionOnSurface::store_part_in_vector(SShapeStore& iCurrentShape,
461
                                                           std::vector<SShapeStore>& iStoreVec)
462
{
463
    if (iCurrentShape.inputShape.IsNull()) {
464
        return false;
465
    }
466
    auto currentType = iCurrentShape.inputShape.ShapeType();
467
    for (auto it = iStoreVec.begin(); it != iStoreVec.end(); ++it) {
468
        if (currentType == TopAbs_FACE) {
469
            if (it->aFace.IsSame(iCurrentShape.inputShape)) {
470
                iStoreVec.erase(it);
471
                return false;
472
            }
473
        }
474
        else if (currentType == TopAbs_EDGE) {
475
            if (it->aEdge.IsSame(iCurrentShape.inputShape)) {
476
                iStoreVec.erase(it);
477
                return false;
478
            }
479
        }
480
    }
481

482
    if (currentType == TopAbs_FACE) {
483
        iCurrentShape.aFace = TopoDS::Face(iCurrentShape.inputShape);
484
    }
485
    else if (currentType == TopAbs_EDGE) {
486
        iCurrentShape.aEdge = TopoDS::Edge(iCurrentShape.inputShape);
487
    }
488

489
    auto valX = ui->doubleSpinBoxDirX->value();
490
    auto valY = ui->doubleSpinBoxDirY->value();
491
    auto valZ = ui->doubleSpinBoxDirZ->value();
492

493
    iCurrentShape.aProjectionDir = gp_Dir(valX, valY, valZ);
494
    if (!m_projectionSurfaceVec.empty()) {
495
        iCurrentShape.surfaceToProject = m_projectionSurfaceVec.front().aFace;
496
    }
497
    iStoreVec.push_back(iCurrentShape);
498
    return true;
499
}
500

501
void PartGui::DlgProjectionOnSurface::create_projection_wire(
502
    std::vector<SShapeStore>& iCurrentShape)
503
{
504
    try {
505
        if (iCurrentShape.empty()) {
506
            return;
507
        }
508
        for (auto& itCurrentShape : iCurrentShape) {
509
            if (m_projectionSurfaceVec.empty()) {
510
                continue;
511
            };
512
            if (!itCurrentShape.aProjectedEdgeVec.empty()) {
513
                continue;
514
            };
515
            if (!itCurrentShape.aProjectedFace.IsNull()) {
516
                continue;
517
            };
518
            if (!itCurrentShape.aProjectedWireVec.empty()) {
519
                continue;
520
            };
521

522
            if (!itCurrentShape.aFace.IsNull()) {
523
                get_all_wire_from_face(itCurrentShape);
524
                for (const auto& itWire : itCurrentShape.aWireVec) {
525
                    BRepProj_Projection aProjection(itWire,
526
                                                    itCurrentShape.surfaceToProject,
527
                                                    itCurrentShape.aProjectionDir);
528
                    double minDistance = std::numeric_limits<double>::max();
529
                    TopoDS_Wire wireToTake;
530
                    for (; aProjection.More(); aProjection.Next()) {
531
                        auto it = aProjection.Current();
532
                        BRepExtrema_DistShapeShape distanceMeasure(it, itCurrentShape.aFace);
533
                        distanceMeasure.Perform();
534
                        auto currentDistance = distanceMeasure.Value();
535
                        if (currentDistance > minDistance) {
536
                            continue;
537
                        }
538
                        wireToTake = it;
539
                        minDistance = currentDistance;
540
                    }
541
                    auto aWire = sort_and_heal_wire(wireToTake, itCurrentShape.surfaceToProject);
542
                    itCurrentShape.aProjectedWireVec.push_back(aWire);
543
                }
544
            }
545
            else if (!itCurrentShape.aEdge.IsNull()) {
546
                BRepProj_Projection aProjection(itCurrentShape.aEdge,
547
                                                itCurrentShape.surfaceToProject,
548
                                                itCurrentShape.aProjectionDir);
549
                double minDistance = std::numeric_limits<double>::max();
550
                TopoDS_Wire wireToTake;
551
                for (; aProjection.More(); aProjection.Next()) {
552
                    auto it = aProjection.Current();
553
                    BRepExtrema_DistShapeShape distanceMeasure(it, itCurrentShape.aEdge);
554
                    distanceMeasure.Perform();
555
                    auto currentDistance = distanceMeasure.Value();
556
                    if (currentDistance > minDistance) {
557
                        continue;
558
                    }
559
                    wireToTake = it;
560
                    minDistance = currentDistance;
561
                }
562
                for (TopExp_Explorer aExplorer(wireToTake, TopAbs_EDGE); aExplorer.More();
563
                     aExplorer.Next()) {
564
                    itCurrentShape.aProjectedEdgeVec.push_back(TopoDS::Edge(aExplorer.Current()));
565
                }
566
            }
567
        }
568
    }
569
    catch (const Standard_Failure& error) {
570
        std::stringstream ssOcc;
571
        error.Print(ssOcc);
572
        throw Base::ValueError(ssOcc.str().c_str());
573
    }
574
}
575

576
TopoDS_Shape
577
PartGui::DlgProjectionOnSurface::create_compound(const std::vector<SShapeStore>& iShapeVec)
578
{
579
    if (iShapeVec.empty()) {
580
        return {};
581
    }
582

583
    TopoDS_Compound aCompound;
584
    TopoDS_Builder aBuilder;
585
    aBuilder.MakeCompound(aCompound);
586

587
    for (const auto& it : iShapeVec) {
588
        if (m_currentShowType == "edges") {
589
            for (const auto& it2 : it.aProjectedEdgeVec) {
590
                aBuilder.Add(aCompound, it2);
591
            }
592
            for (const auto& it2 : it.aProjectedWireVec) {
593
                aBuilder.Add(aCompound, it2);
594
            }
595
        }
596
        else if (m_currentShowType == "faces") {
597
            if (it.aProjectedFace.IsNull()) {
598
                for (const auto& it2 : it.aProjectedWireVec) {
599
                    if (!it2.IsNull()) {
600
                        aBuilder.Add(aCompound, it2);
601
                    }
602
                }
603
            }
604
            else {
605
                aBuilder.Add(aCompound, it.aProjectedFace);
606
            }
607
        }
608
        else if (m_currentShowType == "all") {
609
            if (!it.aProjectedSolid.IsNull()) {
610
                aBuilder.Add(aCompound, it.aProjectedSolid);
611
            }
612
            else if (!it.aProjectedFace.IsNull()) {
613
                aBuilder.Add(aCompound, it.aProjectedFace);
614
            }
615
            else if (!it.aProjectedWireVec.empty()) {
616
                for (const auto& itWire : it.aProjectedWireVec) {
617
                    if (itWire.IsNull()) {
618
                        continue;
619
                    }
620
                    aBuilder.Add(aCompound, itWire);
621
                }
622
            }
623
            else if (!it.aProjectedEdgeVec.empty()) {
624
                for (const auto& itEdge : it.aProjectedEdgeVec) {
625
                    if (itEdge.IsNull()) {
626
                        continue;
627
                    }
628
                    aBuilder.Add(aCompound, itEdge);
629
                }
630
            }
631
        }
632
    }
633
    return {std::move(aCompound)};
634
}
635

636
void PartGui::DlgProjectionOnSurface::show_projected_shapes(
637
    const std::vector<SShapeStore>& iShapeStoreVec)
638
{
639
    if (!m_projectionObject) {
640
        return;
641
    }
642
    auto aCompound = create_compound(iShapeStoreVec);
643
    if (aCompound.IsNull()) {
644
        if (!m_partDocument) {
645
            return;
646
        }
647
        m_projectionObject->Shape.setValue(TopoDS_Shape());
648
        return;
649
    }
650
    auto currentPlacement = m_projectionObject->Placement.getValue();
651
    m_projectionObject->Shape.setValue(aCompound);
652
    m_projectionObject->Placement.setValue(currentPlacement);
653

654
    // set color
655
    auto vp = dynamic_cast<PartGui::ViewProviderPartExt*>(
656
        Gui::Application::Instance->getViewProvider(m_projectionObject));
657
    if (vp) {
658
        const unsigned int color = 0x8ae23400;
659
        vp->LineColor.setValue(color);
660
        vp->ShapeAppearance.setDiffuseColor(App::Color(color));
661
        vp->PointColor.setValue(color);
662
        vp->Transparency.setValue(0);
663
    }
664
}
665

666
void PartGui::DlgProjectionOnSurface::disable_ui_elements(const std::vector<QWidget*>& iObjectVec,
667
                                                          QWidget* iExceptThis)
668
{
669
    for (auto it : iObjectVec) {
670
        if (!it) {
671
            continue;
672
        }
673
        if (it == iExceptThis) {
674
            continue;
675
        }
676
        it->setDisabled(true);
677
    }
678
}
679

680
void PartGui::DlgProjectionOnSurface::enable_ui_elements(const std::vector<QWidget*>& iObjectVec,
681
                                                         QWidget* iExceptThis)
682
{
683
    for (auto it : iObjectVec) {
684
        if (!it) {
685
            continue;
686
        }
687
        if (it == iExceptThis) {
688
            continue;
689
        }
690
        it->setEnabled(true);
691
    }
692
}
693

694
void PartGui::DlgProjectionOnSurface::higlight_object(Part::Feature* iCurrentObject,
695
                                                      const std::string& iShapeName,
696
                                                      bool iHighlight,
697
                                                      unsigned int iColor)
698
{
699
    if (!iCurrentObject) {
700
        return;
701
    }
702
    auto partenShape = iCurrentObject->Shape.getShape().getShape();
703
    auto subShape = iCurrentObject->Shape.getShape().getSubShape(iShapeName.c_str(), true);
704

705
    TopoDS_Shape currentShape = subShape;
706
    if (subShape.IsNull()) {
707
        currentShape = partenShape;
708
    }
709

710
    auto currentShapeType = currentShape.ShapeType();
711
    TopTools_IndexedMapOfShape anIndices;
712
    TopExp::MapShapes(partenShape, currentShapeType, anIndices);
713
    if (anIndices.IsEmpty()) {
714
        return;
715
    }
716
    if (!anIndices.Contains(currentShape)) {
717
        return;
718
    }
719
    auto index = anIndices.FindIndex(currentShape);
720

721
    // set color
722
    auto vp = dynamic_cast<PartGui::ViewProviderPartExt*>(
723
        Gui::Application::Instance->getViewProvider(iCurrentObject));
724
    if (vp) {
725
        std::vector<App::Color> colors;
726
        App::Color defaultColor;
727
        if (currentShapeType == TopAbs_FACE) {
728
            colors = vp->ShapeAppearance.getDiffuseColors();
729
            defaultColor = colors.front();
730
        }
731
        else if (currentShapeType == TopAbs_EDGE) {
732
            colors = vp->LineColorArray.getValues();
733
            defaultColor = vp->LineColor.getValue();
734
        }
735

736
        if (static_cast<Standard_Integer>(colors.size()) != anIndices.Extent()) {
737
            colors.resize(anIndices.Extent(), defaultColor);
738
        }
739

740
        if (iHighlight) {
741
            App::Color aColor;
742
            aColor.setPackedValue(iColor);
743
            colors.at(index - 1) = aColor;
744
        }
745
        else {
746
            colors.at(index - 1) = defaultColor;
747
        }
748
        if (currentShapeType == TopAbs_FACE) {
749
            vp->ShapeAppearance.setDiffuseColors(colors);
750
        }
751
        else if (currentShapeType == TopAbs_EDGE) {
752
            vp->LineColorArray.setValues(colors);
753
        }
754
    }
755
}
756

757
void PartGui::DlgProjectionOnSurface::get_all_wire_from_face(SShapeStore& ioCurrentSahpe)
758
{
759
    auto outerWire = ShapeAnalysis::OuterWire(ioCurrentSahpe.aFace);
760
    ioCurrentSahpe.aWireVec.push_back(outerWire);
761
    for (TopExp_Explorer aExplorer(ioCurrentSahpe.aFace, TopAbs_WIRE); aExplorer.More();
762
         aExplorer.Next()) {
763
        auto currentWire = TopoDS::Wire(aExplorer.Current());
764
        if (currentWire.IsSame(outerWire)) {
765
            continue;
766
        }
767
        ioCurrentSahpe.aWireVec.push_back(currentWire);
768
    }
769
}
770

771
void PartGui::DlgProjectionOnSurface::create_projection_face_from_wire(
772
    std::vector<SShapeStore>& iCurrentShape)
773
{
774
    try {
775
        if (iCurrentShape.empty()) {
776
            return;
777
        }
778

779
        for (auto& itCurrentShape : iCurrentShape) {
780
            if (itCurrentShape.aFace.IsNull()) {
781
                continue;
782
            };
783
            if (itCurrentShape.aProjectedWireVec.empty()) {
784
                continue;
785
            };
786
            if (!itCurrentShape.aProjectedFace.IsNull()) {
787
                continue;
788
            };
789

790
            auto surface = BRep_Tool::Surface(itCurrentShape.surfaceToProject);
791

792
            // create a wire of all edges in parametric space on the surface of the face to
793
            // projected
794
            //  --> otherwise BRepBuilderAPI_MakeFace can not make a face from the wire!
795
            for (const auto& itWireVec : itCurrentShape.aProjectedWireVec) {
796
                std::vector<TopoDS_Shape> edgeVec;
797
                for (TopExp_Explorer aExplorer(itWireVec, TopAbs_EDGE); aExplorer.More();
798
                     aExplorer.Next()) {
799
                    auto currentEdge = TopoDS::Edge(aExplorer.Current());
800
                    edgeVec.push_back(currentEdge);
801
                }
802
                if (edgeVec.empty()) {
803
                    continue;
804
                }
805

806
                std::vector<TopoDS_Edge> edgeInParametricSpaceVec;
807
                for (auto itEdge : edgeVec) {
808
                    Standard_Real first {};
809
                    Standard_Real last {};
810
                    auto currentCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(itEdge),
811
                                                                  itCurrentShape.surfaceToProject,
812
                                                                  first,
813
                                                                  last);
814
                    if (!currentCurve) {
815
                        continue;
816
                    }
817
                    auto edgeInParametricSpace =
818
                        BRepBuilderAPI_MakeEdge(currentCurve, surface, first, last).Edge();
819
                    edgeInParametricSpaceVec.push_back(edgeInParametricSpace);
820
                }
821
                auto aWire =
822
                    sort_and_heal_wire(edgeInParametricSpaceVec, itCurrentShape.surfaceToProject);
823
                itCurrentShape.aProjectedWireInParametricSpaceVec.push_back(aWire);
824
            }
825

826
            // try to create a face from the wires
827
            // the first wire is the otherwise
828
            // the following wires are the inside wires
829
            BRepBuilderAPI_MakeFace faceMaker;
830
            bool first = true;
831
            for (auto itWireVec : itCurrentShape.aProjectedWireInParametricSpaceVec) {
832
                if (first) {
833
                    first = false;
834
                    // change the wire direction, otherwise no face is created
835
                    auto currentWire = TopoDS::Wire(itWireVec.Reversed());
836
                    if (itCurrentShape.surfaceToProject.Orientation() == TopAbs_REVERSED) {
837
                        currentWire = itWireVec;
838
                    }
839
                    faceMaker = BRepBuilderAPI_MakeFace(surface, currentWire);
840
                    ShapeFix_Face fix(faceMaker.Face());
841
                    fix.Perform();
842
                    auto aFace = fix.Face();
843
                    BRepCheck_Analyzer aChecker(aFace);
844
                    if (!aChecker.IsValid()) {
845
                        faceMaker =
846
                            BRepBuilderAPI_MakeFace(surface, TopoDS::Wire(currentWire.Reversed()));
847
                    }
848
                }
849
                else {
850
                    // make a copy of the current face maker
851
                    // if the face fails just try again with the copy
852
                    TopoDS_Face tempCopy = BRepBuilderAPI_MakeFace(faceMaker.Face()).Face();
853
                    faceMaker.Add(TopoDS::Wire(itWireVec.Reversed()));
854
                    ShapeFix_Face fix(faceMaker.Face());
855
                    fix.Perform();
856
                    auto aFace = fix.Face();
857
                    BRepCheck_Analyzer aChecker(aFace);
858
                    if (!aChecker.IsValid()) {
859
                        faceMaker = BRepBuilderAPI_MakeFace(tempCopy);
860
                        faceMaker.Add(TopoDS::Wire(itWireVec));
861
                    }
862
                }
863
            }
864
            // auto doneFlag = faceMaker.IsDone();
865
            // auto error = faceMaker.Error();
866
            itCurrentShape.aProjectedFace = faceMaker.Face();
867
        }
868
    }
869
    catch (const Standard_Failure& error) {
870
        std::stringstream ssOcc;
871
        error.Print(ssOcc);
872
        throw Base::ValueError(ssOcc.str().c_str());
873
    }
874
}
875

876
TopoDS_Wire PartGui::DlgProjectionOnSurface::sort_and_heal_wire(const TopoDS_Shape& iShape,
877
                                                                const TopoDS_Face& iFaceToProject)
878
{
879
    std::vector<TopoDS_Edge> aEdgeVec;
880
    for (TopExp_Explorer aExplorer(iShape, TopAbs_EDGE); aExplorer.More(); aExplorer.Next()) {
881
        auto anEdge = TopoDS::Edge(aExplorer.Current());
882
        aEdgeVec.push_back(anEdge);
883
    }
884
    return sort_and_heal_wire(aEdgeVec, iFaceToProject);
885
}
886

887
TopoDS_Wire
888
PartGui::DlgProjectionOnSurface::sort_and_heal_wire(const std::vector<TopoDS_Edge>& iEdgeVec,
889
                                                    const TopoDS_Face& iFaceToProject)
890
{
891
    // try to sort and heal all wires
892
    // if the wires are not clean making a face will fail!
893
    ShapeAnalysis_FreeBounds shapeAnalyzer;
894
    Handle(TopTools_HSequenceOfShape) shapeList = new TopTools_HSequenceOfShape;
895
    Handle(TopTools_HSequenceOfShape) aWireHandle;
896
    Handle(TopTools_HSequenceOfShape) aWireWireHandle;
897

898
    for (const auto& it : iEdgeVec) {
899
        shapeList->Append(it);
900
    }
901

902
    const double tolerance = 0.0001;
903
    ShapeAnalysis_FreeBounds::ConnectEdgesToWires(shapeList, tolerance, false, aWireHandle);
904
    ShapeAnalysis_FreeBounds::ConnectWiresToWires(aWireHandle, tolerance, false, aWireWireHandle);
905
    if (!aWireWireHandle) {
906
        return {};
907
    }
908
    for (auto it = 1; it <= aWireWireHandle->Length(); ++it) {
909
        auto aShape = TopoDS::Wire(aWireWireHandle->Value(it));
910
        ShapeFix_Wire aWireRepair(aShape, iFaceToProject, tolerance);
911
        aWireRepair.FixAddCurve3dMode() = 1;
912
        aWireRepair.FixAddPCurveMode() = 1;
913
        aWireRepair.Perform();
914
        // return aWireRepair.Wire();
915
        ShapeFix_Wireframe aWireFramFix(aWireRepair.Wire());
916
        aWireFramFix.FixWireGaps();
917
        aWireFramFix.FixSmallEdges();
918
        return TopoDS::Wire(aWireFramFix.Shape());
919
    }
920
    return {};
921
}
922

923
void PartGui::DlgProjectionOnSurface::create_face_extrude(std::vector<SShapeStore>& iCurrentShape)
924
{
925
    try {
926
        if (iCurrentShape.empty()) {
927
            return;
928
        }
929

930
        auto height = ui->doubleSpinBoxExtrudeHeight->value();
931

932
        for (auto& itCurrentShape : iCurrentShape) {
933
            if (itCurrentShape.aProjectedFace.IsNull()) {
934
                continue;
935
            }
936
            if (itCurrentShape.extrudeValue == height) {
937
                continue;
938
            }
939

940
            itCurrentShape.extrudeValue = height;
941
            if (height == 0) {
942
                itCurrentShape.aProjectedSolid.Nullify();
943
            }
944
            else {
945
                gp_Vec directionToExtrude(itCurrentShape.aProjectionDir.XYZ());
946
                directionToExtrude.Reverse();
947
                directionToExtrude.Multiply(height);
948
                BRepPrimAPI_MakePrism extrude(itCurrentShape.aProjectedFace, directionToExtrude);
949
                itCurrentShape.aProjectedSolid = extrude.Shape();
950
            }
951
        }
952
    }
953
    catch (const Standard_Failure& error) {
954
        std::stringstream ssOcc;
955
        error.Print(ssOcc);
956
        throw Base::ValueError(ssOcc.str().c_str());
957
    }
958
}
959

960
void PartGui::DlgProjectionOnSurface::store_wire_in_vector(const SShapeStore& iCurrentShape,
961
                                                           const TopoDS_Shape& iParentShape,
962
                                                           std::vector<SShapeStore>& iStoreVec,
963
                                                           unsigned int iColor)
964
{
965
    if (m_currentSelection != "add_wire") {
966
        return;
967
    }
968
    if (iParentShape.IsNull()) {
969
        return;
970
    }
971
    if (iCurrentShape.inputShape.IsNull()) {
972
        return;
973
    }
974
    auto currentType = iCurrentShape.inputShape.ShapeType();
975
    if (currentType != TopAbs_EDGE) {
976
        return;
977
    }
978

979
    std::vector<TopoDS_Wire> aWireVec;
980
    for (TopExp_Explorer aExplorer(iParentShape, TopAbs_WIRE); aExplorer.More(); aExplorer.Next()) {
981
        aWireVec.push_back(TopoDS::Wire(aExplorer.Current()));
982
    }
983

984
    std::vector<TopoDS_Edge> edgeVec;
985
    for (const auto& it : aWireVec) {
986
        bool edgeExists = false;
987
        for (TopExp_Explorer aExplorer(it, TopAbs_EDGE); aExplorer.More(); aExplorer.Next()) {
988
            auto currentEdge = TopoDS::Edge(aExplorer.Current());
989
            edgeVec.push_back(currentEdge);
990
            if (currentEdge.IsSame(iCurrentShape.inputShape)) {
991
                edgeExists = true;
992
            }
993
        }
994
        if (edgeExists) {
995
            break;
996
        }
997
        edgeVec.clear();
998
    }
999

1000
    if (edgeVec.empty()) {
1001
        return;
1002
    }
1003
    TopTools_IndexedMapOfShape indexMap;
1004
    TopExp::MapShapes(iParentShape, TopAbs_EDGE, indexMap);
1005
    if (indexMap.IsEmpty()) {
1006
        return;
1007
    }
1008

1009
    for (const auto& it : edgeVec) {
1010
        if (it.IsSame(iCurrentShape.inputShape)) {
1011
            continue;
1012
        }
1013
        if (!indexMap.Contains(it)) {
1014
            return;
1015
        }
1016
        auto index = indexMap.FindIndex(it);
1017
        auto newEdgeObject = iCurrentShape;
1018
        newEdgeObject.inputShape = it;
1019
        newEdgeObject.partName = "Edge" + std::to_string(index);
1020

1021
        auto store = store_part_in_vector(newEdgeObject, iStoreVec);
1022
        higlight_object(newEdgeObject.partFeature, newEdgeObject.partName, store, iColor);
1023
    }
1024
}
1025

1026
void PartGui::DlgProjectionOnSurface::set_xyz_dir_spinbox(QDoubleSpinBox* icurrentSpinBox)
1027
{
1028
    auto currentVal = icurrentSpinBox->value();
1029
    auto newVal = 0.0;
1030
    if (currentVal != 1.0 && currentVal != -1.0) {
1031
        newVal = -1;
1032
    }
1033
    else if (currentVal == 1.0) {
1034
        newVal = -1;
1035
    }
1036
    else if (currentVal == -1.0) {
1037
        newVal = 1;
1038
    }
1039
    ui->doubleSpinBoxDirX->setValue(0);
1040
    ui->doubleSpinBoxDirY->setValue(0);
1041
    ui->doubleSpinBoxDirZ->setValue(0);
1042
    icurrentSpinBox->setValue(newVal);
1043
}
1044

1045
void PartGui::DlgProjectionOnSurface::transform_shape_to_global_position(TopoDS_Shape& ioShape,
1046
                                                                         Part::Feature* iPart)
1047
{
1048
    auto currentPos = iPart->Placement.getValue().getPosition();
1049
    auto currentRotation = iPart->Placement.getValue().getRotation();
1050
    auto globalPlacement = iPart->globalPlacement();
1051
    auto globalPosition = globalPlacement.getPosition();
1052
    auto globalRotation = globalPlacement.getRotation();
1053

1054
    if (currentRotation != globalRotation) {
1055
        auto newRotation = globalRotation;
1056
        newRotation *= currentRotation.invert();
1057

1058
        gp_Trsf aAngleTransform;
1059
        Base::Vector3d rotationAxes;
1060
        double rotationAngle {};
1061
        newRotation.getRawValue(rotationAxes, rotationAngle);
1062
        aAngleTransform.SetRotation(gp_Ax1(gp_Pnt(currentPos.x, currentPos.y, currentPos.z),
1063
                                           gp_Dir(rotationAxes.x, rotationAxes.y, rotationAxes.z)),
1064
                                    rotationAngle);
1065
        ioShape = BRepBuilderAPI_Transform(ioShape, aAngleTransform, true).Shape();
1066
    }
1067

1068
    if (currentPos != globalPosition) {
1069
        gp_Trsf aPosTransform;
1070
        aPosTransform.SetTranslation(gp_Pnt(currentPos.x, currentPos.y, currentPos.z),
1071
                                     gp_Pnt(globalPosition.x, globalPosition.y, globalPosition.z));
1072
        ioShape = BRepBuilderAPI_Transform(ioShape, aPosTransform, true).Shape();
1073
    }
1074
}
1075

1076
void PartGui::DlgProjectionOnSurface::onPushButtonAddProjFaceClicked()
1077
{
1078
    if (ui->pushButtonAddProjFace->isChecked()) {
1079
        m_currentSelection = "add_projection_surface";
1080
        disable_ui_elements(m_guiObjectVec, ui->pushButtonAddProjFace);
1081
        if (!filterFace) {
1082
            filterFace = new FaceSelection();
1083
            Gui::Selection().addSelectionGate(filterFace);
1084
        }
1085
    }
1086
    else {
1087
        m_currentSelection = "";
1088
        enable_ui_elements(m_guiObjectVec, nullptr);
1089
        Gui::Selection().rmvSelectionGate();
1090
        filterFace = nullptr;
1091
    }
1092
}
1093
void PartGui::DlgProjectionOnSurface::onRadioButtonShowAllClicked()
1094
{
1095
    m_currentShowType = "all";
1096
    show_projected_shapes(m_shapeVec);
1097
}
1098

1099
void PartGui::DlgProjectionOnSurface::onRadioButtonFacesClicked()
1100
{
1101
    m_currentShowType = "faces";
1102
    show_projected_shapes(m_shapeVec);
1103
}
1104

1105
void PartGui::DlgProjectionOnSurface::onRadioButtonEdgesClicked()
1106
{
1107
    m_currentShowType = "edges";
1108
    show_projected_shapes(m_shapeVec);
1109
}
1110

1111
void PartGui::DlgProjectionOnSurface::onDoubleSpinBoxExtrudeHeightValueChanged(double arg1)
1112
{
1113
    Q_UNUSED(arg1);
1114
    create_face_extrude(m_shapeVec);
1115
    show_projected_shapes(m_shapeVec);
1116
}
1117

1118
void PartGui::DlgProjectionOnSurface::onPushButtonAddWireClicked()
1119
{
1120
    if (ui->pushButtonAddWire->isChecked()) {
1121
        m_currentSelection = "add_wire";
1122
        disable_ui_elements(m_guiObjectVec, ui->pushButtonAddWire);
1123
        if (!filterEdge) {
1124
            filterEdge = new EdgeSelection();
1125
            Gui::Selection().addSelectionGate(filterEdge);
1126
        }
1127
        ui->radioButtonEdges->setChecked(true);
1128
        onRadioButtonEdgesClicked();
1129
    }
1130
    else {
1131
        m_currentSelection = "";
1132
        enable_ui_elements(m_guiObjectVec, nullptr);
1133
        Gui::Selection().rmvSelectionGate();
1134
        filterEdge = nullptr;
1135
    }
1136
}
1137

1138
void PartGui::DlgProjectionOnSurface::onDoubleSpinBoxSolidDepthValueChanged(double arg1)
1139
{
1140
    auto valX = ui->doubleSpinBoxDirX->value();
1141
    auto valY = ui->doubleSpinBoxDirY->value();
1142
    auto valZ = ui->doubleSpinBoxDirZ->value();
1143

1144
    auto valueToMove = arg1 - m_lastDepthVal;
1145
    Base::Vector3d vectorToMove(valX, valY, valZ);
1146
    vectorToMove *= valueToMove;
1147

1148
    auto placment = m_projectionObject->Placement.getValue();
1149
    placment.move(vectorToMove);
1150
    m_projectionObject->Placement.setValue(placment);
1151

1152
    m_lastDepthVal = ui->doubleSpinBoxSolidDepth->value();
1153
}
1154

1155
// ---------------------------------------
1156

1157
TaskProjectionOnSurface::TaskProjectionOnSurface()
1158
    : widget(new DlgProjectionOnSurface())
1159
    , taskbox(new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("Part_ProjectionOnSurface"),
1160
                                         widget->windowTitle(),
1161
                                         true,
1162
                                         nullptr))
1163
{
1164
    taskbox->groupLayout()->addWidget(widget);
1165
    Content.push_back(taskbox);
1166
}
1167

1168
bool TaskProjectionOnSurface::accept()
1169
{
1170
    widget->apply();
1171
    return true;
1172
}
1173

1174
bool TaskProjectionOnSurface::reject()
1175
{
1176
    widget->reject();
1177
    return true;
1178
}
1179

1180
void TaskProjectionOnSurface::clicked(int id)
1181
{
1182
    if (id == QDialogButtonBox::Apply) {
1183
        try {
1184
            widget->apply();
1185
        }
1186
        catch (Base::AbortException&) {
1187
        }
1188
    }
1189
}
1190

1191
// ------------------------------------------------------------------------------------------------
1192

1193
DlgProjectOnSurface::DlgProjectOnSurface(Part::ProjectOnSurface* feature, QWidget* parent)
1194
    : QWidget(parent)
1195
    , ui(new Ui::DlgProjectionOnSurface)
1196
    , filterEdge(nullptr)
1197
    , filterFace(nullptr)
1198
    , feature(feature)
1199
{
1200
    ui->setupUi(this);
1201
    ui->doubleSpinBoxExtrudeHeight->setValue(feature->Height.getValue());
1202
    ui->doubleSpinBoxSolidDepth->setValue(feature->Offset.getValue());
1203
    fetchDirection();
1204
    fetchMode();
1205
    setupConnections();
1206

1207
    ui->pushButtonAddEdge->setCheckable(true);
1208
    ui->pushButtonAddFace->setCheckable(true);
1209
    ui->pushButtonAddProjFace->setCheckable(true);
1210
    ui->pushButtonAddWire->setCheckable(true);
1211
}
1212

1213
DlgProjectOnSurface::~DlgProjectOnSurface()
1214
{
1215
    if (filterFace || filterEdge) {
1216
        Gui::Selection().rmvSelectionGate();
1217
    }
1218
}
1219

1220
void DlgProjectOnSurface::setupConnections()
1221
{
1222
    // clang-format off
1223
    connect(ui->pushButtonAddFace, &QPushButton::clicked,
1224
            this, &DlgProjectOnSurface::onAddFaceClicked);
1225
    connect(ui->pushButtonAddEdge, &QPushButton::clicked,
1226
            this, &DlgProjectOnSurface::onAddEdgeClicked);
1227
    connect(ui->pushButtonGetCurrentCamDir, &QPushButton::clicked,
1228
            this, &DlgProjectOnSurface::onGetCurrentCamDirClicked);
1229
    connect(ui->pushButtonDirX, &QPushButton::clicked,
1230
            this, &DlgProjectOnSurface::onDirXClicked);
1231
    connect(ui->pushButtonDirY, &QPushButton::clicked,
1232
            this, &DlgProjectOnSurface::onDirYClicked);
1233
    connect(ui->pushButtonDirZ, &QPushButton::clicked,
1234
            this, &DlgProjectOnSurface::onDirZClicked);
1235
    connect(ui->pushButtonAddProjFace, &QPushButton::clicked,
1236
            this, &DlgProjectOnSurface::onAddProjFaceClicked);
1237
    connect(ui->radioButtonShowAll, &QRadioButton::clicked,
1238
            this, &DlgProjectOnSurface::onShowAllClicked);
1239
    connect(ui->radioButtonFaces, &QRadioButton::clicked,
1240
            this, &DlgProjectOnSurface::onFacesClicked);
1241
    connect(ui->radioButtonEdges, &QRadioButton::clicked,
1242
            this, &DlgProjectOnSurface::onEdgesClicked);
1243
    connect(ui->doubleSpinBoxExtrudeHeight, qOverload<double>(&QDoubleSpinBox::valueChanged),
1244
            this, &DlgProjectOnSurface::onExtrudeHeightValueChanged);
1245
    connect(ui->pushButtonAddWire, &QPushButton::clicked,
1246
            this, &DlgProjectOnSurface::onAddWireClicked);
1247
    connect(ui->doubleSpinBoxSolidDepth, qOverload<double>(&QDoubleSpinBox::valueChanged),
1248
            this, &DlgProjectOnSurface::onSolidDepthValueChanged);
1249
    // clang-format off
1250
}
1251

1252
void DlgProjectOnSurface::onSelectionChanged(const Gui::SelectionChanges& msg)
1253
{
1254
    // clang-format off
1255
    if (msg.Type == Gui::SelectionChanges::AddSelection) {
1256
        if (selectionMode == SelectionMode::AddFace ||
1257
            selectionMode == SelectionMode::AddEdge) {
1258
            addSelection(msg);
1259
        }
1260
        else if (selectionMode == SelectionMode::AddWire) {
1261
            addWire(msg);
1262
        }
1263
        else if (selectionMode == SelectionMode::SupportFace) {
1264
            ui->pushButtonAddProjFace->setChecked(false);
1265
            setSupportFace(msg);
1266
            onAddProjFaceClicked();
1267
        }
1268
    }
1269
    // clang-format on
1270
}
1271

1272
void DlgProjectOnSurface::accept()
1273
{
1274
    if (!feature.expired()) {
1275
        auto document = feature->getDocument();
1276
        document->commitTransaction();
1277
        document->recompute();
1278
    }
1279
}
1280

1281
void DlgProjectOnSurface::reject()
1282
{
1283
    if (!feature.expired()) {
1284
        auto document = feature->getDocument();
1285
        document->abortTransaction();
1286
    }
1287
}
1288

1289
void DlgProjectOnSurface::onAddProjFaceClicked()
1290
{
1291
    if (ui->pushButtonAddProjFace->isChecked()) {
1292
        selectionMode = SelectionMode::SupportFace;
1293
        if (!filterFace) {
1294
            filterFace = new FaceSelection();
1295
            Gui::Selection().addSelectionGate(filterFace);
1296
        }
1297
    }
1298
    else {
1299
        selectionMode = SelectionMode::None;
1300
        Gui::Selection().rmvSelectionGate();
1301
        filterFace = nullptr;
1302
    }
1303
}
1304

1305
void DlgProjectOnSurface::onAddFaceClicked()
1306
{
1307
    if (ui->pushButtonAddFace->isChecked()) {
1308
        selectionMode = SelectionMode::AddFace;
1309
        if (!filterFace) {
1310
            filterFace = new FaceSelection();
1311
            Gui::Selection().addSelectionGate(filterFace);
1312
        }
1313
    }
1314
    else {
1315
        selectionMode = SelectionMode::None;
1316
        Gui::Selection().rmvSelectionGate();
1317
        filterFace = nullptr;
1318
    }
1319
}
1320

1321
void DlgProjectOnSurface::onAddWireClicked()
1322
{
1323
    if (ui->pushButtonAddWire->isChecked()) {
1324
        selectionMode = SelectionMode::AddWire;
1325
        if (!filterEdge) {
1326
            filterEdge = new EdgeSelection();
1327
            Gui::Selection().addSelectionGate(filterEdge);
1328
        }
1329
        ui->radioButtonEdges->setChecked(true);
1330
        onEdgesClicked();
1331
    }
1332
    else {
1333
        selectionMode = SelectionMode::None;
1334
        Gui::Selection().rmvSelectionGate();
1335
        filterEdge = nullptr;
1336
    }
1337
}
1338

1339
void DlgProjectOnSurface::onAddEdgeClicked()
1340
{
1341
    if (ui->pushButtonAddEdge->isChecked()) {
1342
        selectionMode = SelectionMode::AddEdge;
1343
        if (!filterEdge) {
1344
            filterEdge = new EdgeSelection();
1345
            Gui::Selection().addSelectionGate(filterEdge);
1346
        }
1347
        ui->radioButtonEdges->setChecked(true);
1348
        onEdgesClicked();
1349
    }
1350
    else {
1351
        selectionMode = SelectionMode::None;
1352
        Gui::Selection().rmvSelectionGate();
1353
        filterEdge = nullptr;
1354
    }
1355
}
1356

1357
void DlgProjectOnSurface::onGetCurrentCamDirClicked()
1358
{
1359
    auto mainWindow = Gui::getMainWindow();
1360

1361
    auto mdiObject = dynamic_cast<Gui::View3DInventor*>(mainWindow->activeWindow());
1362
    if (!mdiObject) {
1363
        return;
1364
    }
1365
    auto camerRotation = mdiObject->getViewer()->getCameraOrientation();
1366

1367
    SbVec3f lookAt(0, 0, -1);
1368
    camerRotation.multVec(lookAt, lookAt);
1369

1370
    float valX {};
1371
    float valY {};
1372
    float valZ {};
1373
    lookAt.getValue(valX, valY, valZ);
1374

1375
    ui->doubleSpinBoxDirX->setValue(valX);
1376
    ui->doubleSpinBoxDirY->setValue(valY);
1377
    ui->doubleSpinBoxDirZ->setValue(valZ);
1378
    setDirection();
1379
}
1380

1381
void DlgProjectOnSurface::onDirXClicked()
1382
{
1383
    auto currentVal = ui->doubleSpinBoxDirX->value();
1384
    ui->doubleSpinBoxDirX->setValue(currentVal > 0 ? -1 : 1);
1385
    ui->doubleSpinBoxDirY->setValue(0);
1386
    ui->doubleSpinBoxDirZ->setValue(0);
1387
    setDirection();
1388
}
1389

1390
void DlgProjectOnSurface::onDirYClicked()
1391
{
1392
    auto currentVal = ui->doubleSpinBoxDirY->value();
1393
    ui->doubleSpinBoxDirX->setValue(0);
1394
    ui->doubleSpinBoxDirY->setValue(currentVal > 0 ? -1 : 1);
1395
    ui->doubleSpinBoxDirZ->setValue(0);
1396
    setDirection();
1397
}
1398

1399
void DlgProjectOnSurface::onDirZClicked()
1400
{
1401
    auto currentVal = ui->doubleSpinBoxDirZ->value();
1402
    ui->doubleSpinBoxDirX->setValue(0);
1403
    ui->doubleSpinBoxDirY->setValue(0);
1404
    ui->doubleSpinBoxDirZ->setValue(currentVal > 0 ? -1 : 1);
1405
    setDirection();
1406
}
1407

1408
void DlgProjectOnSurface::setDirection()
1409
{
1410
    if (!feature.expired()) {
1411
        auto xVal = ui->doubleSpinBoxDirX->value();
1412
        auto yVal = ui->doubleSpinBoxDirY->value();
1413
        auto zVal = ui->doubleSpinBoxDirZ->value();
1414
        feature->Direction.setValue(Base::Vector3d(xVal, yVal, zVal));
1415
        feature->recomputeFeature();
1416
    }
1417
}
1418

1419
void DlgProjectOnSurface::addWire(const Gui::SelectionChanges& msg)
1420
{
1421
    auto isEdgePartOf = [](const TopoDS_Shape& wire, const TopoDS_Shape& edge) {
1422
        for (TopExp_Explorer xp(wire, TopAbs_EDGE); xp.More(); xp.Next()) {
1423
            if (edge.IsSame(xp.Current())) {
1424
                return true;
1425
            }
1426
        }
1427

1428
        return false;
1429
    };
1430
    if (selectionMode != SelectionMode::AddWire) {
1431
        return;
1432
    }
1433

1434
    Gui::SelectionObject selObj(msg);
1435
    if (!selObj.hasSubNames()) {
1436
        return;
1437
    }
1438

1439
    Part::TopoShape part = Part::Feature::getTopoShape(selObj.getObject());
1440
    if (part.isNull()) {
1441
        return;
1442
    }
1443

1444
    std::string subName = selObj.getSubNames().front();
1445
    TopoDS_Shape edge = part.getSubShape(subName.c_str(), true);
1446
    if (edge.IsNull() || edge.ShapeType() != TopAbs_EDGE) {
1447
        return;
1448
    }
1449

1450
    int index = 1;
1451
    const TopoDS_Shape& shape = part.getShape();
1452
    for (TopExp_Explorer xp(shape, TopAbs_WIRE); xp.More(); xp.Next()) {
1453
        if (isEdgePartOf(xp.Current(), edge)) {
1454
            std::string name{"Wire"};
1455
            name += std::to_string(index);
1456
            addSelection(msg, name);
1457
            break;
1458
        }
1459
        index++;
1460
    }
1461
}
1462

1463
void DlgProjectOnSurface::addSelection(const Gui::SelectionChanges& msg,
1464
                                       const std::string& subName)
1465
{
1466
    if (!feature.expired()) {
1467
        Gui::SelectionObject selObj(msg);
1468
        feature->Projection.addValue(selObj.getObject(), {subName});
1469
    }
1470
}
1471

1472
void DlgProjectOnSurface::addSelection(const Gui::SelectionChanges& msg)
1473
{
1474
    if (!feature.expired()) {
1475
        Gui::SelectionObject selObj(msg);
1476
        feature->Projection.addValue(selObj.getObject(), selObj.getSubNames());
1477
    }
1478
}
1479

1480
void DlgProjectOnSurface::setSupportFace(const Gui::SelectionChanges& msg)
1481
{
1482
    Gui::SelectionObject selObj(msg);
1483
    if (!feature.expired()) {
1484
        feature->SupportFace.setValue(selObj.getObject(), selObj.getSubNames());
1485
        feature->recomputeFeature();
1486
    }
1487
}
1488

1489
void DlgProjectOnSurface::fetchDirection()
1490
{
1491
    if (!feature.expired()) {
1492
        auto dir = feature->Direction.getValue();
1493
        ui->doubleSpinBoxDirX->setValue(dir.x);
1494
        ui->doubleSpinBoxDirY->setValue(dir.y);
1495
        ui->doubleSpinBoxDirZ->setValue(dir.z);
1496
    }
1497
}
1498

1499
void DlgProjectOnSurface::fetchMode()
1500
{
1501
    if (!feature.expired()) {
1502
        if (strcmp(feature->Mode.getValueAsString(), Part::ProjectOnSurface::AllMode) == 0) {
1503
            ui->radioButtonShowAll->setChecked(true);
1504
        }
1505
        else if (strcmp(feature->Mode.getValueAsString(), Part::ProjectOnSurface::FacesMode) == 0) {
1506
            ui->radioButtonFaces->setChecked(true);
1507
        }
1508
        else if (strcmp(feature->Mode.getValueAsString(), Part::ProjectOnSurface::EdgesMode) == 0) {
1509
            ui->radioButtonEdges->setChecked(true);
1510
        }
1511
    }
1512
}
1513

1514
void DlgProjectOnSurface::onShowAllClicked()
1515
{
1516
    if (!feature.expired()) {
1517
        feature->Mode.setValue(Part::ProjectOnSurface::AllMode);
1518
        feature->recomputeFeature();
1519
    }
1520
}
1521

1522
void DlgProjectOnSurface::onFacesClicked()
1523
{
1524
    if (!feature.expired()) {
1525
        feature->Mode.setValue(Part::ProjectOnSurface::FacesMode);
1526
        feature->recomputeFeature();
1527
    }
1528
}
1529

1530
void DlgProjectOnSurface::onEdgesClicked()
1531
{
1532
    if (!feature.expired()) {
1533
        feature->Mode.setValue(Part::ProjectOnSurface::EdgesMode);
1534
        feature->recomputeFeature();
1535
    }
1536
}
1537

1538
void DlgProjectOnSurface::onExtrudeHeightValueChanged(double value)
1539
{
1540
    if (!feature.expired()) {
1541
        feature->Height.setValue(value);
1542
        feature->recomputeFeature();
1543
    }
1544
}
1545

1546
void DlgProjectOnSurface::onSolidDepthValueChanged(double value)
1547
{
1548
    if (!feature.expired()) {
1549
        feature->Offset.setValue(value);
1550
        feature->recomputeFeature();
1551
    }
1552
}
1553

1554
// ---------------------------------------
1555

1556
TaskProjectOnSurface::TaskProjectOnSurface(App::Document* doc)
1557
{
1558
    setDocumentName(doc->getName());
1559
    doc->openTransaction(QT_TRANSLATE_NOOP("Command", "Project on surface"));
1560
    auto obj = doc->addObject("Part::ProjectOnSurface", "Projection");
1561
    auto feature = dynamic_cast<Part::ProjectOnSurface*>(obj);
1562
    widget = new DlgProjectOnSurface(feature);
1563
    taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("Part_ProjectionOnSurface"),
1564
                                         widget->windowTitle(), true, nullptr);
1565
    taskbox->groupLayout()->addWidget(widget);
1566
    Content.push_back(taskbox);
1567
}
1568

1569
TaskProjectOnSurface::TaskProjectOnSurface(Part::ProjectOnSurface* feature)
1570
    : widget(new DlgProjectOnSurface(feature))
1571
    , taskbox(new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("Part_ProjectionOnSurface"),
1572
                                         widget->windowTitle(),
1573
                                         true,
1574
                                         nullptr))
1575
{
1576
    taskbox->groupLayout()->addWidget(widget);
1577
    Content.push_back(taskbox);
1578
}
1579

1580
void TaskProjectOnSurface::resetEdit()
1581
{
1582
    std::string document = getDocumentName();
1583
    Gui::doCommandT(Gui::Command::Gui, "Gui.getDocument('%s').resetEdit()", document);
1584
}
1585

1586
bool TaskProjectOnSurface::accept()
1587
{
1588
    widget->accept();
1589
    resetEdit();
1590
    return true;
1591
}
1592

1593
bool TaskProjectOnSurface::reject()
1594
{
1595
    widget->reject();
1596
    resetEdit();
1597
    return true;
1598
}
1599

1600
#include "moc_DlgProjectionOnSurface.cpp"
1601

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.