Improve methods to select meshes, allow to smooth only selected area of a mesh

This commit is contained in:
wmayer 2013-04-26 17:21:36 +02:00
parent 2aabac71a7
commit c754280af6
19 changed files with 2050 additions and 481 deletions

View File

@ -41,6 +41,7 @@
#include "DlgSettingsMeshView.h"
#include "SoFCMeshObject.h"
#include "SoFCIndexedFaceSet.h"
#include "SoPolygon.h"
#include "ViewProvider.h"
#include "ViewProviderMeshFaceSet.h"
#include "ViewProviderCurvature.h"
@ -111,6 +112,7 @@ void MeshGuiExport initMeshGui()
MeshGui::SoFCIndexedFaceSet ::initClass();
MeshGui::SoFCMeshPickNode ::initClass();
MeshGui::SoFCMeshGridNode ::initClass();
MeshGui::SoPolygon ::initClass();
MeshGui::PropertyMeshKernelItem ::init();
MeshGui::ViewProviderMesh ::init();
MeshGui::ViewProviderMeshObject ::init();

View File

@ -24,6 +24,7 @@ set(Mesh_MOC_HDRS
MeshEditor.h
PropertyEditorMesh.h
RemoveComponents.h
Selection.h
)
fc_wrap_cpp(Mesh_MOC_SRCS ${Mesh_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${Mesh_MOC_SRCS})
@ -35,6 +36,7 @@ set(Dialogs_UIC_SRCS
DlgSmoothing.ui
RemoveComponents.ui
Segmentation.ui
Selection.ui
)
qt4_wrap_ui(Dialogs_UIC_HDRS ${Dialogs_UIC_SRCS})
SET(Dialogs_SRCS
@ -57,6 +59,9 @@ SET(Dialogs_SRCS
Segmentation.ui
Segmentation.cpp
Segmentation.h
Selection.ui
Selection.cpp
Selection.h
)
SOURCE_GROUP("Dialogs" FILES ${Dialogs_SRCS})
@ -65,6 +70,8 @@ SET(Inventor_SRCS
SoFCIndexedFaceSet.h
SoFCMeshObject.cpp
SoFCMeshObject.h
SoPolygon.cpp
SoPolygon.h
)
SOURCE_GROUP("Inventor" FILES ${Inventor_SRCS})
@ -105,6 +112,8 @@ SET(MeshGui_SRCS
PreCompiled.h
MeshEditor.cpp
MeshEditor.h
MeshSelection.cpp
MeshSelection.h
PropertyEditorMesh.cpp
PropertyEditorMesh.h
Workbench.cpp

View File

@ -1019,9 +1019,19 @@ bool CmdMeshRemoveComponents::isActive(void)
{
// Check for the selected mesh feature (all Mesh types)
App::Document* doc = getDocument();
return (doc && doc->countObjectsOfType
(Mesh::Feature::getClassTypeId()) > 0
&& !Gui::Control().activeDialog());
if (!(doc && doc->countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0))
return false;
Gui::Document* viewDoc = Gui::Application::Instance->getDocument(doc);
Gui::View3DInventor* view = dynamic_cast<Gui::View3DInventor*>(viewDoc->getActiveView());
if (view) {
Gui::View3DInventorViewer* viewer = view->getViewer();
if (viewer->isEditing())
return false;
}
if (Gui::Control().activeDialog())
return false;
return true;
}
//--------------------------------------------------------------------------------------
@ -1120,7 +1130,8 @@ CmdMeshSmoothing::CmdMeshSmoothing()
void CmdMeshSmoothing::activated(int iMsg)
{
MeshGui::DlgSmoothing dlg(Gui::getMainWindow());
#if 0
MeshGui::SmoothingDialog dlg(Gui::getMainWindow());
if (dlg.exec() == QDialog::Accepted) {
Gui::WaitCursor wc;
openCommand("Mesh Smoothing");
@ -1149,10 +1160,17 @@ void CmdMeshSmoothing::activated(int iMsg)
}
commitCommand();
}
#else
Gui::Control().showDialog(new MeshGui::TaskSmoothing());
#endif
}
bool CmdMeshSmoothing::isActive(void)
{
#if 1
if (Gui::Control().activeDialog())
return false;
#endif
// Check for the selected mesh feature (all Mesh types)
return getSelection().countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0;
}

View File

@ -23,17 +23,25 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QButtonGroup>
# include <QDialogButtonBox>
#endif
#include "DlgSmoothing.h"
#include "ui_DlgSmoothing.h"
#include "Selection.h"
#include <Gui/WaitCursor.h>
#include <Gui/Command.h>
#include <Gui/Selection.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Mesh/App/Core/Smoothing.h>
using namespace MeshGui;
/* TRANSLATOR MeshGui::DlgSmoothing */
DlgSmoothing::DlgSmoothing(QWidget* parent, Qt::WFlags fl)
: QDialog(parent, fl), ui(new Ui_DlgSmoothing())
DlgSmoothing::DlgSmoothing(QWidget* parent)
: QWidget(parent), ui(new Ui_DlgSmoothing())
{
ui->setupUi(this);
bg = new QButtonGroup(this);
@ -92,4 +100,130 @@ DlgSmoothing::Smooth DlgSmoothing::method() const
return DlgSmoothing::None;
}
bool DlgSmoothing::smoothSelection() const
{
return ui->checkBoxSelection->isChecked();
}
void DlgSmoothing::on_checkBoxSelection_toggled(bool on)
{
/*emit*/ toggledSelection(on);
}
// ------------------------------------------------
SmoothingDialog::SmoothingDialog(QWidget* parent, Qt::WFlags fl)
: QDialog(parent, fl)
{
widget = new DlgSmoothing(this);
this->setWindowTitle(widget->windowTitle());
QVBoxLayout* hboxLayout = new QVBoxLayout(this);
QDialogButtonBox* buttonBox = new QDialogButtonBox(this);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
connect(buttonBox, SIGNAL(accepted()),
this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()),
this, SLOT(reject()));
hboxLayout->addWidget(widget);
hboxLayout->addWidget(buttonBox);
}
SmoothingDialog::~SmoothingDialog()
{
}
// ---------------------------------------
/* TRANSLATOR MeshGui::TaskSmoothing */
TaskSmoothing::TaskSmoothing()
{
widget = new DlgSmoothing();
Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox(
QPixmap(), widget->windowTitle(), false, 0);
taskbox->groupLayout()->addWidget(widget);
Content.push_back(taskbox);
selection = new Selection();
selection->setObjects(Gui::Selection().getSelectionEx(0, Mesh::Feature::getClassTypeId()));
Gui::TaskView::TaskGroup* tasksel = new Gui::TaskView::TaskGroup();
tasksel->groupLayout()->addWidget(selection);
tasksel->hide();
Content.push_back(tasksel);
connect(widget, SIGNAL(toggledSelection(bool)),
tasksel, SLOT(setVisible(bool)));
}
TaskSmoothing::~TaskSmoothing()
{
// automatically deleted in the sub-class
}
bool TaskSmoothing::accept()
{
std::vector<App::DocumentObject*> meshes = selection->getObjects();
if (meshes.empty())
return true;
Gui::WaitCursor wc;
Gui::Command::openCommand("Mesh Smoothing");
bool hasSelection = false;
for (std::vector<App::DocumentObject*>::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
Mesh::Feature* mesh = static_cast<Mesh::Feature*>(*it);
std::vector<unsigned long> selection;
if (widget->smoothSelection()) {
// clear the selection before editing the mesh to avoid
// to have coloured triangles when doing an 'undo'
const Mesh::MeshObject* mm = mesh->Mesh.getValuePtr();
mm->getFacetsFromSelection(selection);
selection = mm->getPointsFromFacets(selection);
mm->clearFacetSelection();
if (!selection.empty())
hasSelection = true;
}
Mesh::MeshObject* mm = mesh->Mesh.startEditing();
switch (widget->method()) {
case MeshGui::DlgSmoothing::Taubin:
{
MeshCore::TaubinSmoothing s(mm->getKernel());
s.SetLambda(widget->lambdaStep());
s.SetMicro(widget->microStep());
if (widget->smoothSelection()) {
s.SmoothPoints(widget->iterations(), selection);
}
else {
s.Smooth(widget->iterations());
}
} break;
case MeshGui::DlgSmoothing::Laplace:
{
MeshCore::LaplaceSmoothing s(mm->getKernel());
s.SetLambda(widget->lambdaStep());
if (widget->smoothSelection()) {
s.SmoothPoints(widget->iterations(), selection);
}
else {
s.Smooth(widget->iterations());
}
} break;
default:
break;
}
mesh->Mesh.finishEditing();
}
if (widget->smoothSelection() && !hasSelection) {
Gui::Command::abortCommand();
return false;
}
Gui::Command::commitCommand();
return true;
}
#include "moc_DlgSmoothing.cpp"

View File

@ -25,13 +25,16 @@
#define MESHGUI_DLGSMOOTHING_H
#include <QDialog>
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/TaskView/TaskView.h>
class QButtonGroup;
namespace MeshGui {
class Selection;
class Ui_DlgSmoothing;
class DlgSmoothing : public QDialog
class DlgSmoothing : public QWidget
{
Q_OBJECT
@ -42,21 +45,76 @@ public:
Laplace
};
DlgSmoothing(QWidget* parent = 0, Qt::WFlags fl = 0);
DlgSmoothing(QWidget* parent = 0);
~DlgSmoothing();
int iterations() const;
double lambdaStep() const;
double microStep() const;
Smooth method() const;
bool smoothSelection() const;
private Q_SLOTS:
void method_clicked(int);
void on_checkBoxSelection_toggled(bool);
Q_SIGNALS:
void toggledSelection(bool);
private:
Ui_DlgSmoothing* ui;
QButtonGroup* bg;
};
/**
* Embed the panel into a dialog.
*/
class MeshGuiExport SmoothingDialog : public QDialog
{
Q_OBJECT
public:
SmoothingDialog(QWidget* parent = 0, Qt::WFlags fl = 0);
~SmoothingDialog();
int iterations() const
{ return widget->iterations(); }
double lambdaStep() const
{ return widget->lambdaStep(); }
double microStep() const
{ return widget->microStep(); }
DlgSmoothing::Smooth method() const
{ return widget->method(); }
bool smoothSelection() const
{ return widget->smoothSelection(); }
private:
DlgSmoothing* widget;
};
/**
* Embed the panel into a task dialog.
*/
class TaskSmoothing : public Gui::TaskView::TaskDialog
{
Q_OBJECT
public:
TaskSmoothing();
~TaskSmoothing();
public:
bool accept();
virtual QDialogButtonBox::StandardButtons getStandardButtons() const
{ return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; }
virtual bool isAllowedAlterDocument(void) const
{ return true; }
private:
DlgSmoothing* widget;
Selection* selection;
};
}
#endif // MESHGUI_DLGSMOOTHING_H

View File

@ -1,172 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MeshGui::DlgSmoothing</class>
<widget class="QDialog" name="MeshGui::DlgSmoothing">
<widget class="QWidget" name="MeshGui::DlgSmoothing">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>242</width>
<height>251</height>
<width>210</width>
<height>227</height>
</rect>
</property>
<property name="windowTitle">
<string>Smoothing</string>
</property>
<property name="sizeGripEnabled">
<property name="sizeGripEnabled" stdset="0">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string/>
<string>Method</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Method</string>
<widget class="QRadioButton" name="radioButtonTaubin">
<property name="text">
<string>Taubin</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QRadioButton" name="radioButtonTaubin">
<property name="text">
<string>Taubin</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="radioButtonLaplace">
<property name="text">
<string>Laplace</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Parameter</string>
<item row="0" column="1">
<widget class="QRadioButton" name="radioButtonLaplace">
<property name="text">
<string>Laplace</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Iterations:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="iterations">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelLambda">
<property name="text">
<string>Lambda:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="spinLambda">
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.630700000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelMu">
<property name="text">
<string>Mu:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="spinMicro">
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.042400000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Parameter</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Iterations:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="iterations">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelLambda">
<property name="text">
<string>Lambda:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="spinLambda">
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.630700000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelMu">
<property name="text">
<string>Mu:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="spinMicro">
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.042400000000000</double>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="checkBoxSelection">
<property name="text">
<string>Only selection</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MeshGui::DlgSmoothing</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>94</x>
<y>191</y>
</hint>
<hint type="destinationlabel">
<x>-3</x>
<y>193</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MeshGui::DlgSmoothing</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>190</x>
<y>193</y>
</hint>
<hint type="destinationlabel">
<x>219</x>
<y>151</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>

View File

@ -40,15 +40,21 @@
# include <Inventor/nodes/SoFaceSet.h>
# include <Inventor/nodes/SoLineSet.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoShapeHints.h>
# include <boost/bind.hpp>
#endif
#include "MeshEditor.h"
#include "SoFCMeshObject.h"
#include "SoPolygon.h"
#include <App/Document.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Mesh/App/Core/Algorithm.h>
#include <Mod/Mesh/App/Core/Triangulation.h>
#include <Gui/Application.h>
#include <Gui/WaitCursor.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
@ -278,8 +284,19 @@ void MeshFaceAddition::showMarker(SoPickedPoint* pp)
return;
// is a border facet picked?
MeshCore::MeshFacet f = facets[face_index];
if (!f.HasOpenEdge())
return;
if (!f.HasOpenEdge()) {
// check if a neighbour facet is at the border
bool ok=false;
for (int i=0; i<3; i++) {
if (facets[f._aulNeighbours[i]].HasOpenEdge()) {
f = facets[f._aulNeighbours[i]];
ok = true;
break;
}
}
if (!ok)
return;
}
int point_index = -1;
float distance = FLT_MAX;
@ -372,4 +389,326 @@ void MeshFaceAddition::addFacetCallback(void * ud, SoEventCallback * n)
}
}
// ----------------------------------------------------------------------
namespace MeshGui {
// for sorting of elements
struct NofFacetsCompare : public std::binary_function<const std::vector<unsigned long>&,
const std::vector<unsigned long>&, bool>
{
bool operator () (const std::vector<unsigned long> &rclC1,
const std::vector<unsigned long> &rclC2)
{
return rclC1.size() < rclC2.size();
}
};
}
/* TRANSLATOR MeshGui::MeshFillHole */
MeshFillHole::MeshFillHole(MeshHoleFiller& hf, Gui::View3DInventor* parent)
: QObject(parent), myMesh(0), myNumPoints(0), myHoleFiller(hf)
{
myBoundariesRoot = new SoSeparator;
myBoundariesRoot->ref();
myBoundaryRoot = new SoSeparator;
myBoundaryRoot->ref();
myBoundariesGroup = new SoSeparator();
myBoundariesGroup->ref();
myBridgeRoot = new SoSeparator;
myBridgeRoot->ref();
SoDrawStyle* pointStyle = new SoDrawStyle();
pointStyle->style = SoDrawStyle::POINTS;
pointStyle->pointSize = 8.0f;
myBridgeRoot->addChild(pointStyle);
SoBaseColor * markcol = new SoBaseColor;
markcol->rgb.setValue(1.0f, 1.0f, 0.0f);
SoPointSet* marker = new SoPointSet();
myBridgeRoot->addChild(markcol);
myVertex = new SoCoordinate3();
myBridgeRoot->addChild(myVertex);
myBridgeRoot->addChild(new SoPointSet);
}
MeshFillHole::~MeshFillHole()
{
myBoundariesRoot->unref();
myBoundariesGroup->unref();
myBoundaryRoot->unref();
myBridgeRoot->unref();
}
void MeshFillHole::startEditing(MeshGui::ViewProviderMesh* vp)
{
this->myMesh = static_cast<Mesh::Feature*>(vp->getObject());
Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(parent());
Gui::View3DInventorViewer* viewer = view->getViewer();
viewer->setEditing(true);
//viewer->setRedirectToSceneGraph(true);
viewer->addEventCallback(SoEvent::getClassTypeId(),
MeshFillHole::fileHoleCallback, this);
myConnection = App::GetApplication().signalChangedObject.connect(
boost::bind(&MeshFillHole::slotChangedObject, this, _1, _2));
myBoundariesRoot->removeAllChildren();
myBoundariesRoot->addChild(viewer->getHeadlight());
myBoundariesRoot->addChild(viewer->getCamera());
myBoundariesRoot->addChild(myBoundariesGroup);
myBoundaryRoot->removeAllChildren();
myBoundaryRoot->addChild(viewer->getHeadlight());
myBoundaryRoot->addChild(viewer->getCamera());
createPolygons();
static_cast<SoGroup*>(viewer->getSceneGraph())->addChild(myBridgeRoot);
}
void MeshFillHole::finishEditing()
{
Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(parent());
Gui::View3DInventorViewer* viewer = view->getViewer();
viewer->setEditing(false);
//viewer->setRedirectToSceneGraph(false);
viewer->removeEventCallback(SoEvent::getClassTypeId(),
MeshFillHole::fileHoleCallback, this);
myConnection.disconnect();
this->deleteLater();
static_cast<SoGroup*>(viewer->getSceneGraph())->removeChild(myBridgeRoot);
}
void MeshFillHole::closeBridge()
{
// Do the hole-filling
Gui::WaitCursor wc;
TBoundary::iterator it = std::find(myPolygon.begin(), myPolygon.end(), myVertex1);
TBoundary::iterator jt = std::find(myPolygon.begin(), myPolygon.end(), myVertex2);
if (it != myPolygon.end() && jt != myPolygon.end()) {
// which iterator comes first
if (jt < it)
std::swap(it, jt);
// split the boundary into two loops and take the shorter one
std::list<TBoundary> bounds;
TBoundary loop1, loop2;
loop1.insert(loop1.end(), myPolygon.begin(), it);
loop1.insert(loop1.end(), jt, myPolygon.end());
loop2.insert(loop2.end(), it, jt);
// this happens when myVertex1 == myVertex2
if (loop2.empty())
bounds.push_back(loop1);
else if (loop1.size() < loop2.size())
bounds.push_back(loop1);
else
bounds.push_back(loop2);
App::Document* doc = myMesh->getDocument();
doc->openTransaction("Bridge && Fill hole");
Mesh::MeshObject* pMesh = myMesh->Mesh.startEditing();
bool ok = myHoleFiller.fillHoles(*pMesh, bounds, myVertex1, myVertex2);
myMesh->Mesh.finishEditing();
if (ok)
doc->commitTransaction();
else
doc->abortTransaction();
}
}
void MeshFillHole::slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop)
{
if (&Obj == myMesh && strcmp(Prop.getName(),"Mesh") == 0) {
myBoundariesGroup->removeAllChildren();
myVertex->point.setNum(0);
myNumPoints = 0;
myPolygon.clear();
createPolygons();
}
}
void MeshFillHole::createPolygons()
{
Gui::WaitCursor wc;
myPolygons.clear();
SoPickStyle* pickStyle = new SoPickStyle();
pickStyle->style = SoPickStyle::BOUNDING_BOX;
myBoundariesGroup->addChild(pickStyle);
myBoundaryRoot->addChild(pickStyle);
// get mesh kernel
const MeshCore::MeshKernel & rMesh = this->myMesh->Mesh.getValue().getKernel();
// get the mesh boundaries as an array of point indices
std::list<std::vector<unsigned long> > borders;
MeshCore::MeshAlgorithm cAlgo(rMesh);
MeshCore::MeshPointIterator p_iter(rMesh);
cAlgo.GetMeshBorders(borders);
cAlgo.SplitBoundaryLoops(borders);
// sort the borders in ascending order of the number of edges
borders.sort(NofFacetsCompare());
int32_t count=0;
for (std::list<std::vector<unsigned long> >::iterator it =
borders.begin(); it != borders.end(); ++it) {
if (it->front() == it->back())
it->pop_back();
count += it->size();
}
SoCoordinate3* coords = new SoCoordinate3();
myBoundariesGroup->addChild(coords);
myBoundaryRoot->addChild(coords);
coords->point.setNum(count);
int32_t index = 0;
for (std::list<std::vector<unsigned long> >::iterator it =
borders.begin(); it != borders.end(); ++it) {
SoPolygon* polygon = new SoPolygon();
polygon->startIndex = index;
polygon->numVertices = it->size();
myBoundariesGroup->addChild(polygon);
myPolygons[polygon] = *it;
for (std::vector<unsigned long>::iterator jt = it->begin();
jt != it->end(); ++jt) {
p_iter.Set(*jt);
coords->point.set1Value(index++,p_iter->x,p_iter->y,p_iter->z);
}
}
}
SoNode* MeshFillHole::getPickedPolygon(const SoRayPickAction& action/*SoNode* root, const SbVec2s& pos, const SoQtViewer* viewer*/) const
{
SoPolygon* poly = 0;
const SoPickedPointList & points = action.getPickedPointList();
for (int i=0; i < points.getLength(); i++) {
const SoPickedPoint * point = points[i];
if (point && point->getPath()->getTail()->getTypeId() == MeshGui::SoPolygon::getClassTypeId()) {
// we have something picked, now check if it was an SoPolygon node
SoPolygon* node = static_cast<SoPolygon*>(point->getPath()->getTail());
if (!poly) {
poly = node;
}
// check which polygon has less edges
else if (node->numVertices.getValue() < poly->numVertices.getValue()) {
poly = node;
}
}
}
return poly;
}
float MeshFillHole::findClosestPoint(const SbLine& ray, const TBoundary& polygon,
unsigned long& vertex_index, SbVec3f& closestPoint) const
{
// now check which vertex of the polygon is closest to the ray
float minDist = FLT_MAX;
vertex_index = ULONG_MAX;
const MeshCore::MeshKernel & rMesh = myMesh->Mesh.getValue().getKernel();
const MeshCore::MeshPointArray& pts = rMesh.GetPoints();
for (TBoundary::const_iterator it = polygon.begin(); it != polygon.end(); ++it) {
SbVec3f vertex;
const Base::Vector3f& v = pts[*it];
vertex.setValue(v.x,v.y,v.z);
SbVec3f point = ray.getClosestPoint(vertex);
float distance = (vertex-point).sqrLength();
if (distance < minDist) {
minDist = distance;
vertex_index = *it;
closestPoint = vertex;
}
}
return minDist;
}
void MeshFillHole::fileHoleCallback(void * ud, SoEventCallback * n)
{
MeshFillHole* self = reinterpret_cast<MeshFillHole*>(ud);
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(n->getUserData());
const SoEvent* ev = n->getEvent();
if (ev->getTypeId() == SoLocation2Event::getClassTypeId()) {
n->setHandled();
SoRayPickAction rp(view->getViewportRegion());
rp.setPoint(ev->getPosition());
rp.setPickAll(true);
if (self->myNumPoints == 0)
rp.apply(self->myBoundariesRoot);
else
rp.apply(self->myBoundaryRoot);
SoNode* node = self->getPickedPolygon(rp);
if (node) {
std::map<SoNode*, TBoundary>::iterator it = self->myPolygons.find(node);
if (it != self->myPolygons.end()) {
// now check which vertex of the polygon is closest to the ray
unsigned long vertex_index;
SbVec3f closestPoint;
float minDist = self->findClosestPoint(rp.getLine(), it->second, vertex_index, closestPoint);
if (minDist < 1.0f) {
if (self->myNumPoints == 0)
self->myVertex->point.set1Value(0, closestPoint);
else
self->myVertex->point.set1Value(1, closestPoint);
}
}
}
}
else if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {
n->setHandled();
const SoMouseButtonEvent * mbe = static_cast<const SoMouseButtonEvent *>(ev);
if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) {
}
else if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::UP) {
if (self->myNumPoints > 1)
return;
SoRayPickAction rp(view->getViewportRegion());
rp.setPoint(ev->getPosition());
rp.setPickAll(true);
if (self->myNumPoints == 0)
rp.apply(self->myBoundariesRoot);
else
rp.apply(self->myBoundaryRoot);
SoNode* node = self->getPickedPolygon(rp);
if (node) {
std::map<SoNode*, TBoundary>::iterator it = self->myPolygons.find(node);
if (it != self->myPolygons.end()) {
// now check which vertex of the polygon is closest to the ray
unsigned long vertex_index;
SbVec3f closestPoint;
float minDist = self->findClosestPoint(rp.getLine(), it->second, vertex_index, closestPoint);
if (minDist < 1.0f) {
if (self->myNumPoints == 0) {
self->myBoundaryRoot->addChild(node);
self->myVertex->point.set1Value(0, closestPoint);
self->myNumPoints = 1;
self->myVertex1 = vertex_index;
}
else {
// myVertex2 can be equal to myVertex1 which does a full hole-filling
self->myBoundaryRoot->removeChild(node);
self->myVertex->point.set1Value(1, closestPoint);
self->myNumPoints = 2;
self->myVertex2 = vertex_index;
self->myPolygon = it->second;
QTimer::singleShot(300, self, SLOT(closeBridge()));
}
}
}
}
}
else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP) {
QMenu menu;
QAction* fin = menu.addAction(MeshFillHole::tr("Finish"));
QAction* act = menu.exec(QCursor::pos());
if (act == fin) {
QTimer::singleShot(300, self, SLOT(finishEditing()));
}
}
}
}
#include "moc_MeshEditor.cpp"

View File

@ -25,15 +25,22 @@
#include <QObject>
#include <Mod/Mesh/Gui/ViewProvider.h>
#include <boost/signals.hpp>
class SoCoordinate3;
class SoFaceSet;
class SoEventCallback;
class SoPickedPoint;
class SoQtViewer;
class SoGroup;
class SoSeparator;
class SoRayPickAction;
class SbLine;
class SbVec3f;
namespace Gui { class View3DInventor; }
namespace Mesh { class MeshObject; }
namespace Mesh { class Feature; }
namespace MeshGui {
class SoFCMeshPickNode;
@ -95,6 +102,69 @@ private:
ViewProviderFace* faceView;
};
class MeshGuiExport MeshHoleFiller
{
public:
MeshHoleFiller()
{
}
virtual ~MeshHoleFiller()
{
}
virtual bool fillHoles(Mesh::MeshObject& mesh, const std::list<std::vector<unsigned long> >& boundaries,
unsigned long v1, unsigned long v2)
{
return false;
}
};
/**
* Display data of a mesh kernel.
* \author Werner Mayer
*/
class MeshGuiExport MeshFillHole : public QObject
{
Q_OBJECT
public:
MeshFillHole(MeshHoleFiller& hf, Gui::View3DInventor* parent);
virtual ~MeshFillHole();
void startEditing(ViewProviderMesh*);
public Q_SLOTS:
void finishEditing();
private Q_SLOTS:
void closeBridge();
private:
typedef std::vector<unsigned long> TBoundary;
typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection;
static void fileHoleCallback(void * ud, SoEventCallback * n);
void createPolygons();
SoNode* getPickedPolygon(const SoRayPickAction& action) const;
float findClosestPoint(const SbLine& ray, const TBoundary& polygon,
unsigned long&, SbVec3f&) const;
void slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop);
private:
SoSeparator* myBoundariesRoot;
SoGroup* myBoundariesGroup;
SoSeparator* myBoundaryRoot;
SoSeparator* myBridgeRoot;
SoCoordinate3* myVertex;
std::map<SoNode*, TBoundary> myPolygons;
Mesh::Feature* myMesh;
int myNumPoints;
unsigned long myVertex1;
unsigned long myVertex2;
TBoundary myPolygon;
MeshHoleFiller& myHoleFiller;
Connection myConnection;
};
} // namespace MeshGui

View File

@ -0,0 +1,467 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <algorithm>
# include <climits>
# include <Inventor/SbBox2s.h>
# include <Inventor/SoPickedPoint.h>
# include <Inventor/details/SoFaceDetail.h>
# include <Inventor/events/SoLocation2Event.h>
# include <Inventor/events/SoMouseButtonEvent.h>
#endif
#include "MeshSelection.h"
#include "ViewProvider.h"
#include <Base/Console.h>
#include <Base/Tools.h>
#include <App/Application.h>
#include <App/Document.h>
#include <Gui/Application.h>
#include <Gui/Document.h>
#include <Gui/MouseSelection.h>
#include <Gui/NavigationStyle.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Mesh/App/Core/Algorithm.h>
#include <Mod/Mesh/App/Core/MeshKernel.h>
#include <Mod/Mesh/App/Core/Iterator.h>
#include <Mod/Mesh/App/Core/TopoAlgorithm.h>
#include <Mod/Mesh/App/Core/Tools.h>
using namespace MeshGui;
#define CROSS_WIDTH 16
#define CROSS_HEIGHT 16
#define CROSS_HOT_X 7
#define CROSS_HOT_Y 7
unsigned char MeshSelection::cross_bitmap[] = {
0xc0, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
0x40, 0x02, 0x40, 0x02, 0x7f, 0xfe, 0x01, 0x80,
0x01, 0x80, 0x7f, 0xfe, 0x40, 0x02, 0x40, 0x02,
0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xc0, 0x03
};
unsigned char MeshSelection::cross_mask_bitmap[] = {
0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03,
0xc0, 0x03, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xc0, 0x03,
0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03
};
MeshSelection::MeshSelection()
: onlyPointToUserTriangles(false), onlyVisibleTriangles(false), _activeCB(0)
{
}
MeshSelection::~MeshSelection()
{
if (_activeCB) {
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer)
stopInteractiveCallback(viewer);
}
}
void MeshSelection::setObjects(const std::vector<Gui::SelectionObject>& obj)
{
meshObjects = obj;
}
std::vector<App::DocumentObject*> MeshSelection::getObjects() const
{
std::vector<App::DocumentObject*> objs;
if (!meshObjects.empty()) {
for (std::vector<Gui::SelectionObject>::iterator it = meshObjects.begin(); it != meshObjects.end(); ++it) {
App::DocumentObject* obj = it->getObject();
if (obj) {
objs.push_back(obj);
}
}
}
// get all objects of the active document
else {
App::Document* doc = App::GetApplication().getActiveDocument();
if (doc)
objs = doc->getObjectsOfType(Mesh::Feature::getClassTypeId());
}
return objs;
}
std::list<ViewProviderMesh*> MeshSelection::getViewProviders() const
{
std::vector<App::DocumentObject*> objs = getObjects();
std::list<ViewProviderMesh*> vps;
for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it != objs.end(); ++it) {
if ((*it)->isDerivedFrom(Mesh::Feature::getClassTypeId())) {
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(*it);
if (vp->isVisible())
vps.push_back(static_cast<ViewProviderMesh*>(vp));
}
}
return vps;
}
Gui::View3DInventorViewer* MeshSelection::getViewer() const
{
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return 0;
Gui::MDIView* view = doc->getActiveView();
if (view && view->getTypeId().isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>(view)->getViewer();
return viewer;
}
return 0;
}
void MeshSelection::startInteractiveCallback(Gui::View3DInventorViewer* viewer,SoEventCallbackCB *cb)
{
if (this->_activeCB)
return;
viewer->setEditing(true);
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), cb, this);
this->_activeCB = cb;
}
void MeshSelection::stopInteractiveCallback(Gui::View3DInventorViewer* viewer)
{
if (!this->_activeCB)
return;
if (viewer->isEditing()) {
viewer->setEditing(false);
viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), this->_activeCB, this);
this->_activeCB = 0;
}
}
void MeshSelection::prepareBrushSelection(bool add)
{
// a rubberband to select a rectangle area of the meshes
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer) {
stopInteractiveCallback(viewer);
startInteractiveCallback(viewer, selectGLCallback);
// set cross cursor
Gui::BrushSelection* brush = new Gui::BrushSelection();
brush->setColor(1.0f,0.0f,0.0f);
brush->setLineWidth(3.0f);
viewer->navigationStyle()->startSelection(brush);
SoQtCursor::CustomCursor custom;
custom.dim.setValue(CROSS_WIDTH, CROSS_HEIGHT);
custom.hotspot.setValue(CROSS_HOT_X, CROSS_HOT_Y);
custom.bitmap = cross_bitmap;
custom.mask = cross_mask_bitmap;
viewer->setComponentCursor(SoQtCursor(&custom));
this->addToSelection = add;
}
}
void MeshSelection::startSelection()
{
prepareBrushSelection(true);
}
void MeshSelection::startDeselection()
{
prepareBrushSelection(false);
}
void MeshSelection::fullSelection()
{
// select the complete meshes
std::list<ViewProviderMesh*> views = getViewProviders();
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
std::vector<unsigned long> faces(mo->countFacets());
std::generate(faces.begin(), faces.end(), Base::iotaGen<unsigned long>(0));
(*it)->addSelection(faces);
}
}
void MeshSelection::clearSelection()
{
std::list<ViewProviderMesh*> views = getViewProviders();
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
(*it)->clearSelection();
}
}
bool MeshSelection::deleteSelection()
{
// delete all selected faces
bool selected = false;
std::list<ViewProviderMesh*> views = getViewProviders();
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
unsigned long ct = MeshCore::MeshAlgorithm(mf->Mesh.getValue().getKernel()).
CountFacetFlag(MeshCore::MeshFacet::SELECTED);
if (ct > 0) {
selected = true;
break;
}
}
if (!selected)
return false; // nothing todo
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
(*it)->deleteSelection();
}
return true;
}
void MeshSelection::invertSelection()
{
std::list<ViewProviderMesh*> views = getViewProviders();
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
const MeshCore::MeshFacetArray& faces = mo->getKernel().GetFacets();
unsigned long num_notsel = std::count_if(faces.begin(), faces.end(),
std::bind2nd(MeshCore::MeshIsNotFlag<MeshCore::MeshFacet>(),
MeshCore::MeshFacet::SELECTED));
std::vector<unsigned long> notselect;
notselect.reserve(num_notsel);
MeshCore::MeshFacetArray::_TConstIterator beg = faces.begin();
MeshCore::MeshFacetArray::_TConstIterator end = faces.end();
for (MeshCore::MeshFacetArray::_TConstIterator jt = beg; jt != end; ++jt) {
if (!jt->IsFlag(MeshCore::MeshFacet::SELECTED))
notselect.push_back(jt-beg);
}
(*it)->setSelection(notselect);
}
}
void MeshSelection::selectComponent(int size)
{
std::list<ViewProviderMesh*> views = getViewProviders();
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
std::vector<std::vector<unsigned long> > segm;
MeshCore::MeshComponents comp(mo->getKernel());
comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm);
std::vector<unsigned long> faces;
for (std::vector<std::vector<unsigned long> >::iterator jt = segm.begin(); jt != segm.end(); ++jt) {
if (jt->size() < (unsigned long)size)
faces.insert(faces.end(), jt->begin(), jt->end());
}
(*it)->addSelection(faces);
}
}
void MeshSelection::deselectComponent(int size)
{
std::list<ViewProviderMesh*> views = getViewProviders();
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
std::vector<std::vector<unsigned long> > segm;
MeshCore::MeshComponents comp(mo->getKernel());
comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm);
std::vector<unsigned long> faces;
for (std::vector<std::vector<unsigned long> >::iterator jt = segm.begin(); jt != segm.end(); ++jt) {
if (jt->size() > (unsigned long)size)
faces.insert(faces.end(), jt->begin(), jt->end());
}
(*it)->removeSelection(faces);
}
}
void MeshSelection::selectTriangle()
{
this->addToSelection = true;
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer) {
viewer->setEditingCursor(QCursor(Qt::OpenHandCursor));
stopInteractiveCallback(viewer);
startInteractiveCallback(viewer, pickFaceCallback);
}
}
void MeshSelection::deselectTriangle()
{
this->addToSelection = false;
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer) {
viewer->setEditingCursor(QCursor(Qt::OpenHandCursor));
stopInteractiveCallback(viewer);
startInteractiveCallback(viewer, pickFaceCallback);
}
}
void MeshSelection::setCheckOnlyPointToUserTriangles(bool on)
{
onlyPointToUserTriangles = on;
}
void MeshSelection::setCheckOnlyVisibleTriangles(bool on)
{
onlyVisibleTriangles = on;
}
void MeshSelection::setAddComponentOnClick(bool on)
{
addComponent = on;
}
void MeshSelection::setRemoveComponentOnClick(bool on)
{
removeComponent = on;
}
void MeshSelection::selectGLCallback(void * ud, SoEventCallback * n)
{
// When this callback function is invoked we must leave the edit mode
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(n->getUserData());
MeshSelection* self = reinterpret_cast<MeshSelection*>(ud);
self->stopInteractiveCallback(view);
n->setHandled();
std::vector<SbVec2f> polygon = view->getGLPolygon();
if (polygon.size() < 3)
return;
if (polygon.front() != polygon.back())
polygon.push_back(polygon.front());
SbVec3f pnt, dir;
view->getNearPlane(pnt, dir);
Base::Vector3f point (pnt[0],pnt[1],pnt[2]);
Base::Vector3f normal(dir[0],dir[1],dir[2]);
std::list<ViewProviderMesh*> views = self->getViewProviders();
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
ViewProviderMesh* vp = static_cast<ViewProviderMesh*>(*it);
std::vector<unsigned long> faces;
const Mesh::MeshObject& mesh = static_cast<Mesh::Feature*>((*it)->getObject())->Mesh.getValue();
const MeshCore::MeshKernel& kernel = mesh.getKernel();
// simply get all triangles under the polygon
vp->getFacetsFromPolygon(polygon, *view, true, faces);
if (self->onlyVisibleTriangles) {
const SbVec2s& sz = view->getViewportRegion().getWindowSize();
short width,height; sz.getValue(width,height);
std::vector<SbVec2s> pixelPoly = view->getPolygon();
SbBox2s rect;
for (std::vector<SbVec2s>::iterator it = pixelPoly.begin(); it != pixelPoly.end(); ++it) {
const SbVec2s& p = *it;
rect.extendBy(SbVec2s(p[0],height-p[1]));
}
std::vector<unsigned long> rf; rf.swap(faces);
std::vector<unsigned long> vf = vp->getVisibleFacetsAfterZoom
(rect, view->getViewportRegion(), view->getCamera());
// get common facets of the viewport and the visible one
std::sort(vf.begin(), vf.end());
std::sort(rf.begin(), rf.end());
std::back_insert_iterator<std::vector<unsigned long> > biit(faces);
std::set_intersection(vf.begin(), vf.end(), rf.begin(), rf.end(), biit);
}
// if set filter out all triangles which do not point into user direction
if (self->onlyPointToUserTriangles) {
std::vector<unsigned long> screen;
screen.reserve(faces.size());
MeshCore::MeshFacetIterator it_f(kernel);
for (std::vector<unsigned long>::iterator it = faces.begin(); it != faces.end(); ++it) {
it_f.Set(*it);
if (it_f->GetNormal() * normal > 0.0f) {
screen.push_back(*it);
}
}
faces.swap(screen);
}
if (self->addToSelection)
vp->addSelection(faces);
else
vp->removeSelection(faces);
}
view->render();
}
void MeshSelection::pickFaceCallback(void * ud, SoEventCallback * n)
{
// handle only mouse button events
if (n->getEvent()->isOfType(SoMouseButtonEvent::getClassTypeId())) {
const SoMouseButtonEvent * mbe = static_cast<const SoMouseButtonEvent*>(n->getEvent());
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(n->getUserData());
// Mark all incoming mouse button events as handled, especially, to deactivate the selection node
n->getAction()->setHandled();
if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) {
const SoPickedPoint * point = n->getPickedPoint();
if (point == NULL) {
Base::Console().Message("No facet picked.\n");
return;
}
n->setHandled();
// By specifying the indexed mesh node 'pcFaceSet' we make sure that the picked point is
// really from the mesh we render and not from any other geometry
Gui::ViewProvider* vp = static_cast<Gui::ViewProvider*>(view->getViewProviderByPath(point->getPath()));
if (!vp || !vp->getTypeId().isDerivedFrom(ViewProviderMesh::getClassTypeId()))
return;
ViewProviderMesh* mesh = static_cast<ViewProviderMesh*>(vp);
MeshSelection* self = reinterpret_cast<MeshSelection*>(ud);
std::list<ViewProviderMesh*> views = self->getViewProviders();
if (std::find(views.begin(), views.end(), mesh) == views.end())
return;
const SoDetail* detail = point->getDetail(/*mesh->getShapeNode()*/);
if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) {
// get the boundary to the picked facet
unsigned long uFacet = static_cast<const SoFaceDetail*>(detail)->getFaceIndex();
if (self->addToSelection) {
if (self->addComponent)
mesh->selectComponent(uFacet);
else
mesh->selectFacet(uFacet);
}
else {
if (self->removeComponent)
mesh->deselectComponent(uFacet);
else
mesh->deselectFacet(uFacet);
}
}
}
}
}

View File

@ -0,0 +1,89 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MESHGUI_MESHSELECTION_H
#define MESHGUI_MESHSELECTION_H
#include <vector>
#include <QWidget>
#include <Inventor/nodes/SoEventCallback.h>
#include <Gui/SelectionObject.h>
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/TaskView/TaskView.h>
namespace Gui {
class View3DInventorViewer;
}
namespace MeshGui {
class ViewProviderMesh;
class MeshGuiExport MeshSelection
{
public:
MeshSelection();
~MeshSelection();
void startSelection();
void startDeselection();
bool deleteSelection();
void fullSelection();
void clearSelection();
void invertSelection();
void selectComponent(int);
void deselectComponent(int);
void selectTriangle();
void deselectTriangle();
void setCheckOnlyPointToUserTriangles(bool);
void setCheckOnlyVisibleTriangles(bool);
void setAddComponentOnClick(bool);
void setRemoveComponentOnClick(bool);
void setObjects(const std::vector<Gui::SelectionObject>&);
std::vector<App::DocumentObject*> getObjects() const;
private:
std::list<ViewProviderMesh*> getViewProviders() const;
Gui::View3DInventorViewer* getViewer() const;
void startInteractiveCallback(Gui::View3DInventorViewer* viewer,SoEventCallbackCB *cb);
void stopInteractiveCallback(Gui::View3DInventorViewer* viewer);
void prepareBrushSelection(bool);
static void selectGLCallback(void * ud, SoEventCallback * n);
static void pickFaceCallback(void * ud, SoEventCallback * n);
private:
bool onlyPointToUserTriangles, onlyVisibleTriangles;
bool addToSelection, addComponent, removeComponent;
SoEventCallbackCB *_activeCB;
mutable std::vector<Gui::SelectionObject> meshObjects;
static unsigned char cross_bitmap[];
static unsigned char cross_mask_bitmap[];
};
}
#endif // MESHGUI_MESHSELECTION_H

View File

@ -27,12 +27,19 @@
# include <algorithm>
# include <climits>
# include <boost/bind.hpp>
# include <QEventLoop>
# include <QImage>
# include <QPushButton>
# include <Inventor/SbBox2s.h>
# include <Inventor/SoPickedPoint.h>
# include <Inventor/details/SoFaceDetail.h>
# include <Inventor/events/SoLocation2Event.h>
# include <Inventor/events/SoMouseButtonEvent.h>
# include <Inventor/nodes/SoAnnotation.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoOrthographicCamera.h>
# include <Inventor/nodes/SoTranslation.h>
# include <Inventor/nodes/SoImage.h>
#endif
#include "RemoveComponents.h"
@ -42,9 +49,12 @@
#include <Base/Tools.h>
#include <App/Application.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Document.h>
#include <Gui/Selection.h>
#include <Gui/SoFCSelectionAction.h>
#include <Gui/MouseSelection.h>
#include <Gui/NavigationStyle.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Mod/Mesh/App/MeshFeature.h>
@ -56,26 +66,9 @@
using namespace MeshGui;
#define CROSS_WIDTH 16
#define CROSS_HEIGHT 16
#define CROSS_HOT_X 7
#define CROSS_HOT_Y 7
static unsigned char cross_bitmap[] = {
0xc0, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
0x40, 0x02, 0x40, 0x02, 0x7f, 0xfe, 0x01, 0x80,
0x01, 0x80, 0x7f, 0xfe, 0x40, 0x02, 0x40, 0x02,
0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xc0, 0x03
};
static unsigned char cross_mask_bitmap[] = {
0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,
0xc0,0x03
};
RemoveComponents::RemoveComponents(QWidget* parent, Qt::WFlags fl)
: QWidget(parent, fl), _interactiveMode(0)
: QWidget(parent, fl)
{
ui = new Ui_RemoveComponents;
ui->setupUi(this);
@ -83,6 +76,9 @@ RemoveComponents::RemoveComponents(QWidget* parent, Qt::WFlags fl)
ui->spSelectComp->setValue(10);
ui->spDeselectComp->setRange(1, INT_MAX);
ui->spDeselectComp->setValue(10);
meshSel.setCheckOnlyVisibleTriangles(ui->visibleTriangles->isChecked());
meshSel.setCheckOnlyPointToUserTriangles(ui->screenTriangles->isChecked());
}
RemoveComponents::~RemoveComponents()
@ -101,372 +97,266 @@ void RemoveComponents::changeEvent(QEvent *e)
void RemoveComponents::on_selectRegion_clicked()
{
// a rubberband to select a rectangle area of the meshes
this->selectRegion = true;
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer) {
stopInteractiveCallback(viewer);
startInteractiveCallback(viewer, selectGLCallback);
// set cross cursor
viewer->startSelection(Gui::View3DInventorViewer::Lasso);
SoQtCursor::CustomCursor custom;
custom.dim.setValue(CROSS_WIDTH, CROSS_HEIGHT);
custom.hotspot.setValue(CROSS_HOT_X, CROSS_HOT_Y);
custom.bitmap = cross_bitmap;
custom.mask = cross_mask_bitmap;
viewer->setComponentCursor(SoQtCursor(&custom));
}
meshSel.startSelection();
}
void RemoveComponents::on_deselectRegion_clicked()
{
// a rubberband to deselect a rectangle area of the meshes
this->selectRegion = false;
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer) {
stopInteractiveCallback(viewer);
startInteractiveCallback(viewer, selectGLCallback);
// set cross cursor
viewer->startSelection(Gui::View3DInventorViewer::Lasso);
SoQtCursor::CustomCursor custom;
custom.dim.setValue(CROSS_WIDTH, CROSS_HEIGHT);
custom.hotspot.setValue(CROSS_HOT_X, CROSS_HOT_Y);
custom.bitmap = cross_bitmap;
custom.mask = cross_mask_bitmap;
viewer->setComponentCursor(SoQtCursor(&custom));
}
meshSel.startDeselection();
}
void RemoveComponents::on_selectAll_clicked()
{
// select the complete meshes
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return;
std::list<ViewProviderMesh*> views = getViewProviders(doc);
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
std::vector<unsigned long> faces(mo->countFacets());
std::generate(faces.begin(), faces.end(), Base::iotaGen<unsigned long>(0));
(*it)->addSelection(faces);
}
meshSel.fullSelection();
}
void RemoveComponents::on_deselectAll_clicked()
{
// deselect all meshes
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return;
std::list<ViewProviderMesh*> views = getViewProviders(doc);
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
(*it)->clearSelection();
}
meshSel.clearSelection();
}
void RemoveComponents::on_selectComponents_clicked()
{
// select components upto a certain size
int size = ui->spSelectComp->value();
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return;
std::list<ViewProviderMesh*> views = getViewProviders(doc);
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
std::vector<std::vector<unsigned long> > segm;
MeshCore::MeshComponents comp(mo->getKernel());
comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm);
std::vector<unsigned long> faces;
for (std::vector<std::vector<unsigned long> >::iterator jt = segm.begin(); jt != segm.end(); ++jt) {
if (jt->size() < (unsigned long)size)
faces.insert(faces.end(), jt->begin(), jt->end());
}
(*it)->addSelection(faces);
}
meshSel.selectComponent(size);
}
void RemoveComponents::on_deselectComponents_clicked()
{
// deselect components from a certain size on
int size = ui->spDeselectComp->value();
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return;
std::list<ViewProviderMesh*> views = getViewProviders(doc);
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
meshSel.deselectComponent(size);
}
std::vector<std::vector<unsigned long> > segm;
MeshCore::MeshComponents comp(mo->getKernel());
comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm);
std::vector<unsigned long> faces;
for (std::vector<std::vector<unsigned long> >::iterator jt = segm.begin(); jt != segm.end(); ++jt) {
if (jt->size() > (unsigned long)size)
faces.insert(faces.end(), jt->begin(), jt->end());
}
(*it)->removeSelection(faces);
}
void RemoveComponents::on_visibleTriangles_toggled(bool on)
{
meshSel.setCheckOnlyVisibleTriangles(on);
}
void RemoveComponents::on_screenTriangles_toggled(bool on)
{
meshSel.setCheckOnlyPointToUserTriangles(on);
}
void RemoveComponents::on_cbSelectComp_toggled(bool on)
{
meshSel.setAddComponentOnClick(on);
}
void RemoveComponents::on_cbDeselectComp_toggled(bool on)
{
meshSel.setRemoveComponentOnClick(on);
}
void RemoveComponents::deleteSelection()
{
// delete all selected faces
bool selected = false;
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return;
std::list<ViewProviderMesh*> views = getViewProviders(doc);
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
unsigned long ct = MeshCore::MeshAlgorithm(mf->Mesh.getValue().getKernel()).
CountFacetFlag(MeshCore::MeshFacet::SELECTED);
if (ct > 0) {
selected = true;
break;
}
}
if (!selected) return; // nothing todo
// delete all selected faces
doc->openCommand("Delete selection");
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
(*it)->deleteSelection();
}
doc->commitCommand();
bool ok = meshSel.deleteSelection();
if (!ok)
doc->abortCommand();
else
doc->commitCommand();
}
void RemoveComponents::invertSelection()
{
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return;
std::list<ViewProviderMesh*> views = getViewProviders(doc);
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
const MeshCore::MeshFacetArray& faces = mo->getKernel().GetFacets();
unsigned long num_notsel = std::count_if(faces.begin(), faces.end(),
std::bind2nd(MeshCore::MeshIsNotFlag<MeshCore::MeshFacet>(),
MeshCore::MeshFacet::SELECTED));
std::vector<unsigned long> notselect;
notselect.reserve(num_notsel);
MeshCore::MeshFacetArray::_TConstIterator beg = faces.begin();
MeshCore::MeshFacetArray::_TConstIterator end = faces.end();
for (MeshCore::MeshFacetArray::_TConstIterator jt = beg; jt != end; ++jt) {
if (!jt->IsFlag(MeshCore::MeshFacet::SELECTED))
notselect.push_back(jt-beg);
}
(*it)->setSelection(notselect);
}
meshSel.invertSelection();
}
void RemoveComponents::on_selectTriangle_clicked()
{
// a rubberband to select a rectangle area of the meshes
this->selectRegion = true;
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer) {
stopInteractiveCallback(viewer);
startInteractiveCallback(viewer, pickFaceCallback);
}
meshSel.selectTriangle();
meshSel.setAddComponentOnClick(ui->cbSelectComp->isChecked());
}
void RemoveComponents::on_deselectTriangle_clicked()
{
// a rubberband to select a rectangle area of the meshes
this->selectRegion = false;
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer) {
stopInteractiveCallback(viewer);
startInteractiveCallback(viewer, pickFaceCallback);
}
meshSel.deselectTriangle();
meshSel.setRemoveComponentOnClick(ui->cbDeselectComp->isChecked());
}
void RemoveComponents::reject()
{
if (_interactiveMode) {
Gui::View3DInventorViewer* viewer = this->getViewer();
if (viewer)
stopInteractiveCallback(viewer);
}
on_deselectAll_clicked();
// deselect all meshes
meshSel.clearSelection();
}
std::list<ViewProviderMesh*> RemoveComponents::getViewProviders(const Gui::Document* doc) const
void RemoveComponents::paintSelection()
{
std::list<ViewProviderMesh*> vps;
std::vector<Mesh::Feature*> mesh = doc->getDocument()->getObjectsOfType<Mesh::Feature>();
for (std::vector<Mesh::Feature*>::iterator it = mesh.begin(); it != mesh.end(); ++it) {
Gui::ViewProvider* vp = doc->getViewProvider(*it);
if (vp->isVisible())
vps.push_back(static_cast<ViewProviderMesh*>(vp));
}
return vps;
#if 0
SoAnnotation* hudRoot = new SoAnnotation;
hudRoot->ref();
SoOrthographicCamera* hudCam = new SoOrthographicCamera();
hudCam->viewportMapping = SoCamera::LEAVE_ALONE;
// Set the position in the window.
// [0, 0] is in the center of the screen.
//
SoTranslation* hudTrans = new SoTranslation;
hudTrans->translation.setValue(-1.0f, -1.0f, 0.0f);
QImage image(100,100,QImage::Format_ARGB32_Premultiplied);
image.fill(0x00000000);
SoSFImage sfimage;
Gui::BitmapFactory().convert(image, sfimage);
SoImage* hudImage = new SoImage();
hudImage->image = sfimage;
// Assemble the parts...
//
hudRoot->addChild(hudCam);
hudRoot->addChild(hudTrans);
hudRoot->addChild(hudImage);
Gui::View3DInventorViewer* viewer = this->getViewer();
static_cast<SoGroup*>(viewer->getSceneGraph())->addChild(hudRoot);
QWidget* gl = viewer->getGLWidget();
DrawingPlane pln(hudImage->image, viewer, gl);
gl->installEventFilter(&pln);
QEventLoop loop;
QObject::connect(&pln, SIGNAL(emitSelection()), &loop, SLOT(quit()));
loop.exec();
static_cast<SoGroup*>(viewer->getSceneGraph())->removeChild(hudRoot);
#endif
}
Gui::View3DInventorViewer* RemoveComponents::getViewer() const
// ---------------------------------------
DrawingPlane::DrawingPlane(SoSFImage& data, SoQtViewer* s, QWidget* view)
: QObject(), data(data), glView(view), soqt(s), image(view->size(), QImage::Format_ARGB32)
{
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return 0;
Gui::MDIView* view = doc->getActiveView();
if (view && view->getTypeId().isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>(view)->getViewer();
return viewer;
}
image.fill(qRgba(255, 255, 255, 0));
myPenWidth = 50;
return 0;
QRgb p = qRgba(255,255,0,0);
int q = ((p << 16) & 0xff0000) | ((p >> 16) & 0xff) | (p & 0xff00ff00);
int r = qRed(q);
int g = qGreen(q);
int b = qBlue(q);
myPenColor = qRgb(r,g,b);//Qt::yellow;
myRadius = 5.0f;
}
void RemoveComponents::startInteractiveCallback(Gui::View3DInventorViewer* viewer,SoEventCallbackCB *cb)
DrawingPlane::~DrawingPlane()
{
if (this->_interactiveMode)
return;
viewer->setEditing(true);
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), cb, this);
this->_interactiveMode = cb;
}
void RemoveComponents::stopInteractiveCallback(Gui::View3DInventorViewer* viewer)
void DrawingPlane::changeRadius(double radius)
{
if (!this->_interactiveMode)
return;
if (viewer->isEditing()) {
viewer->setEditing(false);
viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), this->_interactiveMode, this);
this->_interactiveMode = 0;
}
}
this->myRadius = (double)radius;
}
void RemoveComponents::selectGLCallback(void * ud, SoEventCallback * n)
{
// When this callback function is invoked we must leave the edit mode
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(n->getUserData());
RemoveComponents* that = reinterpret_cast<RemoveComponents*>(ud);
that->stopInteractiveCallback(view);
n->setHandled();
std::vector<SbVec2f> polygon = view->getGLPolygon();
if (polygon.size() < 3)
return;
if (polygon.front() != polygon.back())
polygon.push_back(polygon.front());
void DrawingPlane::mousePressEvent(QMouseEvent *event)
{
// Calculate the given radius from mm into px
const SbViewportRegion& vp = soqt->getViewportRegion();
float fRatio = vp.getViewportAspectRatio();
const SbVec2s& sp = vp.getViewportSizePixels();
float dX, dY; vp.getViewportSize().getValue(dX, dY);
SbViewVolume vv = soqt->getCamera()->getViewVolume(fRatio);
SbVec3f p1(0,0,0);
SbVec3f p2(0,this->myRadius,0);
vv.projectToScreen(p1, p1);
vv.projectToScreen(p2, p2);
if (fRatio > 1.0f) {
p1[0] = (p1[0] - 0.5f*dX) / fRatio + 0.5f*dX;
p2[0] = (p2[0] - 0.5f*dX) / fRatio + 0.5f*dX;
}
else if (fRatio < 1.0f) {
p1[1] = (p1[1] - 0.5f*dY) * fRatio + 0.5f*dY;
p2[1] = (p2[1] - 0.5f*dY) * fRatio + 0.5f*dY;
}
SbVec3f pnt, dir;
view->getNearPlane(pnt, dir);
Base::Vector3f point (pnt[0],pnt[1],pnt[2]);
Base::Vector3f normal(dir[0],dir[1],dir[2]);
int x1 = p1[0] * sp[0];
int y1 = p1[1] * sp[1];
int x2 = p2[0] * sp[0];
int y2 = p2[1] * sp[1];
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return;
std::list<ViewProviderMesh*> views = that->getViewProviders(doc);
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
ViewProviderMesh* vp = static_cast<ViewProviderMesh*>(*it);
//myPenWidth = 2*abs(y1-y2);
if (event->button() == Qt::LeftButton) {
lastPoint = event->pos();
scribbling = true;
}
}
void DrawingPlane::mouseMoveEvent(QMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton) && scribbling) {
const QPoint& pos = event->pos();
drawLineTo(pos);
std::vector<unsigned long> faces;
const Mesh::MeshObject& mesh = static_cast<Mesh::Feature*>((*it)->getObject())->Mesh.getValue();
const MeshCore::MeshKernel& kernel = mesh.getKernel();
// simply get all triangles under the polygon
vp->getFacetsFromPolygon(polygon, *view, true, faces);
if (that->ui->frontTriangles->isChecked()) {
const SbVec2s& sz = view->getViewportRegion().getWindowSize();
short width,height; sz.getValue(width,height);
std::vector<SbVec2s> pixelPoly = view->getPolygon();
SbBox2s rect;
for (std::vector<SbVec2s>::iterator it = pixelPoly.begin(); it != pixelPoly.end(); ++it) {
const SbVec2s& p = *it;
rect.extendBy(SbVec2s(p[0],height-p[1]));
}
std::vector<unsigned long> rf; rf.swap(faces);
std::vector<unsigned long> vf = vp->getVisibleFacetsAfterZoom
(rect, view->getViewportRegion(), view->getCamera());
// get common facets of the viewport and the visible one
std::sort(vf.begin(), vf.end());
std::sort(rf.begin(), rf.end());
std::back_insert_iterator<std::vector<unsigned long> > biit(faces);
std::set_intersection(vf.begin(), vf.end(), rf.begin(), rf.end(), biit);
}
// if set filter out all triangles which do not point into user direction
if (that->ui->screenTriangles->isChecked()) {
std::vector<unsigned long> screen;
screen.reserve(faces.size());
MeshCore::MeshFacetIterator it_f(kernel);
for (std::vector<unsigned long>::iterator it = faces.begin(); it != faces.end(); ++it) {
it_f.Set(*it);
if (it_f->GetNormal() * normal > 0.0f) {
screen.push_back(*it);
}
}
faces.swap(screen);
}
if (that->selectRegion)
vp->addSelection(faces);
else
vp->removeSelection(faces);
}
view->render();
}
void RemoveComponents::pickFaceCallback(void * ud, SoEventCallback * n)
{
// handle only mouse button events
if (n->getEvent()->isOfType(SoMouseButtonEvent::getClassTypeId())) {
const SoMouseButtonEvent * mbe = static_cast<const SoMouseButtonEvent*>(n->getEvent());
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(n->getUserData());
// Mark all incoming mouse button events as handled, especially, to deactivate the selection node
n->getAction()->setHandled();
if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) {
const SoPickedPoint * point = n->getPickedPoint();
if (point == NULL) {
Base::Console().Message("No facet picked.\n");
return;
}
n->setHandled();
// By specifying the indexed mesh node 'pcFaceSet' we make sure that the picked point is
// really from the mesh we render and not from any other geometry
Gui::ViewProvider* vp = static_cast<Gui::ViewProvider*>(view->getViewProviderByPath(point->getPath()));
if (!vp || !vp->getTypeId().isDerivedFrom(ViewProviderMesh::getClassTypeId()))
return;
ViewProviderMesh* that = static_cast<ViewProviderMesh*>(vp);
RemoveComponents* dlg = reinterpret_cast<RemoveComponents*>(ud);
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (!doc) return;
std::list<ViewProviderMesh*> views = dlg->getViewProviders(doc);
if (std::find(views.begin(), views.end(), that) == views.end())
return;
const SoDetail* detail = point->getDetail(/*that->getShapeNode()*/);
if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) {
// get the boundary to the picked facet
unsigned long uFacet = static_cast<const SoFaceDetail*>(detail)->getFaceIndex();
std::vector<unsigned long> faces; faces.push_back(uFacet);
if (dlg->selectRegion) {
if (dlg->ui->cbSelectComp->isChecked())
that->selectComponent(uFacet);
else
that->selectFacet(uFacet);
}
else {
if (dlg->ui->cbDeselectComp->isChecked())
that->deselectComponent(uFacet);
else
that->removeSelection(faces);
}
}
// filter out some points
if (selection.isEmpty()) {
selection << pos;
}
else {
const QPoint& top = selection.last();
if (abs(top.x()-pos.x()) > 20 ||
abs(top.y()-pos.y()) > 20)
selection << pos;
}
}
}
// ---------------------------------------
void DrawingPlane::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && scribbling) {
drawLineTo(event->pos());
scribbling = false;
/*emit*/ emitSelection();
}
}
bool DrawingPlane::eventFilter(QObject* o, QEvent* e)
{
if (o == glView) {
if (e->type() == QEvent::Resize)
resizeEvent(static_cast<QResizeEvent*>(e));
else if (e->type() == QEvent::MouseButtonPress)
mousePressEvent(static_cast<QMouseEvent*>(e));
else if (e->type() == QEvent::MouseButtonRelease)
mouseReleaseEvent(static_cast<QMouseEvent*>(e));
else if (e->type() == QEvent::MouseMove)
mouseMoveEvent(static_cast<QMouseEvent*>(e));
}
return false;
}
void DrawingPlane::resizeEvent(QResizeEvent *event)
{
QImage img(event->size(), QImage::Format_ARGB32);
img.fill(qRgba(255, 255, 255, 0));
image = img;
}
void DrawingPlane::drawLineTo(const QPoint &endPoint)
{
QPainter painter(&image);
painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap,
Qt::RoundJoin));
painter.setOpacity(0.5);
painter.drawLine(lastPoint.x(), image.height()-lastPoint.y(), endPoint.x(), image.height()-endPoint.y());
QImage img = image;//QGLWidget::convertToGLFormat(image);
int nc = img.numBytes() / ( img.width() * img.height() );
data.setValue(SbVec2s(img.width(), img.height()), nc, img.bits());
soqt->scheduleRedraw();
lastPoint = endPoint;
}
// -------------------------------------------------
RemoveComponentsDialog::RemoveComponentsDialog(QWidget* parent, Qt::WFlags fl)
: QDialog(parent, fl)

View File

@ -25,12 +25,14 @@
#define MESHGUI_REMOVECOMPONENTS_H
#include <QDialog>
#include <Inventor/nodes/SoEventCallback.h>
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/TaskView/TaskView.h>
#include "MeshSelection.h"
// forward declarations
class SoEventCallback;
class SoNode;
class SoQtViewer;
class SoSFImage;
namespace App { class DocumentObject; }
namespace Gui { class View3DInventorViewer; }
namespace Gui { class Document; }
@ -40,6 +42,42 @@ namespace MeshGui {
class ViewProviderMesh;
class Ui_RemoveComponents;
class DrawingPlane : public QObject
{
Q_OBJECT
public:
DrawingPlane(SoSFImage&, SoQtViewer*, QWidget* view);
virtual ~DrawingPlane();
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void resizeEvent(QResizeEvent *event);
bool eventFilter(QObject* o, QEvent* e);
protected Q_SLOTS:
void changeRadius(double);
Q_SIGNALS:
void emitSelection();
private:
void drawLineTo(const QPoint &endPoint);
bool scribbling;
int myPenWidth;
float myRadius;
QColor myPenColor;
QPoint lastPoint;
QList<QPoint> selection;
QImage image;
SoSFImage& data;
SoQtViewer* soqt;
QWidget* glView;
};
/**
* Non-modal dialog to de/select components, regions, the complete or single faces
* of a mesh and delete them.
@ -65,23 +103,18 @@ public Q_SLOTS:
void on_deselectAll_clicked();
void on_deselectComponents_clicked();
void on_deselectTriangle_clicked();
void on_visibleTriangles_toggled(bool);
void on_screenTriangles_toggled(bool);
void on_cbSelectComp_toggled(bool);
void on_cbDeselectComp_toggled(bool);
protected:
void changeEvent(QEvent *e);
private:
std::list<ViewProviderMesh*> getViewProviders(const Gui::Document*) const;
Gui::View3DInventorViewer* getViewer() const;
void startInteractiveCallback(Gui::View3DInventorViewer* ,SoEventCallbackCB *);
void stopInteractiveCallback(Gui::View3DInventorViewer*);
static void selectGLCallback(void * ud, SoEventCallback * n);
static void pickFaceCallback(void * ud, SoEventCallback * n);
void paintSelection();
private:
Ui_RemoveComponents* ui;
SoEventCallbackCB *_interactiveMode;
bool selectRegion;
MeshSelection meshSel;
};
/**

View File

@ -193,12 +193,12 @@
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QCheckBox" name="frontTriangles">
<widget class="QCheckBox" name="visibleTriangles">
<property name="text">
<string>Respect only visible triangles</string>
</property>
<property name="checked">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
@ -207,6 +207,9 @@
<property name="text">
<string>Respect only triangles with normals facing screen</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>

View File

@ -0,0 +1,108 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include "Selection.h"
#include "ui_Selection.h"
using namespace MeshGui;
/* TRANSLATOR MeshGui::Selection */
Selection::Selection(QWidget* parent)
: QWidget(parent), ui(new Ui_Selection())
{
ui->setupUi(this);
ui->addSelection->installEventFilter(this);
ui->clearSelection->installEventFilter(this);
meshSel.setCheckOnlyVisibleTriangles(ui->visibleTriangles->isChecked());
meshSel.setCheckOnlyPointToUserTriangles(ui->screenTriangles->isChecked());
}
/*
* Destroys the object and frees any allocated resources
*/
Selection::~Selection()
{
// no need to delete child widgets, Qt does it all for us
delete ui;
meshSel.clearSelection();
}
void Selection::setObjects(const std::vector<Gui::SelectionObject>& o)
{
meshSel.setObjects(o);
}
std::vector<App::DocumentObject*> Selection::getObjects() const
{
return meshSel.getObjects();
}
bool Selection::eventFilter(QObject* o, QEvent* e)
{
if (e->type() == QEvent::HoverEnter) {
if (o == ui->addSelection) {
ui->label->setText(tr("Use a brush tool to select the area"));
}
else if (o == ui->clearSelection) {
ui->label->setText(tr("Clears completely the selected area"));
}
}
else if (e->type() == QEvent::HoverLeave) {
if (o == ui->addSelection) {
ui->label->clear();
}
else if (o == ui->clearSelection) {
ui->label->clear();
}
}
return false;
}
void Selection::on_addSelection_clicked()
{
meshSel.startSelection();
}
void Selection::on_clearSelection_clicked()
{
meshSel.clearSelection();
}
void Selection::on_visibleTriangles_toggled(bool on)
{
meshSel.setCheckOnlyVisibleTriangles(on);
}
void Selection::on_screenTriangles_toggled(bool on)
{
meshSel.setCheckOnlyPointToUserTriangles(on);
}
#include "moc_Selection.cpp"

View File

@ -0,0 +1,62 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MESHGUI_SELECTION_H
#define MESHGUI_SELECTION_H
#include <vector>
#include <QWidget>
#include <Inventor/nodes/SoEventCallback.h>
#include <Gui/SelectionObject.h>
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/TaskView/TaskView.h>
#include "MeshSelection.h"
namespace MeshGui {
class Ui_Selection;
class Selection : public QWidget
{
Q_OBJECT
public:
Selection(QWidget* parent = 0);
~Selection();
void setObjects(const std::vector<Gui::SelectionObject>&);
std::vector<App::DocumentObject*> getObjects() const;
bool eventFilter(QObject*, QEvent*);
private Q_SLOTS:
void on_addSelection_clicked();
void on_clearSelection_clicked();
void on_visibleTriangles_toggled(bool);
void on_screenTriangles_toggled(bool);
private:
MeshSelection meshSel;
Ui_Selection* ui;
};
}
#endif // MESHGUI_SELECTION_H

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MeshGui::Selection</class>
<widget class="QWidget" name="MeshGui::Selection">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>143</height>
</rect>
</property>
<property name="windowTitle">
<string>Selection</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Selection</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QPushButton" name="addSelection">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="clearSelection">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QCheckBox" name="visibleTriangles">
<property name="text">
<string>Respect only visible triangles</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QCheckBox" name="screenTriangles">
<property name="text">
<string>Respect only triangles with normals facing screen</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,175 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# ifdef FC_OS_WIN32
# include <windows.h>
# endif
# ifdef FC_OS_MACOSX
# include <OpenGL/gl.h>
# else
# include <GL/gl.h>
# endif
# include <float.h>
# include <algorithm>
# include <Inventor/actions/SoCallbackAction.h>
# include <Inventor/actions/SoGetBoundingBoxAction.h>
# include <Inventor/actions/SoGetPrimitiveCountAction.h>
# include <Inventor/actions/SoGLRenderAction.h>
# include <Inventor/actions/SoPickAction.h>
# include <Inventor/actions/SoWriteAction.h>
# include <Inventor/bundles/SoMaterialBundle.h>
# include <Inventor/bundles/SoTextureCoordinateBundle.h>
# include <Inventor/elements/SoGLCacheContextElement.h>
# include <Inventor/errors/SoReadError.h>
# include <Inventor/misc/SoState.h>
#endif
# include <Inventor/elements/SoCoordinateElement.h>
# include <float.h>
#include "SoPolygon.h"
using namespace MeshGui;
SO_NODE_SOURCE(SoPolygon);
void SoPolygon::initClass()
{
SO_NODE_INIT_CLASS(SoPolygon, SoShape, "Shape");
}
SoPolygon::SoPolygon()
{
SO_NODE_CONSTRUCTOR(SoPolygon);
SO_NODE_ADD_FIELD(startIndex, (0));
SO_NODE_ADD_FIELD(numVertices, (0));
SO_NODE_ADD_FIELD(highlight, (FALSE));
SO_NODE_ADD_FIELD(render, (TRUE));
}
/**
* Renders the polygon.
*/
void SoPolygon::GLRender(SoGLRenderAction *action)
{
if (shouldGLRender(action) && render.getValue())
{
SoState* state = action->getState();
const SoCoordinateElement * coords = SoCoordinateElement::getInstance(state);
if (!coords) return;
const SbVec3f * points = coords->getArrayPtr3();
if (!points) return;
SoMaterialBundle mb(action);
SoTextureCoordinateBundle tb(action, TRUE, FALSE);
SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
mb.sendFirst(); // make sure we have the correct material
int32_t len = coords->getNum();
drawPolygon(points, len);
}
}
/**
* Renders the polygon.
*/
void SoPolygon::drawPolygon(const SbVec3f * points,int32_t len) const
{
glLineWidth(3.0f);
int32_t beg = startIndex.getValue();
int32_t cnt = numVertices.getValue();
int32_t end = beg + cnt;
if (end > len)
return; // wrong setup, too few points
// draw control mesh
glBegin(GL_LINES);
for (int32_t i = beg; i < end; ++i) {
int32_t j = (i-beg+1) % cnt + beg;
glVertex3fv(points[i].getValue());
glVertex3fv(points[j].getValue());
}
glEnd();
}
/**
* Calculates picked point based on primitives generated by subclasses.
*/
void
SoPolygon::rayPick(SoRayPickAction * action)
{
//if (this->shouldRayPick(action)) {
// this->computeObjectSpaceRay(action);
// const SoBoundingBoxCache* bboxcache = getBoundingBoxCache();
// if (!bboxcache || !bboxcache->isValid(action->getState()) ||
// SoFCMeshObjectShape_ray_intersect(action, bboxcache->getProjectedBox())) {
// this->generatePrimitives(action);
// }
//}
inherited::rayPick(action);
}
void SoPolygon::generatePrimitives(SoAction* action)
{
}
/**
* Sets the bounding box of the mesh to \a box and its center to \a center.
*/
void SoPolygon::computeBBox(SoAction *action, SbBox3f &box, SbVec3f &center)
{
SoState* state = action->getState();
const SoCoordinateElement * coords = SoCoordinateElement::getInstance(state);
if (!coords) return;
const SbVec3f * points = coords->getArrayPtr3();
if (!points) return;
float maxX=-FLT_MAX, minX=FLT_MAX,
maxY=-FLT_MAX, minY=FLT_MAX,
maxZ=-FLT_MAX, minZ=FLT_MAX;
int32_t len = coords->getNum();
int32_t beg = startIndex.getValue();
int32_t cnt = numVertices.getValue();
int32_t end = beg + cnt;
if (end <= len) {
for (int32_t i=beg; i<end; i++) {
maxX = std::max<float>(maxX,points[i][0]);
minX = std::min<float>(minX,points[i][0]);
maxY = std::max<float>(maxY,points[i][1]);
minY = std::min<float>(minY,points[i][1]);
maxZ = std::max<float>(maxZ,points[i][2]);
minZ = std::min<float>(minZ,points[i][2]);
}
box.setBounds(minX,minY,minZ,maxX,maxY,maxZ);
center.setValue(0.5f*(minX+maxX),0.5f*(minY+maxY),0.5f*(minZ+maxZ));
}
else {
box.setBounds(SbVec3f(0,0,0), SbVec3f(0,0,0));
center.setValue(0.0f,0.0f,0.0f);
}
}

View File

@ -0,0 +1,65 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MESHGUI_SOPOLYGON_H
#define MESHGUI_SOPOLYGON_H
#include <Inventor/fields/SoSFUInt32.h>
#include <Inventor/fields/SoSFInt32.h>
#include <Inventor/fields/SoSFBool.h>
#include <Inventor/fields/SoSubField.h>
#include <Inventor/nodes/SoSubNode.h>
#include <Inventor/nodes/SoShape.h>
#include <Inventor/elements/SoReplacedElement.h>
namespace MeshGui {
class MeshGuiExport SoPolygon : public SoShape {
typedef SoShape inherited;
SO_NODE_HEADER(SoPolygon);
public:
static void initClass();
SoPolygon();
SoSFInt32 startIndex;
SoSFInt32 numVertices;
SoSFBool highlight;
SoSFBool render;
protected:
virtual ~SoPolygon() {};
virtual void GLRender(SoGLRenderAction *action);
virtual void computeBBox(SoAction *action, SbBox3f &box, SbVec3f &center);
virtual void rayPick (SoRayPickAction *action);
virtual void generatePrimitives(SoAction *action);
private:
void drawPolygon(const SbVec3f *,int32_t) const;
};
} // namespace MeshGui
#endif // MESHGUI_SOPOLYGON_H

View File

@ -1069,8 +1069,14 @@ std::vector<unsigned long> ViewProviderMesh::getVisibleFacets(const SbViewportRe
}
mat->diffuseColor.finishEditing();
// backface culling
//SoShapeHints* hints = new SoShapeHints;
//hints->shapeType = SoShapeHints::SOLID;
//hints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
SoMaterialBinding* bind = new SoMaterialBinding();
bind->value = SoMaterialBinding::PER_FACE;
//root->addChild(hints);
root->addChild(mat);
root->addChild(bind);
#endif
@ -1514,12 +1520,17 @@ void ViewProviderMesh::deselectFacet(unsigned long facet)
pcMatBinding->value = SoMaterialBinding::PER_FACE;
int uCtFacets = (int)rMesh.countFacets();
if (uCtFacets != pcShapeMaterial->diffuseColor.getNum()) {
highlightSelection();
if (rMesh.hasSelectedFacets()) {
if (uCtFacets != pcShapeMaterial->diffuseColor.getNum()) {
highlightSelection();
}
else {
App::Color c = ShapeColor.getValue();
pcShapeMaterial->diffuseColor.set1Value(facet,c.r,c.g,c.b);
}
}
else {
App::Color c = ShapeColor.getValue();
pcShapeMaterial->diffuseColor.set1Value(facet,c.r,c.g,c.b);
unhighlightSelection();
}
}
@ -1552,7 +1563,10 @@ void ViewProviderMesh::deselectComponent(unsigned long uFacet)
rMesh.removeFacetsFromSelection(selection);
// Colorize the selection
highlightSelection();
if (rMesh.hasSelectedFacets())
highlightSelection();
else
unhighlightSelection();
}
void ViewProviderMesh::setSelection(const std::vector<unsigned long>& indices)
@ -1583,7 +1597,10 @@ void ViewProviderMesh::removeSelection(const std::vector<unsigned long>& indices
rMesh.removeFacetsFromSelection(indices);
// Colorize the selection
highlightSelection();
if (rMesh.hasSelectedFacets())
highlightSelection();
else
unhighlightSelection();
}
void ViewProviderMesh::clearSelection()
@ -1600,6 +1617,7 @@ void ViewProviderMesh::deleteSelection()
const Mesh::MeshObject& rMesh = meshProp.getValue();
rMesh.getFacetsFromSelection(indices);
if (!indices.empty()) {
rMesh.clearFacetSelection();
unhighlightSelection();
Mesh::MeshObject* pMesh = meshProp.startEditing();