| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <algorithm> |
| | #include <QBitmap> |
| |
|
| | #include <Inventor/SbBox2s.h> |
| | #include <Inventor/SoPickedPoint.h> |
| | #include <Inventor/details/SoFaceDetail.h> |
| | #include <Inventor/events/SoMouseButtonEvent.h> |
| | #include <Inventor/nodes/SoCamera.h> |
| |
|
| | #include <App/Application.h> |
| | #include <App/Document.h> |
| | #include <Base/Console.h> |
| | #include <Base/Tools.h> |
| | #include <Gui/Application.h> |
| | #include <Gui/Document.h> |
| | #include <Gui/MouseSelection.h> |
| | #include <Gui/Navigation/NavigationStyle.h> |
| | #include <Gui/Utilities.h> |
| | #include <Gui/View3DInventor.h> |
| | #include <Gui/View3DInventorViewer.h> |
| | #include <Mod/Mesh/App/MeshFeature.h> |
| | #include <Mod/Mesh/App/Core/MeshKernel.h> |
| | #include <Mod/Mesh/App/Core/Iterator.h> |
| | #include <Mod/Mesh/App/Core/TopoAlgorithm.h> |
| |
|
| | #include "MeshSelection.h" |
| | #include "ViewProvider.h" |
| |
|
| |
|
| | using namespace MeshGui; |
| |
|
| | #define CROSS_WIDTH 16 |
| | #define CROSS_HEIGHT 16 |
| | #define CROSS_HOT_X 7 |
| | #define CROSS_HOT_Y 7 |
| |
|
| | |
| | |
| | unsigned char MeshSelection::cross_bitmap[] = { |
| | 0xc0, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, |
| | 0x40, 0x02, 0x40, 0x02, 0x7f, 0xfe, 0x01, 0x80, |
| | 0x01, 0x80, 0x7f, 0xfe, 0x40, 0x02, 0x40, 0x02, |
| | 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xc0, 0x03}; |
| |
|
| | unsigned char MeshSelection::cross_mask_bitmap[] = { |
| | 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, |
| | 0xc0, 0x03, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, |
| | 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xc0, 0x03, |
| | 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03}; |
| | |
| | |
| |
|
| | MeshSelection::MeshSelection() |
| | { |
| | 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); |
| | } |
| | } |
| | } |
| | |
| | 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 (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) |
| | { |
| | |
| | Gui::View3DInventorViewer* viewer = this->getViewer(); |
| | if (viewer) { |
| | |
| | |
| | stopInteractiveCallback(viewer); |
| | startInteractiveCallback(viewer, cb); |
| | viewer->navigationStyle()->stopSelection(); |
| |
|
| | |
| | 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); |
| | #if defined(Q_OS_WIN32) |
| | double dpr = viewer->devicePixelRatio(); |
| | cursor.setDevicePixelRatio(dpr); |
| | mask.setDevicePixelRatio(dpr); |
| | #endif |
| | 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() |
| | { |
| | |
| | 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() |
| | { |
| | |
| | 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; |
| | } |
| |
|
| | for (auto view : views) { |
| | view->deleteSelection(); |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | bool MeshSelection::deleteSelectionBorder() |
| | { |
| | |
| | bool deletion = false; |
| | std::list<ViewProviderMesh*> views = getViewProviders(); |
| | for (auto view : views) { |
| | Mesh::Feature* mf = view->getObject<Mesh::Feature>(); |
| |
|
| | |
| | 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); |
| |
|
| | |
| | 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; |
| | |
| | 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) |
| | { |
| | |
| | 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(); |
| |
|
| | |
| | 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() |
| | ); |
| |
|
| | |
| | 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 (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) |
| | { |
| | |
| | if (n->getEvent()->isOfType(SoMouseButtonEvent::getClassTypeId())) { |
| | const SoMouseButtonEvent* mbe = static_cast<const SoMouseButtonEvent*>(n->getEvent()); |
| | Gui::View3DInventorViewer* view = static_cast<Gui::View3DInventorViewer*>(n->getUserData()); |
| |
|
| | |
| | |
| | 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(); |
| |
|
| | |
| | |
| | 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(); |
| | if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) { |
| | |
| | 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); |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|