diff --git a/app/ObjectTree.qml b/app/ObjectTree.qml index b5b2c2717568f210147a09b7826d8ee3a39f6b2a..7203308fdd1b4e430ab00b388985c88bfc122082 100644 --- a/app/ObjectTree.qml +++ b/app/ObjectTree.qml @@ -44,7 +44,8 @@ Pane { clip: true flickDeceleration: 100000 boundsBehavior: Flickable.StopAtBounds - columnWidthProvider: function(column) { return treeView.width } + columnWidthProvider: function(column) { return colWidth } + property real colWidth: treeView.width property int toggleExpandRow: -1 onExpanded: (row, depth) => toggleExpandRow = row diff --git a/app/Selector.qml b/app/Selector.qml index 62cbfaa233ae1746f13cf76dbd5e7822e498de6e..3f9233cbcbf4ca37bb92c2ccda3a709a06bb4c2d 100644 --- a/app/Selector.qml +++ b/app/Selector.qml @@ -24,6 +24,10 @@ RowLayout { ListElement { text: "面" } ListElement { text: "体" } ListElement { text: "块" } + ListElement{text: "几何点"} + ListElement{text: "几何边"} + ListElement{text: "几何面"} + ListElement{text: "几何体"} } onCurrentTextChanged: { if(currentText === "..."){ @@ -44,6 +48,18 @@ RowLayout { if(currentText === "体"){ App.selection.selectMode = "Solid" } + if(currentText === "几何点"){ + App.selection.selectMode = "GeometryVertex" + } + if(currentText === "几何边"){ + App.selection.selectMode = "GeometryEdge" + } + if(currentText === "几何面"){ + App.selection.selectMode = "GeometryFace" + } + if(currentText === "几何体"){ + App.selection.selectMode = "GeometrySolid" + } } enabled: root.cur_model >= 0 opacity: enabled ? 1.0 : 0.6 diff --git a/app/model/QModelQuery.cpp b/app/model/QModelQuery.cpp index 8f754f34996935a39993dcb49681a9a0014e514f..e5cdda9d85abc9f2fddd712e76ab2babc2b62b6b 100644 --- a/app/model/QModelQuery.cpp +++ b/app/model/QModelQuery.cpp @@ -114,7 +114,7 @@ std::vector QModelQuery::getGeometryVtkData(Index model_id) if (!comp || !comp->geometry || !comp->geometry->rootShape) continue; - result.push_back(GeometryDataVtk { *comp->geometry->rootShape, comp->id }); + result.push_back(GeometryDataVtk { *comp->geometry->rootShape, comp->id, &comp->geometry->index }); } return result; @@ -126,7 +126,7 @@ std::optional QModelQuery::getGeometryVtkDataByComponent(Index if (!comp || !comp->geometry || !comp->geometry->rootShape) return std::nullopt; - return GeometryDataVtk { *comp->geometry->rootShape, comp->id }; + return GeometryDataVtk { *comp->geometry->rootShape, comp->id, &comp->geometry->index }; } diff --git a/app/render/CMakeLists.txt b/app/render/CMakeLists.txt index a4e3fb9a6703fc4618fdd94410914daab91f85e3..cbd58ac9b8f1eabab999781137bc2dbee342216a 100644 --- a/app/render/CMakeLists.txt +++ b/app/render/CMakeLists.txt @@ -1,9 +1,13 @@ add_library(vtkPart STATIC MeshActor.cpp MeshActorSelectOp.cpp + GeometryActorSelectOp.cpp SelectorHighlight.cpp + GeometrySelectorHighlight.cpp QRenderWindowStyle.cpp SelectManager.cpp + GeometrySelectManager.cpp + MeshSelectManager.cpp GeometryActor.cpp MeshActorManager.cpp GeometryActorManager.cpp diff --git a/app/render/EdgeSelectorHighlight.cpp b/app/render/EdgeSelectorHighlight.cpp index 7ad885e6d38ded0fc2cda534a1d127fee80e1a5b..5e69144735bfae6d16963604a0339e45b47b4e31 100644 --- a/app/render/EdgeSelectorHighlight.cpp +++ b/app/render/EdgeSelectorHighlight.cpp @@ -53,22 +53,25 @@ bool _is_selected(std::array v_local_id, const std::optionalselected_actor_ = vtkSmartPointer::New(); + this->highlight_actor_ = highlight_actor; this->renderer_ = renderer; selected_mapper_->SetInputData(vtkPolyData::New()); - selected_actor_->SetMapper(selected_mapper_); - selected_actor_->GetProperty()->SetColor(MeshActor::colors->GetColor3d("red").GetData()); - selected_actor_->GetProperty()->SetLineWidth(5); - renderer_->AddActor(selected_actor_); + if (highlight_actor_) { + highlight_actor_->SetMapper(selected_mapper_); + vtkNew prop; + prop->SetColor(MeshActor::colors->GetColor3d("red").GetData()); + prop->SetLineWidth(5); + highlight_actor_->SetProperty(prop); + } } -EdgeSelectorHighlight::~EdgeSelectorHighlight() -{ - renderer_->RemoveActor(selected_actor_); +EdgeSelectorHighlight::~EdgeSelectorHighlight() +{ + clear(); } void EdgeSelectorHighlight::clear() diff --git a/app/render/FaceSelectorHighlight.cpp b/app/render/FaceSelectorHighlight.cpp index f21e230d585b5190a85ffec3b8b771f1dc1f5e66..c7c04a3d76ad516b9eb5a6e9986a874482f5a9cd 100644 --- a/app/render/FaceSelectorHighlight.cpp +++ b/app/render/FaceSelectorHighlight.cpp @@ -25,25 +25,28 @@ std::vector::const_iterator _find_selected(vtkIdType new_face_id, con } } -FaceSelectorHighlight::FaceSelectorHighlight(vtkRenderer* renderer) +FaceSelectorHighlight::FaceSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor) { - this->selected_actor_ = vtkSmartPointer::New(); + this->highlight_actor_ = highlight_actor; this->renderer_ = renderer; selected_mapper_->SetInputData(vtkPolyData::New()); - selected_actor_->SetMapper(selected_mapper_); - selected_actor_->GetProperty()->SetColor(1.0, 0.0, 0.0); // 红色高亮 - selected_actor_->GetProperty()->SetLineWidth(2.0); - selected_actor_->GetProperty()->EdgeVisibilityOn(); - selected_actor_->GetProperty()->SetEdgeColor(1.0, 0.0, 0.0); - selected_actor_->PickableOff(); // 防止自己被选中 - - renderer_->AddActor(selected_actor_); + selected_mapper_->SetRelativeCoincidentTopologyPolygonOffsetParameters(0, -0.5); + + if (highlight_actor_) { + highlight_actor_->SetMapper(selected_mapper_); + vtkNew prop; + prop->SetColor(1.0, 0.0, 0.0); // 红色高亮 + prop->SetLineWidth(2.0); + prop->EdgeVisibilityOn(); + prop->SetEdgeColor(1.0, 0.0, 0.0); + highlight_actor_->SetProperty(prop); + } } -FaceSelectorHighlight::~FaceSelectorHighlight() -{ - renderer_->RemoveActor(selected_actor_); +FaceSelectorHighlight::~FaceSelectorHighlight() +{ + clear(); } SelectionVtk FaceSelectorHighlight::get() diff --git a/app/render/GeometryActor.cpp b/app/render/GeometryActor.cpp index 064413227891efc4098b16bc58e437d4ade13505..1abad756ac986b525ab444aeff466eb407059258 100644 --- a/app/render/GeometryActor.cpp +++ b/app/render/GeometryActor.cpp @@ -2,15 +2,105 @@ #include "Core.h" #include #include -#include +#include #include #include #include +#include +#include +#include +#include +#include +#include + +#include +#include + +static vtkSmartPointer findSubIdArray(vtkPolyData* pd, const OccShapeHandle& occShape) +{ + if (!pd || occShape.IsNull()) + return nullptr; + + vtkCellData* cd = pd->GetCellData(); + if (!cd) + return nullptr; + + const vtkIdType nCells = pd->GetNumberOfCells(); + if (nCells <= 0) + return nullptr; + + vtkDataArray* best = nullptr; + vtkIdType bestValidCount = 0; + bool bestHasLineValid = false; + + for (int i = 0; i < cd->GetNumberOfArrays(); ++i) { + vtkDataArray* a = cd->GetArray(i); + if (!a) + continue; + if (a->GetNumberOfComponents() != 1) + continue; + if (a->GetNumberOfTuples() != nCells) + continue; + + const char* name = a->GetName(); + if (name) { + if (std::strcmp(name, "vtkOriginalCellIds") == 0) + continue; + if (std::strcmp(name, "vtkOriginalPointIds") == 0) + continue; + } + + vtkIdType validCount = 0; + bool hasLineValid = false; + for (vtkIdType c = 0; c < nCells; ++c) { + IVtk_IdType sid = static_cast(a->GetTuple1(c)); + if (sid > 0) { + try { + if (!occShape->GetSubShape(sid).IsNull()) { + ++validCount; + if (!hasLineValid && pd->GetCellType(c) == VTK_LINE) + hasLineValid = true; + } + } catch (...) { + } + } + } + + bool better = false; + if (!best) { + better = true; + } else if (hasLineValid && !bestHasLineValid) { + better = true; + } else if (!hasLineValid && bestHasLineValid) { + } else if (validCount > bestValidCount) { + better = true; + } + + if (better) { + bestValidCount = validCount; + bestHasLineValid = hasLineValid; + best = a; + } + } + + if (best && bestValidCount > 0) { + spdlog::info("[GeometryActor] found subId array '{}' valid={}/{} hasLine={}", + (best->GetName() ? best->GetName() : "(null)"), + static_cast(bestValidCount), static_cast(nCells), + bestHasLineValid ? "yes" : "no"); + return best; + } + + spdlog::warn("[GeometryActor] no valid subId array found in polydata with {} cells", static_cast(nCells)); + return nullptr; +} GeometryActor::GeometryActor(vtkRenderer* renderer, GeometryRenderMode render_mode) { this->renderer_ = renderer; this->render_mode_ = render_mode; + this->edge_render = false; + this->visibility_ = true; } GeometryActor::~GeometryActor() @@ -30,41 +120,103 @@ bool GeometryActor::getIsEdgeRender() void GeometryActor::loadShape(const GeometryDataVtk& geometry_data) { - this->geometry_data_ = std::make_unique(geometry_data); - IVtkOCC_Shape::Handle aShapeImpl = new IVtkOCC_Shape(geometry_data.shape); + OccShapeHandle aShapeImpl = new IVtkOCC_Shape(geometry_data.shape); + aShapeImpl->SetId(static_cast(geometry_data.component_id)); + this->occ_shape_ = aShapeImpl; + this->geometry_index_ = geometry_data.geometry_index; vtkSmartPointer DS = vtkSmartPointer::New(); DS->SetShape(aShapeImpl); DS->Update(); - vtkPolyData* geometry_poly_data = DS->GetOutput(); + vtkPolyData* src = DS->GetOutput(); + + const vtkIdType nV = src->GetNumberOfVerts(); + const vtkIdType nL = src->GetNumberOfLines(); + const vtkIdType nP = src->GetNumberOfPolys(); - // 分开 polys 和 lines - vtkNew line_only; - line_only->SetPoints(geometry_poly_data->GetPoints()); - line_only->SetLines(geometry_poly_data->GetLines()); + spdlog::info("[GeometryActor] loadShape component={} verts={} lines={} polys={}", + geometry_data.component_id, static_cast(nV), static_cast(nL), static_cast(nP)); - vtkNew poly_only; - poly_only->SetPoints(geometry_poly_data->GetPoints()); - poly_only->SetPolys(geometry_poly_data->GetPolys()); - poly_only->GetPointData()->SetNormals(geometry_poly_data->GetPointData()->GetNormals()); + auto ExtractCellRangeToPolyData = [](vtkPolyData* in, vtkIdType start, vtkIdType count) -> vtkSmartPointer { + vtkNew ids; + ids->SetNumberOfComponents(1); + ids->SetNumberOfValues(count); + for (vtkIdType i = 0; i < count; ++i) + ids->SetValue(i, start + i); + + vtkNew node; + node->SetFieldType(vtkSelectionNode::CELL); + node->SetContentType(vtkSelectionNode::INDICES); + node->SetSelectionList(ids); + + vtkNew sel; + sel->AddNode(node); + + vtkNew extract; + extract->SetInputData(0, in); + extract->SetInputData(1, sel); + extract->Update(); + + vtkNew geom; + geom->SetInputConnection(extract->GetOutputPort()); + geom->Update(); + + return vtkPolyData::SafeDownCast(geom->GetOutput()); + }; + + vtkSmartPointer line_only = ExtractCellRangeToPolyData(src, 0, nV + nL); + vtkSmartPointer poly_only = ExtractCellRangeToPolyData(src, nV + nL, nP); + + if (!line_only) + line_only = vtkSmartPointer::New(); + if (!poly_only) + poly_only = vtkSmartPointer::New(); + + this->line_only_ = line_only; + this->poly_only_ = poly_only; + + line_sub_id_array_ = findSubIdArray(line_only, occ_shape_); + poly_sub_id_array_ = findSubIdArray(poly_only, occ_shape_); + + NCollection_Map edgeVertexIds; + for (TopExp_Explorer exp(geometry_data.shape, TopAbs_EDGE); exp.More(); exp.Next()) { + IVtk_IdType id = aShapeImpl->GetSubShapeId(exp.Current()); + if (id >= 0) edgeVertexIds.Add(id); + } + for (TopExp_Explorer exp(geometry_data.shape, TopAbs_VERTEX); exp.More(); exp.Next()) { + IVtk_IdType id = aShapeImpl->GetSubShapeId(exp.Current()); + if (id >= 0) edgeVertexIds.Add(id); + } + + auto lineEdgeFilter = vtkSmartPointer::New(); + lineEdgeFilter->SetInputData(line_only); + lineEdgeFilter->SetDoFiltering(true); + if (line_sub_id_array_ && line_sub_id_array_->GetName()) + lineEdgeFilter->SetIdsArrayName(line_sub_id_array_->GetName()); + lineEdgeFilter->SetData(edgeVertexIds); - // 渲染面(带光照) vtkNew poly_mapper; poly_mapper->SetInputData(poly_only); + poly_mapper->SetRelativeCoincidentTopologyPolygonOffsetParameters(0, 0); - this->poly_actor_->SetMapper(poly_mapper); - this->renderer_->AddActor(this->poly_actor_); + poly_actor_->SetMapper(poly_mapper); + poly_actor_->GetProperty()->SetColor(200.0 / 255.0, 200.0 / 255.0, 200.0 / 255.0); + renderer_->AddActor(poly_actor_); - // 渲染线(无光照) vtkNew line_mapper; - line_mapper->SetInputData(line_only); - line_mapper->SetRelativeCoincidentTopologyLineOffsetParameters(0, -0.1); - - this->line_actor_->SetMapper(line_mapper); - this->line_actor_->GetProperty()->LightingOff(); // 关键:关闭光照防止线变色 - this->line_actor_->GetProperty()->SetColor(0.0, 0.0, 0.0); - this->line_actor_->GetProperty()->SetLineWidth(2.0); - this->line_actor_->GetProperty()->RenderLinesAsTubesOn(); // 关键:线条抗锯齿 - this->renderer_->AddActor(this->line_actor_); + line_mapper->SetInputConnection(lineEdgeFilter->GetOutputPort()); + line_mapper->SetRelativeCoincidentTopologyLineOffsetParameters(0, 4); + line_mapper->SetRelativeCoincidentTopologyPointOffsetParameter(8); + + line_actor_->SetMapper(line_mapper); + line_actor_->GetProperty()->LightingOff(); + line_actor_->GetProperty()->SetLineWidth(2.0); + line_actor_->GetProperty()->RenderLinesAsTubesOn(); + line_actor_->GetProperty()->SetPointSize(6.0); + line_actor_->GetProperty()->SetColor(0.0, 0.0, 0.0); + renderer_->AddActor(line_actor_); + + spdlog::info("[GeometryActor] component={} actors added, face_cells={} line_cells={}", + geometry_data.component_id, static_cast(poly_only->GetNumberOfCells()), static_cast(line_only->GetNumberOfCells())); } void GeometryActor::deleteGeometryActor() @@ -84,11 +236,10 @@ void GeometryActor::setVisibility(bool visibility) void GeometryActor::setRenderMode(GeometryRenderMode render_mode) { - // 没用 } void GeometryActor::setRenderEdge(bool is_render) { this->edge_render = is_render; this->line_actor_->SetVisibility(is_render && this->visibility_); -} +} \ No newline at end of file diff --git a/app/render/GeometryActor.h b/app/render/GeometryActor.h index 4e79a089f3c3b2f4685f2ba602227c4ec092e7f3..193472ff33f5125aeaa5180f9107ece57d75460c 100644 --- a/app/render/GeometryActor.h +++ b/app/render/GeometryActor.h @@ -2,11 +2,23 @@ #define GEOMETRY_ACTOR_H #include "Core.h" #include "GeometryDataVtk.h" +#include "GeometrySubshapeIndex.h" #include +#include #include #include +#include + +#include +#include +#include +typedef Handle(IVtkOCC_Shape) OccShapeHandle; + +class GeometryActorSelectOp; +class vtkPolyData; class GeometryActor { + friend GeometryActorSelectOp; public: GeometryActor(vtkRenderer* renderer, GeometryRenderMode render_mode); @@ -27,11 +39,17 @@ private: GeometryRenderMode render_mode_; bool edge_render; bool visibility_; - std::unique_ptr geometry_data_; + OccShapeHandle occ_shape_; + const GeometrySubshapeIndex* geometry_index_; vtkNew poly_actor_; vtkNew line_actor_; vtkRenderer* renderer_; + vtkSmartPointer line_sub_id_array_; + vtkSmartPointer poly_sub_id_array_; + + vtkSmartPointer poly_only_; + vtkSmartPointer line_only_; }; #endif \ No newline at end of file diff --git a/app/render/GeometryActorManager.cpp b/app/render/GeometryActorManager.cpp index 07f8621cf47cbdc0ed1776047c49e527d68ee6e9..3f20dcad88d8389db167be476cadb3d474f4e111 100644 --- a/app/render/GeometryActorManager.cpp +++ b/app/render/GeometryActorManager.cpp @@ -16,15 +16,13 @@ void GeometryActorManager::bindRender(vtkRenderer* renderer) this->renderer_ = renderer; } -const GeometryActor* GeometryActorManager::getGeometryActor(Index component_id) +std::shared_ptr GeometryActorManager::getComponentActor(Index component_id) const { auto it = component_actors_.find(component_id); if (it != component_actors_.end()) { - return it->second.get(); - } else { - spdlog::error("GeometryActorManager getGeometryActor error"); - return nullptr; + return it->second; } + return nullptr; } GeometryRenderMode GeometryActorManager::getGeometryRenderMode(Index component_id) @@ -64,7 +62,7 @@ void GeometryActorManager::loadGeometry(const GeometryDataVtk& geometry_data) Index component_id = geometry_data.component_id; if (!component_actors_.count(component_id)) { - component_actors_[component_id] = std::make_unique(this->renderer_, GeometryRenderMode::Face); + component_actors_[component_id] = std::make_shared(this->renderer_, GeometryRenderMode::Face); } component_actors_[component_id]->loadShape(geometry_data); diff --git a/app/render/GeometryActorManager.h b/app/render/GeometryActorManager.h index 11855129f3b32a571d09063438343d0d64d6152f..a01c4adf24daccbd1bdf6e8c700e57b26ae5f638 100644 --- a/app/render/GeometryActorManager.h +++ b/app/render/GeometryActorManager.h @@ -15,7 +15,7 @@ public: ~GeometryActorManager(); void bindRender(vtkRenderer* renderer); - const GeometryActor* getGeometryActor(Index component_id); + std::shared_ptr getComponentActor(Index component_id) const; GeometryRenderMode getGeometryRenderMode(Index component_id); bool getIsEdgeRender(Index component_id); bool hasComponent(Index component_id) const; @@ -28,7 +28,7 @@ public: void setRenderEdge(Index component_id, bool is_render); private: - std::unordered_map> component_actors_; + std::unordered_map> component_actors_; vtkRenderer* renderer_; }; diff --git a/app/render/GeometryActorSelectOp.cpp b/app/render/GeometryActorSelectOp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42b6185030901a9c3519ee8efa3f66525eb7e4aa --- /dev/null +++ b/app/render/GeometryActorSelectOp.cpp @@ -0,0 +1,317 @@ +#include "GeometryActorSelectOp.h" +#include "GeometryActor.h" +#include "GeometrySubshapeIndex.h" +#include "Selection.h" +#include "Core.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static constexpr IVtk_SelectionMode kSelVertex = SM_Vertex; +static constexpr IVtk_SelectionMode kSelEdge = SM_Edge; +static constexpr IVtk_SelectionMode kSelFace = SM_Face; + +static int toleranceForMode(const SelectMode m) +{ + if (m == SelectMode::Vertex) + return 40; + if (m == SelectMode::Edge) + return 25; + if (m == SelectMode::Solid) + return 8; + return 8; +} + +static bool firstId(const NCollection_List& list, IVtk_IdType& outId) +{ + if (list.IsEmpty()) + return false; + outId = list.First(); + return true; +} + +static std::optional mapSubshapeToGeomId(const OccShapeHandle& occShape, + const GeometrySubshapeIndex& geomIndex, + TopAbs_ShapeEnum wantType, + IVtk_IdType subId, + ElementEnum::Type& outType) +{ + if (occShape.IsNull()) + return std::nullopt; + + const TopoDS_Shape& sub = occShape->GetSubShape(subId); + if (sub.IsNull()) + return std::nullopt; + + const int ti = GeometrySubshapeIndex::typeIndex(wantType); + if (ti < 0) + return std::nullopt; + + const int localTypeId = geomIndex.type_maps[static_cast(ti)].FindIndex(sub); + if (localTypeId <= 0) + return std::nullopt; + + if (wantType == TopAbs_FACE) { + GeomFaceId gid = geomIndex.faceGlobalId(localTypeId); + if (gid == kInvalidGeomFaceId) + return std::nullopt; + outType = ElementEnum::Face; + return gid; + } else if (wantType == TopAbs_EDGE) { + GeomEdgeId gid = geomIndex.edgeGlobalId(localTypeId); + if (gid == kInvalidGeomEdgeId) + return std::nullopt; + outType = ElementEnum::Edge; + return gid; + } else if (wantType == TopAbs_VERTEX) { + GeomVertexId gid = geomIndex.vertexGlobalId(localTypeId); + if (gid == kInvalidGeomVertexId) + return std::nullopt; + outType = ElementEnum::Vertex; + return gid; + } else if (wantType == TopAbs_SOLID) { + GeomSolidId gid = geomIndex.solidGlobalId(localTypeId); + if (gid == kInvalidGeomSolidId) + return std::nullopt; + outType = ElementEnum::Solid; + return gid; + } + return std::nullopt; +} + +GeometryActorSelectOpFactory::GeometryActorSelectOpFactory() = default; +GeometryActorSelectOpFactory::GeometryActorSelectOpFactory(std::weak_ptr geometry_actor) + : geometry_actor_(geometry_actor) +{ +} + +std::optional GeometryActorSelectOpFactory::lock() +{ + if (auto geometry_actor = geometry_actor_.lock()) { + return { geometry_actor }; + } + return {}; +} + +GeometryActorSelectOp::GeometryActorSelectOp(std::shared_ptr geometry_actor) + : geometry_actor_(geometry_actor) +{ + if (!geometry_actor_) { + throw std::runtime_error("GeometryActorSelectOp: geometry_actor is nullptr"); + } +} + +void GeometryActorSelectOp::disablePickerModes(IVtkTools_ShapePicker* picker) +{ + if (!picker) + return; + + const OccShapeHandle& occ = geometry_actor_->occ_shape_; + vtkActor* poly = geometry_actor_->poly_actor_.GetPointer(); + vtkActor* line = geometry_actor_->line_actor_.GetPointer(); + + picker->SetSelectionMode(occ, kSelFace, false); + picker->SetSelectionMode(occ, kSelEdge, false); + picker->SetSelectionMode(occ, kSelVertex, false); + picker->SetSelectionMode(poly, kSelFace, false); + picker->SetSelectionMode(poly, kSelEdge, false); + picker->SetSelectionMode(poly, kSelVertex, false); + picker->SetSelectionMode(line, kSelFace, false); + picker->SetSelectionMode(line, kSelEdge, false); + picker->SetSelectionMode(line, kSelVertex, false); + picker->InitializePickList(); +} + +void GeometryActorSelectOp::configurePicker(IVtkTools_ShapePicker* picker, SelectMode mode) +{ + if (!picker) + return; + + const OccShapeHandle& occ = geometry_actor_->occ_shape_; + vtkActor* poly = geometry_actor_->poly_actor_.GetPointer(); + vtkActor* line = geometry_actor_->line_actor_.GetPointer(); + + const bool useLine = (mode == SelectMode::Edge || mode == SelectMode::Vertex); + + picker->PickFromListOn(); + picker->InitializePickList(); + picker->AddPickList(useLine ? line : poly); + if (useLine) + picker->AddPickList(poly); + picker->SetPixelTolerance(toleranceForMode(mode)); + + picker->SetSelectionMode(occ, kSelFace, false); + picker->SetSelectionMode(occ, kSelEdge, false); + picker->SetSelectionMode(occ, kSelVertex, false); + picker->SetSelectionMode(poly, kSelFace, false); + picker->SetSelectionMode(poly, kSelEdge, false); + picker->SetSelectionMode(poly, kSelVertex, false); + picker->SetSelectionMode(line, kSelFace, false); + picker->SetSelectionMode(line, kSelEdge, false); + picker->SetSelectionMode(line, kSelVertex, false); + + switch (mode) { + case SelectMode::Face: + case SelectMode::Solid: + picker->SetSelectionMode(occ, kSelFace, true); + picker->SetSelectionMode(poly, kSelFace, true); + break; + case SelectMode::Edge: + picker->SetSelectionMode(occ, kSelEdge, true); + picker->SetSelectionMode(line, kSelEdge, true); + break; + case SelectMode::Vertex: + picker->SetSelectionMode(occ, kSelVertex, true); + picker->SetSelectionMode(line, kSelVertex, true); + break; + default: + break; + } +} + +std::optional GeometryActorSelectOp::pickSubshape(IVtkTools_ShapePicker* picker, vtkRenderer* renderer, + double posx, double posy, SelectMode mode, IVtk_IdType& out_sub_id) +{ + if (!picker) + return std::nullopt; + + TopAbs_ShapeEnum wantType; + if (mode == SelectMode::Face) + wantType = TopAbs_FACE; + else if (mode == SelectMode::Edge) + wantType = TopAbs_EDGE; + else if (mode == SelectMode::Vertex) + wantType = TopAbs_VERTEX; + else + return std::nullopt; + + const int n = picker->Pick(posx, posy, 0.0, renderer); + if (n <= 0) + return std::nullopt; + + IVtk_IdType shapeId = -1; + if (!firstId(picker->GetPickedShapesIds(false), shapeId)) + return std::nullopt; + + out_sub_id = -1; + if (!firstId(picker->GetPickedSubShapesIds(shapeId, false), out_sub_id)) + return std::nullopt; + + const GeometrySubshapeIndex* geomIndex = geometry_actor_->geometry_index_; + if (!geomIndex) + return std::nullopt; + + ElementEnum::Type elemType = ElementEnum::None; + return mapSubshapeToGeomId(geometry_actor_->occ_shape_, *geomIndex, wantType, out_sub_id, elemType); +} + +bool GeometryActorSelectOp::pickSolid(IVtkTools_ShapePicker* picker, vtkRenderer* renderer, double posx, double posy, + GeomSolidId& out_solid_id, std::vector& out_face_sub_ids) +{ + if (!picker) + return false; + + const int n = picker->Pick(posx, posy, 0.0, renderer); + if (n <= 0) + return false; + + IVtk_IdType shapeId = -1; + if (!firstId(picker->GetPickedShapesIds(false), shapeId)) + return false; + + IVtk_IdType subId = -1; + if (!firstId(picker->GetPickedSubShapesIds(shapeId, false), subId)) + return false; + + const OccShapeHandle& occ = geometry_actor_->occ_shape_; + const TopoDS_Shape& pickedSub = occ->GetSubShape(subId); + if (pickedSub.IsNull()) + return false; + + const GeometrySubshapeIndex* geomIndex = geometry_actor_->geometry_index_; + if (!geomIndex) + return false; + + const int solidTi = GeometrySubshapeIndex::typeIndex(TopAbs_SOLID); + + TopoDS_Shape solidShape; + if (pickedSub.ShapeType() == TopAbs_SOLID) { + solidShape = pickedSub; + } else { + const int nSolids = geomIndex->type_maps[solidTi].Extent(); + for (int localId = 1; localId <= nSolids; ++localId) { + const TopoDS_Shape& solid = geomIndex->type_maps[solidTi].FindKey(localId); + for (TopExp_Explorer exp(solid, TopAbs_FACE); exp.More(); exp.Next()) { + if (exp.Current().IsSame(pickedSub)) { + solidShape = solid; + break; + } + } + if (!solidShape.IsNull()) + break; + } + if (solidShape.IsNull()) + return false; + } + + const int localTypeId = geomIndex->type_maps[solidTi].FindIndex(solidShape); + if (localTypeId <= 0) + return false; + + GeomSolidId gid = geomIndex->solidGlobalId(localTypeId); + if (gid == kInvalidGeomSolidId) + return false; + + out_solid_id = gid; + out_face_sub_ids.clear(); + for (TopExp_Explorer expF(solidShape, TopAbs_FACE); expF.More(); expF.Next()) { + IVtk_IdType faceSubId = occ->GetSubShapeId(expF.Current()); + if (faceSubId >= 0) + out_face_sub_ids.push_back(faceSubId); + } + return true; +} + +GeometryHighlightPipeline GeometryActorSelectOp::buildHighlight(SelectMode mode) +{ + GeometryHighlightPipeline hl; + + const bool useLine = (mode == SelectMode::Edge || mode == SelectMode::Vertex); + vtkPolyData* source = useLine ? geometry_actor_->line_only_.GetPointer() + : geometry_actor_->poly_only_.GetPointer(); + vtkDataArray* idArray = useLine ? geometry_actor_->line_sub_id_array_.GetPointer() + : geometry_actor_->poly_sub_id_array_.GetPointer(); + if (!source) + return hl; + + hl.filter = vtkSmartPointer::New(); + hl.filter->SetInputData(source); + hl.filter->SetDoFiltering(true); + if (idArray && idArray->GetName()) + hl.filter->SetIdsArrayName(idArray->GetName()); + + hl.mapper = vtkSmartPointer::New(); + hl.mapper->SetInputConnection(hl.filter->GetOutputPort()); + + if (useLine) { + // 相对显示 mapper 默认值:线 (0,-5),点 (-10) + hl.mapper->SetRelativeCoincidentTopologyLineOffsetParameters(0, -1); + hl.mapper->SetRelativeCoincidentTopologyPointOffsetParameter(-2); + } else { + // 相对显示 mapper 默认值:多边形 (0,-1) + hl.mapper->SetRelativeCoincidentTopologyPolygonOffsetParameters(0, -5); + } + + return hl; +} diff --git a/app/render/GeometryActorSelectOp.h b/app/render/GeometryActorSelectOp.h new file mode 100644 index 0000000000000000000000000000000000000000..b204b99e6cbdff5805cc91eb13226fdccefa4c8c --- /dev/null +++ b/app/render/GeometryActorSelectOp.h @@ -0,0 +1,58 @@ +#ifndef GEOMETRY_ACTOR_SELECT_OP_H +#define GEOMETRY_ACTOR_SELECT_OP_H +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Core.h" +#include "GeometryActor.h" + +class GeometryActorSelectOp; +class IVtkTools_ShapePicker; +class vtkRenderer; + +struct GeometryHighlightPipeline { + vtkSmartPointer filter; + vtkSmartPointer mapper; +}; + +class GeometryActorSelectOpFactory { + friend GeometryActorSelectOp; + +public: + GeometryActorSelectOpFactory(); + GeometryActorSelectOpFactory(std::weak_ptr geometry_actor); + std::optional lock(); + +private: + std::weak_ptr geometry_actor_; +}; + +class GeometryActorSelectOp { + friend GeometryActorSelectOpFactory; + +public: + GeometryActorSelectOp(std::shared_ptr geometry_actor); + + void disablePickerModes(IVtkTools_ShapePicker* picker); + + void configurePicker(IVtkTools_ShapePicker* picker, SelectMode mode); + + std::optional pickSubshape(IVtkTools_ShapePicker* picker, vtkRenderer* renderer, + double posx, double posy, SelectMode mode, IVtk_IdType& out_sub_id); + + bool pickSolid(IVtkTools_ShapePicker* picker, vtkRenderer* renderer, double posx, double posy, + GeomSolidId& out_solid_id, std::vector& out_face_sub_ids); + + GeometryHighlightPipeline buildHighlight(SelectMode mode); + +private: + std::shared_ptr geometry_actor_; +}; +#endif // GEOMETRY_ACTOR_SELECT_OP_H diff --git a/app/render/GeometrySelectManager.cpp b/app/render/GeometrySelectManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7d13e021a1be23be00799a144ca3552b97c784c --- /dev/null +++ b/app/render/GeometrySelectManager.cpp @@ -0,0 +1,108 @@ +#include "GeometrySelectManager.h" +#include "GeometryActor.h" +#include +#include +#include + +void GeometrySelectManager::bindRenderer(vtkRenderer* renderer, vtkActor* highlight_actor) +{ + this->renderer_ = renderer; + this->highlight_actor_ = highlight_actor; + if (!picker_) { + picker_ = vtkSmartPointer::New(); + picker_->SetRenderer(renderer); + picker_->SetAreaSelection(false); + } +} + +void GeometrySelectManager::select(double posx, double posy) +{ + if (this->selector_) { + this->selector_->select(posx, posy); + } +} + +void GeometrySelectManager::setSelectActor(std::weak_ptr geom_actor) +{ + this->cur_geom_actor_ = GeometryActorSelectOpFactory { geom_actor }; + if (this->selector_) { + this->selector_->clear(); + this->selector_->setPicker(picker_); + this->selector_->setCurGeomActor(*cur_geom_actor_); + } +} + +void GeometrySelectManager::setSelectMode(SelectMode select_mode) +{ + this->clearSelection(); + this->select_mode_ = select_mode; + + if (this->selector_) { + this->selector_->setPicker(picker_); + this->selector_->setCurGeomActor(GeometryActorSelectOpFactory {}); + } + + if (this->select_mode_ == SelectMode::GeometryVertex) { + this->selector_ = std::make_unique(this->renderer_, this->highlight_actor_); + } else if (this->select_mode_ == SelectMode::GeometryFace) { + this->selector_ = std::make_unique(this->renderer_, this->highlight_actor_); + } else if (this->select_mode_ == SelectMode::GeometryEdge) { + this->selector_ = std::make_unique(this->renderer_, this->highlight_actor_); + } else if (this->select_mode_ == SelectMode::GeometrySolid) { + this->selector_ = std::make_unique(this->renderer_, this->highlight_actor_); + } else { + this->selector_ = nullptr; + } + + if (this->selector_ && this->cur_geom_actor_) { + this->selector_->setPicker(picker_); + this->selector_->setCurGeomActor(*cur_geom_actor_); + } +} + +void GeometrySelectManager::clearSelection() +{ + if (this->selector_) { + this->selector_->clear(); + } + if (this->renderer_ && this->renderer_->GetRenderWindow()) + this->renderer_->GetRenderWindow()->Render(); +} + +std::unique_ptr GeometrySelectManager::getSelection() +{ + std::unique_ptr selection = std::make_unique(); + + if (!this->selector_) + { + return nullptr; + } + + if (this->select_mode_ == SelectMode::GeometryVertex) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::GeometryVertex; + } else if (this->select_mode_ == SelectMode::GeometryFace) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::GeometryFace; + } else if (this->select_mode_ == SelectMode::GeometryEdge) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::GeometryEdge; + } else if (this->select_mode_ == SelectMode::GeometrySolid) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::GeometrySolid; + } else { + if (this->selector_) + this->selector_->clear(); + return nullptr; + } + + return selection; +} diff --git a/app/render/GeometrySelectManager.h b/app/render/GeometrySelectManager.h new file mode 100644 index 0000000000000000000000000000000000000000..f18a80a471d3cbce2676add91d51d95f78c00fce --- /dev/null +++ b/app/render/GeometrySelectManager.h @@ -0,0 +1,36 @@ +#ifndef GEOMETRY_SELECT_MANAGER_H +#define GEOMETRY_SELECT_MANAGER_H +#include "GeometrySelectorHighlight.h" +#include "GeometryActorSelectOp.h" +#include "Core.h" + +#include +#include +#include +#include +#include + +class vtkRenderer; +struct GeometrySubshapeIndex; + +class GeometrySelectManager { +public: + void bindRenderer(vtkRenderer* renderer, vtkActor* highlight_actor); + void select(double posx, double posy); + + void setSelectActor(std::weak_ptr geom_actor); + void setSelectMode(SelectMode select_mode); + void clearSelection(); + std::unique_ptr getSelection(); + +private: + std::optional cur_geom_actor_ {}; + SelectMode select_mode_ { SelectMode::None }; + vtkNew selection_actor_; + vtkNew selection_mapper_; + vtkSmartPointer picker_ {}; + vtkRenderer* renderer_ { nullptr }; + vtkActor* highlight_actor_ { nullptr }; + std::unique_ptr selector_ {}; +}; +#endif // GEOMETRY_SELECT_MANAGER_H diff --git a/app/render/GeometrySelectorHighlight.cpp b/app/render/GeometrySelectorHighlight.cpp new file mode 100644 index 0000000000000000000000000000000000000000..107cc56d366044e784dd99fad4721abeb2679acb --- /dev/null +++ b/app/render/GeometrySelectorHighlight.cpp @@ -0,0 +1,355 @@ +#include "GeometrySelectorHighlight.h" +#include "GeometryActorSelectOp.h" +#include "Core.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static void flushHighlight(IVtkTools_SubPolyDataFilter* filter, vtkRenderer* renderer) +{ + if (!filter || !renderer) + return; + filter->Modified(); + if (renderer->GetRenderWindow()) + renderer->GetRenderWindow()->Render(); +} + +// 把共享高亮 actor 挂到当前 selector 的 mapper 上,并按模式套用完整样式(避免残留上一模式属性) +static void mountHighlight(vtkActor* actor, const GeometryHighlightPipeline& hl, SelectMode mode) +{ + if (!actor || !hl.mapper) + return; + + actor->SetMapper(hl.mapper); + + vtkNew prop; + prop->SetColor(1.0, 0.0, 0.0); + if (mode == SelectMode::Edge || mode == SelectMode::Vertex) { + prop->SetOpacity(0.5); + prop->RenderLinesAsTubesOn(); + prop->SetLineWidth(3.0); + prop->SetPointSize(8.0); + prop->LightingOff(); + } else { + prop->SetOpacity(1.0); + } + actor->SetProperty(prop); +} + +// ─── Face ────────────────────────────────────────────── + +GeometryFaceSelectorHighlight::GeometryFaceSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor) + : renderer_(renderer) + , highlight_actor_(highlight_actor) +{ +} + +GeometryFaceSelectorHighlight::~GeometryFaceSelectorHighlight() +{ + clear(); +} + +void GeometryFaceSelectorHighlight::clear() +{ + selections_.clear(); + if (hl_.filter) { + hl_.filter->Clear(); + hl_.filter->Modified(); + } + if (renderer_ && renderer_->GetRenderWindow()) + renderer_->GetRenderWindow()->Render(); +} + +GeometrySelectionVtk GeometryFaceSelectorHighlight::get() const +{ + GeometrySelectionVtk s; + s.type = ElementEnum::GeometryFace; + s.component_id = -1; + for (const auto& [subId, geomId] : selections_) + s.ids.push_back(geomId); + return s; +} + +void GeometryFaceSelectorHighlight::select(double posx, double posy) +{ + auto op = geom_actor_.lock(); + if (!op) + return; + + IVtk_IdType subId = -1; + auto geomId = op->pickSubshape(picker_, renderer_, posx, posy, SelectMode::Face, subId); + if (!geomId) + return; + + auto [it, inserted] = selections_.insert_or_assign(subId, *geomId); + if (!inserted) + selections_.erase(it); + + NCollection_List ids; + for (const auto& [sid, gid] : selections_) + ids.Append(sid); + + if (hl_.filter) + hl_.filter->SetData(ids); + flushHighlight(hl_.filter, renderer_); +} + +void GeometryFaceSelectorHighlight::setCurGeomActor(GeometryActorSelectOpFactory geom_actor) +{ + if (auto oldOp = geom_actor_.lock()) + oldOp->disablePickerModes(picker_); + + clear(); + hl_ = {}; + + geom_actor_ = std::move(geom_actor); + + auto op = geom_actor_.lock(); + if (op) { + hl_ = op->buildHighlight(SelectMode::Face); + mountHighlight(highlight_actor_, hl_, SelectMode::Face); + op->configurePicker(picker_, SelectMode::Face); + } +} + +// ─── Edge ────────────────────────────────────────────── + +GeometryEdgeSelectorHighlight::GeometryEdgeSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor) + : renderer_(renderer) + , highlight_actor_(highlight_actor) +{ +} + +GeometryEdgeSelectorHighlight::~GeometryEdgeSelectorHighlight() +{ + clear(); +} + +void GeometryEdgeSelectorHighlight::clear() +{ + selections_.clear(); + if (hl_.filter) { + hl_.filter->Clear(); + hl_.filter->Modified(); + } + if (renderer_ && renderer_->GetRenderWindow()) + renderer_->GetRenderWindow()->Render(); +} + +GeometrySelectionVtk GeometryEdgeSelectorHighlight::get() const +{ + GeometrySelectionVtk s; + s.type = ElementEnum::GeometryEdge; + s.component_id = -1; + for (const auto& [subId, geomId] : selections_) + s.ids.push_back(geomId); + return s; +} + +void GeometryEdgeSelectorHighlight::select(double posx, double posy) +{ + auto op = geom_actor_.lock(); + if (!op) + return; + + IVtk_IdType subId = -1; + auto geomId = op->pickSubshape(picker_, renderer_, posx, posy, SelectMode::Edge, subId); + if (!geomId) + return; + + auto [it, inserted] = selections_.insert_or_assign(subId, *geomId); + if (!inserted) + selections_.erase(it); + + NCollection_List ids; + for (const auto& [sid, gid] : selections_) + ids.Append(sid); + + if (hl_.filter) + hl_.filter->SetData(ids); + flushHighlight(hl_.filter, renderer_); +} + +void GeometryEdgeSelectorHighlight::setCurGeomActor(GeometryActorSelectOpFactory geom_actor) +{ + if (auto oldOp = geom_actor_.lock()) + oldOp->disablePickerModes(picker_); + + clear(); + hl_ = {}; + + geom_actor_ = std::move(geom_actor); + + auto op = geom_actor_.lock(); + if (op) { + hl_ = op->buildHighlight(SelectMode::Edge); + mountHighlight(highlight_actor_, hl_, SelectMode::Edge); + op->configurePicker(picker_, SelectMode::Edge); + } +} + +// ─── Vertex ──────────────────────────────────────────── + +GeometryVertexSelectorHighlight::GeometryVertexSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor) + : renderer_(renderer) + , highlight_actor_(highlight_actor) +{ +} + +GeometryVertexSelectorHighlight::~GeometryVertexSelectorHighlight() +{ + clear(); +} + +void GeometryVertexSelectorHighlight::clear() +{ + selections_.clear(); + if (hl_.filter) { + hl_.filter->Clear(); + hl_.filter->Modified(); + } + if (renderer_ && renderer_->GetRenderWindow()) + renderer_->GetRenderWindow()->Render(); +} + +GeometrySelectionVtk GeometryVertexSelectorHighlight::get() const +{ + GeometrySelectionVtk s; + s.type = ElementEnum::GeometryVertex; + s.component_id = -1; + for (const auto& [subId, geomId] : selections_) + s.ids.push_back(geomId); + return s; +} + +void GeometryVertexSelectorHighlight::select(double posx, double posy) +{ + auto op = geom_actor_.lock(); + if (!op) + return; + + IVtk_IdType subId = -1; + auto geomId = op->pickSubshape(picker_, renderer_, posx, posy, SelectMode::Vertex, subId); + if (!geomId) + return; + + auto [it, inserted] = selections_.insert_or_assign(subId, *geomId); + if (!inserted) + selections_.erase(it); + + NCollection_List ids; + for (const auto& [sid, gid] : selections_) + ids.Append(sid); + + if (hl_.filter) + hl_.filter->SetData(ids); + flushHighlight(hl_.filter, renderer_); +} + +void GeometryVertexSelectorHighlight::setCurGeomActor(GeometryActorSelectOpFactory geom_actor) +{ + if (auto oldOp = geom_actor_.lock()) + oldOp->disablePickerModes(picker_); + + clear(); + hl_ = {}; + + geom_actor_ = std::move(geom_actor); + + auto op = geom_actor_.lock(); + if (op) { + hl_ = op->buildHighlight(SelectMode::Vertex); + mountHighlight(highlight_actor_, hl_, SelectMode::Vertex); + op->configurePicker(picker_, SelectMode::Vertex); + } +} + +// ─── Solid ───────────────────────────────────────────── + +GeometrySolidSelectorHighlight::GeometrySolidSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor) + : renderer_(renderer) + , highlight_actor_(highlight_actor) +{ +} + +GeometrySolidSelectorHighlight::~GeometrySolidSelectorHighlight() +{ + clear(); +} + +void GeometrySolidSelectorHighlight::clear() +{ + selections_.clear(); + highlighted_face_ids_.clear(); + if (hl_.filter) { + hl_.filter->Clear(); + hl_.filter->Modified(); + } + if (renderer_ && renderer_->GetRenderWindow()) + renderer_->GetRenderWindow()->Render(); +} + +GeometrySelectionVtk GeometrySolidSelectorHighlight::get() const +{ + GeometrySelectionVtk s; + s.type = ElementEnum::GeometrySolid; + s.component_id = -1; + for (const auto& [subId, geomId] : selections_) + s.ids.push_back(geomId); + return s; +} + +void GeometrySolidSelectorHighlight::select(double posx, double posy) +{ + auto op = geom_actor_.lock(); + if (!op) + return; + + GeomSolidId gid = kInvalidGeomSolidId; + std::vector faceSubIds; + if (!op->pickSolid(picker_, renderer_, posx, posy, gid, faceSubIds)) + return; + + auto [it, inserted] = selections_.insert_or_assign(gid, gid); + if (!inserted) + selections_.erase(it); + + for (IVtk_IdType faceSubId : faceSubIds) { + if (!inserted) + highlighted_face_ids_.erase(faceSubId); + else + highlighted_face_ids_.insert(faceSubId); + } + + NCollection_List ids; + for (const auto& fid : highlighted_face_ids_) + ids.Append(fid); + + if (hl_.filter) + hl_.filter->SetData(ids); + flushHighlight(hl_.filter, renderer_); +} + +void GeometrySolidSelectorHighlight::setCurGeomActor(GeometryActorSelectOpFactory geom_actor) +{ + if (auto oldOp = geom_actor_.lock()) + oldOp->disablePickerModes(picker_); + + clear(); + hl_ = {}; + + geom_actor_ = std::move(geom_actor); + + auto op = geom_actor_.lock(); + if (op) { + hl_ = op->buildHighlight(SelectMode::Solid); + mountHighlight(highlight_actor_, hl_, SelectMode::Solid); + op->configurePicker(picker_, SelectMode::Solid); + } +} diff --git a/app/render/GeometrySelectorHighlight.h b/app/render/GeometrySelectorHighlight.h new file mode 100644 index 0000000000000000000000000000000000000000..ba0c86aa0a63645f90903f2dec2d74e097964f6a --- /dev/null +++ b/app/render/GeometrySelectorHighlight.h @@ -0,0 +1,104 @@ +#ifndef GEOMETRY_SELECTOR_HIGHLIGHT_H +#define GEOMETRY_SELECTOR_HIGHLIGHT_H +#include "GeometryActorSelectOp.h" +#include "Selection.h" + +#include +#include +#include +#include + +class vtkRenderer; +class vtkActor; +class IVtkTools_SubPolyDataFilter; +class IVtkTools_ShapePicker; +struct GeometrySubshapeIndex; + +using GeometrySelectionVtk = Selection; + +class GeometrySelectorHighlight { +public: + virtual ~GeometrySelectorHighlight() = default; + virtual void select(double posx, double posy) = 0; + virtual void clear() = 0; + virtual GeometrySelectionVtk get() const = 0; + virtual void setCurGeomActor(GeometryActorSelectOpFactory geom_actor) = 0; + void setPicker(vtkSmartPointer picker) { picker_ = picker; } + +protected: + vtkSmartPointer picker_; +}; + +class GeometryFaceSelectorHighlight final : public GeometrySelectorHighlight { +public: + GeometryFaceSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor); + ~GeometryFaceSelectorHighlight() override; + void clear() override; + GeometrySelectionVtk get() const override; + void select(double posx, double posy) override; + void setCurGeomActor(GeometryActorSelectOpFactory geom_actor) override; + +private: + vtkRenderer* renderer_; + vtkActor* highlight_actor_ {}; + GeometryActorSelectOpFactory geom_actor_; + GeometryHighlightPipeline hl_; + + std::unordered_map selections_; +}; + +class GeometryEdgeSelectorHighlight final : public GeometrySelectorHighlight { +public: + GeometryEdgeSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor); + ~GeometryEdgeSelectorHighlight() override; + void clear() override; + GeometrySelectionVtk get() const override; + void select(double posx, double posy) override; + void setCurGeomActor(GeometryActorSelectOpFactory geom_actor) override; + +private: + vtkRenderer* renderer_; + vtkActor* highlight_actor_ {}; + GeometryActorSelectOpFactory geom_actor_; + GeometryHighlightPipeline hl_; + + std::unordered_map selections_; +}; + +class GeometryVertexSelectorHighlight final : public GeometrySelectorHighlight { +public: + GeometryVertexSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor); + ~GeometryVertexSelectorHighlight() override; + void clear() override; + GeometrySelectionVtk get() const override; + void select(double posx, double posy) override; + void setCurGeomActor(GeometryActorSelectOpFactory geom_actor) override; + +private: + vtkRenderer* renderer_; + vtkActor* highlight_actor_ {}; + GeometryActorSelectOpFactory geom_actor_; + GeometryHighlightPipeline hl_; + + std::unordered_map selections_; +}; + +class GeometrySolidSelectorHighlight final : public GeometrySelectorHighlight { +public: + GeometrySolidSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor); + ~GeometrySolidSelectorHighlight() override; + void clear() override; + GeometrySelectionVtk get() const override; + void select(double posx, double posy) override; + void setCurGeomActor(GeometryActorSelectOpFactory geom_actor) override; + +private: + vtkRenderer* renderer_; + vtkActor* highlight_actor_ {}; + GeometryActorSelectOpFactory geom_actor_; + GeometryHighlightPipeline hl_; + + std::unordered_map selections_; + std::unordered_set highlighted_face_ids_; +}; +#endif // GEOMETRY_SELECTOR_HIGHLIGHT_H diff --git a/app/render/MeshActorManager.cpp b/app/render/MeshActorManager.cpp index 3b992a92b587397d52689d15bc4c871b7cd56ca8..946a904a7f2960aba6fa729efc06fb59a5fbef66 100644 --- a/app/render/MeshActorManager.cpp +++ b/app/render/MeshActorManager.cpp @@ -11,7 +11,7 @@ MeshActorManager::MeshActorManager(vtkPoints* global_points) { } -std::shared_ptr MeshActorManager::getComponentActor(Index component_id) const +std::shared_ptr MeshActorManager::getComponentActor(Index component_id) const { if (this->component_actors_.count(component_id)) return this->component_actors_.at(component_id); diff --git a/app/render/MeshActorManager.h b/app/render/MeshActorManager.h index e9d8d64916b7084eee85b6f5d07df67e0b6c86e7..690c42ecab29bc0f184804f14a3ba1a82a0abadb 100644 --- a/app/render/MeshActorManager.h +++ b/app/render/MeshActorManager.h @@ -12,10 +12,10 @@ public: explicit MeshActorManager(vtkPoints* global_points); void bindRender(vtkRenderer* renderer); bool hasComponent(Index component_id) const; - std::shared_ptr getComponentActor(Index component_id) const; + std::shared_ptr getComponentActor(Index component_id) const; void deleteComponent(Index component_id); void loadMesh(Index component_id, const MeshDataVtk& model_data, - vtkRenderer* renderer, ModelRenderMode render_mode = ModelRenderMode::Face); + vtkRenderer* renderer, ModelRenderMode render_mode = ModelRenderMode::Face); void setVisibility(Index component_id, bool visibility); void setRenderMode(Index component_id, ModelRenderMode render_mode); diff --git a/app/render/MeshActorSelectOp.cpp b/app/render/MeshActorSelectOp.cpp index e2a935f92fd28b68df100e959adbf376b1f2b432..ef55948960b60cdbe0c0de22c5e16f14a3d9fbe9 100644 --- a/app/render/MeshActorSelectOp.cpp +++ b/app/render/MeshActorSelectOp.cpp @@ -8,7 +8,7 @@ #include MeshActorSelectOpFactory::MeshActorSelectOpFactory() = default; -MeshActorSelectOpFactory::MeshActorSelectOpFactory(std::weak_ptr mesh_actor) +MeshActorSelectOpFactory::MeshActorSelectOpFactory(std::weak_ptr mesh_actor) : mesh_actor_(mesh_actor) { } @@ -21,7 +21,7 @@ std::optional MeshActorSelectOpFactory::lock() return {}; } -MeshActorSelectOp::MeshActorSelectOp(std::shared_ptr mesh_actor) +MeshActorSelectOp::MeshActorSelectOp(std::shared_ptr mesh_actor) : mesh_actor_(mesh_actor) { if (!mesh_actor_) { diff --git a/app/render/MeshActorSelectOp.h b/app/render/MeshActorSelectOp.h index 6e85372c7ffec8214360c1833d8ce9c25b8f4b66..26eef70420b24f540067388e767c5f3fd6dd5a98 100644 --- a/app/render/MeshActorSelectOp.h +++ b/app/render/MeshActorSelectOp.h @@ -18,7 +18,7 @@ class MeshActorSelectOpFactory { public: MeshActorSelectOpFactory(); - MeshActorSelectOpFactory(std::weak_ptr mesh_actor); + MeshActorSelectOpFactory(std::weak_ptr mesh_actor); /** * @brief 获取操作对象 * @return 如果MeshActor还存在,返回MeshActorSelectOp对象,否则返回std::nullopt @@ -26,7 +26,7 @@ public: std::optional lock(); private: - std::weak_ptr mesh_actor_; + std::weak_ptr mesh_actor_; }; /** @@ -36,7 +36,7 @@ class MeshActorSelectOp { friend MeshActorSelectOpFactory; public: - MeshActorSelectOp(std::shared_ptr mesh_actor); + MeshActorSelectOp(std::shared_ptr mesh_actor); vtkProp& getSolidActor(); vtkProp& getFaceActor(); @@ -65,6 +65,6 @@ public: vtkSmartPointer extractEdge(std::vector>& ids); private: - std::shared_ptr mesh_actor_; // 非空 + std::shared_ptr mesh_actor_; // 非空 }; #endif // MESH_ACTOR_SELECT_OP_H \ No newline at end of file diff --git a/app/render/MeshSelectManager.cpp b/app/render/MeshSelectManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99ed50ca910be3f1f5f3f8ec1d08f35786a01459 --- /dev/null +++ b/app/render/MeshSelectManager.cpp @@ -0,0 +1,98 @@ +#include "MeshSelectManager.h" +#include "MeshActor.h" +#include "Selection.h" +#include "SelectorHighlight.h" +#include +#include +#include +#include + +void MeshSelectManager::bindRenderer(vtkRenderer* renderer, vtkActor* highlight_actor) +{ + this->renderer_ = renderer; + this->highlight_actor_ = highlight_actor; +} + +void MeshSelectManager::select(double posx, double posy) +{ + if (this->selector_) { + assert(this->select_mode_ != SelectMode::None); + this->selector_->select(posx, posy); + } +} + +void MeshSelectManager::setSelectActor(std::weak_ptr model_actor_) +{ + this->cur_model_actor_ = MeshActorSelectOpFactory { model_actor_ }; + if (this->selector_) { + this->selector_->clear(); + this->selector_->setCurModelActor(*cur_model_actor_); + } +} + +void MeshSelectManager::setSelectMode(SelectMode select_mode) +{ + this->select_mode_ = select_mode; + if (this->select_mode_ == SelectMode::Vertex) { + this->selector_ = std::make_unique(this->renderer_, this->highlight_actor_); + } else if (this->select_mode_ == SelectMode::Face) { + this->selector_ = std::make_unique(this->renderer_, this->highlight_actor_); + } else if (this->select_mode_ == SelectMode::Block) { + this->selector_ = std::make_unique(this->renderer_); + } else if (this->select_mode_ == SelectMode::Edge) { + this->selector_ = std::make_unique(this->renderer_, this->highlight_actor_); + } else if (this->select_mode_ == SelectMode::Solid) { + this->selector_ = std::make_unique(this->renderer_, this->highlight_actor_); + } else { + this->selector_ = nullptr; + } + + if (this->selector_ && this->cur_model_actor_) { + this->selector_->setCurModelActor(*cur_model_actor_); + } +} + +void MeshSelectManager::clearSelection() +{ + if (this->selector_) { + this->selector_->clear(); + } +} + +std::unique_ptr MeshSelectManager::getSelection() +{ + std::unique_ptr selection = std::make_unique(); + + if (this->select_mode_ == SelectMode::Vertex) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::Vertex; + } else if (this->select_mode_ == SelectMode::Face) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::Face; + } else if (this->select_mode_ == SelectMode::Block) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::Block; + }else if (this->select_mode_ == SelectMode::Solid) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::Solid; + } else if (this->select_mode_ == SelectMode::Edge) { + for (const auto& id : this->selector_->get().ids) { + selection->ids.push_back(id); + } + selection->type = ElementEnum::Edge; + } else { + if (this->selector_) + this->selector_->clear(); + return nullptr; + } + + return selection; +} diff --git a/app/render/MeshSelectManager.h b/app/render/MeshSelectManager.h new file mode 100644 index 0000000000000000000000000000000000000000..3682aff30409dfaf2ad5a3e87bf5951f0848d2e0 --- /dev/null +++ b/app/render/MeshSelectManager.h @@ -0,0 +1,32 @@ +#ifndef MESH_SELECT_MANAGER_H +#define MESH_SELECT_MANAGER_H +#include "Selection.h" +#include "SelectorHighlight.h" +#include "MeshActorSelectOp.h" +#include "Core.h" + +#include +#include +#include +#include + +class MeshSelectManager { + +public: + void bindRenderer(vtkRenderer* renderer, vtkActor* highlight_actor); + void select(double posx, double posy); + void setSelectActor(std::weak_ptr model_actor_); + void setSelectMode(SelectMode select_mode); + void clearSelection(); + std::unique_ptr getSelection(); + +private: + std::optional cur_model_actor_ {}; + SelectMode select_mode_; + vtkNew selection_actor_; + vtkNew selection_mapper_; + vtkRenderer* renderer_; + vtkActor* highlight_actor_ {}; + std::unique_ptr selector_; +}; +#endif diff --git a/app/render/QRenderWindow.cpp b/app/render/QRenderWindow.cpp index e5b6dd954d78d2dc586da3785a59caba4112d500..cca29656f9e8f6931fd5c181467fbcb08d6d7e5c 100644 --- a/app/render/QRenderWindow.cpp +++ b/app/render/QRenderWindow.cpp @@ -289,7 +289,7 @@ void QRenderWindow::setComponentVisibility(Index component_id, bool visibility) QSelection* QRenderWindow::selectedIDs() { - std::unique_ptr data(this->selectManager_->getSelection()); + std::unique_ptr data = this->selectManager_->getSelection(); if (!data) { return nullptr; } @@ -336,39 +336,33 @@ void QRenderWindow::setSelectComponent(Index component_id) { dispatch_async([component_id, this](vtkRenderWindow* renderWindow, vtkUserData userData) -> void { Data* vtk = Data::SafeDownCast(userData); - selectManager_->bindRenderer(vtk->renderer_); this->cur_component_id_ = component_id; this->setCurEdgeRender(this->getIsEdgeRender(*vtk, component_id)); - std::shared_ptr mesh_actor; + std::shared_ptr mesh_actor; if (vtk->mesh_actor_manager_->hasComponent(component_id)) mesh_actor = vtk->mesh_actor_manager_->getComponentActor(component_id); if (mesh_actor) selectManager_->setSelectActor(mesh_actor); else - selectManager_->setSelectActor({}); + selectManager_->setSelectActor(std::weak_ptr {}); + + std::shared_ptr geometry_actor; + if (vtk->geometry_actor_manager_->hasComponent(component_id)) + geometry_actor = vtk->geometry_actor_manager_->getComponentActor(component_id); + + if (geometry_actor) + selectManager_->setSelectActor(geometry_actor); + else + selectManager_->setSelectActor(std::weak_ptr {}); }); } void QRenderWindow::setSelectMode(QString select_mode) { dispatch_async([select_mode, this](vtkRenderWindow* renderWindow, vtkUserData userData) -> void { - Data* vtk = Data::SafeDownCast(userData); - if (select_mode == "Vertex") { - select_mode_ = SelectMode::Vertex; - } else if (select_mode == "Face") { - select_mode_ = SelectMode::Face; - } else if (select_mode == "Edge") { - select_mode_ = SelectMode::Edge; - } else if (select_mode == "Block") { - select_mode_ = SelectMode::Block; - } else if (select_mode == "Solid") { - select_mode_ = SelectMode::Solid; - } else { - select_mode_ = SelectMode::None; - } - selectManager_->setSelectMode(select_mode_); + selectManager_->setSelectMode(select_mode.toStdString()); }); } diff --git a/app/render/QRenderWindow.h b/app/render/QRenderWindow.h index 8937158cb014904f0fbcd4bb07a8ab530e0600d4..ee5ba19c37034b65451e15b1dda7c87feae83214 100644 --- a/app/render/QRenderWindow.h +++ b/app/render/QRenderWindow.h @@ -171,7 +171,6 @@ signals: private: bool edge_render_ {}; ModelRenderMode renderMode_ {}; - SelectMode select_mode_ {}; vtkNew _camera; diff --git a/app/render/QRenderWindowStyle.cpp b/app/render/QRenderWindowStyle.cpp index 1230564cc179e7b6bc9ff45cf2b23e788e14843d..68a486f472bdb549e6a1b39c7f2e360a602df952 100644 --- a/app/render/QRenderWindowStyle.cpp +++ b/app/render/QRenderWindowStyle.cpp @@ -17,206 +17,13 @@ void QRenderWindowStyle::SetSelectManager(SelectManager* select_manager) void QRenderWindowStyle::OnLeftButtonUp() { - if (click_ && select_manager_) { + if (click_) { click_ = false; int pos[2]; this->GetInteractor()->GetEventPosition(pos); - select_manager_->select(pos[0], pos[1]); + if (select_manager_) + select_manager_->select(pos[0], pos[1]); } vtkInteractorStyleTrackballCamera::OnLeftButtonUp(); } - -//vtkStandardNewMacro(MouseInteractorHighLightActor); -//void MouseInteractorHighLightActor::OnLeftButtonUp() -//{ -// if (selector_ != nullptr && click_) -// { -// click_ = false; -// int pos[2]; -// this->GetInteractor()->GetEventPosition(pos); -// OnSelect(pos[0], pos[1]); -// } -// vtkInteractorStyleTrackballCamera::OnLeftButtonUp(); -//} -// -//void MouseInteractorHighLightActor::OnSelect(double posx, double posy) -//{ -// selector_->select(posx, posy); -//} -// -// -// -//void MouseInteractorHighLightActor::SetClick() -//{ -// click_ = true; -//} -// -//void MouseInteractorHighLightActor::ClearSelections() -//{ -// selector_->clear(); -//} -// -//std::unique_ptr MouseInteractorHighLightActor::GetSelectedIDs(const std::unordered_map>& mActors, SelectMode mode) -//{ -// auto actors = selector_->get(); -// std::unique_ptr selection = std::make_unique(); -// //std::vector ids; -// vtkPropAssembly* assembly_ = selector_->getAssembly(); -// MeshActor* modelactor_; -// -// for (const auto& pair : mActors) -// { -// modelactor_= pair.second.get()->getModelActor(assembly_); -// -// if (modelactor_ != NULL) -// { -// selection->model_name = pair.first; -// break; -// } -// } -// -// -// int (MeshActor::*actor_id)(vtkActor*) {}; -// if (mode == SelectMode::Group) -// { -// actor_id = &MeshActor::group_actor_id; -// selection->type = Element::Type::Group; -// } else if (mode == SelectMode::Block) { -// actor_id = &MeshActor::block_actor_id; -// selection->type = Element::Type::Block; -// } else { -// assert(false); -// } -// -// for (vtkActor* actor : actors) -// { -// selection->ids.push_back((modelactor_->*actor_id)(actor)); -// } -// return selection; -//} -//std::unique_ptr MouseInteractorHighLightFace::GetSelectedIDs(const std::unordered_map>& mActors, SelectMode mode) -//{ -// auto actors = selector_->get(); -// std::unique_ptr selection = std::make_unique(); -// //std::vector face_ids; -// vtkPropAssembly* assembly_ = selector_->getAssembly(); -// MeshActor* modelactor_; -// for (const auto& pair : mActors) -// { -// modelactor_ = pair.second.get()->getModelActor(assembly_); -// -// if (modelactor_ != NULL) -// { -// selection->model_name = pair.first; -// break; -// } -// } -// if (actors) -// { -// selection->ids.reserve(2); -// -// int patch_id = modelactor_->patch_actor_id(actors->patch_actor); -// selection->ids.push_back(modelactor_->patch_global_fid(patch_id,actors->local_id)); -// selection->type = Element::Type::Face; -// } -// -// return selection; -//} -//std::unique_ptr MouseInteractorHighLightEdge::GetSelectedIDs(const std::unordered_map>& mActors, SelectMode mode) -//{ -// auto actors = selector_->get(); -// std::unique_ptr selection=std::make_unique(); -// //std::vector point_ids; -// vtkPropAssembly* assembly_ = selector_->getAssembly(); -// MeshActor* modelactor_; -// for (const auto& pair : mActors) -// { -// modelactor_ = pair.second.get()->getModelActor(assembly_); -// -// if (modelactor_ != NULL) -// { -// selection->model_name = pair.first; -// break; -// } -// } -// if (actors) -// { -// selection->ids.reserve(3); -// -// int patch_id = modelactor_->patch_actor_id(actors->actor); -// selection->ids.push_back(modelactor_->patch_global_vid(patch_id,actors->v_local_id[0])); -// selection->ids.push_back(modelactor_->patch_global_vid(patch_id, actors->v_local_id[1])); -// selection->type = Element::Type::Edge; -// } -// -// return selection; -//} -// -//void MouseInteractorHighLightActor::SetSelector(std::unique_ptr selector) -//{ -// selector_ = std::move(selector); -//} -// -// -//vtkStandardNewMacro(MouseInteractorHighLightFace); -//void MouseInteractorHighLightFace::OnLeftButtonUp() -//{ -// if (selector_ != nullptr && click_) -// { -// click_ = false; -// int pos[2]; -// this->GetInteractor()->GetEventPosition(pos); -// selector_->select(pos[0], pos[1]); -// } -// vtkInteractorStyleTrackballCamera::OnLeftButtonUp(); -//} -// -// -// -//void MouseInteractorHighLightFace::SetClick() -//{ -// click_ = true; -//} -// -//void MouseInteractorHighLightFace::ClearSelections() -//{ -// selector_->clear(); -//} -// -//void MouseInteractorHighLightFace::SetSelector(std::unique_ptr selector) -//{ -// selector_ = std::move(selector); -//} -// -//vtkStandardNewMacro(MouseInteractorHighLightEdge); -//void MouseInteractorHighLightEdge::OnLeftButtonUp() -//{ -// if (selector_ != nullptr && click_) -// { -// click_ = false; -// int pos[2]; -// this->GetInteractor()->GetEventPosition(pos); -// selector_->select(pos[0], pos[1]); -// } -// vtkInteractorStyleTrackballCamera::OnLeftButtonUp(); -//} -// -// -//void MouseInteractorHighLightEdge::SetClick() -//{ -// click_ = true; -//} -// -//void MouseInteractorHighLightEdge::ClearSelections() -//{ -// selector_->clear(); -//} -// -// -//void MouseInteractorHighLightEdge::SetSelector(std::unique_ptr selector) -//{ -// selector_ = std::move(selector); -//} - - diff --git a/app/render/QRenderWindowStyle.h b/app/render/QRenderWindowStyle.h index f8444244c45dc5124325e38fb9432b441f531806..6d1bf63f9cfb3d50c33dabfcf264b56ca733e240 100644 --- a/app/render/QRenderWindowStyle.h +++ b/app/render/QRenderWindowStyle.h @@ -10,7 +10,6 @@ class SelectManager; - class QRenderWindowStyle : public vtkInteractorStyleTrackballCamera { public: static QRenderWindowStyle* New(); @@ -22,98 +21,5 @@ public: private: bool click_ {}; SelectManager* select_manager_{}; - }; - -//class MouseInteractorHighLightActor : public vtkInteractorStyleWithClick { -//public: -// static MouseInteractorHighLightActor* New(); -// vtkTypeMacro(MouseInteractorHighLightActor, -// vtkInteractorStyleTrackballCamera); -// -// virtual ~MouseInteractorHighLightActor() { } -// void OnLeftButtonUp() override; -// /* -// * @brief 调用select -// -// -// */ -// void OnSelect(double posx, double posy); -// -// void SetClick() override; -// void ClearSelections() override; -// /* -// * @brief 获取选中的Selection -// * -// * 判断选中的对象所属的模型,将全局ID转化为ModelActor中的局部ID,并存入Selection -// * @param[in] mActors 所有模型与模型名的映射 -// * @param[in] mode 当前的选择模式 -// -// */ -// std::unique_ptr GetSelectedIDs(const std::unordered_map>& mActors, SelectMode mode) override; -// -// void SetSelector(std::unique_ptr selector); -// -//private: -// bool click_ {}; -// std::unique_ptr selector_; -//}; -// -//class MouseInteractorHighLightFace : public vtkInteractorStyleWithClick { -//public: -// static MouseInteractorHighLightFace* New(); -// vtkTypeMacro(MouseInteractorHighLightFace, -// vtkInteractorStyleTrackballCamera); -// -// virtual ~MouseInteractorHighLightFace() { } -// virtual void OnLeftButtonUp() override; -// -// -// void SetClick() override; -// void ClearSelections() override; -// void SetSelector(std::unique_ptr selector); -// /* -// * @brief 获取选中的Selection -// * -// * 判断选中的对象所属的模型,将全局ID转化为ModelActor中的局部ID,并存入Selection -// * @param[in] mActors 所有模型与模型名的映射 -// * @param[in] mode 当前的选择模式 -// -// */ -// std::unique_ptr GetSelectedIDs(const std::unordered_map>& mActors, SelectMode mode) override; -// -//private: -// -// bool click_ {}; -// std::unique_ptr selector_; -//}; -// -//class MouseInteractorHighLightEdge : public vtkInteractorStyleWithClick { -//public: -// static MouseInteractorHighLightEdge* New(); -// vtkTypeMacro(MouseInteractorHighLightEdge, -// vtkInteractorStyleTrackballCamera); -// -// virtual ~MouseInteractorHighLightEdge() { } -// virtual void OnLeftButtonUp() override; -// -// -// -// void SetClick() override; -// void ClearSelections() override; -// void SetSelector(std::unique_ptr selector); -// /* -// * @brief 获取选中的Selection -// * -// * 判断选中的对象所属的模型,将全局ID转化为ModelActor中的局部ID,并存入Selection -// * @param[in] mActors 所有模型与模型名的映射 -// * @param[in] mode 当前的选择模式 -// -// */ -// std::unique_ptr GetSelectedIDs(const std::unordered_map>& mActors, SelectMode mode) override; -//private: -// -// bool click_ {}; -// std::unique_ptr selector_; -//}; -#endif // STYLE_H +#endif // Q_RENDER_WINDOW_STYLE_H diff --git a/app/render/SelectManager.cpp b/app/render/SelectManager.cpp index b2b4ab59b6fd1c45a1650a56133aa089647ca17c..6820cf82f4b7348b4bb261fede388a75c1bd20bb 100644 --- a/app/render/SelectManager.cpp +++ b/app/render/SelectManager.cpp @@ -1,98 +1,90 @@ #include "SelectManager.h" +#include "MeshSelectManager.h" +#include "GeometrySelectManager.h" +#include "GeometryActor.h" #include "MeshActor.h" -#include "Selection.h" -#include "SelectorHighlight.h" -#include -#include -#include -#include + +#include +#include +#include + +SelectManager::SelectManager() + : mesh_(std::make_unique()) + , geom_(std::make_unique()) +{ + // 共享 actor 始终持有一个空 mapper(None 或未激活时的兜底,避免空 mapper / 残留旧数据) + vtkNew empty; + empty_mapper_->SetInputData(empty); + highlight_actor_->SetMapper(empty_mapper_); + highlight_actor_->PickableOff(); + highlight_actor_->SetVisibility(true); +} + +SelectManager::~SelectManager() = default; void SelectManager::bindRenderer(vtkRenderer* renderer) { - this->renderer_ = renderer; + if (renderer) + renderer->AddActor(highlight_actor_); + mesh_->bindRenderer(renderer, highlight_actor_); + geom_->bindRenderer(renderer, highlight_actor_); } void SelectManager::select(double posx, double posy) { - if (this->selector_) { - assert(this->select_mode_ != SelectMode::None); - this->selector_->select(posx, posy); - } + mesh_->select(posx, posy); + geom_->select(posx, posy); } -void SelectManager::setSelectActor(std::weak_ptr model_actor_) +void SelectManager::setSelectActor(std::weak_ptr mesh_actor) { - this->cur_model_actor_ = MeshActorSelectOpFactory { model_actor_ }; - if (this->selector_) { - this->selector_->clear(); - this->selector_->setCurModelActor(*cur_model_actor_); - } + mesh_->setSelectActor(mesh_actor); } -void SelectManager::setSelectMode(SelectMode select_mode) +void SelectManager::setSelectActor(std::weak_ptr geom_actor) { - this->select_mode_ = select_mode; - if (this->select_mode_ == SelectMode::Vertex) { - this->selector_ = std::make_unique(this->renderer_); - } else if (this->select_mode_ == SelectMode::Face) { - this->selector_ = std::make_unique(this->renderer_); - } else if (this->select_mode_ == SelectMode::Block) { - this->selector_ = std::make_unique(this->renderer_); - } else if (this->select_mode_ == SelectMode::Edge) { - this->selector_ = std::make_unique(this->renderer_); - } else if (this->select_mode_ == SelectMode::Solid) { - this->selector_ = std::make_unique(this->renderer_); - } else { - assert(this->select_mode_ == SelectMode::None); - this->selector_ = nullptr; - } + geom_->setSelectActor(geom_actor); +} + +void SelectManager::setSelectMode(const std::string& select_mode) +{ + highlight_actor_->SetMapper(empty_mapper_); - if (this->selector_ && this->cur_model_actor_) { - this->selector_->setCurModelActor(*cur_model_actor_); + SelectMode mode = SelectMode::None; + if (select_mode == "Vertex") { + mode = SelectMode::Vertex; + } else if (select_mode == "Face") { + mode = SelectMode::Face; + } else if (select_mode == "Edge") { + mode = SelectMode::Edge; + } else if (select_mode == "Block") { + mode = SelectMode::Block; + } else if (select_mode == "Solid") { + mode = SelectMode::Solid; + } else if (select_mode == "GeometryVertex") { + mode = SelectMode::GeometryVertex; + } else if (select_mode == "GeometryEdge") { + mode = SelectMode::GeometryEdge; + } else if (select_mode == "GeometryFace") { + mode = SelectMode::GeometryFace; + } else if (select_mode == "GeometrySolid") { + mode = SelectMode::GeometrySolid; } + + mesh_->setSelectMode(mode); + geom_->setSelectMode(mode); } void SelectManager::clearSelection() { - if (this->selector_) { - this->selector_->clear(); - } + mesh_->clearSelection(); + geom_->clearSelection(); } std::unique_ptr SelectManager::getSelection() { - std::unique_ptr selection = std::make_unique(); - - if (this->select_mode_ == SelectMode::Vertex) { - for (const auto& id : this->selector_->get().ids) { - selection->ids.push_back(id); - } - selection->type = ElementEnum::Vertex; - } else if (this->select_mode_ == SelectMode::Face) { - for (const auto& id : this->selector_->get().ids) { - selection->ids.push_back(id); - } - selection->type = ElementEnum::Face; - } else if (this->select_mode_ == SelectMode::Block) { - for (const auto& id : this->selector_->get().ids) { - selection->ids.push_back(id); - } - selection->type = ElementEnum::Block; - }else if (this->select_mode_ == SelectMode::Solid) { - for (const auto& id : this->selector_->get().ids) { - selection->ids.push_back(id); - } - selection->type = ElementEnum::Solid; - } else if (this->select_mode_ == SelectMode::Edge) { - for (const auto& id : this->selector_->get().ids) { - selection->ids.push_back(id); - } - selection->type = ElementEnum::Edge; - } else { - if (this->selector_) - this->selector_->clear(); - return nullptr; + if (auto geom_selection = geom_->getSelection()) { + return geom_selection; } - - return selection; + return mesh_->getSelection(); } diff --git a/app/render/SelectManager.h b/app/render/SelectManager.h index 09694d5f799db3ff163a411f39b54c62ed8cb45e..00b5e9d888a772e01e63dd1237dfacce702721a7 100644 --- a/app/render/SelectManager.h +++ b/app/render/SelectManager.h @@ -1,42 +1,39 @@ #ifndef SELECT_MANAGER_H #define SELECT_MANAGER_H -#include "Selection.h" -#include "SelectorHighlight.h" -#include "MeshActorSelectOp.h" #include "Core.h" +#include "Selection.h" -#include +#include +#include #include -#include -#include +#include +#include -class SelectManager { +class vtkRenderer; +class MeshActor; +class GeometryActor; +class MeshSelectManager; +class GeometrySelectManager; +class SelectManager { public: - void bindRenderer(vtkRenderer* renderer); - /** - * @brief 传入renderer - * - * @param posx - * @param posy - */ - void select(double posx, double posy); + SelectManager(); + ~SelectManager(); + + void bindRenderer(vtkRenderer* renderer); + void select(double posx, double posy); + + void setSelectActor(std::weak_ptr mesh_actor); + void setSelectActor(std::weak_ptr geom_actor); - void setSelectActor(std::weak_ptr model_actor_); - /** - * @brief 传入选择模型 - * @param select_mode - */ - void setSelectMode(SelectMode select_mode); - void clearSelection(); - std::unique_ptr getSelection(); + void setSelectMode(const std::string& select_mode); + void clearSelection(); + std::unique_ptr getSelection(); private: - std::optional cur_model_actor_ {}; - SelectMode select_mode_; - vtkNew selection_actor_; - vtkNew selection_mapper_; - vtkRenderer* renderer_; - std::unique_ptr selector_; + std::unique_ptr mesh_; + std::unique_ptr geom_; + vtkNew highlight_actor_; + vtkNew empty_mapper_; }; #endif \ No newline at end of file diff --git a/app/render/SelectorHighlight.h b/app/render/SelectorHighlight.h index 420dbfacb1d55a3efc2b7ec8a39652b8c59f737e..6e895bd4babef03a583e1fd5b5e2195f9197fc5f 100644 --- a/app/render/SelectorHighlight.h +++ b/app/render/SelectorHighlight.h @@ -93,7 +93,7 @@ public: // int local_id; //}; //! @brief 将actor绑定到renderer,mapper绑定到actor - FaceSelectorHighlight(vtkRenderer* renderer); + FaceSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor); //! @brief 将actor从renderer中删除 ~FaceSelectorHighlight() override; //! @brief 返回当前选择的面 @@ -109,7 +109,7 @@ private: vtkRenderer* renderer_; std::vector selections_; vtkNew selected_mapper_; - vtkSmartPointer selected_actor_; + vtkActor* highlight_actor_ {}; vtkNew collection_; MeshActorSelectOpFactory model_actor_; }; @@ -117,7 +117,7 @@ private: class EdgeSelectorHighlight : public SelectorHighlight { public: //! @brief 将actor绑定到renderer,mapper绑定到actor - EdgeSelectorHighlight(vtkRenderer* renderer); + EdgeSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor); //! @brief 将actor从renderer中删除 ~EdgeSelectorHighlight() override; //! @brief 获取当前选择的边 @@ -138,7 +138,7 @@ private: vtkRenderer* renderer_; std::vector> selections_; vtkNew selected_mapper_; - vtkSmartPointer selected_actor_; + vtkActor* highlight_actor_ {}; vtkNew collection_; MeshActorSelectOpFactory model_actor_; }; @@ -146,7 +146,7 @@ private: class SolidSelectorHighlight : public SelectorHighlight { public: //! @brief 将actor绑定到renderer,mapper绑定到actor - SolidSelectorHighlight(vtkRenderer* renderer); + SolidSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor); //! @brief 将actor从renderer中删除 ~SolidSelectorHighlight() override; //! @brief 返回当前选择的体 @@ -160,7 +160,8 @@ public: private: vtkRenderer* renderer_; - vtkNew highlight_actor_; + vtkActor* highlight_actor_ {}; + vtkSmartPointer mapper_; MeshActorSelectOpFactory model_actor_; //> 当前操作的模型,可能为空 vtkNew selected_ids_; //> 存储选中的体id,绑定到了mapper,用于触发高亮体cell修改 }; @@ -171,7 +172,7 @@ private: class VertexSelectorHighlight : public SelectorHighlight { public: //! @brief 将actor绑定到renderer,mapper绑定到actor - VertexSelectorHighlight(vtkRenderer* renderer); + VertexSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor); //! @brief 将actor从renderer中删除 ~VertexSelectorHighlight() override; //! @brief 返回当前选择的点集 @@ -185,7 +186,8 @@ public: private: vtkRenderer* renderer_; - vtkNew highlight_actor_; + vtkActor* highlight_actor_ {}; + vtkSmartPointer mapper_; MeshActorSelectOpFactory model_actor_; //> 当前操作的模型,可能为空 vtkNew selected_ids_; //> 存储选中的点id,绑定到了mapper,用于触发高亮顶点修改 }; diff --git a/app/render/SolidSelectorHighlight.cpp b/app/render/SolidSelectorHighlight.cpp index 248851df8400b3919bac59b4b909d5879a36cdcf..cc54248e87f412268e4bb8123e642bef1a12a3f2 100644 --- a/app/render/SolidSelectorHighlight.cpp +++ b/app/render/SolidSelectorHighlight.cpp @@ -32,30 +32,33 @@ vtkIdType _is_selected(vtkIdType new_solid, const vtkIdTypeArray& selected_ids_) } } -SolidSelectorHighlight::SolidSelectorHighlight(vtkRenderer* renderer) +SolidSelectorHighlight::SolidSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor) : renderer_(renderer) + , highlight_actor_(highlight_actor) { this->selected_ids_->SetName("vtkOriginalCellIds"); this->selected_ids_->SetNumberOfComponents(1); this->selected_ids_->SetNumberOfValues(0); vtkNew dummy; - vtkNew mapper; - mapper->SetInputData(dummy); + this->mapper_ = vtkSmartPointer::New(); + this->mapper_->SetInputData(dummy); + this->mapper_->SetRelativeCoincidentTopologyPolygonOffsetParameters(0, -0.5); - this->highlight_actor_->SetMapper(mapper); - this->highlight_actor_->GetProperty()->SetColor(1.0, 1.0, 0.0); // 黄色高亮 - this->highlight_actor_->GetProperty()->EdgeVisibilityOn(); - this->highlight_actor_->GetProperty()->SetEdgeColor(1.0, 0.0, 0.0); // 红色边框 - this->highlight_actor_->GetProperty()->SetLineWidth(2.0); - - renderer_->AddActor(this->highlight_actor_); + if (highlight_actor_) { + highlight_actor_->SetMapper(mapper_); + vtkNew prop; + prop->SetColor(1.0, 1.0, 0.0); // 黄色高亮 + prop->EdgeVisibilityOn(); + prop->SetEdgeColor(1.0, 0.0, 0.0); // 红色边框 + prop->SetLineWidth(2.0); + highlight_actor_->SetProperty(prop); + } } SolidSelectorHighlight::~SolidSelectorHighlight() { clear(); - renderer_->RemoveActor(this->highlight_actor_); } SelectionVtk SolidSelectorHighlight::get() @@ -123,6 +126,6 @@ void SolidSelectorHighlight::setCurModelActor(MeshActorSelectOpFactory model_act this->model_actor_ = model_actor; if (auto model_actor = this->model_actor_.lock()) { vtkSmartPointer extract_selection = model_actor->extractSolid(selected_ids_); - this->highlight_actor_->GetMapper()->SetInputConnection(extract_selection->GetOutputPort()); + this->mapper_->SetInputConnection(extract_selection->GetOutputPort()); } } \ No newline at end of file diff --git a/app/render/VertexSelectorHighlight.cpp b/app/render/VertexSelectorHighlight.cpp index bc19b2ed1bfe10809cd87299629982a52ce69089..332db0f032d15f43ce25a5403a3fb6b40b76230b 100644 --- a/app/render/VertexSelectorHighlight.cpp +++ b/app/render/VertexSelectorHighlight.cpp @@ -25,28 +25,29 @@ vtkIdType _is_selected(vtkIdType new_vertex, const vtkIdTypeArray& selected_ids_ } } -VertexSelectorHighlight::VertexSelectorHighlight(vtkRenderer* renderer) +VertexSelectorHighlight::VertexSelectorHighlight(vtkRenderer* renderer, vtkActor* highlight_actor) : renderer_(renderer) + , highlight_actor_(highlight_actor) { vtkNew dummy; - vtkNew mapper; - mapper->SetInputData(dummy); + this->mapper_ = vtkSmartPointer::New(); + this->mapper_->SetInputData(dummy); - this->highlight_actor_->SetMapper(mapper); - this->highlight_actor_->GetProperty()->SetColor(1.0, 0.0, 0.0); // 红色高亮 - this->highlight_actor_->GetProperty()->SetPointSize(6.0); - this->highlight_actor_->PickableOff(); // 防止自己被选中 + if (highlight_actor_) { + highlight_actor_->SetMapper(mapper_); + vtkNew prop; + prop->SetColor(1.0, 0.0, 0.0); // 红色高亮 + prop->SetPointSize(6.0); + highlight_actor_->SetProperty(prop); + } this->selected_ids_->SetNumberOfTuples(1); this->selected_ids_->SetNumberOfValues(0); - - this->renderer_->AddActor(this->highlight_actor_); } VertexSelectorHighlight::~VertexSelectorHighlight() { clear(); - this->renderer_->RemoveActor(this->highlight_actor_); } SelectionVtk VertexSelectorHighlight::get() @@ -117,6 +118,6 @@ void VertexSelectorHighlight::setCurModelActor(MeshActorSelectOpFactory model_ac this->model_actor_ = model_actor; if (auto model_actor = this->model_actor_.lock()) { auto extract_selection = model_actor->extractVertex(this->selected_ids_); - this->highlight_actor_->GetMapper()->SetInputConnection(extract_selection->GetOutputPort()); + this->mapper_->SetInputConnection(extract_selection->GetOutputPort()); } } diff --git a/app/render/test/CMakeLists.txt b/app/render/test/CMakeLists.txt index 2786d57b692dc73114cfb888e3078c956a6cd390..dee27561bd01c5f502fd97e3c04bfcaa6ac0239c 100644 --- a/app/render/test/CMakeLists.txt +++ b/app/render/test/CMakeLists.txt @@ -55,3 +55,26 @@ target_link_libraries(TestMeshData PRIVATE VTK::InteractionStyle VTK::CommonColor VTK::RenderingCore VTK::RenderingUI VTK::RenderingOpenGL2 VTK::FiltersGeometry ) vtk_module_autoinit(TARGETS TestVertexSelectorHighlight MODULES VTK::InteractionStyle VTK::CommonColor VTK::RenderingCore VTK::RenderingUI VTK::RenderingOpenGL2 VTK::FiltersGeometry) + +# TestCadShapePicker (OCCT IVtkTools_ShapePicker) +add_executable(TestCadShapePicker "TestGeometryShapePicker.cpp") +target_link_libraries(TestCadShapePicker PRIVATE + vtkPart TestDeps + spdlog::spdlog + + VTK::InteractionStyle VTK::CommonColor + VTK::RenderingCore VTK::RenderingUI VTK::RenderingOpenGL2 + + TKIVtk + TKPrim TKBRep TKGeomBase TKMath TKernel TKTopAlgo + TKDESTEP + TKXCAF + TKVCAF + TKCAF + TKLCAF +) +vtk_module_autoinit(TARGETS TestCadShapePicker MODULES + VTK::InteractionStyle VTK::CommonColor + VTK::RenderingCore VTK::RenderingUI VTK::RenderingOpenGL2 +) +install(TARGETS TestCadShapePicker) \ No newline at end of file diff --git a/app/render/test/TestEdgeSelectorHighlight.cpp b/app/render/test/TestEdgeSelectorHighlight.cpp index 4c13f6694117015db4c4be9a3854228ee9e84e66..7adc29c430865057a2c1326cba02405330f02f59 100644 --- a/app/render/test/TestEdgeSelectorHighlight.cpp +++ b/app/render/test/TestEdgeSelectorHighlight.cpp @@ -2,6 +2,7 @@ #include "SelectorHighlight.h" #include +#include #include #include #include @@ -76,7 +77,10 @@ int main(int argc, char* argv[]) meshActor->loadModelData(test_mesh_data); // 集成 EdgeSelectorHighlight - EdgeSelectorHighlight selector(renderer); + vtkNew highlightActor; + highlightActor->PickableOff(); + renderer->AddActor(highlightActor); + EdgeSelectorHighlight selector(renderer, highlightActor); selector.setCurModelActor(MeshActorSelectOpFactory(meshActor)); style->SetSelectorHighlight(&selector); diff --git a/app/render/test/TestFaceSelectorHighlight.cpp b/app/render/test/TestFaceSelectorHighlight.cpp index d9e8a8bd1b2c768df0effea4cac6c4f3331fb83b..0b2ea0857c773ea87b4effc9984185e7d6949c6b 100644 --- a/app/render/test/TestFaceSelectorHighlight.cpp +++ b/app/render/test/TestFaceSelectorHighlight.cpp @@ -2,6 +2,7 @@ #include "SelectorHighlight.h" #include +#include #include #include #include @@ -76,7 +77,10 @@ int main(int argc, char* argv[]) meshActor->loadModelData(test_mesh_data); // 集成 FaceSelectorHighlight - FaceSelectorHighlight selector(renderer); + vtkNew highlightActor; + highlightActor->PickableOff(); + renderer->AddActor(highlightActor); + FaceSelectorHighlight selector(renderer, highlightActor); selector.setCurModelActor(MeshActorSelectOpFactory(meshActor)); style->SetSelectorHighlight(&selector); diff --git a/app/render/test/TestGeometryShapePicker.cpp b/app/render/test/TestGeometryShapePicker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b45c9d998c8fd7041a4e60fd2d01fff9ae02fb1f --- /dev/null +++ b/app/render/test/TestGeometryShapePicker.cpp @@ -0,0 +1,284 @@ +#include "GeometryActor.h" +#include "GeometryActorManager.h" +#include "GeometrySelectManager.h" + +#include "GeometryRegistry.h" +#include "GeometrySubshapeIndex.h" +#include "Selection.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +static std::optional loadStepAsSingleShape_XDE(const std::filesystem::path& path) +{ + Handle(TDocStd_Document) doc; + Handle(XCAFApp_Application)::DownCast(XCAFApp_Application::GetApplication()) + ->NewDocument("MDTV-XCAF", doc); + + STEPCAFControl_Reader reader; + IFSelect_ReturnStatus stat = reader.ReadFile(path.string().c_str()); + if (stat != IFSelect_RetDone) { + spdlog::error("Failed to read STEP file: {}", path.string()); + return std::nullopt; + } + if (!reader.Transfer(doc)) { + spdlog::error("Failed to transfer STEP file: {}", path.string()); + return std::nullopt; + } + + Handle(XCAFDoc_ShapeTool) shapeTool = XCAFDoc_DocumentTool::ShapeTool(doc->Main()); + if (shapeTool.IsNull()) { + spdlog::error("Failed to get XCAF shape tool"); + return std::nullopt; + } + + TDF_LabelSequence freeShapes; + shapeTool->GetFreeShapes(freeShapes); + if (freeShapes.Length() <= 0) { + spdlog::error("No free shapes in STEP: {}", path.string()); + return std::nullopt; + } + + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + + int added = 0; + for (Standard_Integer i = 1; i <= freeShapes.Length(); ++i) { + TopoDS_Shape s = shapeTool->GetShape(freeShapes.Value(i)); + if (s.IsNull()) + continue; + builder.Add(comp, s); + ++added; + } + + if (added == 0) { + spdlog::error("All free shapes are null in STEP: {}", path.string()); + return std::nullopt; + } + + spdlog::info("STEP loaded: {}, freeShapes={}, merged={}", path.string(), freeShapes.Length(), added); + return TopoDS_Shape(comp); +} + +class GeometrySelectInteractorStyle : public vtkInteractorStyleTrackballCamera { +public: + static GeometrySelectInteractorStyle* New(); + vtkTypeMacro(GeometrySelectInteractorStyle, vtkInteractorStyleTrackballCamera); + + void SetSelectManager(GeometrySelectManager* m) { mgr_ = m; } + + void OnLeftButtonDown() override + { + button_down_ = true; + click_ = true; + trackball_started_ = false; + this->GetInteractor()->GetEventPosition(downPos_); + } + + void OnMouseMove() override + { + if (button_down_ && click_) { + int cur[2]; + this->GetInteractor()->GetEventPosition(cur); + const int dx = cur[0] - downPos_[0]; + const int dy = cur[1] - downPos_[1]; + if (dx * dx + dy * dy > 25) { + click_ = false; + if (!trackball_started_) { + trackball_started_ = true; + vtkInteractorStyleTrackballCamera::OnLeftButtonDown(); + } + } + } + vtkInteractorStyleTrackballCamera::OnMouseMove(); + } + + void OnLeftButtonUp() override + { + button_down_ = false; + if (click_ && mgr_) { + click_ = false; + int pos[2]; + this->GetInteractor()->GetEventPosition(pos); + mgr_->select(pos[0], pos[1]); + return; + } + vtkInteractorStyleTrackballCamera::OnLeftButtonUp(); + } + + void OnKeyPress() override + { + const std::string key = this->GetInteractor()->GetKeySym() + ? this->GetInteractor()->GetKeySym() + : ""; + + if (!mgr_) { + vtkInteractorStyleTrackballCamera::OnKeyPress(); + return; + } + + if (key == "1") { + mgr_->setSelectMode(SelectMode::GeometryVertex); + spdlog::info("[GEOMETRY] mode=Vertex"); + return; + } + if (key == "2") { + mgr_->setSelectMode(SelectMode::GeometryEdge); + spdlog::info("[GEOMETRY] mode=Edge"); + return; + } + if (key == "3") { + mgr_->setSelectMode(SelectMode::GeometryFace); + spdlog::info("[GEOMETRY] mode=Face"); + return; + } + if (key == "4") { + mgr_->setSelectMode(SelectMode::GeometrySolid); + spdlog::info("[GEOMETRY] mode=Solid"); + return; + } + if (key == "c" || key == "C") { + mgr_->clearSelection(); + spdlog::info("[GEOMETRY] clear selection"); + return; + } + + vtkInteractorStyleTrackballCamera::OnKeyPress(); + } + +private: + bool click_ = false; + bool trackball_started_ = false; + bool button_down_ = false; + int downPos_[2] { 0, 0 }; + GeometrySelectManager* mgr_ = nullptr; +}; + +vtkStandardNewMacro(GeometrySelectInteractorStyle); + +} // namespace + +int main(int argc, char** argv) +{ + std::optional stepPath; + std::string modeStr = "face"; + + if (argc >= 2) { + std::filesystem::path p = argv[1]; + if (std::filesystem::exists(p)) { + stepPath = p; + if (argc >= 3) + modeStr = argv[2]; + } else { + modeStr = argv[1]; + } + std::transform(modeStr.begin(), modeStr.end(), modeStr.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); + if (modeStr != "face" && modeStr != "edge" && modeStr != "vertex" && modeStr != "solid") + modeStr = "face"; + } + + SelectMode mode = SelectMode::GeometryFace; + if (modeStr == "edge") + mode = SelectMode::GeometryEdge; + else if (modeStr == "vertex") + mode = SelectMode::GeometryVertex; + else if (modeStr == "solid") + mode = SelectMode::GeometrySolid; + + TopoDS_Shape root; + if (stepPath) { + auto s = loadStepAsSingleShape_XDE(*stepPath); + if (!s) + return 1; + root = *s; + } else { + root = BRepPrimAPI_MakeBox(100.0, 80.0, 60.0).Shape(); + } + + GeometryRegistry reg; + GeometrySubshapeIndex cadIndex; + cadIndex.build(root, reg); + + vtkNew renderer; + renderer->SetBackground(0.2, 0.3, 0.4); + + vtkNew rw; + rw->AddRenderer(renderer); + rw->SetSize(900, 700); + + vtkNew iren; + iren->SetRenderWindow(rw); + + GeometryActorManager gmgr; + gmgr.bindRender(renderer); + + const Index component_id = 123; + GeometryDataVtk gd { root, component_id, &cadIndex }; + gmgr.loadGeometry(gd); + + auto ga = gmgr.getComponentActor(component_id); + if (!ga) { + spdlog::error("GeometryActor not found for component_id={}", component_id); + return 1; + } + + gmgr.setRenderEdge(component_id, true); + gmgr.setVisibility(component_id, true); + + GeometrySelectManager selMgr; + vtkNew highlightActor; + highlightActor->PickableOff(); + renderer->AddActor(highlightActor); + selMgr.bindRenderer(renderer, highlightActor); + + auto geomActor = gmgr.getComponentActor(component_id); + selMgr.setSelectActor(geomActor); + selMgr.setSelectMode(mode); + + vtkNew style; + style->SetDefaultRenderer(renderer); + style->SetSelectManager(&selMgr); + + iren->SetInteractorStyle(style); + + renderer->ResetCamera(); + rw->Render(); + + spdlog::info("GEOMETRY selector hotkeys: [1]=Vertex [2]=Edge [3]=Face [4]=Solid [C]=Clear"); + + iren->Start(); + return 0; +} diff --git a/app/render/test/TestSolidSelectorHighlight.cpp b/app/render/test/TestSolidSelectorHighlight.cpp index 0712658049c3f2d867d9cd9b1c87ae4e2ef5ec65..f0f3c88d79f25535df1d7514350cfc1e46b9210e 100644 --- a/app/render/test/TestSolidSelectorHighlight.cpp +++ b/app/render/test/TestSolidSelectorHighlight.cpp @@ -75,7 +75,10 @@ int main(int argc, char* argv[]) meshActor->loadModelData(test_mesh_data); // 体元高亮选择器 - SolidSelectorHighlight selector(renderer); + vtkNew highlightActor; + highlightActor->PickableOff(); + renderer->AddActor(highlightActor); + SolidSelectorHighlight selector(renderer, highlightActor); selector.setCurModelActor(MeshActorSelectOpFactory(meshActor)); style->SetSelectorHighlight(&selector); diff --git a/app/render/test/TestVertexSelectorHighlight.cpp b/app/render/test/TestVertexSelectorHighlight.cpp index 84cd3f8d1e5685cd98111781ddbb75aba6081674..e1b547ecc16eaebf0fa34ad2a4d6c2826d917686 100644 --- a/app/render/test/TestVertexSelectorHighlight.cpp +++ b/app/render/test/TestVertexSelectorHighlight.cpp @@ -2,6 +2,7 @@ #include "SelectorHighlight.h" #include #include +#include #include #include #include @@ -64,7 +65,10 @@ int main(int argc, char* argv[]) meshActor->loadModelData(test_mesh_data); // 集成 VertexSelectorHighlight - VertexSelectorHighlight selector(renderer); + vtkNew highlightActor; + highlightActor->PickableOff(); + renderer->AddActor(highlightActor); + VertexSelectorHighlight selector(renderer, highlightActor); selector.setCurModelActor(MeshActorSelectOpFactory(meshActor)); style->SetSelectorHighlight(&selector); diff --git a/core/Core.h b/core/Core.h index 8328c258cb7f34ec6d87126acc7d584c565a98f6..45aa21a370b47d3a5965f0fa6997a7a1eb7f9c75 100644 --- a/core/Core.h +++ b/core/Core.h @@ -23,7 +23,11 @@ enum class SelectMode { Face, Edge, Solid, - Block + Block, + GeometryVertex, + GeometryEdge, + GeometryFace, + GeometrySolid }; /** diff --git a/core/GeometryDataVtk.h b/core/GeometryDataVtk.h index 249e1501e97ad356b6fe66b1f1dd2c63404c85f0..023e9e3d285f6690d51eedc8c50908de8c23732d 100644 --- a/core/GeometryDataVtk.h +++ b/core/GeometryDataVtk.h @@ -1,9 +1,11 @@ #ifndef GEOMETRY_DATA_VTK_H #define GEOMETRY_DATA_VTK_H class TopoDS_Shape; +struct GeometrySubshapeIndex; struct GeometryDataVtk { - TopoDS_Shape& shape; + const TopoDS_Shape& shape; Index component_id { -1 }; + const GeometrySubshapeIndex* geometry_index { nullptr }; }; #endif // !GEOMETRY_DATA_VTK_H diff --git a/core/Selection.h b/core/Selection.h index 1d19aef7880c24733556a799eae0634ca3808646..ae6a674638d27a30b328af2759bf8f5ae29b6fd4 100644 --- a/core/Selection.h +++ b/core/Selection.h @@ -13,7 +13,11 @@ public: Edge, Vertex, Block, - Group + Group, + GeometrySolid, + GeometryFace, + GeometryEdge, + GeometryVertex }; }; diff --git a/model/data/GeometrySubshapeIndex.cpp b/model/data/GeometrySubshapeIndex.cpp index 843bb236b9bca422184e05e7f0e92941c0b17fd0..f3db40dd82e498e0f2a970b04efd613ef1ee479b 100644 --- a/model/data/GeometrySubshapeIndex.cpp +++ b/model/data/GeometrySubshapeIndex.cpp @@ -1,6 +1,8 @@ #include "GeometrySubshapeIndex.h" #include "GeometryRegistry.h" +#include + #include #include #include @@ -25,6 +27,21 @@ void GeometrySubshapeIndex::build(const TopoDS_Shape& root, GeometryRegistry& re TopExp::MapShapes(root, type, type_maps[ti]); } + { + const int nVertices = type_maps[typeIndex(TopAbs_VERTEX)].Extent(); + const int nEdges = type_maps[typeIndex(TopAbs_EDGE)].Extent(); + const int nWires = type_maps[typeIndex(TopAbs_WIRE)].Extent(); + const int nFaces = type_maps[typeIndex(TopAbs_FACE)].Extent(); + const int nShells = type_maps[typeIndex(TopAbs_SHELL)].Extent(); + const int nSolids = type_maps[typeIndex(TopAbs_SOLID)].Extent(); + const int nCompounds = type_maps[typeIndex(TopAbs_COMPOUND)].Extent(); + const int nCompSolids = type_maps[typeIndex(TopAbs_COMPSOLID)].Extent(); + + spdlog::info("[GeometryIndex] sub-shape summary:" + " Vertex={}, Edge={}, Wire={}, Face={}, Shell={}, Solid={}, CompSolid={}, Compound={}", + nVertices, nEdges, nWires, nFaces, nShells, nSolids, nCompSolids, nCompounds); + } + // 2) Vertex: localTypeId -> GeomVertexId { const int ti = typeIndex(TopAbs_VERTEX);