FreeCAD

Форк
0
/
MeshEditor.cpp 
776 строк · 27.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2010 Werner Mayer <wmayer[at]users.sourceforge.net>     *
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

25
#ifndef _PreComp_
26
#include <algorithm>
27
#include <functional>
28
#include <QMenu>
29
#include <QTimer>
30

31
#include <Inventor/SbLine.h>
32
#include <Inventor/SoPickedPoint.h>
33
#include <Inventor/details/SoFaceDetail.h>
34
#include <Inventor/events/SoKeyboardEvent.h>
35
#include <Inventor/events/SoLocation2Event.h>
36
#include <Inventor/events/SoMouseButtonEvent.h>
37
#include <Inventor/nodes/SoBaseColor.h>
38
#include <Inventor/nodes/SoCamera.h>
39
#include <Inventor/nodes/SoCoordinate3.h>
40
#include <Inventor/nodes/SoDirectionalLight.h>
41
#include <Inventor/nodes/SoDrawStyle.h>
42
#include <Inventor/nodes/SoFaceSet.h>
43
#include <Inventor/nodes/SoPickStyle.h>
44
#include <Inventor/nodes/SoPointSet.h>
45
#include <Inventor/nodes/SoSeparator.h>
46
#include <Inventor/nodes/SoShapeHints.h>
47
#endif
48

49
#include <App/Application.h>
50
#include <App/Document.h>
51
#include <Gui/View3DInventor.h>
52
#include <Gui/View3DInventorViewer.h>
53
#include <Gui/WaitCursor.h>
54
#include <Mod/Mesh/App/MeshFeature.h>
55
#include <Mod/Mesh/App/Core/Algorithm.h>
56

57
#include "MeshEditor.h"
58
#include "SoFCMeshObject.h"
59
#include "SoPolygon.h"
60

61

62
using namespace MeshGui;
63
namespace sp = std::placeholders;
64

65
PROPERTY_SOURCE(MeshGui::ViewProviderFace, Gui::ViewProviderDocumentObject)
66

67
ViewProviderFace::ViewProviderFace()
68
{
69
    // NOLINTBEGIN
70
    pcCoords = new SoCoordinate3();
71
    pcCoords->ref();
72
    pcCoords->point.setNum(0);
73
    pcFaces = new SoFaceSet;
74
    pcFaces->ref();
75
    pcMeshPick = new SoFCMeshPickNode();
76
    pcMeshPick->ref();
77
    // NOLINTEND
78
}
79

80
ViewProviderFace::~ViewProviderFace()
81
{
82
    pcCoords->unref();
83
    pcFaces->unref();
84
    pcMeshPick->unref();
85
}
86

87
void ViewProviderFace::attach(App::DocumentObject* obj)
88
{
89
    ViewProviderDocumentObject::attach(obj);
90

91
    pcMeshPick->mesh.setValue(static_cast<Mesh::Feature*>(obj)->Mesh.getValuePtr());
92

93
    // Draw markers
94
    SoGroup* markers = new SoGroup();
95
    SoDrawStyle* pointStyle = new SoDrawStyle();
96
    pointStyle->style = SoDrawStyle::POINTS;
97
    pointStyle->pointSize = 8.0F;
98
    markers->addChild(pointStyle);
99

100
    SoBaseColor* markcol = new SoBaseColor;
101
    markcol->rgb.setValue(1.0F, 1.0F, 0.0F);
102
    SoPointSet* marker = new SoPointSet();
103
    markers->addChild(markcol);
104
    markers->addChild(pcCoords);
105
    markers->addChild(marker);
106

107
    // Draw face
108
    SoGroup* faces = new SoGroup();
109
    SoDrawStyle* faceStyle = new SoDrawStyle();
110
    faceStyle->style = SoDrawStyle::FILLED;
111
    faces->addChild(faceStyle);
112

113
    SoShapeHints* flathints = new SoShapeHints;
114
    // flathints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE ;
115
    // flathints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
116
    faces->addChild(flathints);
117

118
    SoBaseColor* basecol = new SoBaseColor;
119
    if (mesh) {
120
        App::Color col = mesh->ShapeColor.getValue();
121
        basecol->rgb.setValue(col.r, col.g, col.b);
122
    }
123
    else {
124
        basecol->rgb.setValue(1.0F, 0.0F, 0.0F);
125
    }
126

127
    faces->addChild(basecol);
128
    faces->addChild(pcCoords);
129
    faces->addChild(pcFaces);
130

131
    SoGroup* face_marker = new SoGroup();
132
    face_marker->addChild(faces);
133
    face_marker->addChild(markers);
134

135
    addDisplayMaskMode(markers, "Marker");
136
    addDisplayMaskMode(face_marker, "Face");
137
    setDisplayMode("Marker");
138
}
139

140
void ViewProviderFace::setDisplayMode(const char* ModeName)
141
{
142
    if (strcmp(ModeName, "Face") == 0) {
143
        setDisplayMaskMode("Face");
144
    }
145
    else if (strcmp(ModeName, "Marker") == 0) {
146
        setDisplayMaskMode("Marker");
147
    }
148
    ViewProviderDocumentObject::setDisplayMode(ModeName);
149
}
150

151
const char* ViewProviderFace::getDefaultDisplayMode() const
152
{
153
    return "Marker";
154
}
155

156
std::vector<std::string> ViewProviderFace::getDisplayModes() const
157
{
158
    std::vector<std::string> modes;
159
    modes.emplace_back("Marker");
160
    modes.emplace_back("Face");
161
    return modes;
162
}
163

164
SoPickedPoint* ViewProviderFace::getPickedPoint(const SbVec2s& pos,
165
                                                const Gui::View3DInventorViewer* viewer) const
166
{
167
    SoSeparator* root = new SoSeparator;
168
    root->ref();
169
    root->addChild(viewer->getHeadlight());
170
    root->addChild(viewer->getSoRenderManager()->getCamera());
171
    root->addChild(this->pcMeshPick);
172

173
    SoRayPickAction rp(viewer->getSoRenderManager()->getViewportRegion());
174
    rp.setPoint(pos);
175
    rp.apply(root);
176
    root->unref();
177

178
    // returns a copy of the point
179
    SoPickedPoint* pick = rp.getPickedPoint();
180
    // return (pick ? pick->copy() : 0); // needs the same instance of CRT under MS Windows
181
    return (pick ? new SoPickedPoint(*pick) : nullptr);
182
}
183

184
// ----------------------------------------------------------------------
185

186
/* TRANSLATOR MeshGui::MeshFaceAddition */
187

188
MeshFaceAddition::MeshFaceAddition(Gui::View3DInventor* parent)
189
    : QObject(parent)
190
    , faceView(new MeshGui::ViewProviderFace())
191
{}
192

193
MeshFaceAddition::~MeshFaceAddition()
194
{
195
    delete faceView;
196
}
197

198
void MeshFaceAddition::startEditing(MeshGui::ViewProviderMesh* vp)
199
{
200
    Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(parent());
201
    Gui::View3DInventorViewer* viewer = view->getViewer();
202
    viewer->setEditing(true);
203
    viewer->setSelectionEnabled(false);
204
    viewer->setRedirectToSceneGraph(true);
205
    viewer->setRedirectToSceneGraphEnabled(true);
206

207
    faceView->mesh = vp;
208
    faceView->attach(vp->getObject());
209
    viewer->addViewProvider(faceView);
210
    // faceView->mesh->startEditing();
211
    viewer->addEventCallback(SoEvent::getClassTypeId(), MeshFaceAddition::addFacetCallback, this);
212
}
213

214
void MeshFaceAddition::finishEditing()
215
{
216
    Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(parent());
217
    Gui::View3DInventorViewer* viewer = view->getViewer();
218
    viewer->setEditing(false);
219
    viewer->setSelectionEnabled(true);
220
    viewer->setRedirectToSceneGraph(false);
221
    viewer->setRedirectToSceneGraphEnabled(false);
222

223
    viewer->removeViewProvider(faceView);
224
    // faceView->mesh->finishEditing();
225
    viewer->removeEventCallback(SoEvent::getClassTypeId(),
226
                                MeshFaceAddition::addFacetCallback,
227
                                this);
228
    this->deleteLater();
229
}
230

231
void MeshFaceAddition::addFace()
232
{
233
    Mesh::Feature* mf = static_cast<Mesh::Feature*>(faceView->mesh->getObject());
234
    App::Document* doc = mf->getDocument();
235
    doc->openTransaction("Add triangle");
236
    Mesh::MeshObject* mesh = mf->Mesh.startEditing();
237
    MeshCore::MeshFacet f;
238
    f._aulPoints[0] = faceView->index[0];
239
    f._aulPoints[1] = faceView->index[1];
240
    f._aulPoints[2] = faceView->index[2];
241
    std::vector<MeshCore::MeshFacet> faces;
242
    faces.push_back(f);
243
    mesh->addFacets(faces, true);
244
    mf->Mesh.finishEditing();
245
    doc->commitTransaction();
246

247
    clearPoints();
248
}
249

250
void MeshFaceAddition::clearPoints()
251
{
252
    faceView->index.clear();
253
    faceView->current_index = -1;
254
    faceView->pcCoords->point.setNum(0);
255
    faceView->setDisplayMode("Marker");
256
}
257

258
void MeshFaceAddition::flipNormal()
259
{
260
    if (faceView->index.size() < 3) {
261
        return;
262
    }
263
    std::swap(faceView->index[0], faceView->index[1]);
264
    SbVec3f v1 = faceView->pcCoords->point[0];
265
    SbVec3f v2 = faceView->pcCoords->point[1];
266
    faceView->pcCoords->point.set1Value(0, v2);
267
    faceView->pcCoords->point.set1Value(1, v1);
268
}
269

270
bool MeshFaceAddition::addMarkerPoint()
271
{
272
    if (faceView->current_index < 0) {
273
        return false;
274
    }
275
    if (faceView->index.size() >= 3) {
276
        return false;
277
    }
278
    faceView->index.push_back(faceView->current_index);
279
    faceView->current_index = -1;
280
    if (faceView->index.size() == 3) {
281
        faceView->setDisplayMode("Face");
282
    }
283
    return true;
284
}
285

286
void MeshFaceAddition::showMarker(SoPickedPoint* pp)
287
{
288
    const SbVec3f& vec = pp->getPoint();
289
    const SoDetail* detail = pp->getDetail();
290
    if (detail) {
291
        if (detail->isOfType(SoFaceDetail::getClassTypeId())) {
292
            const SoFaceDetail* fd = static_cast<const SoFaceDetail*>(detail);
293
            Mesh::Feature* mf = static_cast<Mesh::Feature*>(faceView->mesh->getObject());
294
            const MeshCore::MeshFacetArray& facets =
295
                mf->Mesh.getValuePtr()->getKernel().GetFacets();
296
            const MeshCore::MeshPointArray& points =
297
                mf->Mesh.getValuePtr()->getKernel().GetPoints();
298
            // is the face index valid?
299
            int face_index = fd->getFaceIndex();
300
            if (face_index >= (int)facets.size()) {
301
                return;
302
            }
303
            // is a border facet picked?
304
            MeshCore::MeshFacet f = facets[face_index];
305
            if (!f.HasOpenEdge()) {
306
                // check if a neighbour facet is at the border
307
                bool ok = false;
308
                for (Mesh::FacetIndex nbIndex : f._aulNeighbours) {
309
                    if (facets[nbIndex].HasOpenEdge()) {
310
                        f = facets[nbIndex];
311
                        ok = true;
312
                        break;
313
                    }
314
                }
315
                if (!ok) {
316
                    return;
317
                }
318
            }
319

320
            int point_index = -1;
321
            float distance = FLT_MAX;
322
            Base::Vector3f pnt;
323
            SbVec3f face_pnt;
324

325
            for (int i = 0; i < 3; i++) {
326
                int index = (int)f._aulPoints[i];
327
                if (std::find(faceView->index.begin(), faceView->index.end(), index)
328
                    != faceView->index.end()) {
329
                    continue;  // already inside
330
                }
331
                if (f._aulNeighbours[i] == MeshCore::FACET_INDEX_MAX
332
                    || f._aulNeighbours[(i + 2) % 3] == MeshCore::FACET_INDEX_MAX) {
333
                    pnt = points[index];
334
                    float len = Base::DistanceP2(pnt, Base::Vector3f(vec[0], vec[1], vec[2]));
335
                    if (len < distance) {
336
                        distance = len;
337
                        point_index = index;
338
                        face_pnt.setValue(pnt.x, pnt.y, pnt.z);
339
                    }
340
                }
341
            }
342

343
            if (point_index < 0) {
344
                return;  // picked point is rejected
345
            }
346

347
            int num = faceView->pcCoords->point.getNum();
348
            if (faceView->current_index >= 0) {
349
                num = std::max<int>(num - 1, 0);
350
            }
351
            faceView->current_index = point_index;
352
            faceView->pcCoords->point.set1Value(num, face_pnt);
353
            return;
354
        }
355
    }
356
}
357

358
void MeshFaceAddition::addFacetCallback(void* ud, SoEventCallback* n)
359
{
360
    MeshFaceAddition* that = static_cast<MeshFaceAddition*>(ud);
361
    ViewProviderFace* face = that->faceView;
362
    Gui::View3DInventorViewer* view = static_cast<Gui::View3DInventorViewer*>(n->getUserData());
363

364
    const SoEvent* ev = n->getEvent();
365
    // If we are in navigation mode then ignore all but key events
366
    if (!view->isRedirectedToSceneGraph()) {
367
        if (!ev->getTypeId().isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
368
            return;
369
        }
370
    }
371
    if (ev->getTypeId() == SoLocation2Event::getClassTypeId()) {
372
        n->setHandled();
373
        if (face->index.size() < 3) {
374
            SoPickedPoint* point = face->getPickedPoint(ev->getPosition(), view);
375
            if (point) {
376
                that->showMarker(point);
377
                delete point;
378
            }
379
        }
380
    }
381
    else if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {
382
        const SoMouseButtonEvent* mbe = static_cast<const SoMouseButtonEvent*>(ev);
383
        if (mbe->getButton() == SoMouseButtonEvent::BUTTON1
384
            || mbe->getButton() == SoMouseButtonEvent::BUTTON2
385
            || mbe->getButton() == SoMouseButtonEvent::BUTTON3) {
386
            n->setHandled();
387
        }
388
        if (mbe->getButton() == SoMouseButtonEvent::BUTTON1
389
            && mbe->getState() == SoButtonEvent::DOWN) {
390
            that->addMarkerPoint();
391
        }
392
        else if (mbe->getButton() == SoMouseButtonEvent::BUTTON1
393
                 && mbe->getState() == SoButtonEvent::UP) {
394
            if (face->index.size() == 3) {
395
                QMenu menu;
396
                QAction* add = menu.addAction(MeshFaceAddition::tr("Add triangle"));
397
                QAction* swp = menu.addAction(MeshFaceAddition::tr("Flip normal"));
398
                QAction* clr = menu.addAction(MeshFaceAddition::tr("Clear"));
399
                QAction* act = menu.exec(QCursor::pos());
400
                if (act == add) {
401
                    QTimer::singleShot(300, that, &MeshFaceAddition::addFace);
402
                }
403
                else if (act == swp) {
404
                    QTimer::singleShot(300, that, &MeshFaceAddition::flipNormal);
405
                }
406
                else if (act == clr) {
407
                    QTimer::singleShot(300, that, &MeshFaceAddition::clearPoints);
408
                }
409
            }
410
        }
411
        else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2
412
                 && mbe->getState() == SoButtonEvent::UP) {
413
            QMenu menu;
414
            QAction* fin = menu.addAction(MeshFaceAddition::tr("Finish"));
415
            QAction* act = menu.exec(QCursor::pos());
416
            if (act == fin) {
417
                QTimer::singleShot(300, that, &MeshFaceAddition::finishEditing);
418
            }
419
        }
420
    }
421
    // toggle between edit and navigation mode
422
    else if (ev->getTypeId().isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
423
        const SoKeyboardEvent* const ke = static_cast<const SoKeyboardEvent*>(ev);
424
        if (ke->getState() == SoButtonEvent::DOWN && ke->getKey() == SoKeyboardEvent::ESCAPE) {
425
            SbBool toggle = view->isRedirectedToSceneGraph();
426
            view->setRedirectToSceneGraph(!toggle);
427
            n->setHandled();
428
        }
429
    }
430
}
431

432
// ----------------------------------------------------------------------
433

434
namespace MeshGui
435
{
436
// for sorting of elements
437
struct NofFacetsCompare
438
{
439
    bool operator()(const std::vector<Mesh::PointIndex>& rclC1,
440
                    const std::vector<Mesh::PointIndex>& rclC2)
441
    {
442
        return rclC1.size() < rclC2.size();
443
    }
444
};
445
}  // namespace MeshGui
446

447
/* TRANSLATOR MeshGui::MeshFillHole */
448

449
MeshFillHole::MeshFillHole(MeshHoleFiller& hf, Gui::View3DInventor* parent)
450
    : QObject(parent)
451
    , myHoleFiller(hf)
452
{
453
    // NOLINTBEGIN
454
    myBoundariesRoot = new SoSeparator;
455
    myBoundariesRoot->ref();
456
    myBoundaryRoot = new SoSeparator;
457
    myBoundaryRoot->ref();
458
    myBoundariesGroup = new SoSeparator();
459
    myBoundariesGroup->ref();
460
    myBridgeRoot = new SoSeparator;
461
    myBridgeRoot->ref();
462

463
    SoDrawStyle* pointStyle = new SoDrawStyle();
464
    pointStyle->style = SoDrawStyle::POINTS;
465
    pointStyle->pointSize = 8.0f;
466
    myBridgeRoot->addChild(pointStyle);
467

468
    SoBaseColor* markcol = new SoBaseColor;
469
    markcol->rgb.setValue(1.0f, 1.0f, 0.0f);
470
    myBridgeRoot->addChild(markcol);
471

472
    myVertex = new SoCoordinate3();
473
    myBridgeRoot->addChild(myVertex);
474
    myBridgeRoot->addChild(new SoPointSet);
475
    // NOLINTEND
476
}
477

478
MeshFillHole::~MeshFillHole()
479
{
480
    myBoundariesRoot->unref();
481
    myBoundariesGroup->unref();
482
    myBoundaryRoot->unref();
483
    myBridgeRoot->unref();
484
}
485

486
void MeshFillHole::startEditing(MeshGui::ViewProviderMesh* vp)
487
{
488
    this->myMesh = static_cast<Mesh::Feature*>(vp->getObject());
489

490
    Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(parent());
491
    Gui::View3DInventorViewer* viewer = view->getViewer();
492
    viewer->setEditing(true);
493
    // viewer->setRedirectToSceneGraph(true);
494
    viewer->addEventCallback(SoEvent::getClassTypeId(), MeshFillHole::fileHoleCallback, this);
495
    // NOLINTBEGIN
496
    myConnection = App::GetApplication().signalChangedObject.connect(
497
        std::bind(&MeshFillHole::slotChangedObject, this, sp::_1, sp::_2));
498
    // NOLINTEND
499

500
    Gui::coinRemoveAllChildren(myBoundariesRoot);
501
    myBoundariesRoot->addChild(viewer->getHeadlight());
502
    myBoundariesRoot->addChild(viewer->getSoRenderManager()->getCamera());
503
    myBoundariesRoot->addChild(myBoundariesGroup);
504
    Gui::coinRemoveAllChildren(myBoundaryRoot);
505
    myBoundaryRoot->addChild(viewer->getHeadlight());
506
    myBoundaryRoot->addChild(viewer->getSoRenderManager()->getCamera());
507
    createPolygons();
508
    static_cast<SoGroup*>(viewer->getSceneGraph())->addChild(myBridgeRoot);
509
}
510

511
void MeshFillHole::finishEditing()
512
{
513
    Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(parent());
514
    Gui::View3DInventorViewer* viewer = view->getViewer();
515
    viewer->setEditing(false);
516
    // viewer->setRedirectToSceneGraph(false);
517
    viewer->removeEventCallback(SoEvent::getClassTypeId(), MeshFillHole::fileHoleCallback, this);
518
    myConnection.disconnect();
519
    this->deleteLater();
520
    static_cast<SoGroup*>(viewer->getSceneGraph())->removeChild(myBridgeRoot);
521
}
522

523
void MeshFillHole::closeBridge()
524
{
525
    // Do the hole-filling
526
    Gui::WaitCursor wc;
527
    auto it = std::find(myPolygon.begin(), myPolygon.end(), myVertex1);
528
    auto jt = std::find(myPolygon.begin(), myPolygon.end(), myVertex2);
529
    if (it != myPolygon.end() && jt != myPolygon.end()) {
530
        // which iterator comes first
531
        if (jt < it) {
532
            std::swap(it, jt);
533
        }
534
        // split the boundary into two loops and take the shorter one
535
        std::list<TBoundary> bounds;
536
        TBoundary loop1;
537
        TBoundary loop2;
538
        loop1.insert(loop1.end(), myPolygon.begin(), it);
539
        loop1.insert(loop1.end(), jt, myPolygon.end());
540
        loop2.insert(loop2.end(), it, jt);
541
        // this happens when myVertex1 == myVertex2
542
        if (loop2.empty()) {
543
            bounds.push_back(loop1);
544
        }
545
        else if (loop1.size() < loop2.size()) {
546
            bounds.push_back(loop1);
547
        }
548
        else {
549
            bounds.push_back(loop2);
550
        }
551

552
        App::Document* doc = myMesh->getDocument();
553
        doc->openTransaction("Bridge && Fill hole");
554
        Mesh::MeshObject* pMesh = myMesh->Mesh.startEditing();
555
        bool ok = myHoleFiller.fillHoles(*pMesh, bounds, myVertex1, myVertex2);
556
        myMesh->Mesh.finishEditing();
557
        if (ok) {
558
            doc->commitTransaction();
559
        }
560
        else {
561
            doc->abortTransaction();
562
        }
563
    }
564
}
565

566
void MeshFillHole::slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop)
567
{
568
    if (&Obj == myMesh && strcmp(Prop.getName(), "Mesh") == 0) {
569
        Gui::coinRemoveAllChildren(myBoundariesGroup);
570
        myVertex->point.setNum(0);
571
        myNumPoints = 0;
572
        myPolygon.clear();
573

574
        createPolygons();
575
    }
576
}
577

578
void MeshFillHole::createPolygons()
579
{
580
    Gui::WaitCursor wc;
581
    myPolygons.clear();
582

583
    SoPickStyle* pickStyle = new SoPickStyle();
584
    pickStyle->style = SoPickStyle::BOUNDING_BOX;
585
    myBoundariesGroup->addChild(pickStyle);
586
    myBoundaryRoot->addChild(pickStyle);
587

588
    // get mesh kernel
589
    const MeshCore::MeshKernel& rMesh = this->myMesh->Mesh.getValue().getKernel();
590

591
    // get the mesh boundaries as an array of point indices
592
    std::list<std::vector<Mesh::PointIndex>> borders;
593
    MeshCore::MeshAlgorithm cAlgo(rMesh);
594
    MeshCore::MeshPointIterator p_iter(rMesh);
595
    cAlgo.GetMeshBorders(borders);
596
    cAlgo.SplitBoundaryLoops(borders);
597

598
    // sort the borders in ascending order of the number of edges
599
    borders.sort(NofFacetsCompare());
600

601
    int32_t count = 0;
602
    for (auto& border : borders) {
603
        if (border.front() == border.back()) {
604
            border.pop_back();
605
        }
606
        count += border.size();
607
    }
608

609
    SoCoordinate3* coords = new SoCoordinate3();
610
    myBoundariesGroup->addChild(coords);
611
    myBoundaryRoot->addChild(coords);
612

613
    coords->point.setNum(count);
614
    int32_t index = 0;
615
    for (const auto& border : borders) {
616
        SoPolygon* polygon = new SoPolygon();
617
        polygon->startIndex = index;
618
        polygon->numVertices = border.size();
619
        myBoundariesGroup->addChild(polygon);
620
        myPolygons[polygon] = border;
621
        for (Mesh::PointIndex jt : border) {
622
            p_iter.Set(jt);
623
            coords->point.set1Value(index++, p_iter->x, p_iter->y, p_iter->z);
624
        }
625
    }
626
}
627

628
SoNode* MeshFillHole::getPickedPolygon(
629
    const SoRayPickAction& action /*SoNode* root, const SbVec2s& pos*/) const
630
{
631
    SoPolygon* poly = nullptr;
632
    const SoPickedPointList& points = action.getPickedPointList();
633
    for (int i = 0; i < points.getLength(); i++) {
634
        const SoPickedPoint* point = points[i];
635
        if (point
636
            && point->getPath()->getTail()->getTypeId() == MeshGui::SoPolygon::getClassTypeId()) {
637
            // we have something picked, now check if it was an SoPolygon node
638
            SoPolygon* node = static_cast<SoPolygon*>(point->getPath()->getTail());
639
            if (!poly) {
640
                poly = node;
641
            }
642
            // check which polygon has less edges
643
            else if (node->numVertices.getValue() < poly->numVertices.getValue()) {
644
                poly = node;
645
            }
646
        }
647
    }
648

649
    return poly;
650
}
651

652
float MeshFillHole::findClosestPoint(const SbLine& ray,
653
                                     const TBoundary& polygon,
654
                                     Mesh::PointIndex& vertex_index,
655
                                     SbVec3f& closestPoint) const
656
{
657
    // now check which vertex of the polygon is closest to the ray
658
    float minDist = FLT_MAX;
659
    vertex_index = MeshCore::POINT_INDEX_MAX;
660

661
    const MeshCore::MeshKernel& rMesh = myMesh->Mesh.getValue().getKernel();
662
    const MeshCore::MeshPointArray& pts = rMesh.GetPoints();
663
    for (Mesh::PointIndex it : polygon) {
664
        SbVec3f vertex;
665
        const Base::Vector3f& v = pts[it];
666
        vertex.setValue(v.x, v.y, v.z);
667
        SbVec3f point = ray.getClosestPoint(vertex);
668
        float distance = (vertex - point).sqrLength();
669
        if (distance < minDist) {
670
            minDist = distance;
671
            vertex_index = it;
672
            closestPoint = vertex;
673
        }
674
    }
675

676
    return minDist;
677
}
678

679
void MeshFillHole::fileHoleCallback(void* ud, SoEventCallback* n)
680
{
681
    MeshFillHole* self = static_cast<MeshFillHole*>(ud);
682
    Gui::View3DInventorViewer* view = static_cast<Gui::View3DInventorViewer*>(n->getUserData());
683

684
    const SoEvent* ev = n->getEvent();
685
    if (ev->getTypeId() == SoLocation2Event::getClassTypeId()) {
686
        n->setHandled();
687
        SoRayPickAction rp(view->getSoRenderManager()->getViewportRegion());
688
        rp.setPoint(ev->getPosition());
689
        rp.setPickAll(true);
690
        if (self->myNumPoints == 0) {
691
            rp.apply(self->myBoundariesRoot);
692
        }
693
        else {
694
            rp.apply(self->myBoundaryRoot);
695
        }
696
        SoNode* node = self->getPickedPolygon(rp);
697
        if (node) {
698
            auto it = self->myPolygons.find(node);
699
            if (it != self->myPolygons.end()) {
700
                // now check which vertex of the polygon is closest to the ray
701
                Mesh::PointIndex vertex_index {};
702
                SbVec3f closestPoint;
703
                float minDist =
704
                    self->findClosestPoint(rp.getLine(), it->second, vertex_index, closestPoint);
705
                if (minDist < 1.0F) {
706
                    if (self->myNumPoints == 0) {
707
                        self->myVertex->point.set1Value(0, closestPoint);
708
                    }
709
                    else {
710
                        self->myVertex->point.set1Value(1, closestPoint);
711
                    }
712
                }
713
            }
714
        }
715
    }
716
    else if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {
717
        n->setHandled();
718
        const SoMouseButtonEvent* mbe = static_cast<const SoMouseButtonEvent*>(ev);
719
        if (mbe->getButton() == SoMouseButtonEvent::BUTTON1
720
            && mbe->getState() == SoButtonEvent::UP) {
721
            if (self->myNumPoints > 1) {
722
                return;
723
            }
724
            SoRayPickAction rp(view->getSoRenderManager()->getViewportRegion());
725
            rp.setPoint(ev->getPosition());
726
            rp.setPickAll(true);
727
            if (self->myNumPoints == 0) {
728
                rp.apply(self->myBoundariesRoot);
729
            }
730
            else {
731
                rp.apply(self->myBoundaryRoot);
732
            }
733
            SoNode* node = self->getPickedPolygon(rp);
734
            if (node) {
735
                auto it = self->myPolygons.find(node);
736
                if (it != self->myPolygons.end()) {
737
                    // now check which vertex of the polygon is closest to the ray
738
                    Mesh::PointIndex vertex_index {};
739
                    SbVec3f closestPoint;
740
                    float minDist = self->findClosestPoint(rp.getLine(),
741
                                                           it->second,
742
                                                           vertex_index,
743
                                                           closestPoint);
744
                    if (minDist < 1.0F) {
745
                        if (self->myNumPoints == 0) {
746
                            self->myBoundaryRoot->addChild(node);
747
                            self->myVertex->point.set1Value(0, closestPoint);
748
                            self->myNumPoints = 1;
749
                            self->myVertex1 = vertex_index;
750
                        }
751
                        else {
752
                            // myVertex2 can be equal to myVertex1 which does a full hole-filling
753
                            self->myBoundaryRoot->removeChild(node);
754
                            self->myVertex->point.set1Value(1, closestPoint);
755
                            self->myNumPoints = 2;
756
                            self->myVertex2 = vertex_index;
757
                            self->myPolygon = it->second;
758
                            QTimer::singleShot(300, self, &MeshFillHole::closeBridge);
759
                        }
760
                    }
761
                }
762
            }
763
        }
764
        else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2
765
                 && mbe->getState() == SoButtonEvent::UP) {
766
            QMenu menu;
767
            QAction* fin = menu.addAction(MeshFillHole::tr("Finish"));
768
            QAction* act = menu.exec(QCursor::pos());
769
            if (act == fin) {
770
                QTimer::singleShot(300, self, &MeshFillHole::finishEditing);
771
            }
772
        }
773
    }
774
}
775

776
#include "moc_MeshEditor.cpp"
777

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

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

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

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