diff --git a/src/Mod/Mesh/Gui/AppMeshGui.cpp b/src/Mod/Mesh/Gui/AppMeshGui.cpp index a3ff09cc6..624d56972 100644 --- a/src/Mod/Mesh/Gui/AppMeshGui.cpp +++ b/src/Mod/Mesh/Gui/AppMeshGui.cpp @@ -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(); diff --git a/src/Mod/Mesh/Gui/CMakeLists.txt b/src/Mod/Mesh/Gui/CMakeLists.txt index ae4701a0f..cafca6c7c 100644 --- a/src/Mod/Mesh/Gui/CMakeLists.txt +++ b/src/Mod/Mesh/Gui/CMakeLists.txt @@ -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 diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 1bc39d291..2e71e4ed9 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -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(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; } diff --git a/src/Mod/Mesh/Gui/DlgSmoothing.cpp b/src/Mod/Mesh/Gui/DlgSmoothing.cpp index 9efebc9ea..4541d83e7 100644 --- a/src/Mod/Mesh/Gui/DlgSmoothing.cpp +++ b/src/Mod/Mesh/Gui/DlgSmoothing.cpp @@ -23,17 +23,25 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include #endif #include "DlgSmoothing.h" #include "ui_DlgSmoothing.h" +#include "Selection.h" + +#include +#include +#include +#include +#include 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 meshes = selection->getObjects(); + if (meshes.empty()) + return true; + + Gui::WaitCursor wc; + Gui::Command::openCommand("Mesh Smoothing"); + + bool hasSelection = false; + for (std::vector::const_iterator it = meshes.begin(); it != meshes.end(); ++it) { + Mesh::Feature* mesh = static_cast(*it); + std::vector 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" diff --git a/src/Mod/Mesh/Gui/DlgSmoothing.h b/src/Mod/Mesh/Gui/DlgSmoothing.h index e3bf61d54..fafccd3e1 100644 --- a/src/Mod/Mesh/Gui/DlgSmoothing.h +++ b/src/Mod/Mesh/Gui/DlgSmoothing.h @@ -25,13 +25,16 @@ #define MESHGUI_DLGSMOOTHING_H #include +#include +#include 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 diff --git a/src/Mod/Mesh/Gui/DlgSmoothing.ui b/src/Mod/Mesh/Gui/DlgSmoothing.ui index 691484639..69844eec0 100644 --- a/src/Mod/Mesh/Gui/DlgSmoothing.ui +++ b/src/Mod/Mesh/Gui/DlgSmoothing.ui @@ -1,172 +1,130 @@ MeshGui::DlgSmoothing - + 0 0 - 242 - 251 + 210 + 227 Smoothing - + true - + - + - + Method - + - - - Method + + + Taubin + + + true - - - - - Taubin - - - true - - - - - - - Laplace - - - - - - - - Parameter + + + + Laplace - - - - - Iterations: - - - - - - - 1 - - - 4 - - - - - - - Lambda: - - - - - - - 4 - - - 1.000000000000000 - - - 0.001000000000000 - - - 0.630700000000000 - - - - - - - Mu: - - - - - - - 4 - - - 1.000000000000000 - - - 0.001000000000000 - - - 0.042400000000000 - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + Parameter + + + + + Iterations: + + + + + + + 1 + + + 4 + + + + + + + Lambda: + + + + + + + 4 + + + 1.000000000000000 + + + 0.001000000000000 + + + 0.630700000000000 + + + + + + + Mu: + + + + + + + 4 + + + 1.000000000000000 + + + 0.001000000000000 + + + 0.042400000000000 + + + + + + + Only selection + + + + - - - buttonBox - accepted() - MeshGui::DlgSmoothing - accept() - - - 94 - 191 - - - -3 - 193 - - - - - buttonBox - rejected() - MeshGui::DlgSmoothing - reject() - - - 190 - 193 - - - 219 - 151 - - - - + diff --git a/src/Mod/Mesh/Gui/MeshEditor.cpp b/src/Mod/Mesh/Gui/MeshEditor.cpp index 2f819554e..11c2a2c20 100644 --- a/src/Mod/Mesh/Gui/MeshEditor.cpp +++ b/src/Mod/Mesh/Gui/MeshEditor.cpp @@ -40,15 +40,21 @@ # include # include # include +# include # include # include +# include #endif #include "MeshEditor.h" #include "SoFCMeshObject.h" +#include "SoPolygon.h" #include #include +#include +#include #include +#include #include #include @@ -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&, bool> + { + bool operator () (const std::vector &rclC1, + const std::vector &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(vp->getObject()); + + Gui::View3DInventor* view = static_cast(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(viewer->getSceneGraph())->addChild(myBridgeRoot); +} + +void MeshFillHole::finishEditing() +{ + Gui::View3DInventor* view = static_cast(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(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 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 > 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 >::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 >::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::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(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(ud); + Gui::View3DInventorViewer* view = reinterpret_cast(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::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(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::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" diff --git a/src/Mod/Mesh/Gui/MeshEditor.h b/src/Mod/Mesh/Gui/MeshEditor.h index c10a39470..c7fb12f4d 100644 --- a/src/Mod/Mesh/Gui/MeshEditor.h +++ b/src/Mod/Mesh/Gui/MeshEditor.h @@ -25,15 +25,22 @@ #include #include +#include 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 >& 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 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 myPolygons; + Mesh::Feature* myMesh; + int myNumPoints; + unsigned long myVertex1; + unsigned long myVertex2; + TBoundary myPolygon; + MeshHoleFiller& myHoleFiller; + Connection myConnection; +}; + } // namespace MeshGui diff --git a/src/Mod/Mesh/Gui/MeshSelection.cpp b/src/Mod/Mesh/Gui/MeshSelection.cpp new file mode 100644 index 000000000..a724f96ce --- /dev/null +++ b/src/Mod/Mesh/Gui/MeshSelection.cpp @@ -0,0 +1,467 @@ +/*************************************************************************** + * Copyright (c) 2013 Werner Mayer * + * * + * 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 +# include +# include +# include +# include +# include +# include +#endif + +#include "MeshSelection.h" +#include "ViewProvider.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& obj) +{ + meshObjects = obj; +} + +std::vector MeshSelection::getObjects() const +{ + std::vector objs; + if (!meshObjects.empty()) { + for (std::vector::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 MeshSelection::getViewProviders() const +{ + std::vector objs = getObjects(); + std::list vps; + for (std::vector::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(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(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 views = getViewProviders(); + for (std::list::iterator it = views.begin(); it != views.end(); ++it) { + Mesh::Feature* mf = static_cast((*it)->getObject()); + const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); + std::vector faces(mo->countFacets()); + std::generate(faces.begin(), faces.end(), Base::iotaGen(0)); + (*it)->addSelection(faces); + } +} + +void MeshSelection::clearSelection() +{ + std::list views = getViewProviders(); + for (std::list::iterator it = views.begin(); it != views.end(); ++it) { + (*it)->clearSelection(); + } +} + +bool MeshSelection::deleteSelection() +{ + // delete all selected faces + bool selected = false; + std::list views = getViewProviders(); + for (std::list::iterator it = views.begin(); it != views.end(); ++it) { + Mesh::Feature* mf = static_cast((*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::iterator it = views.begin(); it != views.end(); ++it) { + (*it)->deleteSelection(); + } + + return true; +} + +void MeshSelection::invertSelection() +{ + std::list views = getViewProviders(); + for (std::list::iterator it = views.begin(); it != views.end(); ++it) { + Mesh::Feature* mf = static_cast((*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::SELECTED)); + std::vector 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 views = getViewProviders(); + for (std::list::iterator it = views.begin(); it != views.end(); ++it) { + Mesh::Feature* mf = static_cast((*it)->getObject()); + const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); + + std::vector > segm; + MeshCore::MeshComponents comp(mo->getKernel()); + comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm); + + std::vector faces; + for (std::vector >::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 views = getViewProviders(); + for (std::list::iterator it = views.begin(); it != views.end(); ++it) { + Mesh::Feature* mf = static_cast((*it)->getObject()); + const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); + + std::vector > segm; + MeshCore::MeshComponents comp(mo->getKernel()); + comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm); + + std::vector faces; + for (std::vector >::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(n->getUserData()); + MeshSelection* self = reinterpret_cast(ud); + self->stopInteractiveCallback(view); + n->setHandled(); + std::vector 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 views = self->getViewProviders(); + for (std::list::iterator it = views.begin(); it != views.end(); ++it) { + ViewProviderMesh* vp = static_cast(*it); + + std::vector faces; + const Mesh::MeshObject& mesh = static_cast((*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 pixelPoly = view->getPolygon(); + SbBox2s rect; + for (std::vector::iterator it = pixelPoly.begin(); it != pixelPoly.end(); ++it) { + const SbVec2s& p = *it; + rect.extendBy(SbVec2s(p[0],height-p[1])); + } + std::vector rf; rf.swap(faces); + std::vector 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 > 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 screen; + screen.reserve(faces.size()); + MeshCore::MeshFacetIterator it_f(kernel); + for (std::vector::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(n->getEvent()); + Gui::View3DInventorViewer* view = reinterpret_cast(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(view->getViewProviderByPath(point->getPath())); + if (!vp || !vp->getTypeId().isDerivedFrom(ViewProviderMesh::getClassTypeId())) + return; + ViewProviderMesh* mesh = static_cast(vp); + MeshSelection* self = reinterpret_cast(ud); + std::list 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(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); + } + } + } + } +} diff --git a/src/Mod/Mesh/Gui/MeshSelection.h b/src/Mod/Mesh/Gui/MeshSelection.h new file mode 100644 index 000000000..e2857ba02 --- /dev/null +++ b/src/Mod/Mesh/Gui/MeshSelection.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (c) 2013 Werner Mayer * + * * + * 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 +#include +#include +#include +#include +#include + +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&); + std::vector getObjects() const; + +private: + std::list 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 meshObjects; + + static unsigned char cross_bitmap[]; + static unsigned char cross_mask_bitmap[]; +}; + +} + +#endif // MESHGUI_MESHSELECTION_H diff --git a/src/Mod/Mesh/Gui/RemoveComponents.cpp b/src/Mod/Mesh/Gui/RemoveComponents.cpp index 708eb8b4e..a66e3f500 100644 --- a/src/Mod/Mesh/Gui/RemoveComponents.cpp +++ b/src/Mod/Mesh/Gui/RemoveComponents.cpp @@ -27,12 +27,19 @@ # include # include # include +# include +# include # include # include # include # include +# include # include +# include # include +# include +# include +# include #endif #include "RemoveComponents.h" @@ -42,9 +49,12 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -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 views = getViewProviders(doc); - for (std::list::iterator it = views.begin(); it != views.end(); ++it) { - Mesh::Feature* mf = static_cast((*it)->getObject()); - const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); - std::vector faces(mo->countFacets()); - std::generate(faces.begin(), faces.end(), Base::iotaGen(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 views = getViewProviders(doc); - for (std::list::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 views = getViewProviders(doc); - for (std::list::iterator it = views.begin(); it != views.end(); ++it) { - Mesh::Feature* mf = static_cast((*it)->getObject()); - const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); - - std::vector > segm; - MeshCore::MeshComponents comp(mo->getKernel()); - comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm); - - std::vector faces; - for (std::vector >::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 views = getViewProviders(doc); - for (std::list::iterator it = views.begin(); it != views.end(); ++it) { - Mesh::Feature* mf = static_cast((*it)->getObject()); - const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); + meshSel.deselectComponent(size); +} - std::vector > segm; - MeshCore::MeshComponents comp(mo->getKernel()); - comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm); - - std::vector faces; - for (std::vector >::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 views = getViewProviders(doc); - for (std::list::iterator it = views.begin(); it != views.end(); ++it) { - Mesh::Feature* mf = static_cast((*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::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 views = getViewProviders(doc); - for (std::list::iterator it = views.begin(); it != views.end(); ++it) { - Mesh::Feature* mf = static_cast((*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::SELECTED)); - std::vector 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 RemoveComponents::getViewProviders(const Gui::Document* doc) const +void RemoveComponents::paintSelection() { - std::list vps; - std::vector mesh = doc->getDocument()->getObjectsOfType(); - for (std::vector::iterator it = mesh.begin(); it != mesh.end(); ++it) { - Gui::ViewProvider* vp = doc->getViewProvider(*it); - if (vp->isVisible()) - vps.push_back(static_cast(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(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(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(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(n->getUserData()); - RemoveComponents* that = reinterpret_cast(ud); - that->stopInteractiveCallback(view); - n->setHandled(); - std::vector 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 views = that->getViewProviders(doc); - for (std::list::iterator it = views.begin(); it != views.end(); ++it) { - ViewProviderMesh* vp = static_cast(*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 faces; - const Mesh::MeshObject& mesh = static_cast((*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 pixelPoly = view->getPolygon(); - SbBox2s rect; - for (std::vector::iterator it = pixelPoly.begin(); it != pixelPoly.end(); ++it) { - const SbVec2s& p = *it; - rect.extendBy(SbVec2s(p[0],height-p[1])); - } - std::vector rf; rf.swap(faces); - std::vector 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 > 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 screen; - screen.reserve(faces.size()); - MeshCore::MeshFacetIterator it_f(kernel); - for (std::vector::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(n->getEvent()); - Gui::View3DInventorViewer* view = reinterpret_cast(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(view->getViewProviderByPath(point->getPath())); - if (!vp || !vp->getTypeId().isDerivedFrom(ViewProviderMesh::getClassTypeId())) - return; - ViewProviderMesh* that = static_cast(vp); - RemoveComponents* dlg = reinterpret_cast(ud); - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (!doc) return; - std::list 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(detail)->getFaceIndex(); - std::vector 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(e)); + else if (e->type() == QEvent::MouseButtonPress) + mousePressEvent(static_cast(e)); + else if (e->type() == QEvent::MouseButtonRelease) + mouseReleaseEvent(static_cast(e)); + else if (e->type() == QEvent::MouseMove) + mouseMoveEvent(static_cast(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) diff --git a/src/Mod/Mesh/Gui/RemoveComponents.h b/src/Mod/Mesh/Gui/RemoveComponents.h index 1ae66850d..96f25a131 100644 --- a/src/Mod/Mesh/Gui/RemoveComponents.h +++ b/src/Mod/Mesh/Gui/RemoveComponents.h @@ -25,12 +25,14 @@ #define MESHGUI_REMOVECOMPONENTS_H #include -#include #include #include +#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 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 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; }; /** diff --git a/src/Mod/Mesh/Gui/RemoveComponents.ui b/src/Mod/Mesh/Gui/RemoveComponents.ui index 7fb4401b2..04dc1d179 100644 --- a/src/Mod/Mesh/Gui/RemoveComponents.ui +++ b/src/Mod/Mesh/Gui/RemoveComponents.ui @@ -193,12 +193,12 @@ - + Respect only visible triangles - true + false @@ -207,6 +207,9 @@ Respect only triangles with normals facing screen + + true + diff --git a/src/Mod/Mesh/Gui/Selection.cpp b/src/Mod/Mesh/Gui/Selection.cpp new file mode 100644 index 000000000..ae6e1aeaf --- /dev/null +++ b/src/Mod/Mesh/Gui/Selection.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (c) 2013 Werner Mayer * + * * + * 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& o) +{ + meshSel.setObjects(o); +} + +std::vector 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" diff --git a/src/Mod/Mesh/Gui/Selection.h b/src/Mod/Mesh/Gui/Selection.h new file mode 100644 index 000000000..bb6952a50 --- /dev/null +++ b/src/Mod/Mesh/Gui/Selection.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (c) 2013 Werner Mayer * + * * + * 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 +#include +#include +#include +#include +#include +#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&); + std::vector 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 diff --git a/src/Mod/Mesh/Gui/Selection.ui b/src/Mod/Mesh/Gui/Selection.ui new file mode 100644 index 000000000..db50a2643 --- /dev/null +++ b/src/Mod/Mesh/Gui/Selection.ui @@ -0,0 +1,71 @@ + + + MeshGui::Selection + + + + 0 + 0 + 304 + 143 + + + + Selection + + + + + + Selection + + + + + + Add + + + + + + + Clear + + + + + + + Respect only visible triangles + + + false + + + + + + + Respect only triangles with normals facing screen + + + true + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Mesh/Gui/SoPolygon.cpp b/src/Mod/Mesh/Gui/SoPolygon.cpp new file mode 100644 index 000000000..66818d898 --- /dev/null +++ b/src/Mod/Mesh/Gui/SoPolygon.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (c) 2008 Werner Mayer * + * * + * 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 +# endif +# ifdef FC_OS_MACOSX +# include +# else +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +# include +# include + +#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 ¢er) +{ + 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(maxX,points[i][0]); + minX = std::min(minX,points[i][0]); + maxY = std::max(maxY,points[i][1]); + minY = std::min(minY,points[i][1]); + maxZ = std::max(maxZ,points[i][2]); + minZ = std::min(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); + } +} diff --git a/src/Mod/Mesh/Gui/SoPolygon.h b/src/Mod/Mesh/Gui/SoPolygon.h new file mode 100644 index 000000000..3df9d3a27 --- /dev/null +++ b/src/Mod/Mesh/Gui/SoPolygon.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (c) 2008 Werner Mayer * + * * + * 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 +#include +#include +#include +#include +#include +#include + +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 ¢er); + virtual void rayPick (SoRayPickAction *action); + virtual void generatePrimitives(SoAction *action); + +private: + void drawPolygon(const SbVec3f *,int32_t) const; +}; + +} // namespace MeshGui + + +#endif // MESHGUI_SOPOLYGON_H + diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp index 196857b06..3682f76e0 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.cpp +++ b/src/Mod/Mesh/Gui/ViewProvider.cpp @@ -1069,8 +1069,14 @@ std::vector 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& indices) @@ -1583,7 +1597,10 @@ void ViewProviderMesh::removeSelection(const std::vector& 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();