FreeCAD

Форк
0
/
ViewProviderExt.cpp 
1345 строк · 52.3 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2011 Juergen Riegel <juergen.riegel@web.de>             *
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 <Bnd_Box.hxx>
27
# include <BRep_Tool.hxx>
28
# include <BRepBndLib.hxx>
29
# include <BRepBuilderAPI_MakeVertex.hxx>
30
# include <BRepExtrema_DistShapeShape.hxx>
31
# include <BRepMesh_IncrementalMesh.hxx>
32
# include <gp_Trsf.hxx>
33
# include <Precision.hxx>
34
# include <Poly_Array1OfTriangle.hxx>
35
# include <Poly_Polygon3D.hxx>
36
# include <Poly_PolygonOnTriangulation.hxx>
37
# include <Poly_Triangulation.hxx>
38
# include <Standard_Version.hxx>
39
# include <TColgp_Array1OfDir.hxx>
40
# include <TColgp_Array1OfPnt.hxx>
41
# include <TColStd_Array1OfInteger.hxx>
42
# include <TopExp.hxx>
43
# include <TopExp_Explorer.hxx>
44
# include <TopoDS.hxx>
45
# include <TopoDS_Edge.hxx>
46
# include <TopoDS_Face.hxx>
47
# include <TopoDS_Shape.hxx>
48
# include <TopoDS_Vertex.hxx>
49
# include <TopTools_IndexedMapOfShape.hxx>
50

51
# include <QAction>
52
# include <QMenu>
53
# include <sstream>
54

55
# include <Inventor/SoPickedPoint.h>
56
# include <Inventor/details/SoFaceDetail.h>
57
# include <Inventor/details/SoLineDetail.h>
58
# include <Inventor/details/SoPointDetail.h>
59
# include <Inventor/errors/SoDebugError.h>
60
# include <Inventor/nodes/SoCoordinate3.h>
61
# include <Inventor/nodes/SoDrawStyle.h>
62
# include <Inventor/nodes/SoMaterial.h>
63
# include <Inventor/nodes/SoMaterialBinding.h>
64
# include <Inventor/nodes/SoNormal.h>
65
# include <Inventor/nodes/SoNormalBinding.h>
66
# include <Inventor/nodes/SoPolygonOffset.h>
67
# include <Inventor/nodes/SoSeparator.h>
68
# include <Inventor/nodes/SoShapeHints.h>
69

70
# include <boost/algorithm/string/predicate.hpp>
71
#endif
72

73
#include <App/Application.h>
74
#include <App/Document.h>
75
#include <Base/Console.h>
76
#include <Base/Parameter.h>
77
#include <Base/TimeInfo.h>
78
#include <Base/Tools.h>
79

80
#include <Gui/BitmapFactory.h>
81
#include <Gui/Control.h>
82
#include <Gui/SoFCSelectionAction.h>
83
#include <Gui/SoFCUnifiedSelection.h>
84
#include <Gui/ViewParams.h>
85
#include <Mod/Part/App/ShapeMapHasher.h>
86
#include <Mod/Part/App/Tools.h>
87

88
#include "ViewProviderExt.h"
89
#include "ViewProviderPartExtPy.h"
90
#include "SoBrepEdgeSet.h"
91
#include "SoBrepFaceSet.h"
92
#include "SoBrepPointSet.h"
93
#include "TaskFaceAppearances.h"
94

95

96
FC_LOG_LEVEL_INIT("Part", true, true)
97

98
using namespace PartGui;
99

100
// Helper functions to consistently convert between float and long
101
namespace {
102
float fromPercent(long value)
103
{
104
    return std::roundf(value) / 100.0F;
105
}
106

107
long toPercent(float value)
108
{
109
    return std::lround(100.0 * value);
110
}
111
}
112

113
PROPERTY_SOURCE(PartGui::ViewProviderPartExt, Gui::ViewProviderGeometryObject)
114

115

116
//**************************************************************************
117
// Construction/Destruction
118

119
App::PropertyFloatConstraint::Constraints ViewProviderPartExt::sizeRange = {1.0,64.0,1.0};
120
App::PropertyFloatConstraint::Constraints ViewProviderPartExt::tessRange = {0.01,100.0,0.01};
121
App::PropertyQuantityConstraint::Constraints ViewProviderPartExt::angDeflectionRange = {1.0,180.0,0.05};
122
const char* ViewProviderPartExt::LightingEnums[]= {"One side","Two side",nullptr};
123
const char* ViewProviderPartExt::DrawStyleEnums[]= {"Solid","Dashed","Dotted","Dashdot",nullptr};
124

125
ViewProviderPartExt::ViewProviderPartExt()
126
{
127
    texture.initExtension(this);
128

129
    VisualTouched = true;
130
    forceUpdateCount = 0;
131
    NormalsFromUV = true;
132

133
    // get default line color
134
    unsigned long lcol = Gui::ViewParams::instance()->getDefaultShapeLineColor(); // dark grey (25,25,25)
135
    float lr,lg,lb;
136
    lr = ((lcol >> 24) & 0xff) / 255.0; lg = ((lcol >> 16) & 0xff) / 255.0; lb = ((lcol >> 8) & 0xff) / 255.0;
137
    // get default vertex color
138
    unsigned long vcol = Gui::ViewParams::instance()->getDefaultShapeVertexColor();
139
    float vr,vg,vb;
140
    vr = ((vcol >> 24) & 0xff) / 255.0; vg = ((vcol >> 16) & 0xff) / 255.0; vb = ((vcol >> 8) & 0xff) / 255.0;
141
    int lwidth = Gui::ViewParams::instance()->getDefaultShapeLineWidth();
142
    int psize = Gui::ViewParams::instance()->getDefaultShapePointSize();
143

144

145

146
    ParameterGrp::handle hPart = App::GetApplication().GetParameterGroupByPath
147
        ("User parameter:BaseApp/Preferences/Mod/Part");
148
    NormalsFromUV = hPart->GetBool("NormalsFromUVNodes", NormalsFromUV);
149

150
    long twoside = hPart->GetBool("TwoSideRendering", true) ? 1 : 0;
151

152
    // Let the user define a custom lower limit but a value less than
153
    // OCCT's epsilon is not allowed
154
    double lowerLimit = hPart->GetFloat("MinimumDeviation", tessRange.LowerBound);
155
    lowerLimit = std::max(lowerLimit, Precision::Confusion());
156
    tessRange.LowerBound = lowerLimit;
157

158
    static const char *osgroup = "Object Style";
159

160
    App::Material lmat;
161
    lmat.ambientColor.set(0.2f,0.2f,0.2f);
162
    lmat.diffuseColor.set(lr,lg,lb);
163
    lmat.specularColor.set(0.0f,0.0f,0.0f);
164
    lmat.emissiveColor.set(0.0f,0.0f,0.0f);
165
    lmat.shininess = 1.0f;
166
    lmat.transparency = 0.0f;
167

168
    App::Material vmat;
169
    vmat.ambientColor.set(0.2f,0.2f,0.2f);
170
    vmat.diffuseColor.set(vr,vg,vb);
171
    vmat.specularColor.set(0.0f,0.0f,0.0f);
172
    vmat.emissiveColor.set(0.0f,0.0f,0.0f);
173
    vmat.shininess = 1.0f;
174
    vmat.transparency = 0.0f;
175

176
    ADD_PROPERTY_TYPE(LineMaterial,(lmat), osgroup, App::Prop_None, "Object line material.");
177
    ADD_PROPERTY_TYPE(PointMaterial,(vmat), osgroup, App::Prop_None, "Object point material.");
178
    ADD_PROPERTY_TYPE(LineColor, (lmat.diffuseColor), osgroup, App::Prop_None, "Set object line color.");
179
    ADD_PROPERTY_TYPE(PointColor, (vmat.diffuseColor), osgroup, App::Prop_None, "Set object point color");
180
    ADD_PROPERTY_TYPE(PointColorArray, (PointColor.getValue()), osgroup, App::Prop_None, "Object point color array.");
181
    ADD_PROPERTY_TYPE(LineColorArray,(LineColor.getValue()), osgroup, App::Prop_None, "Object line color array.");
182
    ADD_PROPERTY_TYPE(LineWidth,(lwidth), osgroup, App::Prop_None, "Set object line width.");
183
    LineWidth.setConstraints(&sizeRange);
184
    PointSize.setConstraints(&sizeRange);
185
    ADD_PROPERTY_TYPE(PointSize,(psize), osgroup, App::Prop_None, "Set object point size.");
186
    ADD_PROPERTY_TYPE(Deviation,(0.5f), osgroup, App::Prop_None,
187
            "Sets the accuracy of the polygonal representation of the model\n"
188
            "in the 3D view (tessellation). Lower values indicate better quality.\n"
189
            "The value is in percent of object's size.");
190
    Deviation.setConstraints(&tessRange);
191
    ADD_PROPERTY_TYPE(AngularDeflection,(28.5), osgroup, App::Prop_None,
192
            "Specify how finely to generate the mesh for rendering on screen or when exporting.\n"
193
            "The default value is 28.5 degrees, or 0.5 radians. The smaller the value\n"
194
            "the smoother the appearance in the 3D view, and the finer the mesh that will be exported.");
195
    AngularDeflection.setConstraints(&angDeflectionRange);
196
    ADD_PROPERTY_TYPE(Lighting,(twoside), osgroup, App::Prop_None, "Set object lighting.");
197
    Lighting.setEnums(LightingEnums);
198
    ADD_PROPERTY_TYPE(DrawStyle,((long int)0), osgroup, App::Prop_None, "Defines the style of the edges in the 3D view.");
199
    DrawStyle.setEnums(DrawStyleEnums);
200

201
    coords = new SoCoordinate3();
202
    coords->ref();
203
    faceset = new SoBrepFaceSet();
204
    faceset->ref();
205
    norm = new SoNormal;
206
    norm->ref();
207
    normb = new SoNormalBinding;
208
    normb->value = SoNormalBinding::PER_VERTEX_INDEXED;
209
    normb->ref();
210
    lineset = new SoBrepEdgeSet();
211
    lineset->ref();
212
    nodeset = new SoBrepPointSet();
213
    nodeset->ref();
214

215
    pcFaceBind = new SoMaterialBinding();
216
    pcFaceBind->ref();
217

218
    pcLineBind = new SoMaterialBinding();
219
    pcLineBind->ref();
220
    pcLineMaterial = new SoMaterial;
221
    pcLineMaterial->ref();
222
    LineMaterial.touch();
223

224
    pcPointBind = new SoMaterialBinding();
225
    pcPointBind->ref();
226
    pcPointMaterial = new SoMaterial;
227
    pcPointMaterial->ref();
228
    PointMaterial.touch();
229

230
    pcLineStyle = new SoDrawStyle();
231
    pcLineStyle->ref();
232
    pcLineStyle->style = SoDrawStyle::LINES;
233
    pcLineStyle->lineWidth = LineWidth.getValue();
234

235
    pcPointStyle = new SoDrawStyle();
236
    pcPointStyle->ref();
237
    pcPointStyle->style = SoDrawStyle::POINTS;
238
    pcPointStyle->pointSize = PointSize.getValue();
239

240
    pShapeHints = new SoShapeHints;
241
    pShapeHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
242
    pShapeHints->ref();
243
    Lighting.touch();
244
    DrawStyle.touch();
245

246
    sPixmap = "Part_3D_object";
247
    loadParameter();
248
}
249

250
ViewProviderPartExt::~ViewProviderPartExt()
251
{
252
    pcFaceBind->unref();
253
    pcLineBind->unref();
254
    pcPointBind->unref();
255
    pcLineMaterial->unref();
256
    pcPointMaterial->unref();
257
    pcLineStyle->unref();
258
    pcPointStyle->unref();
259
    pShapeHints->unref();
260
    coords->unref();
261
    faceset->unref();
262
    norm->unref();
263
    normb->unref();
264
    lineset->unref();
265
    nodeset->unref();
266
}
267

268
PyObject* ViewProviderPartExt::getPyObject()
269
{
270
    if (!pyViewObject) {
271
        pyViewObject = new ViewProviderPartExtPy(this);
272
    }
273
    pyViewObject->IncRef();
274
    return pyViewObject;
275
}
276

277
void ViewProviderPartExt::onChanged(const App::Property* prop)
278
{
279
    // The lower limit of the deviation has been increased to avoid
280
    // to freeze the GUI
281
    // https://forum.freecad.org/viewtopic.php?f=3&t=24912&p=195613
282
    if (prop == &Deviation) {
283
        if(isUpdateForced()||Visibility.getValue())
284
            updateVisual();
285
        else
286
            VisualTouched = true;
287
    }
288
    if (prop == &AngularDeflection) {
289
        if(isUpdateForced()||Visibility.getValue())
290
            updateVisual();
291
        else
292
            VisualTouched = true;
293
    }
294
    if (prop == &LineWidth) {
295
        pcLineStyle->lineWidth = LineWidth.getValue();
296
    }
297
    else if (prop == &PointSize) {
298
        pcPointStyle->pointSize = PointSize.getValue();
299
    }
300
    else if (prop == &LineColor) {
301
        const App::Color& c = LineColor.getValue();
302
        pcLineMaterial->diffuseColor.setValue(c.r,c.g,c.b);
303
        if (c != LineMaterial.getValue().diffuseColor)
304
            LineMaterial.setDiffuseColor(c);
305
        LineColorArray.setValue(LineColor.getValue());
306
    }
307
    else if (prop == &PointColor) {
308
        const App::Color& c = PointColor.getValue();
309
        pcPointMaterial->diffuseColor.setValue(c.r,c.g,c.b);
310
        if (c != PointMaterial.getValue().diffuseColor)
311
            PointMaterial.setDiffuseColor(c);
312
        PointColorArray.setValue(PointColor.getValue());
313
    }
314
    else if (prop == &LineMaterial) {
315
        const App::Material& Mat = LineMaterial.getValue();
316
        if (LineColor.getValue() != Mat.diffuseColor)
317
            LineColor.setValue(Mat.diffuseColor);
318
        pcLineMaterial->ambientColor.setValue(Mat.ambientColor.r,Mat.ambientColor.g,Mat.ambientColor.b);
319
        pcLineMaterial->diffuseColor.setValue(Mat.diffuseColor.r,Mat.diffuseColor.g,Mat.diffuseColor.b);
320
        pcLineMaterial->specularColor.setValue(Mat.specularColor.r,Mat.specularColor.g,Mat.specularColor.b);
321
        pcLineMaterial->emissiveColor.setValue(Mat.emissiveColor.r,Mat.emissiveColor.g,Mat.emissiveColor.b);
322
        pcLineMaterial->shininess.setValue(Mat.shininess);
323
        pcLineMaterial->transparency.setValue(Mat.transparency);
324
    }
325
    else if (prop == &PointMaterial) {
326
        const App::Material& Mat = PointMaterial.getValue();
327
        if (PointColor.getValue() != Mat.diffuseColor)
328
            PointColor.setValue(Mat.diffuseColor);
329
        pcPointMaterial->ambientColor.setValue(Mat.ambientColor.r,Mat.ambientColor.g,Mat.ambientColor.b);
330
        pcPointMaterial->diffuseColor.setValue(Mat.diffuseColor.r,Mat.diffuseColor.g,Mat.diffuseColor.b);
331
        pcPointMaterial->specularColor.setValue(Mat.specularColor.r,Mat.specularColor.g,Mat.specularColor.b);
332
        pcPointMaterial->emissiveColor.setValue(Mat.emissiveColor.r,Mat.emissiveColor.g,Mat.emissiveColor.b);
333
        pcPointMaterial->shininess.setValue(Mat.shininess);
334
        pcPointMaterial->transparency.setValue(Mat.transparency);
335
    }
336
    else if (prop == &PointColorArray) {
337
        setHighlightedPoints(PointColorArray.getValues());
338
    }
339
    else if (prop == &LineColorArray) {
340
        setHighlightedEdges(LineColorArray.getValues());
341
    }
342
    else if (prop == &_diffuseColor) {
343
        // Used to load the old DiffuseColor values asynchronously
344
        ShapeAppearance.setDiffuseColors(_diffuseColor.getValues());
345
        ShapeAppearance.setTransparency(Transparency.getValue() / 100.0F);
346
    }
347
    else if (prop == &ShapeAppearance) {
348
        setHighlightedFaces(ShapeAppearance);
349
        ViewProviderGeometryObject::onChanged(prop);
350
    }
351
    else if (prop == &Transparency) {
352
        const App::Material& Mat = ShapeAppearance[0];
353
        long value = toPercent(Mat.transparency);
354
        if (value != Transparency.getValue()) {
355
            float trans = fromPercent(Transparency.getValue());
356
            ShapeAppearance.setTransparency(trans);
357
        }
358
    }
359
    else if (prop == &Lighting) {
360
        if (Lighting.getValue() == 0)
361
            pShapeHints->vertexOrdering = SoShapeHints::UNKNOWN_ORDERING;
362
        else
363
            pShapeHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
364
    }
365
    else if (prop == &DrawStyle) {
366
        if (DrawStyle.getValue() == 0)
367
            pcLineStyle->linePattern = 0xffff;
368
        else if (DrawStyle.getValue() == 1)
369
            pcLineStyle->linePattern = 0xf00f;
370
        else if (DrawStyle.getValue() == 2)
371
            pcLineStyle->linePattern = 0x0f0f;
372
        else
373
            pcLineStyle->linePattern = 0xff88;
374
    }
375
    else {
376
        // if the object was invisible and has been changed, recreate the visual
377
        if (prop == &Visibility && (isUpdateForced() || Visibility.getValue()) && VisualTouched) {
378
            updateVisual();
379
            // updateVisual() may not be triggered by any change (e.g.
380
            // triggered by an external object through forceUpdate()). And
381
            // since ShapeAppearance is not changed here either, do not falsely set
382
            // the document modified status
383
            Base::ObjectStatusLocker<App::Property::Status,App::Property> guard(
384
                    App::Property::NoModify, &ShapeAppearance);
385
            // The material has to be checked again (#0001736)
386
            onChanged(&ShapeAppearance);
387
        }
388
    }
389

390
    ViewProviderGeometryObject::onChanged(prop);
391
}
392

393
bool ViewProviderPartExt::allowOverride(const App::DocumentObject &) const {
394
    // Many derived view providers still uses static_cast to get object
395
    // pointer, so check for exact type here.
396
    return is<ViewProviderPartExt>();
397
}
398

399
void ViewProviderPartExt::attach(App::DocumentObject *pcFeat)
400
{
401
    // call parent attach method
402
    ViewProviderGeometryObject::attach(pcFeat);
403

404
    // Workaround for #0000433, i.e. use SoSeparator instead of SoGroup
405
    auto* pcNormalRoot = new SoSeparator();
406
    auto* pcFlatRoot = new SoSeparator();
407
    auto* pcWireframeRoot = new SoSeparator();
408
    auto* pcPointsRoot = new SoSeparator();
409
    auto* wireframe = new SoSeparator();
410

411
    // Must turn off all intermediate render caching, and let pcRoot to handle
412
    // cache without interference.
413
    pcNormalRoot->renderCaching =
414
        pcFlatRoot->renderCaching =
415
        pcWireframeRoot->renderCaching =
416
        pcPointsRoot->renderCaching =
417
        wireframe->renderCaching = SoSeparator::OFF;
418

419
    pcNormalRoot->boundingBoxCaching =
420
        pcFlatRoot->boundingBoxCaching =
421
        pcWireframeRoot->boundingBoxCaching =
422
        pcPointsRoot->boundingBoxCaching =
423
        wireframe->boundingBoxCaching = SoSeparator::OFF;
424

425
    // Avoid any Z-buffer artifacts, so that the lines always appear on top of the faces
426
    // The correct order is Edges, Polygon offset, Faces.
427
    SoPolygonOffset* offset = new SoPolygonOffset();
428

429
    // wireframe node
430
    wireframe->setName("Edge");
431
    wireframe->addChild(pcLineBind);
432
    wireframe->addChild(pcLineMaterial);
433
    wireframe->addChild(pcLineStyle);
434
    wireframe->addChild(lineset);
435

436
    // normal viewing with edges and points
437
    pcNormalRoot->addChild(pcPointsRoot);
438
    pcNormalRoot->addChild(wireframe);
439
    pcNormalRoot->addChild(offset);
440
    pcNormalRoot->addChild(pcFlatRoot);
441

442
    // just faces with no edges or points
443
    pcFlatRoot->addChild(pShapeHints);
444
    pcFlatRoot->addChild(pcFaceBind);
445
    pcFlatRoot->addChild(texture.getAppearance());
446
    texture.setup(pcShapeMaterial);
447
    SoDrawStyle* pcFaceStyle = new SoDrawStyle();
448
    pcFaceStyle->style = SoDrawStyle::FILLED;
449
    pcFlatRoot->addChild(pcFaceStyle);
450
    pcFlatRoot->addChild(norm);
451
    pcFlatRoot->addChild(normb);
452
    pcFlatRoot->addChild(faceset);
453

454
    // edges and points
455
    pcWireframeRoot->addChild(wireframe);
456
    pcWireframeRoot->addChild(pcPointsRoot);
457

458
    // normal viewing with edges and points
459
    pcPointsRoot->addChild(pcPointBind);
460
    pcPointsRoot->addChild(pcPointMaterial);
461
    pcPointsRoot->addChild(pcPointStyle);
462
    pcPointsRoot->addChild(nodeset);
463

464
    // Move 'coords' before the switch
465
    pcRoot->insertChild(coords,pcRoot->findChild(pcModeSwitch));
466

467
    // putting all together with the switch
468
    addDisplayMaskMode(pcNormalRoot, "Flat Lines");
469
    addDisplayMaskMode(pcFlatRoot, "Shaded");
470
    addDisplayMaskMode(pcWireframeRoot, "Wireframe");
471
    addDisplayMaskMode(pcPointsRoot, "Point");
472
}
473

474
void ViewProviderPartExt::setDisplayMode(const char* ModeName)
475
{
476
    if ( strcmp("Flat Lines",ModeName)==0 )
477
        setDisplayMaskMode("Flat Lines");
478
    else if ( strcmp("Shaded",ModeName)==0 )
479
        setDisplayMaskMode("Shaded");
480
    else if ( strcmp("Wireframe",ModeName)==0 )
481
        setDisplayMaskMode("Wireframe");
482
    else if ( strcmp("Points",ModeName)==0 )
483
        setDisplayMaskMode("Point");
484

485
    ViewProviderGeometryObject::setDisplayMode( ModeName );
486
}
487

488
std::vector<std::string> ViewProviderPartExt::getDisplayModes() const
489
{
490
    // get the modes of the father
491
    std::vector<std::string> StrList = ViewProviderGeometryObject::getDisplayModes();
492

493
    // add your own modes
494
    StrList.emplace_back("Flat Lines");
495
    StrList.emplace_back("Shaded");
496
    StrList.emplace_back("Wireframe");
497
    StrList.emplace_back("Points");
498

499
    return StrList;
500
}
501

502
std::string ViewProviderPartExt::getElement(const SoDetail* detail) const
503
{
504
    std::stringstream str;
505
    if (detail) {
506
        if (detail->getTypeId() == SoFaceDetail::getClassTypeId()) {
507
            const SoFaceDetail* face_detail = static_cast<const SoFaceDetail*>(detail);
508
            int face = face_detail->getPartIndex() + 1;
509
            str << "Face" << face;
510
        }
511
        else if (detail->getTypeId() == SoLineDetail::getClassTypeId()) {
512
            const SoLineDetail* line_detail = static_cast<const SoLineDetail*>(detail);
513
            int edge = line_detail->getLineIndex() + 1;
514
            str << "Edge" << edge;
515
        }
516
        else if (detail->getTypeId() == SoPointDetail::getClassTypeId()) {
517
            const SoPointDetail* point_detail = static_cast<const SoPointDetail*>(detail);
518
            int vertex = point_detail->getCoordinateIndex() - nodeset->startIndex.getValue() + 1;
519
            str << "Vertex" << vertex;
520
        }
521
    }
522

523
    return str.str();
524
}
525

526
SoDetail* ViewProviderPartExt::getDetail(const char* subelement) const
527
{
528
    auto type = Part::TopoShape::getElementTypeAndIndex(subelement);
529
    std::string element = type.first;
530
    int index = type.second;
531

532
    if (element == "Face") {
533
        SoFaceDetail* detail = new SoFaceDetail();
534
        detail->setPartIndex(index - 1);
535
        return detail;
536
    }
537
    else if (element == "Edge") {
538
        SoLineDetail* detail = new SoLineDetail();
539
        detail->setLineIndex(index - 1);
540
        return detail;
541
    }
542
    else if (element == "Vertex") {
543
        SoPointDetail* detail = new SoPointDetail();
544
        static_cast<SoPointDetail*>(detail)->setCoordinateIndex(index + nodeset->startIndex.getValue() - 1);
545
        return detail;
546
    }
547

548
    return nullptr;
549
}
550

551
std::vector<Base::Vector3d> ViewProviderPartExt::getModelPoints(const SoPickedPoint* pp) const
552
{
553
    try {
554
        std::vector<Base::Vector3d> pts;
555
        std::string element = this->getElement(pp->getDetail());
556
        const auto &shape = Part::Feature::getTopoShape(getObject());
557

558
        TopoDS_Shape subShape = shape.getSubShape(element.c_str());
559

560
        // get the point of the vertex directly
561
        if (subShape.ShapeType() == TopAbs_VERTEX) {
562
            const TopoDS_Vertex& v = TopoDS::Vertex(subShape);
563
            gp_Pnt p = BRep_Tool::Pnt(v);
564
            pts.emplace_back(p.X(),p.Y(),p.Z());
565
        }
566
        // get the nearest point on the edge
567
        else if (subShape.ShapeType() == TopAbs_EDGE) {
568
            const SbVec3f& vec = pp->getPoint();
569
            BRepBuilderAPI_MakeVertex mkVert(gp_Pnt(vec[0],vec[1],vec[2]));
570
            BRepExtrema_DistShapeShape distSS(subShape, mkVert.Vertex(), 0.1);
571
            if (distSS.NbSolution() > 0) {
572
                gp_Pnt p = distSS.PointOnShape1(1);
573
                pts.emplace_back(p.X(),p.Y(),p.Z());
574
            }
575
        }
576
        // get the nearest point on the face
577
        else if (subShape.ShapeType() == TopAbs_FACE) {
578
            const SbVec3f& vec = pp->getPoint();
579
            BRepBuilderAPI_MakeVertex mkVert(gp_Pnt(vec[0],vec[1],vec[2]));
580
            BRepExtrema_DistShapeShape distSS(subShape, mkVert.Vertex(), 0.1);
581
            if (distSS.NbSolution() > 0) {
582
                gp_Pnt p = distSS.PointOnShape1(1);
583
                pts.emplace_back(p.X(),p.Y(),p.Z());
584
            }
585
        }
586

587
        return pts;
588
    }
589
    catch (...) {
590
    }
591

592
    // if something went wrong returns an empty array
593
    return {};
594
}
595

596
std::vector<Base::Vector3d> ViewProviderPartExt::getSelectionShape(const char* /*Element*/) const
597
{
598
    return {};
599
}
600

601
void ViewProviderPartExt::setHighlightedFaces(const std::vector<App::Material>& materials)
602
{
603
    if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange))
604
        getObject()->touch(true);
605

606
    Gui::SoUpdateVBOAction action;
607
    action.apply(this->faceset);
608

609
    int size = static_cast<int>(materials.size());
610
    if (size > 1 && size == this->faceset->partIndex.getNum()) {
611
        pcFaceBind->value = SoMaterialBinding::PER_PART;
612
        texture.activateMaterial();
613

614
        pcShapeMaterial->diffuseColor.setNum(size);
615
        pcShapeMaterial->ambientColor.setNum(size);
616
        pcShapeMaterial->specularColor.setNum(size);
617
        pcShapeMaterial->emissiveColor.setNum(size);
618
        pcShapeMaterial->shininess.setNum(size);
619
        pcShapeMaterial->transparency.setNum(size);
620

621
        SbColor* dc = pcShapeMaterial->diffuseColor.startEditing();
622
        SbColor* ac = pcShapeMaterial->ambientColor.startEditing();
623
        SbColor* sc = pcShapeMaterial->specularColor.startEditing();
624
        SbColor* ec = pcShapeMaterial->emissiveColor.startEditing();
625
        float* sh = pcShapeMaterial->shininess.startEditing();
626
        float* tr = pcShapeMaterial->transparency.startEditing();
627

628
        for (int i = 0; i < size; i++) {
629
            dc[i].setValue(materials[i].diffuseColor.r, materials[i].diffuseColor.g, materials[i].diffuseColor.b);
630
            ac[i].setValue(materials[i].ambientColor.r, materials[i].ambientColor.g, materials[i].ambientColor.b);
631
            sc[i].setValue(materials[i].specularColor.r, materials[i].specularColor.g, materials[i].specularColor.b);
632
            ec[i].setValue(materials[i].emissiveColor.r, materials[i].emissiveColor.g, materials[i].emissiveColor.b);
633
            sh[i] = materials[i].shininess;
634
            tr[i] = materials[i].transparency;
635
        }
636

637
        pcShapeMaterial->diffuseColor.finishEditing();
638
        pcShapeMaterial->ambientColor.finishEditing();
639
        pcShapeMaterial->specularColor.finishEditing();
640
        pcShapeMaterial->emissiveColor.finishEditing();
641
        pcShapeMaterial->shininess.finishEditing();
642
        pcShapeMaterial->transparency.finishEditing();
643
    }
644
    else if (size == 1) {
645
        pcFaceBind->value = SoMaterialBinding::OVERALL;
646
        setCoinAppearance(materials[0]);
647
    }
648
}
649

650
void ViewProviderPartExt::setHighlightedFaces(const App::PropertyMaterialList& appearance)
651
{
652
    setHighlightedFaces(appearance.getValues());
653
}
654

655
std::map<std::string,App::Color> ViewProviderPartExt::getElementColors(const char *element) const {
656
    std::map<std::string,App::Color> ret;
657

658
    if(!element || !element[0]) {
659
        auto color = ShapeAppearance.getDiffuseColor();
660
        color.a = Transparency.getValue()/100.0f;
661
        ret["Face"] = color;
662
        ret["Edge"] = LineColor.getValue();
663
        ret["Vertex"] = PointColor.getValue();
664
        return ret;
665
    }
666

667
    if(boost::starts_with(element,"Face")) {
668
        auto size = ShapeAppearance.getSize();
669
        if(element[4]=='*') {
670
            auto color = ShapeAppearance.getDiffuseColor();
671
            color.a = Transparency.getValue()/100.0f;
672
            bool singleColor = true;
673
            for(int i=0;i<size;++i) {
674
                if (ShapeAppearance.getDiffuseColor(i) != color) {
675
                    ret[std::string(element, 4) + std::to_string(i + 1)] =
676
                        ShapeAppearance.getDiffuseColor(i);
677
                }
678
                singleColor = singleColor
679
                    && ShapeAppearance.getDiffuseColor(0) == ShapeAppearance.getDiffuseColor(i);
680
            }
681
            if(size && singleColor) {
682
                color = ShapeAppearance.getDiffuseColor(0);
683
                color.a = Transparency.getValue()/100.0f;
684
                ret.clear();
685
            }
686
            ret["Face"] = color;
687
        }else{
688
            int idx = atoi(element+4);
689
            if(idx>0 && idx<=size)
690
                ret[element] = ShapeAppearance.getDiffuseColor(idx - 1);
691
            else
692
                ret[element] = ShapeAppearance.getDiffuseColor();
693
            if(size==1)
694
                ret[element].a = Transparency.getValue()/100.0f;
695
        }
696
    } else if (boost::starts_with(element,"Edge")) {
697
        auto size = LineColorArray.getSize();
698
        if(element[4]=='*') {
699
            auto color = LineColor.getValue();
700
            bool singleColor = true;
701
            for(int i=0;i<size;++i) {
702
                if(LineColorArray[i]!=color)
703
                    ret[std::string(element,4)+std::to_string(i+1)] = LineColorArray[i];
704
                singleColor = singleColor && LineColorArray[0]==LineColorArray[i];
705
            }
706
            if(singleColor && size) {
707
                color = LineColorArray[0];
708
                ret.clear();
709
            }
710
            ret["Edge"] = color;
711
        }else{
712
            int idx = atoi(element+4);
713
            if(idx>0 && idx<=size)
714
                ret[element] = LineColorArray[idx-1];
715
            else
716
                ret[element] = LineColor.getValue();
717
        }
718
    } else if (boost::starts_with(element,"Vertex")) {
719
        auto size = PointColorArray.getSize();
720
        if(element[5]=='*') {
721
            auto color = PointColor.getValue();
722
            bool singleColor = true;
723
            for(int i=0;i<size;++i) {
724
                if(PointColorArray[i]!=color)
725
                    ret[std::string(element,5)+std::to_string(i+1)] = PointColorArray[i];
726
                singleColor = singleColor && PointColorArray[0]==PointColorArray[i];
727
            }
728
            if(singleColor && size) {
729
                color = PointColorArray[0];
730
                ret.clear();
731
            }
732
            ret["Vertex"] = color;
733
        }else{
734
            int idx = atoi(element+5);
735
            if(idx>0 && idx<=size)
736
                ret[element] = PointColorArray[idx-1];
737
            else
738
                ret[element] = PointColor.getValue();
739
        }
740
    }
741
    return ret;
742
}
743

744
void ViewProviderPartExt::unsetHighlightedFaces()
745
{
746
    ShapeAppearance.touch();
747
    Transparency.touch();
748
}
749

750
void ViewProviderPartExt::setHighlightedEdges(const std::vector<App::Color>& colors)
751
{
752
    if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange))
753
        getObject()->touch(true);
754
    int size = static_cast<int>(colors.size());
755
    if (size > 1) {
756
        // Although indexed lineset is used the material binding must be PER_FACE!
757
        pcLineBind->value = SoMaterialBinding::PER_FACE;
758
        const int32_t* cindices = this->lineset->coordIndex.getValues(0);
759
        int numindices = this->lineset->coordIndex.getNum();
760
        pcLineMaterial->diffuseColor.setNum(size);
761
        SbColor* ca = pcLineMaterial->diffuseColor.startEditing();
762
        int linecount = 0;
763

764
        for (int i = 0; i < numindices; ++i) {
765
            if (cindices[i] < 0) {
766
                ca[linecount].setValue(colors[linecount].r, colors[linecount].g, colors[linecount].b);
767
                linecount++;
768
                if (linecount >= size)
769
                    break;
770
            }
771
        }
772

773
        pcLineMaterial->diffuseColor.finishEditing();
774
    }
775
    else if (size == 1) {
776
        pcLineBind->value = SoMaterialBinding::OVERALL;
777
        pcLineMaterial->diffuseColor.setValue(colors[0].r, colors[0].g, colors[0].b);
778
    }
779
}
780

781
void ViewProviderPartExt::unsetHighlightedEdges()
782
{
783
    pcLineBind->value = SoMaterialBinding::OVERALL;
784
    LineMaterial.touch();
785
}
786

787
void ViewProviderPartExt::setHighlightedPoints(const std::vector<App::Color>& colors)
788
{
789
    if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange))
790
        getObject()->touch(true);
791
    int size = static_cast<int>(colors.size());
792
    if (size > 1) {
793
        pcPointBind->value = SoMaterialBinding::PER_VERTEX;
794
        pcPointMaterial->diffuseColor.setNum(size);
795
        SbColor* ca = pcPointMaterial->diffuseColor.startEditing();
796
        for (int i = 0; i < size; ++i)
797
            ca[i].setValue(colors[i].r, colors[i].g, colors[i].b);
798
        pcPointMaterial->diffuseColor.finishEditing();
799
    }
800
    else if (size == 1) {
801
        pcPointBind->value = SoMaterialBinding::OVERALL;
802
        pcPointMaterial->diffuseColor.setValue(colors[0].r, colors[0].g, colors[0].b);
803
    }
804
}
805

806
void ViewProviderPartExt::unsetHighlightedPoints()
807
{
808
    PointColorArray.touch();
809
}
810

811
bool ViewProviderPartExt::loadParameter()
812
{
813
    bool changed = false;
814
    ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
815
        ("User parameter:BaseApp/Preferences/Mod/Part");
816
    float deviation = hGrp->GetFloat("MeshDeviation",0.2);
817
    float angularDeflection = hGrp->GetFloat("MeshAngularDeflection",28.65);
818
    NormalsFromUV = hGrp->GetBool("NormalsFromUVNodes", NormalsFromUV);
819

820
    if (Deviation.getValue() != deviation) {
821
        Deviation.setValue(deviation);
822
        changed = true;
823
    }
824
    if (AngularDeflection.getValue() != angularDeflection ) {
825
        AngularDeflection.setValue(angularDeflection);
826
    }
827

828
    return changed;
829
}
830

831
void ViewProviderPartExt::reload()
832
{
833
    if (loadParameter())
834
        updateVisual();
835
}
836

837
void ViewProviderPartExt::updateData(const App::Property* prop)
838
{
839
    const char *propName = prop->getName();
840
    if (propName && (strcmp(propName, "Shape") == 0 || strstr(propName, "Touched"))) {
841
        // calculate the visual only if visible
842
        if (isUpdateForced() || Visibility.getValue())
843
            updateVisual();
844
        else
845
            VisualTouched = true;
846

847
        if (!VisualTouched) {
848
            if (this->faceset->partIndex.getNum() >
849
                this->pcShapeMaterial->diffuseColor.getNum()) {
850
                this->pcFaceBind->value = SoMaterialBinding::OVERALL;
851
            }
852
        }
853
    }
854
    Gui::ViewProviderGeometryObject::updateData(prop);
855
}
856

857
void ViewProviderPartExt::startRestoring()
858
{
859
    Gui::ViewProviderGeometryObject::startRestoring();
860
}
861

862
void ViewProviderPartExt::finishRestoring()
863
{
864
    // The ShapeAppearance property is restored after DiffuseColor
865
    // and currently sets a single color.
866
    // In case DiffuseColor has defined multiple colors they will
867
    // be passed to the scene graph now.
868
    if (_diffuseColor.getSize() > 1) {
869
        onChanged(&_diffuseColor);
870
    }
871
    Gui::ViewProviderGeometryObject::finishRestoring();
872
}
873

874
void ViewProviderPartExt::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
875
{
876
    QIcon iconObject = mergeGreyableOverlayIcons(Gui::BitmapFactory().pixmap("Part_ColorFace.svg"));
877
    Gui::ViewProviderGeometryObject::setupContextMenu(menu, receiver, member);
878
    QAction* act = menu->addAction(iconObject, QObject::tr("Set appearance per face..."), receiver, member);
879
    act->setData(QVariant((int)ViewProvider::Color));
880
}
881

882
bool ViewProviderPartExt::changeFaceAppearances()
883
{
884
    Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
885
    if (dlg) {
886
        Gui::Control().showDialog(dlg);
887
        return false;
888
    }
889

890
    Gui::Selection().clearSelection();
891
    Gui::Control().showDialog(new TaskFaceAppearances(this));
892
    return true;
893
}
894

895
bool ViewProviderPartExt::setEdit(int ModNum)
896
{
897
    if (ModNum == ViewProvider::Color) {
898
        // When double-clicking on the item for this pad the
899
        // object unsets and sets its edit mode without closing
900
        // the task panel
901
        return changeFaceAppearances();
902
    }
903
    else {
904
        return Gui::ViewProviderGeometryObject::setEdit(ModNum);
905
    }
906
}
907

908
void ViewProviderPartExt::unsetEdit(int ModNum)
909
{
910
    if (ModNum == ViewProvider::Color) {
911
        // Do nothing here
912
    }
913
    else {
914
        Gui::ViewProviderGeometryObject::unsetEdit(ModNum);
915
    }
916
}
917

918
void ViewProviderPartExt::updateVisual()
919
{
920
    Gui::SoUpdateVBOAction action;
921
    action.apply(this->faceset);
922

923
    // Clear selection
924
    Gui::SoSelectionElementAction saction(Gui::SoSelectionElementAction::None);
925
    saction.apply(this->faceset);
926
    saction.apply(this->lineset);
927
    saction.apply(this->nodeset);
928

929
    // Clear highlighting
930
    Gui::SoHighlightElementAction haction;
931
    haction.apply(this->faceset);
932
    haction.apply(this->lineset);
933
    haction.apply(this->nodeset);
934

935
    TopoDS_Shape cShape = Part::Feature::getShape(getObject());
936
    if (cShape.IsNull()) {
937
        coords  ->point      .setNum(0);
938
        norm    ->vector     .setNum(0);
939
        faceset ->coordIndex .setNum(0);
940
        faceset ->partIndex  .setNum(0);
941
        lineset ->coordIndex .setNum(0);
942
        nodeset ->startIndex .setValue(0);
943
        VisualTouched = false;
944
        return;
945
    }
946

947
    // time measurement and book keeping
948
    Base::TimeElapsed start_time;
949
    int numTriangles=0,numNodes=0,numNorms=0,numFaces=0,numEdges=0,numLines=0;
950
    std::set<int> faceEdges;
951

952
    try {
953
        // calculating the deflection value
954
        Bnd_Box bounds;
955
        BRepBndLib::Add(cShape, bounds);
956
        bounds.SetGap(0.0);
957
        Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
958
        bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
959
        Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
960

961
        // Since OCCT 7.6 a value of equal 0 is not allowed any more, this can happen if a single vertex
962
        // should be displayed.
963
        if (deflection < gp::Resolution()) {
964
            deflection = Precision::Confusion();
965
        }
966

967
        // For very big objects the computed deflection can become very high and thus leads to a useless
968
        // tessellation. To avoid this the upper limit is set to 20.0
969
        // See also forum: https://forum.freecad.org/viewtopic.php?t=77521
970
        deflection = std::min(deflection, 20.0);
971

972
        // create or use the mesh on the data structure
973
        Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI;
974

975
#if OCC_VERSION_HEX >= 0x070500
976
        IMeshTools_Parameters meshParams;
977
        meshParams.Deflection = deflection;
978
        meshParams.Relative = Standard_False;
979
        meshParams.Angle = AngDeflectionRads;
980
        meshParams.InParallel = Standard_True;
981
        meshParams.AllowQualityDecrease = Standard_True;
982

983
        BRepMesh_IncrementalMesh(cShape, meshParams);
984
#else
985
        BRepMesh_IncrementalMesh(cShape, deflection, Standard_False, AngDeflectionRads, Standard_True);
986
#endif
987

988
        // We must reset the location here because the transformation data
989
        // are set in the placement property
990
        TopLoc_Location aLoc;
991
        cShape.Location(aLoc);
992

993
        // count triangles and nodes in the mesh
994
        TopTools_IndexedMapOfShape faceMap;
995
        TopExp::MapShapes(cShape, TopAbs_FACE, faceMap);
996
        for (int i=1; i <= faceMap.Extent(); i++) {
997
            Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(faceMap(i)), aLoc);
998
            if (mesh.IsNull()) {
999
                mesh = Part::Tools::triangulationOfFace(TopoDS::Face(faceMap(i)));
1000
            }
1001
            // Note: we must also count empty faces
1002
            if (!mesh.IsNull()) {
1003
                numTriangles += mesh->NbTriangles();
1004
                numNodes     += mesh->NbNodes();
1005
                numNorms     += mesh->NbNodes();
1006
            }
1007

1008
            TopExp_Explorer xp;
1009
            for (xp.Init(faceMap(i),TopAbs_EDGE);xp.More();xp.Next()) {
1010
                faceEdges.insert(Part::ShapeMapHasher{}(xp.Current()));
1011
            }
1012
            numFaces++;
1013
        }
1014

1015
        // get an indexed map of edges
1016
        TopTools_IndexedMapOfShape edgeMap;
1017
        TopExp::MapShapes(cShape, TopAbs_EDGE, edgeMap);
1018

1019
         // key is the edge number, value the coord indexes. This is needed to keep the same order as the edges.
1020
        std::map<int, std::vector<int32_t> > lineSetMap;
1021
        std::set<int>          edgeIdxSet;
1022
        std::vector<int32_t>   edgeVector;
1023

1024
        // count and index the edges
1025
        for (int i=1; i <= edgeMap.Extent(); i++) {
1026
            edgeIdxSet.insert(i);
1027
            numEdges++;
1028

1029
            const TopoDS_Edge& aEdge = TopoDS::Edge(edgeMap(i));
1030
            TopLoc_Location aLoc;
1031

1032
            // handling of the free edge that are not associated to a face
1033
            // Note: The assumption that if for an edge BRep_Tool::Polygon3D
1034
            // returns a valid object is wrong. This e.g. happens for ruled
1035
            // surfaces which gets created by two edges or wires.
1036
            // So, we have to store the hashes of the edges associated to a face.
1037
            // If the hash of a given edge is not in this list we know it's really
1038
            // a free edge.
1039
            int hash = Part::ShapeMapHasher{}(aEdge);
1040
            if (faceEdges.find(hash) == faceEdges.end()) {
1041
                Handle(Poly_Polygon3D) aPoly = Part::Tools::polygonOfEdge(aEdge, aLoc);
1042
                if (!aPoly.IsNull()) {
1043
                    int nbNodesInEdge = aPoly->NbNodes();
1044
                    numNodes += nbNodesInEdge;
1045
                }
1046
            }
1047
        }
1048

1049
        // handling of the vertices
1050
        TopTools_IndexedMapOfShape vertexMap;
1051
        TopExp::MapShapes(cShape, TopAbs_VERTEX, vertexMap);
1052
        numNodes += vertexMap.Extent();
1053

1054
        // create memory for the nodes and indexes
1055
        coords  ->point      .setNum(numNodes);
1056
        norm    ->vector     .setNum(numNorms);
1057
        faceset ->coordIndex .setNum(numTriangles*4);
1058
        faceset ->partIndex  .setNum(numFaces);
1059
        // get the raw memory for fast fill up
1060
        SbVec3f* verts = coords  ->point       .startEditing();
1061
        SbVec3f* norms = norm    ->vector      .startEditing();
1062
        int32_t* index = faceset ->coordIndex  .startEditing();
1063
        int32_t* parts = faceset ->partIndex   .startEditing();
1064

1065
        // preset the normal vector with null vector
1066
        for (int i=0;i < numNorms;i++)
1067
            norms[i]= SbVec3f(0.0,0.0,0.0);
1068

1069
        int ii = 0,faceNodeOffset=0,faceTriaOffset=0;
1070
        for (int i=1; i <= faceMap.Extent(); i++, ii++) {
1071
            TopLoc_Location aLoc;
1072
            const TopoDS_Face &actFace = TopoDS::Face(faceMap(i));
1073
            // get the mesh of the shape
1074
            Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc);
1075
            if (mesh.IsNull()) {
1076
                mesh = Part::Tools::triangulationOfFace(actFace);
1077
            }
1078
            if (mesh.IsNull()) {
1079
                parts[ii] = 0;
1080
                continue;
1081
            }
1082

1083
            // getting the transformation of the shape/face
1084
            gp_Trsf myTransf;
1085
            Standard_Boolean identity = true;
1086
            if (!aLoc.IsIdentity()) {
1087
                identity = false;
1088
                myTransf = aLoc.Transformation();
1089
            }
1090

1091
            // getting size of node and triangle array of this face
1092
            int nbNodesInFace = mesh->NbNodes();
1093
            int nbTriInFace   = mesh->NbTriangles();
1094
            // check orientation
1095
            TopAbs_Orientation orient = actFace.Orientation();
1096

1097

1098
            // cycling through the poly mesh
1099
#if OCC_VERSION_HEX < 0x070600
1100
            const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
1101
            const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
1102
            TColgp_Array1OfDir Normals (Nodes.Lower(), Nodes.Upper());
1103
#else
1104
            int numNodes =  mesh->NbNodes();
1105
            TColgp_Array1OfDir Normals (1, numNodes);
1106
#endif
1107
            if (NormalsFromUV)
1108
                Part::Tools::getPointNormals(actFace, mesh, Normals);
1109

1110
            for (int g=1;g<=nbTriInFace;g++) {
1111
                // Get the triangle
1112
                Standard_Integer N1,N2,N3;
1113
#if OCC_VERSION_HEX < 0x070600
1114
                Triangles(g).Get(N1,N2,N3);
1115
#else
1116
                mesh->Triangle(g).Get(N1,N2,N3);
1117
#endif
1118

1119
                // change orientation of the triangle if the face is reversed
1120
                if ( orient != TopAbs_FORWARD ) {
1121
                    Standard_Integer tmp = N1;
1122
                    N1 = N2;
1123
                    N2 = tmp;
1124
                }
1125

1126
                // get the 3 points of this triangle
1127
#if OCC_VERSION_HEX < 0x070600
1128
                gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
1129
#else
1130
                gp_Pnt V1(mesh->Node(N1)), V2(mesh->Node(N2)), V3(mesh->Node(N3));
1131
#endif
1132

1133
                // get the 3 normals of this triangle
1134
                gp_Vec NV1, NV2, NV3;
1135
                if (NormalsFromUV) {
1136
                    NV1.SetXYZ(Normals(N1).XYZ());
1137
                    NV2.SetXYZ(Normals(N2).XYZ());
1138
                    NV3.SetXYZ(Normals(N3).XYZ());
1139
                }
1140
                else {
1141
                    gp_Vec v1(V1.X(),V1.Y(),V1.Z()),
1142
                           v2(V2.X(),V2.Y(),V2.Z()),
1143
                           v3(V3.X(),V3.Y(),V3.Z());
1144
                    gp_Vec normal = (v2-v1)^(v3-v1);
1145
                    NV1 = normal;
1146
                    NV2 = normal;
1147
                    NV3 = normal;
1148
                }
1149

1150
                // transform the vertices and normals to the place of the face
1151
                if (!identity) {
1152
                    V1.Transform(myTransf);
1153
                    V2.Transform(myTransf);
1154
                    V3.Transform(myTransf);
1155
                    if (NormalsFromUV) {
1156
                        NV1.Transform(myTransf);
1157
                        NV2.Transform(myTransf);
1158
                        NV3.Transform(myTransf);
1159
                    }
1160
                }
1161

1162
                // add the normals for all points of this triangle
1163
                norms[faceNodeOffset+N1-1] += SbVec3f(NV1.X(),NV1.Y(),NV1.Z());
1164
                norms[faceNodeOffset+N2-1] += SbVec3f(NV2.X(),NV2.Y(),NV2.Z());
1165
                norms[faceNodeOffset+N3-1] += SbVec3f(NV3.X(),NV3.Y(),NV3.Z());
1166

1167
                // set the vertices
1168
                verts[faceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));
1169
                verts[faceNodeOffset+N2-1].setValue((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z()));
1170
                verts[faceNodeOffset+N3-1].setValue((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z()));
1171

1172
                // set the index vector with the 3 point indexes and the end delimiter
1173
                index[faceTriaOffset*4+4*(g-1)]   = faceNodeOffset+N1-1;
1174
                index[faceTriaOffset*4+4*(g-1)+1] = faceNodeOffset+N2-1;
1175
                index[faceTriaOffset*4+4*(g-1)+2] = faceNodeOffset+N3-1;
1176
                index[faceTriaOffset*4+4*(g-1)+3] = SO_END_FACE_INDEX;
1177
            }
1178

1179
            parts[ii] = nbTriInFace; // new part
1180

1181
            // handling the edges lying on this face
1182
            TopExp_Explorer Exp;
1183
            for(Exp.Init(actFace,TopAbs_EDGE);Exp.More();Exp.Next()) {
1184
                const TopoDS_Edge &curEdge = TopoDS::Edge(Exp.Current());
1185
                // get the overall index of this edge
1186
                int edgeIndex = edgeMap.FindIndex(curEdge);
1187
                edgeVector.push_back((int32_t)edgeIndex-1);
1188
                // already processed this index ?
1189
                if (edgeIdxSet.find(edgeIndex)!=edgeIdxSet.end()) {
1190

1191
                    // this holds the indices of the edge's triangulation to the current polygon
1192
                    Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(curEdge, mesh, aLoc);
1193
                    if (aPoly.IsNull())
1194
                        continue; // polygon does not exist
1195

1196
                    // getting the indexes of the edge polygon
1197
                    const TColStd_Array1OfInteger& indices = aPoly->Nodes();
1198
                    for (Standard_Integer i=indices.Lower();i <= indices.Upper();i++) {
1199
                        int nodeIndex = indices(i);
1200
                        int index = faceNodeOffset+nodeIndex-1;
1201
                        lineSetMap[edgeIndex].push_back(index);
1202

1203
                        // usually the coordinates for this edge are already set by the
1204
                        // triangles of the face this edge belongs to. However, there are
1205
                        // rare cases where some points are only referenced by the polygon
1206
                        // but not by any triangle. Thus, we must apply the coordinates to
1207
                        // make sure that everything is properly set.
1208
#if OCC_VERSION_HEX < 0x070600
1209
                        gp_Pnt p(Nodes(nodeIndex));
1210
#else
1211
                        gp_Pnt p(mesh->Node(nodeIndex));
1212
#endif
1213
                        if (!identity)
1214
                            p.Transform(myTransf);
1215
                        verts[index].setValue((float)(p.X()),(float)(p.Y()),(float)(p.Z()));
1216
                    }
1217

1218
                    // remove the handled edge index from the set
1219
                    edgeIdxSet.erase(edgeIndex);
1220
                }
1221
            }
1222

1223
            edgeVector.push_back(-1);
1224

1225
            // counting up the per Face offsets
1226
            faceNodeOffset += nbNodesInFace;
1227
            faceTriaOffset += nbTriInFace;
1228
        }
1229

1230
        // handling of the free edges
1231
        for (int i=1; i <= edgeMap.Extent(); i++) {
1232
            const TopoDS_Edge& aEdge = TopoDS::Edge(edgeMap(i));
1233
            Standard_Boolean identity = true;
1234
            gp_Trsf myTransf;
1235
            TopLoc_Location aLoc;
1236

1237
            // handling of the free edge that are not associated to a face
1238
            int hash = Part::ShapeMapHasher{}(aEdge);
1239
            if (faceEdges.find(hash) == faceEdges.end()) {
1240
                Handle(Poly_Polygon3D) aPoly = Part::Tools::polygonOfEdge(aEdge, aLoc);
1241
                if (!aPoly.IsNull()) {
1242
                    if (!aLoc.IsIdentity()) {
1243
                        identity = false;
1244
                        myTransf = aLoc.Transformation();
1245
                    }
1246

1247
                    const TColgp_Array1OfPnt& aNodes = aPoly->Nodes();
1248
                    int nbNodesInEdge = aPoly->NbNodes();
1249

1250
                    gp_Pnt pnt;
1251
                    for (Standard_Integer j=1;j <= nbNodesInEdge;j++) {
1252
                        pnt = aNodes(j);
1253
                        if (!identity)
1254
                            pnt.Transform(myTransf);
1255
                        int index = faceNodeOffset+j-1;
1256
                        verts[index].setValue((float)(pnt.X()),(float)(pnt.Y()),(float)(pnt.Z()));
1257
                        lineSetMap[i].push_back(index);
1258
                    }
1259

1260
                    faceNodeOffset += nbNodesInEdge;
1261
                }
1262
            }
1263
        }
1264

1265
        nodeset->startIndex.setValue(faceNodeOffset);
1266
        for (int i=0; i<vertexMap.Extent(); i++) {
1267
            const TopoDS_Vertex& aVertex = TopoDS::Vertex(vertexMap(i+1));
1268
            gp_Pnt pnt = BRep_Tool::Pnt(aVertex);
1269
            verts[faceNodeOffset+i].setValue((float)(pnt.X()),(float)(pnt.Y()),(float)(pnt.Z()));
1270
        }
1271

1272
        // normalize all normals
1273
        for (int i = 0; i< numNorms ;i++)
1274
            norms[i].normalize();
1275

1276
        std::vector<int32_t> lineSetCoords;
1277
        for (const auto & it : lineSetMap) {
1278
            lineSetCoords.insert(lineSetCoords.end(), it.second.begin(), it.second.end());
1279
            lineSetCoords.push_back(-1);
1280
        }
1281

1282
        // preset the index vector size
1283
        numLines =  lineSetCoords.size();
1284
        lineset ->coordIndex .setNum(numLines);
1285
        int32_t* lines = lineset ->coordIndex  .startEditing();
1286

1287
        int l=0;
1288
        for (std::vector<int32_t>::const_iterator it=lineSetCoords.begin();it!=lineSetCoords.end();++it,l++)
1289
            lines[l] = *it;
1290

1291
        // end the editing of the nodes
1292
        coords  ->point       .finishEditing();
1293
        norm    ->vector      .finishEditing();
1294
        faceset ->coordIndex  .finishEditing();
1295
        faceset ->partIndex   .finishEditing();
1296
        lineset ->coordIndex  .finishEditing();
1297
    }
1298
    catch (const Standard_Failure& e) {
1299
        FC_ERR("Cannot compute Inventor representation for the shape of "
1300
               << pcObject->getFullName() << ": " << e.GetMessageString());
1301
    }
1302
    catch (...) {
1303
        FC_ERR("Cannot compute Inventor representation for the shape of " << pcObject->getFullName());
1304
    }
1305

1306
#   ifdef FC_DEBUG
1307
        // printing some information
1308
        Base::Console().Log("ViewProvider update time: %f s\n",Base::TimeElapsed::diffTimeF(start_time,Base::TimeElapsed()));
1309
        Base::Console().Log("Shape tria info: Faces:%d Edges:%d Nodes:%d Triangles:%d IdxVec:%d\n",numFaces,numEdges,numNodes,numTriangles,numLines);
1310
#   else
1311
    (void)numEdges;
1312
#   endif
1313
    VisualTouched = false;
1314

1315
    // The material has to be checked again
1316
    setHighlightedFaces(ShapeAppearance.getValues());
1317
    setHighlightedEdges(LineColorArray.getValues());
1318
    setHighlightedPoints(PointColorArray.getValue());
1319
}
1320

1321
void ViewProviderPartExt::forceUpdate(bool enable) {
1322
    if(enable) {
1323
        if(++forceUpdateCount == 1) {
1324
            if(!isShow() && VisualTouched)
1325
                updateVisual();
1326
        }
1327
    }else if(forceUpdateCount)
1328
        --forceUpdateCount;
1329
}
1330

1331

1332
void ViewProviderPartExt::handleChangedPropertyName(Base::XMLReader& reader,
1333
                                                    const char* TypeName,
1334
                                                    const char* PropName)
1335
{
1336
    if (strcmp(PropName, "DiffuseColor") == 0
1337
        && strcmp(TypeName, App::PropertyColorList::getClassTypeId().getName()) == 0) {
1338

1339
        // PropertyColorLists are loaded asynchronously as they're stored in separate files
1340
        _diffuseColor.Restore(reader);
1341
    }
1342
    else {
1343
        Gui::ViewProviderGeometryObject::handleChangedPropertyName(reader, TypeName, PropName);
1344
    }
1345
}
1346

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

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

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

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