1
/***************************************************************************
2
* Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
25
#include <boost/math/special_functions/fpclassify.hpp>
28
#include <Inventor/errors/SoDebugError.h>
29
#include <Inventor/events/SoMouseButtonEvent.h>
30
#include <Inventor/nodes/SoCamera.h>
31
#include <Inventor/nodes/SoCoordinate3.h>
32
#include <Inventor/nodes/SoDrawStyle.h>
33
#include <Inventor/nodes/SoIndexedPointSet.h>
34
#include <Inventor/nodes/SoMaterial.h>
35
#include <Inventor/nodes/SoMaterialBinding.h>
36
#include <Inventor/nodes/SoNormal.h>
37
#include <Inventor/nodes/SoPointSet.h>
40
#include <App/Document.h>
41
#include <Base/Vector3D.h>
42
#include <Gui/Application.h>
43
#include <Gui/Document.h>
44
#include <Gui/SoFCSelection.h>
45
#include <Gui/View3DInventorViewer.h>
46
#include <Mod/Points/App/PointsFeature.h>
47
#include <Mod/Points/App/Properties.h>
49
#include "ViewProvider.h"
52
using namespace PointsGui;
53
using namespace Points;
56
PROPERTY_SOURCE_ABSTRACT(PointsGui::ViewProviderPoints, Gui::ViewProviderGeometryObject)
59
App::PropertyFloatConstraint::Constraints ViewProviderPoints::floatRange = {1.0, 64.0, 1.0};
61
ViewProviderPoints::ViewProviderPoints()
63
static const char* osgroup = "Object Style";
65
ADD_PROPERTY_TYPE(PointSize, (2.0F), osgroup, App::Prop_None, "Set point size");
66
PointSize.setConstraints(&floatRange);
68
// Create the selection node
69
pcHighlight = Gui::ViewProviderBuilder::createSelection();
71
if (pcHighlight->selectionMode.getValue() == Gui::SoFCSelection::SEL_OFF) {
72
Selectable.setValue(false);
76
SelectionStyle.setValue(1);
78
pcPointsCoord = new SoCoordinate3();
80
pcPointsNormal = new SoNormal();
81
pcPointsNormal->ref();
82
pcColorMat = new SoMaterial;
85
pcPointStyle = new SoDrawStyle();
87
pcPointStyle->style = SoDrawStyle::POINTS;
88
pcPointStyle->pointSize = PointSize.getValue();
91
ViewProviderPoints::~ViewProviderPoints()
94
pcPointsCoord->unref();
95
pcPointsNormal->unref();
97
pcPointStyle->unref();
100
void ViewProviderPoints::onChanged(const App::Property* prop)
102
if (prop == &PointSize) {
103
pcPointStyle->pointSize = PointSize.getValue();
105
else if (prop == &SelectionStyle) {
107
SelectionStyle.getValue() ? Gui::SoFCSelection::BOX : Gui::SoFCSelection::EMISSIVE;
110
ViewProviderGeometryObject::onChanged(prop);
114
void ViewProviderPoints::setVertexColorMode(App::PropertyColorList* pcProperty)
116
const std::vector<App::Color>& val = pcProperty->getValues();
118
pcColorMat->diffuseColor.setNum(val.size());
119
SbColor* col = pcColorMat->diffuseColor.startEditing();
122
for (const auto& it : val) {
123
col[i++].setValue(it.r, it.g, it.b);
126
pcColorMat->diffuseColor.finishEditing();
129
void ViewProviderPoints::setVertexGreyvalueMode(Points::PropertyGreyValueList* pcProperty)
131
const std::vector<float>& val = pcProperty->getValues();
133
pcColorMat->diffuseColor.setNum(val.size());
134
SbColor* col = pcColorMat->diffuseColor.startEditing();
137
for (float it : val) {
138
col[i++].setValue(it, it, it);
141
pcColorMat->diffuseColor.finishEditing();
144
void ViewProviderPoints::setVertexNormalMode(Points::PropertyNormalList* pcProperty)
146
const std::vector<Base::Vector3f>& val = pcProperty->getValues();
148
pcPointsNormal->vector.setNum(val.size());
149
SbVec3f* norm = pcPointsNormal->vector.startEditing();
152
for (const auto& it : val) {
153
norm[i++].setValue(it.x, it.y, it.z);
156
pcPointsNormal->vector.finishEditing();
159
void ViewProviderPoints::setDisplayMode(const char* ModeName)
161
int numPoints = pcPointsCoord->point.getNum();
163
if (strcmp("Color", ModeName) == 0) {
164
std::map<std::string, App::Property*> Map;
165
pcObject->getPropertyMap(Map);
166
for (auto& it : Map) {
167
Base::Type type = it.second->getTypeId();
168
if (type == App::PropertyColorList::getClassTypeId()) {
169
App::PropertyColorList* colors = static_cast<App::PropertyColorList*>(it.second);
170
if (numPoints != colors->getSize()) {
172
SoDebugError::postWarning(
173
"ViewProviderPoints::setDisplayMode",
174
"The number of points (%d) doesn't match with the number of colors (%d).",
179
setDisplayMaskMode("Point");
182
setVertexColorMode(colors);
183
setDisplayMaskMode("Color");
189
else if (strcmp("Intensity", ModeName) == 0) {
190
std::map<std::string, App::Property*> Map;
191
pcObject->getPropertyMap(Map);
192
for (const auto& it : Map) {
193
Base::Type type = it.second->getTypeId();
194
if (type == Points::PropertyGreyValueList::getClassTypeId()) {
195
Points::PropertyGreyValueList* greyValues =
196
static_cast<Points::PropertyGreyValueList*>(it.second);
197
if (numPoints != greyValues->getSize()) {
199
SoDebugError::postWarning("ViewProviderPoints::setDisplayMode",
200
"The number of points (%d) doesn't match with the "
201
"number of grey values (%d).",
203
greyValues->getSize());
205
// Intensity mode is not possible then set the default () mode instead.
206
setDisplayMaskMode("Point");
209
setVertexGreyvalueMode((Points::PropertyGreyValueList*)it.second);
210
setDisplayMaskMode("Color");
216
else if (strcmp("Shaded", ModeName) == 0) {
217
std::map<std::string, App::Property*> Map;
218
pcObject->getPropertyMap(Map);
219
for (const auto& it : Map) {
220
Base::Type type = it.second->getTypeId();
221
if (type == Points::PropertyNormalList::getClassTypeId()) {
222
Points::PropertyNormalList* normals =
223
static_cast<Points::PropertyNormalList*>(it.second);
224
if (numPoints != normals->getSize()) {
226
SoDebugError::postWarning(
227
"ViewProviderPoints::setDisplayMode",
228
"The number of points (%d) doesn't match with the number of normals (%d).",
233
setDisplayMaskMode("Point");
236
setVertexNormalMode(normals);
237
setDisplayMaskMode("Shaded");
243
else if (strcmp("Points", ModeName) == 0) {
244
setDisplayMaskMode("Point");
247
ViewProviderGeometryObject::setDisplayMode(ModeName);
250
std::vector<std::string> ViewProviderPoints::getDisplayModes() const
252
std::vector<std::string> StrList;
253
StrList.emplace_back("Points");
255
// FIXME: This way all display modes are added even if the points feature
256
// doesn't support it.
257
// For the future a more flexible way is needed to add new display modes
260
StrList.emplace_back("Color");
261
StrList.emplace_back("Shaded");
262
StrList.emplace_back("Intensity");
266
std::map<std::string, App::Property*> Map;
267
pcObject->getPropertyMap(Map);
269
for (std::map<std::string, App::Property*>::iterator it = Map.begin(); it != Map.end();
271
Base::Type type = it->second->getTypeId();
272
if (type == Points::PropertyNormalList::getClassTypeId()) {
273
StrList.push_back("Shaded");
275
else if (type == Points::PropertyGreyValueList::getClassTypeId()) {
276
StrList.push_back("Intensity");
278
else if (type == App::PropertyColorList::getClassTypeId()) {
279
StrList.push_back("Color");
288
QIcon ViewProviderPoints::getIcon() const
291
static const char * const Points_Feature_xpm[] = {
313
QPixmap px(Points_Feature_xpm);
318
bool ViewProviderPoints::setEdit(int ModNum)
320
if (ModNum == ViewProvider::Transform) {
321
return ViewProviderGeometryObject::setEdit(ModNum);
323
else if (ModNum == ViewProvider::Cutting) {
329
void ViewProviderPoints::unsetEdit(int ModNum)
331
if (ModNum == ViewProvider::Transform) {
332
ViewProviderGeometryObject::unsetEdit(ModNum);
336
void ViewProviderPoints::clipPointsCallback(void*, SoEventCallback* n)
338
// When this callback function is invoked we must in either case leave the edit mode
339
Gui::View3DInventorViewer* view = static_cast<Gui::View3DInventorViewer*>(n->getUserData());
340
view->setEditing(false);
341
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), clipPointsCallback);
344
std::vector<SbVec2f> clPoly = view->getGLPolygon();
345
if (clPoly.size() < 3) {
348
if (clPoly.front() != clPoly.back()) {
349
clPoly.push_back(clPoly.front());
352
std::vector<Gui::ViewProvider*> views =
353
view->getViewProvidersOfType(ViewProviderPoints::getClassTypeId());
354
for (auto it : views) {
355
ViewProviderPoints* that = static_cast<ViewProviderPoints*>(it);
356
if (that->getEditingMode() > -1) {
357
that->finishEditing();
358
that->cut(clPoly, *view);
365
// -------------------------------------------------
367
PROPERTY_SOURCE(PointsGui::ViewProviderScattered, PointsGui::ViewProviderPoints)
369
ViewProviderScattered::ViewProviderScattered()
371
pcPoints = new SoPointSet();
375
ViewProviderScattered::~ViewProviderScattered()
380
void ViewProviderScattered::attach(App::DocumentObject* pcObj)
382
// call parent's attach to define display modes
383
ViewProviderGeometryObject::attach(pcObj);
385
pcHighlight->objectName = pcObj->getNameInDocument();
386
pcHighlight->documentName = pcObj->getDocument()->getName();
387
pcHighlight->subElementName = "Main";
389
// Highlight for selection
390
pcHighlight->addChild(pcPointsCoord);
391
pcHighlight->addChild(pcPoints);
393
std::vector<std::string> modes = getDisplayModes();
395
// points part ---------------------------------------------
396
SoGroup* pcPointRoot = new SoGroup();
397
pcPointRoot->addChild(pcPointStyle);
398
pcPointRoot->addChild(pcShapeMaterial);
399
pcPointRoot->addChild(pcHighlight);
400
addDisplayMaskMode(pcPointRoot, "Point");
402
// points shaded ---------------------------------------------
403
if (std::find(modes.begin(), modes.end(), std::string("Shaded")) != modes.end()) {
404
SoGroup* pcPointShadedRoot = new SoGroup();
405
pcPointShadedRoot->addChild(pcPointStyle);
406
pcPointShadedRoot->addChild(pcShapeMaterial);
407
pcPointShadedRoot->addChild(pcPointsNormal);
408
pcPointShadedRoot->addChild(pcHighlight);
409
addDisplayMaskMode(pcPointShadedRoot, "Shaded");
412
// color shaded ------------------------------------------
413
if (std::find(modes.begin(), modes.end(), std::string("Color")) != modes.end()
414
|| std::find(modes.begin(), modes.end(), std::string("Intensity")) != modes.end()) {
415
SoGroup* pcColorShadedRoot = new SoGroup();
416
pcColorShadedRoot->addChild(pcPointStyle);
417
SoMaterialBinding* pcMatBinding = new SoMaterialBinding;
418
pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
419
pcColorShadedRoot->addChild(pcColorMat);
420
pcColorShadedRoot->addChild(pcMatBinding);
421
pcColorShadedRoot->addChild(pcHighlight);
422
addDisplayMaskMode(pcColorShadedRoot, "Color");
426
void ViewProviderScattered::updateData(const App::Property* prop)
428
ViewProviderPoints::updateData(prop);
429
if (prop->is<Points::PropertyPointKernel>()) {
430
ViewProviderPointsBuilder builder;
431
builder.createPoints(prop, pcPointsCoord, pcPoints);
433
// The number of points might have changed, so force also a resize of the Inventor internals
436
else if (prop->is<Points::PropertyNormalList>()) {
439
else if (prop->is<Points::PropertyGreyValueList>()) {
442
else if (prop->is<App::PropertyColorList>()) {
447
void ViewProviderScattered::cut(const std::vector<SbVec2f>& picked,
448
Gui::View3DInventorViewer& Viewer)
450
// create the polygon from the picked points
451
Base::Polygon2d cPoly;
452
for (const auto& it : picked) {
453
cPoly.Add(Base::Vector2d(it[0], it[1]));
456
// get a reference to the point feature
457
Points::Feature* fea = static_cast<Points::Feature*>(pcObject);
458
const Points::PointKernel& points = fea->Points.getValue();
460
SoCamera* pCam = Viewer.getSoRenderManager()->getCamera();
461
SbViewVolume vol = pCam->getViewVolume();
463
// search for all points inside/outside the polygon
464
std::vector<unsigned long> removeIndices;
465
removeIndices.reserve(points.size());
467
unsigned long index = 0;
468
for (Points::PointKernel::const_iterator jt = points.begin(); jt != points.end();
470
SbVec3f pt(jt->x, jt->y, jt->z);
472
// project from 3d to 2d
473
vol.projectToScreen(pt, pt);
474
if (cPoly.Contains(Base::Vector2d(pt[0], pt[1]))) {
475
removeIndices.push_back(index);
479
if (removeIndices.empty()) {
480
return; // nothing needs to be done
483
// Remove the points from the cloud and open a transaction object for the undo/redo stuff
484
Gui::Application::Instance->activeDocument()->openCommand(
485
QT_TRANSLATE_NOOP("Command", "Cut points"));
487
// sets the points outside the polygon to update the Inventor node
488
fea->Points.removeIndices(removeIndices);
490
std::map<std::string, App::Property*> Map;
491
pcObject->getPropertyMap(Map);
493
for (const auto& it : Map) {
494
Base::Type type = it.second->getTypeId();
495
if (type == Points::PropertyNormalList::getClassTypeId()) {
496
static_cast<Points::PropertyNormalList*>(it.second)->removeIndices(removeIndices);
498
else if (type == Points::PropertyGreyValueList::getClassTypeId()) {
499
static_cast<Points::PropertyGreyValueList*>(it.second)->removeIndices(removeIndices);
501
else if (type == App::PropertyColorList::getClassTypeId()) {
502
// static_cast<App::PropertyColorList*>(it->second)->removeIndices(removeIndices);
503
const std::vector<App::Color>& colors =
504
static_cast<App::PropertyColorList*>(it.second)->getValues();
506
if (removeIndices.size() > colors.size()) {
510
std::vector<App::Color> remainValue;
511
remainValue.reserve(colors.size() - removeIndices.size());
513
std::vector<unsigned long>::iterator pos = removeIndices.begin();
514
for (std::vector<App::Color>::const_iterator jt = colors.begin(); jt != colors.end();
516
unsigned long index = jt - colors.begin();
517
if (pos == removeIndices.end()) {
518
remainValue.push_back(*jt);
520
else if (index != *pos) {
521
remainValue.push_back(*jt);
528
static_cast<App::PropertyColorList*>(it.second)->setValues(remainValue);
532
// unset the modified flag because we don't need the features' execute() to be called
533
Gui::Application::Instance->activeDocument()->commitCommand();
537
// -------------------------------------------------
539
PROPERTY_SOURCE(PointsGui::ViewProviderStructured, PointsGui::ViewProviderPoints)
541
ViewProviderStructured::ViewProviderStructured()
543
pcPoints = new SoIndexedPointSet();
547
ViewProviderStructured::~ViewProviderStructured()
552
void ViewProviderStructured::attach(App::DocumentObject* pcObj)
554
// call parent's attach to define display modes
555
ViewProviderGeometryObject::attach(pcObj);
557
pcHighlight->objectName = pcObj->getNameInDocument();
558
pcHighlight->documentName = pcObj->getDocument()->getName();
559
pcHighlight->subElementName = "Main";
561
// Highlight for selection
562
pcHighlight->addChild(pcPointsCoord);
563
pcHighlight->addChild(pcPoints);
565
std::vector<std::string> modes = getDisplayModes();
567
// points part ---------------------------------------------
568
SoGroup* pcPointRoot = new SoGroup();
569
pcPointRoot->addChild(pcPointStyle);
570
pcPointRoot->addChild(pcShapeMaterial);
571
pcPointRoot->addChild(pcHighlight);
572
addDisplayMaskMode(pcPointRoot, "Point");
574
// points shaded ---------------------------------------------
575
if (std::find(modes.begin(), modes.end(), std::string("Shaded")) != modes.end()) {
576
SoGroup* pcPointShadedRoot = new SoGroup();
577
pcPointShadedRoot->addChild(pcPointStyle);
578
pcPointShadedRoot->addChild(pcShapeMaterial);
579
pcPointShadedRoot->addChild(pcPointsNormal);
580
pcPointShadedRoot->addChild(pcHighlight);
581
addDisplayMaskMode(pcPointShadedRoot, "Shaded");
584
// color shaded ------------------------------------------
585
if (std::find(modes.begin(), modes.end(), std::string("Color")) != modes.end()
586
|| std::find(modes.begin(), modes.end(), std::string("Intensity")) != modes.end()) {
587
SoGroup* pcColorShadedRoot = new SoGroup();
588
pcColorShadedRoot->addChild(pcPointStyle);
589
SoMaterialBinding* pcMatBinding = new SoMaterialBinding;
590
pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
591
pcColorShadedRoot->addChild(pcColorMat);
592
pcColorShadedRoot->addChild(pcMatBinding);
593
pcColorShadedRoot->addChild(pcHighlight);
594
addDisplayMaskMode(pcColorShadedRoot, "Color");
598
void ViewProviderStructured::updateData(const App::Property* prop)
600
ViewProviderPoints::updateData(prop);
601
if (prop->is<Points::PropertyPointKernel>()) {
602
ViewProviderPointsBuilder builder;
603
builder.createPoints(prop, pcPointsCoord, pcPoints);
605
// The number of points might have changed, so force also a resize of the Inventor internals
610
void ViewProviderStructured::cut(const std::vector<SbVec2f>& picked,
611
Gui::View3DInventorViewer& Viewer)
613
// create the polygon from the picked points
614
Base::Polygon2d cPoly;
615
for (const auto& it : picked) {
616
cPoly.Add(Base::Vector2d(it[0], it[1]));
619
// get a reference to the point feature
620
Points::Feature* fea = static_cast<Points::Feature*>(pcObject);
621
const Points::PointKernel& points = fea->Points.getValue();
623
SoCamera* pCam = Viewer.getSoRenderManager()->getCamera();
624
SbViewVolume vol = pCam->getViewVolume();
626
// search for all points inside/outside the polygon
627
Points::PointKernel newKernel;
628
newKernel.reserve(points.size());
630
bool invalidatePoints = false;
631
double nan = std::numeric_limits<double>::quiet_NaN();
632
for (const auto& point : points) {
634
Base::Vector3d vec(point);
635
if (!(boost::math::isnan(point.x) || boost::math::isnan(point.y)
636
|| boost::math::isnan(point.z))) {
637
SbVec3f pt(point.x, point.y, point.z);
639
// project from 3d to 2d
640
vol.projectToScreen(pt, pt);
641
if (cPoly.Contains(Base::Vector2d(pt[0], pt[1]))) {
642
invalidatePoints = true;
643
vec.Set(nan, nan, nan);
647
newKernel.push_back(vec);
650
if (invalidatePoints) {
651
// Remove the points from the cloud and open a transaction object for the undo/redo stuff
652
Gui::Application::Instance->activeDocument()->openCommand(
653
QT_TRANSLATE_NOOP("Command", "Cut points"));
655
// sets the points outside the polygon to update the Inventor node
656
fea->Points.setValue(newKernel);
658
// unset the modified flag because we don't need the features' execute() to be called
659
Gui::Application::Instance->activeDocument()->commitCommand();
664
// -------------------------------------------------
669
PROPERTY_SOURCE_TEMPLATE(PointsGui::ViewProviderPython, PointsGui::ViewProviderScattered)
672
// explicit template instantiation
673
template class PointsGuiExport ViewProviderFeaturePythonT<PointsGui::ViewProviderScattered>;
676
// -------------------------------------------------
678
void ViewProviderPointsBuilder::buildNodes(const App::Property* prop,
679
std::vector<SoNode*>& nodes) const
681
SoCoordinate3* pcPointsCoord = nullptr;
682
SoPointSet* pcPoints = nullptr;
685
pcPointsCoord = new SoCoordinate3();
686
nodes.push_back(pcPointsCoord);
687
pcPoints = new SoPointSet();
688
nodes.push_back(pcPoints);
690
else if (nodes.size() == 2) {
691
if (nodes[0]->getTypeId() == SoCoordinate3::getClassTypeId()) {
692
pcPointsCoord = static_cast<SoCoordinate3*>(nodes[0]);
694
if (nodes[1]->getTypeId() == SoPointSet::getClassTypeId()) {
695
pcPoints = static_cast<SoPointSet*>(nodes[1]);
699
if (pcPointsCoord && pcPoints) {
700
createPoints(prop, pcPointsCoord, pcPoints);
704
void ViewProviderPointsBuilder::createPoints(const App::Property* prop,
705
SoCoordinate3* coords,
706
SoPointSet* points) const
708
const Points::PropertyPointKernel* prop_points =
709
static_cast<const Points::PropertyPointKernel*>(prop);
710
const Points::PointKernel& cPts = prop_points->getValue();
712
coords->point.setNum(cPts.size());
713
SbVec3f* vec = coords->point.startEditing();
717
const std::vector<Points::PointKernel::value_type>& kernel = cPts.getBasicPoints();
718
for (std::vector<Points::PointKernel::value_type>::const_iterator it = kernel.begin();
721
vec[idx].setValue(it->x, it->y, it->z);
724
points->numPoints = cPts.size();
725
coords->point.finishEditing();
728
void ViewProviderPointsBuilder::createPoints(const App::Property* prop,
729
SoCoordinate3* coords,
730
SoIndexedPointSet* points) const
732
const Points::PropertyPointKernel* prop_points =
733
static_cast<const Points::PropertyPointKernel*>(prop);
734
const Points::PointKernel& cPts = prop_points->getValue();
736
coords->point.setNum(cPts.size());
737
SbVec3f* vec = coords->point.startEditing();
741
std::vector<int32_t> indices;
742
indices.reserve(cPts.size());
743
const std::vector<Points::PointKernel::value_type>& kernel = cPts.getBasicPoints();
744
for (std::vector<Points::PointKernel::value_type>::const_iterator it = kernel.begin();
747
vec[idx].setValue(it->x, it->y, it->z);
749
if (!(boost::math::isnan(it->x) || boost::math::isnan(it->y)
750
|| boost::math::isnan(it->z))) {
751
indices.push_back(idx);
754
coords->point.finishEditing();
756
// get all point indices
758
points->coordIndex.setNum(indices.size());
759
int32_t* pos = points->coordIndex.startEditing();
760
for (int32_t index : indices) {
763
points->coordIndex.finishEditing();