Download src/Mod/Mesh/Gui/MeshSelection.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 20.1 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Mesh/Gui/MeshSelection.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/Mesh/Gui/MeshSelection.cpp
-
curl -L -o MeshSelection.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Mesh/Gui/MeshSelection.cpp
20.1 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * 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 * | |
| * * | |
| ***************************************************************************/ | |
| using namespace MeshGui; | |
| // NOLINTBEGIN | |
| // clang-format off | |
| 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}; | |
| // clang-format on | |
| // NOLINTEND | |
| MeshSelection::MeshSelection() | |
| { | |
| setCallback(selectGLCallback); | |
| } | |
| MeshSelection::~MeshSelection() | |
| { | |
| if (this->activeCB) { | |
| Gui::View3DInventorViewer* viewer = this->getViewer(); | |
| if (viewer) { | |
| stopInteractiveCallback(viewer); | |
| } | |
| } | |
| } | |
| void MeshSelection::setEnabledViewerSelection(bool on) | |
| { | |
| Gui::View3DInventorViewer* viewer = this->getViewer(); | |
| if (viewer) { | |
| viewer->setSelectionEnabled(on); | |
| } | |
| } | |
| void MeshSelection::setCallback(SoEventCallbackCB* cb) | |
| { | |
| selectionCB = cb; | |
| } | |
| 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 (auto& it : meshObjects) { | |
| 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 (auto obj : objs) { | |
| if (obj->isDerivedFrom<Mesh::Feature>()) { | |
| Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(obj); | |
| if (vp->isVisible()) { | |
| vps.push_back(static_cast<ViewProviderMesh*>(vp)); | |
| } | |
| } | |
| } | |
| return vps; | |
| } | |
| void MeshSelection::setViewer(Gui::View3DInventorViewer* v) | |
| { | |
| ivViewer = v; | |
| } | |
| Gui::View3DInventorViewer* MeshSelection::getViewer() const | |
| { | |
| // if a special viewer was set from outside then use this | |
| if (ivViewer) { | |
| return ivViewer; | |
| } | |
| Gui::Document* doc = Gui::Application::Instance->activeDocument(); | |
| if (!doc) { | |
| return nullptr; | |
| } | |
| Gui::MDIView* view = doc->getActiveView(); | |
| if (view && view->isDerivedFrom<Gui::View3DInventor>()) { | |
| Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>(view)->getViewer(); | |
| return viewer; | |
| } | |
| return nullptr; | |
| } | |
| 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; | |
| } | |
| viewer->setEditing(false); | |
| viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), this->activeCB, this); | |
| this->activeCB = nullptr; | |
| } | |
| void MeshSelection::prepareFreehandSelection(bool add, SoEventCallbackCB* cb) | |
| { | |
| // a rubberband to select a rectangle area of the meshes | |
| Gui::View3DInventorViewer* viewer = this->getViewer(); | |
| if (viewer) { | |
| // Note: It is possible that the mouse selection mode can be stopped | |
| // but then the callback function is still active. | |
| stopInteractiveCallback(viewer); | |
| startInteractiveCallback(viewer, cb); | |
| viewer->navigationStyle()->stopSelection(); | |
| // set cross cursor | |
| Gui::FreehandSelection* freehand = new Gui::FreehandSelection(); | |
| freehand->setClosed(true); | |
| freehand->setColor(1.0F, 0.0F, 0.0F); | |
| freehand->setLineWidth(3.0F); | |
| viewer->navigationStyle()->startSelection(freehand); | |
| auto setComponentCursor = [=]() { | |
| QBitmap cursor = QBitmap::fromData(QSize(CROSS_WIDTH, CROSS_HEIGHT), cross_bitmap); | |
| QBitmap mask = QBitmap::fromData(QSize(CROSS_WIDTH, CROSS_HEIGHT), cross_mask_bitmap); | |
| double dpr = viewer->devicePixelRatio(); | |
| cursor.setDevicePixelRatio(dpr); | |
| mask.setDevicePixelRatio(dpr); | |
| QCursor custom(cursor, mask, CROSS_HOT_X, CROSS_HOT_Y); | |
| viewer->setComponentCursor(custom); | |
| }; | |
| QObject::connect(viewer, &Gui::View3DInventorViewer::devicePixelRatioChanged, setComponentCursor); | |
| setComponentCursor(); | |
| this->addToSelection = add; | |
| } | |
| } | |
| void MeshSelection::startSelection() | |
| { | |
| prepareFreehandSelection(true, selectionCB); | |
| } | |
| void MeshSelection::startDeselection() | |
| { | |
| prepareFreehandSelection(false, selectionCB); | |
| } | |
| void MeshSelection::stopSelection() | |
| { | |
| Gui::View3DInventorViewer* viewer = getViewer(); | |
| if (viewer) { | |
| stopInteractiveCallback(viewer); | |
| viewer->navigationStyle()->stopSelection(); | |
| } | |
| } | |
| void MeshSelection::fullSelection() | |
| { | |
| // select the complete meshes | |
| std::list<ViewProviderMesh*> views = getViewProviders(); | |
| for (auto view : views) { | |
| Mesh::Feature* mf = view->getObject<Mesh::Feature>(); | |
| const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); | |
| std::vector<Mesh::FacetIndex> faces(mo->countFacets()); | |
| std::generate(faces.begin(), faces.end(), Base::iotaGen<Mesh::FacetIndex>(0)); | |
| view->addSelection(faces); | |
| } | |
| } | |
| void MeshSelection::clearSelection() | |
| { | |
| std::list<ViewProviderMesh*> views = getViewProviders(); | |
| for (auto view : views) { | |
| view->clearSelection(); | |
| } | |
| } | |
| bool MeshSelection::deleteSelection() | |
| { | |
| // delete all selected faces | |
| bool selected = false; | |
| std::list<ViewProviderMesh*> views = getViewProviders(); | |
| for (auto view : views) { | |
| Mesh::Feature* mf = view->getObject<Mesh::Feature>(); | |
| 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 (auto view : views) { | |
| view->deleteSelection(); | |
| } | |
| return true; | |
| } | |
| bool MeshSelection::deleteSelectionBorder() | |
| { | |
| // delete all selected faces | |
| bool deletion = false; | |
| std::list<ViewProviderMesh*> views = getViewProviders(); | |
| for (auto view : views) { | |
| Mesh::Feature* mf = view->getObject<Mesh::Feature>(); | |
| // mark the selected facet as visited | |
| std::vector<Mesh::FacetIndex> selection; | |
| std::vector<Mesh::FacetIndex> remove; | |
| std::set<Mesh::PointIndex> borderPoints; | |
| MeshCore::MeshAlgorithm meshAlg(mf->Mesh.getValue().getKernel()); | |
| meshAlg.GetFacetsFlag(selection, MeshCore::MeshFacet::SELECTED); | |
| meshAlg.GetBorderPoints(selection, borderPoints); | |
| std::vector<Mesh::PointIndex> border; | |
| border.insert(border.begin(), borderPoints.begin(), borderPoints.end()); | |
| meshAlg.ResetFacetFlag(MeshCore::MeshFacet::VISIT); | |
| meshAlg.SetFacetsFlag(selection, MeshCore::MeshFacet::VISIT); | |
| meshAlg.ResetPointFlag(MeshCore::MeshPoint::VISIT); | |
| meshAlg.SetPointsFlag(border, MeshCore::MeshPoint::VISIT); | |
| // collect neighbour facets that are not selected and that share a border point | |
| const MeshCore::MeshPointArray& points = mf->Mesh.getValue().getKernel().GetPoints(); | |
| const MeshCore::MeshFacetArray& faces = mf->Mesh.getValue().getKernel().GetFacets(); | |
| unsigned long numFaces = faces.size(); | |
| for (unsigned long i = 0; i < numFaces; i++) { | |
| const MeshCore::MeshFacet& face = faces[i]; | |
| if (!face.IsFlag(MeshCore::MeshFacet::VISIT)) { | |
| for (Mesh::PointIndex ptIndex : face._aulPoints) { | |
| if (points[ptIndex].IsFlag(MeshCore::MeshPoint::VISIT)) { | |
| remove.push_back(i); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| if (!remove.empty()) { | |
| deletion = true; | |
| // remove duplicates | |
| std::sort(remove.begin(), remove.end()); | |
| remove.erase(std::unique(remove.begin(), remove.end()), remove.end()); | |
| view->setSelection(remove); | |
| view->deleteSelection(); | |
| } | |
| } | |
| return deletion; | |
| } | |
| void MeshSelection::invertSelection() | |
| { | |
| std::list<ViewProviderMesh*> views = getViewProviders(); | |
| for (auto view : views) { | |
| view->invertSelection(); | |
| } | |
| } | |
| void MeshSelection::selectComponent(int size) | |
| { | |
| std::list<ViewProviderMesh*> views = getViewProviders(); | |
| for (auto view : views) { | |
| Mesh::Feature* mf = view->getObject<Mesh::Feature>(); | |
| const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); | |
| std::vector<std::vector<Mesh::FacetIndex>> segm; | |
| MeshCore::MeshComponents comp(mo->getKernel()); | |
| comp.SearchForComponents(MeshCore::MeshComponents::OverEdge, segm); | |
| std::vector<Mesh::FacetIndex> faces; | |
| for (const auto& jt : segm) { | |
| if (jt.size() < (Mesh::FacetIndex)size) { | |
| faces.insert(faces.end(), jt.begin(), jt.end()); | |
| } | |
| } | |
| view->addSelection(faces); | |
| } | |
| } | |
| void MeshSelection::deselectComponent(int size) | |
| { | |
| std::list<ViewProviderMesh*> views = getViewProviders(); | |
| for (auto view : views) { | |
| Mesh::Feature* mf = view->getObject<Mesh::Feature>(); | |
| const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); | |
| std::vector<std::vector<Mesh::FacetIndex>> segm; | |
| MeshCore::MeshComponents comp(mo->getKernel()); | |
| comp.SearchForComponents(MeshCore::MeshComponents::OverEdge, segm); | |
| std::vector<Mesh::FacetIndex> faces; | |
| for (const auto& jt : segm) { | |
| if (jt.size() > (Mesh::FacetIndex)size) { | |
| faces.insert(faces.end(), jt.begin(), jt.end()); | |
| } | |
| } | |
| view->removeSelection(faces); | |
| } | |
| } | |
| void MeshSelection::selectTriangle() | |
| { | |
| this->addToSelection = true; | |
| Gui::View3DInventorViewer* viewer = this->getViewer(); | |
| if (viewer) { | |
| stopInteractiveCallback(viewer); | |
| viewer->navigationStyle()->stopSelection(); | |
| startInteractiveCallback(viewer, pickFaceCallback); | |
| viewer->setEditingCursor(QCursor(Qt::PointingHandCursor)); | |
| } | |
| } | |
| void MeshSelection::deselectTriangle() | |
| { | |
| this->addToSelection = false; | |
| Gui::View3DInventorViewer* viewer = this->getViewer(); | |
| if (viewer) { | |
| stopInteractiveCallback(viewer); | |
| viewer->navigationStyle()->stopSelection(); | |
| startInteractiveCallback(viewer, pickFaceCallback); | |
| viewer->setEditingCursor(QCursor(Qt::PointingHandCursor)); | |
| } | |
| } | |
| void MeshSelection::setCheckOnlyPointToUserTriangles(bool on) | |
| { | |
| onlyPointToUserTriangles = on; | |
| } | |
| bool MeshSelection::isCheckedOnlyPointToUserTriangles() const | |
| { | |
| return onlyPointToUserTriangles; | |
| } | |
| void MeshSelection::setCheckOnlyVisibleTriangles(bool on) | |
| { | |
| onlyVisibleTriangles = on; | |
| } | |
| bool MeshSelection::isCheckedOnlyVisibleTriangles() const | |
| { | |
| return onlyVisibleTriangles; | |
| } | |
| 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 = static_cast<Gui::View3DInventorViewer*>(n->getUserData()); | |
| MeshSelection* self = static_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; | |
| SbVec3f dir; | |
| view->getNearPlane(pnt, dir); | |
| Base::Vector3f normal(dir[0], dir[1], dir[2]); | |
| std::list<ViewProviderMesh*> views = self->getViewProviders(); | |
| for (auto vp : views) { | |
| std::vector<Mesh::FacetIndex> faces; | |
| const Mesh::MeshObject& mesh = vp->getObject<Mesh::Feature>()->Mesh.getValue(); | |
| const MeshCore::MeshKernel& kernel = mesh.getKernel(); | |
| // simply get all triangles under the polygon | |
| SoCamera* cam = view->getSoRenderManager()->getCamera(); | |
| SbViewVolume vv = cam->getViewVolume(); | |
| Gui::ViewVolumeProjection proj(vv); | |
| Base::Placement plm = vp->getObject<Mesh::Feature>()->Placement.getValue(); | |
| proj.setTransform(plm.toMatrix()); | |
| vp->getFacetsFromPolygon(polygon, proj, true, faces); | |
| if (self->onlyVisibleTriangles) { | |
| const SbVec2s& sz = view->getSoRenderManager()->getViewportRegion().getWindowSize(); | |
| short width {}; | |
| short height {}; | |
| sz.getValue(width, height); | |
| std::vector<SbVec2s> pixelPoly = view->getPolygon(); | |
| SbBox2s rect; | |
| for (const auto& p : pixelPoly) { | |
| rect.extendBy(SbVec2s(p[0], height - p[1])); | |
| } | |
| std::vector<Mesh::FacetIndex> rf; | |
| rf.swap(faces); | |
| std::vector<Mesh::FacetIndex> vf = vp->getVisibleFacetsAfterZoom( | |
| rect, | |
| view->getSoRenderManager()->getViewportRegion(), | |
| view->getSoRenderManager()->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<Mesh::FacetIndex>> 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<Mesh::FacetIndex> screen; | |
| screen.reserve(faces.size()); | |
| MeshCore::MeshFacetIterator it_f(kernel); | |
| for (Mesh::FacetIndex face : faces) { | |
| it_f.Set(face); | |
| if (it_f->GetNormal() * normal > 0.0F) { | |
| screen.push_back(face); | |
| } | |
| } | |
| faces.swap(screen); | |
| } | |
| if (self->addToSelection) { | |
| vp->addSelection(faces); | |
| } | |
| else { | |
| vp->removeSelection(faces); | |
| } | |
| } | |
| view->redraw(); | |
| } | |
| 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 = static_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) { | |
| 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 = view->getViewProviderByPathFromTail(point->getPath()); | |
| if (!vp || !vp->isDerivedFrom<ViewProviderMesh>()) { | |
| return; | |
| } | |
| const auto mesh = static_cast<ViewProviderMesh*>(vp); | |
| const auto self = static_cast<MeshSelection*>(ud); | |
| if (std::list<ViewProviderMesh*> views = self->getViewProviders(); | |
| std::ranges::find(views, mesh) == views.end()) { | |
| return; | |
| } | |
| const SoDetail* detail = point->getDetail(/*mesh->getShapeNode()*/); | |
| if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) { | |
| // get the boundary to the picked facet | |
| Mesh::FacetIndex 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); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |