diff --git a/app/AttributeRenderPanel.qml b/app/AttributeRenderPanel.qml index 6cc3ca470b1be03f440d75f7243b634eba573ab6..94e6a991d657ba6096dcdca7cad94641907ebdba 100644 --- a/app/AttributeRenderPanel.qml +++ b/app/AttributeRenderPanel.qml @@ -74,7 +74,7 @@ Item { function canApply() { let attr = selectedAttribute() - if (!attr || !attr.renderable || !App.registry.renderWindow) + if (!attr || !App.registry.renderWindow) return false if (modeCombo.currentIndex === 0 && attr.componentCount !== 3) @@ -137,7 +137,6 @@ Item { color: root.selectedIndex === index ? "#cfe8ff" : "transparent" border.color: "#d0d0d0" border.width: 1 - opacity: modelData.renderable ? 1.0 : 0.45 RowLayout { anchors.fill: parent @@ -163,9 +162,7 @@ Item { } } Label { - text: modelData.renderable - ? (modelData.componentCount > 0 ? modelData.componentCount + "分量" : "") - : "暂不支持" + text: modelData.componentCount > 0 ? modelData.componentCount + "分量" : "" elide: Text.ElideRight } } @@ -174,7 +171,6 @@ Item { id: attributeMouse anchors.fill: parent hoverEnabled: true - enabled: modelData.renderable onClicked: { root.selectedIndex = index modeCombo.currentIndex = root.inferMode(modelData) diff --git a/app/model/QModelQuery.cpp b/app/model/QModelQuery.cpp index 244d61d668a20a61c52ec35c1c930c0a80d0fa12..ae0ca211344dda49b872f002f4943cced71070aa 100644 --- a/app/model/QModelQuery.cpp +++ b/app/model/QModelQuery.cpp @@ -45,7 +45,6 @@ void appendAttributeInfo( item["type"] = static_cast(type); item["typeName"] = type_name; item["attrType"] = attr_type; - item["renderable"] = type != Element::Type::Edge; item["componentCount"] = component_count; out.append(item); } @@ -524,4 +523,4 @@ std::optional QModelQuery::resolveGeometrySolidLocalId(Index compon return std::nullopt; return gid; -} \ No newline at end of file +} diff --git a/app/render/MeshActor.cpp b/app/render/MeshActor.cpp index a3c53aa5d1bad7910d0b4b235165d2a90f1d4db0..92113c6f864d48d6d1d29cb3553ee26c7023595b 100644 --- a/app/render/MeshActor.cpp +++ b/app/render/MeshActor.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -60,7 +59,7 @@ void addPointAttributes( } } -// 将面属性或体属性写入对应 VTK 数据对象的 CellData。 +// 将边、面或体属性写入对应 VTK 数据对象的 CellData。 void addCellAttributes( vtkCellData& cell_data, const std::map>& attributes, @@ -130,6 +129,11 @@ void MeshActor::loadModelData(const MeshDataVtk& model_data) { this->model_data_ = std::make_unique(model_data); + // 单元中心只依赖当前网格;重新加载后先失效,首次向量渲染时再按需计算。 + edge_cell_centers_ = nullptr; + face_cell_centers_ = nullptr; + solid_cell_centers_ = nullptr; + // 组件私有点集:坐标自持,连通性数组直接以局部点 id 作 VTK 点索引 const auto& positions = model_data.vertex_positions_; const vtkIdType point_count = static_cast(positions.size()); @@ -204,6 +208,8 @@ void MeshActor::loadModelData(const MeshDataVtk& model_data) edge_poly->SetLines(edge_cells); edge_poly->GetPointData()->AddArray(original_point_ids_.GetPointer()); + addCellAttributes(*edge_poly->GetCellData(), model_data.edge_attributes_, + edge_poly->GetNumberOfCells(), "edge"); } // solid data @@ -227,19 +233,6 @@ void MeshActor::loadModelData(const MeshDataVtk& model_data) addPointAttributes(*solid_ugird->GetPointData(), model_data.vertex_attributes_, point_count); addCellAttributes(*solid_ugird->GetCellData(), model_data.solid_attributes_, solid_cells_count, "solid"); - // 单元中心点只和几何拓扑有关,在加载数据时统一计算并缓存,属性渲染阶段直接复用。 - { - vtkNew face_centers; - face_centers->SetInputData(face_poly); - face_centers->Update(); - face_cell_centers_->DeepCopy(face_centers->GetOutput()); - - vtkNew solid_centers; - solid_centers->SetInputData(solid_ugird); - solid_centers->Update(); - solid_cell_centers_->DeepCopy(solid_centers->GetOutput()); - } - solid_filter_->SetInputData(solid_ugird); solid_edge_extractor_->SetInputData(solid_ugird); diff --git a/app/render/MeshActor.h b/app/render/MeshActor.h index 7de099413f34efc57f0e811a7f5af42393b7ffbd..f8ec72e8cd263483d01918d7a01eaefaa68faa6e 100644 --- a/app/render/MeshActor.h +++ b/app/render/MeshActor.h @@ -13,6 +13,7 @@ #include #include #include +#include class vtkGeometryFilter; class vtkExtractGeometry; class vtkExtractPolyDataGeometry; @@ -102,10 +103,10 @@ private: vtkNew face_data_; vtkNew edge_data_; - // 缓存面单元中心点。 - vtkNew face_cell_centers_; - // 缓存体单元中心点。 - vtkNew solid_cell_centers_; + // 边、面、体单元中心点在首次向量渲染时计算,网格重新加载后置空失效。 + vtkSmartPointer edge_cell_centers_; + vtkSmartPointer face_cell_centers_; + vtkSmartPointer solid_cell_centers_; FaceAttributeOffsetState face_attribute_offset_; diff --git a/app/render/renderStrategy/AttriRenderStrategyRGB.cpp b/app/render/renderStrategy/AttriRenderStrategyRGB.cpp index ae3af540bc6bb7848388c430fa09862e45a4dc25..d20df4e9d454140647931f77b132d2a387e92ba6 100644 --- a/app/render/renderStrategy/AttriRenderStrategyRGB.cpp +++ b/app/render/renderStrategy/AttriRenderStrategyRGB.cpp @@ -28,6 +28,16 @@ void AttriRenderStrategyRGB::render( solid_mapper->SetColorModeToDirectScalars(); return; } + // 判断是否是边属性 + array = op.getEdgeCellData()->GetArray(attr_name.c_str()); + if (array) { + op.getEdgeCellData()->SetActiveScalars(attr_name.c_str()); + vtkPolyDataMapper* edge_mapper = op.getEdgeMapper(); + edge_mapper->SetScalarModeToUseCellData(); + edge_mapper->SetScalarVisibility(1); + edge_mapper->SetColorModeToDirectScalars(); + return; + } // 判断是否是面属性 array = op.getFaceCellData()->GetArray(attr_name.c_str()); if (array) { @@ -51,5 +61,5 @@ void AttriRenderStrategyRGB::render( return; } - spdlog::error("Attribute {} not found in point, face or solid data.", attr_name); -} \ No newline at end of file + spdlog::error("Attribute {} not found in point, edge, face or solid data.", attr_name); +} diff --git a/app/render/renderStrategy/AttriRenderStrategyScalar.cpp b/app/render/renderStrategy/AttriRenderStrategyScalar.cpp index 26870209b216b2407fd1b7d422c598dc1ea4ac5b..d5ea3114534ba8af755b119ffe945e6094fb4c7f 100644 --- a/app/render/renderStrategy/AttriRenderStrategyScalar.cpp +++ b/app/render/renderStrategy/AttriRenderStrategyScalar.cpp @@ -102,6 +102,21 @@ void AttriRenderStrategyScalar::render( solid_mapper->SetLookupTable(face_mapper->GetLookupTable()); return; } + // 判断是否是边属性 + array = op.getEdgeCellData()->GetArray(attr_name.c_str()); + if (array) { + double range[2]; + resolveRange(array, range); + + op.getEdgeCellData()->SetActiveScalars(attr_name.c_str()); + vtkPolyDataMapper* edge_mapper = op.getEdgeMapper(); + edge_mapper->SetScalarRange(range[0], range[1]); + edge_mapper->SetScalarModeToUseCellData(); + edge_mapper->SetScalarVisibility(1); + edge_mapper->SetColorModeToMapScalars(); + showScalarBar(edge_mapper, attr_name, range); + return; + } // 判断是否是面属性 array = op.getFaceCellData()->GetArray(attr_name.c_str()); if (array) { @@ -135,5 +150,5 @@ void AttriRenderStrategyScalar::render( return; } - spdlog::error("Attribute {} not found in point, face or solid data.", attr_name); + spdlog::error("Attribute {} not found in point, edge, face or solid data.", attr_name); } diff --git a/app/render/renderStrategy/AttriRenderStrategyVector.cpp b/app/render/renderStrategy/AttriRenderStrategyVector.cpp index 130026f3121bcf1f9f6fcedba9ff7083f09f55bd..ab242e060868e4831db92c8032ac6aa73afa25cd 100644 --- a/app/render/renderStrategy/AttriRenderStrategyVector.cpp +++ b/app/render/renderStrategy/AttriRenderStrategyVector.cpp @@ -57,6 +57,15 @@ void AttriRenderStrategyVector::render( createGlyph3D(op, point_data, { 1.0, 0.0, 0.0 }, glyph_scale); return; } + // 判断是否是边属性 + array = op.getEdgeCellData()->GetArray(attr_name.c_str()); + if (array) { + if (!isValidVectorArray(array, attr_name)) + return; + vtkSmartPointer glyph_input = op.getEdgeGlyphInput(attr_name); + createGlyph3D(op, glyph_input, { 1.0, 0.6, 0.0 }, glyph_scale); + return; + } // 判断是否是面属性 array = op.getFaceCellData()->GetArray(attr_name.c_str()); if (array) { @@ -76,7 +85,7 @@ void AttriRenderStrategyVector::render( return; } - spdlog::error("Attribute {} not found in point, face or solid data.", attr_name); + spdlog::error("Attribute {} not found in point, edge, face or solid data.", attr_name); } void AttriRenderStrategyVector::createGlyph3D(AttributeOperator& op, vtkDataSet* input, const std::array& color, double scale) diff --git a/app/render/renderStrategy/AttributeOperator.cpp b/app/render/renderStrategy/AttributeOperator.cpp index 6733ed3f47f6a66ac8003ec73ab5886b1f6cbbc8..d37de0cffb3fe7b5c18985ab024b83334b8b2696 100644 --- a/app/render/renderStrategy/AttributeOperator.cpp +++ b/app/render/renderStrategy/AttributeOperator.cpp @@ -1,8 +1,11 @@ #include "AttributeOperator.h" +#include #include #include +#include #include #include +#include #include #include #include @@ -15,6 +18,20 @@ namespace { constexpr Index kMaxEdgeSamples = 1000; +//! @brief 首次请求时计算单元中心,后续向量渲染直接复用缓存 +vtkPolyData* ensureCellCenters(vtkDataSet& data, vtkSmartPointer& cache) +{ + if (!cache) { + vtkNew centers; + centers->SetInputData(&data); + centers->Update(); + + // vtkSmartPointer 持有输出对象,局部 filter 析构后缓存仍然有效。 + cache = centers->GetOutput(); + } + return cache.GetPointer(); +} + double distanceBetweenPoints(vtkPoints& points, Index point_id_a, Index point_id_b) { double a[3] {}; @@ -123,6 +140,11 @@ vtkPolyDataMapper* AttributeOperator::getFaceMapper() { return mesh_actor_->face_mapper_; } +vtkPolyDataMapper* AttributeOperator::getEdgeMapper() +{ + return mesh_actor_->edge_mapper_; +} + vtkPolyDataMapper* AttributeOperator::getSolidMapper() { return mesh_actor_->solid_mapper_; @@ -151,6 +173,11 @@ vtkPointData* AttributeOperator::getFacePointData() return mesh_actor_->face_data_->GetPointData(); } +vtkCellData* AttributeOperator::getEdgeCellData() +{ + return mesh_actor_->edge_data_->GetCellData(); +} + vtkCellData* AttributeOperator::getSolidCellData() { return mesh_actor_->solid_data_->GetCellData(); @@ -216,8 +243,7 @@ vtkSmartPointer AttributeOperator::getFaceGlyphInput(const std::str if (!array) return nullptr; - // 使用加载阶段缓存的面中心点,避免属性切换或重复渲染时重新计算 vtkCellCenters。 - vtkPolyData* centers = mesh_actor_->face_cell_centers_; + vtkPolyData* centers = ensureCellCenters(*face_data, mesh_actor_->face_cell_centers_); if (!centers || !centers->GetPoints()) return nullptr; @@ -229,6 +255,27 @@ vtkSmartPointer AttributeOperator::getFaceGlyphInput(const std::str return glyphInput; } +vtkSmartPointer AttributeOperator::getEdgeGlyphInput(const std::string& attr_name) +{ + vtkPolyData* edge_data = mesh_actor_->edge_data_; + if (!edge_data) + return nullptr; + + vtkDataArray* array = edge_data->GetCellData()->GetArray(attr_name.c_str()); + if (!array) + return nullptr; + + // 边向量位于线段中心,首次请求时计算并缓存中心点。 + vtkPolyData* centers = ensureCellCenters(*edge_data, mesh_actor_->edge_cell_centers_); + if (!centers || !centers->GetPoints()) + return nullptr; + + vtkSmartPointer glyph_input = vtkSmartPointer::New(); + glyph_input->SetPoints(centers->GetPoints()); + glyph_input->GetPointData()->SetVectors(array); + return glyph_input; +} + vtkSmartPointer AttributeOperator::getPointGlyphInput(const std::string& attr_name) { vtkPolyData* face_data = mesh_actor_->face_data_; @@ -280,8 +327,7 @@ vtkSmartPointer AttributeOperator::getSolidGlyphInput(const std::st if (!array) return nullptr; - //使用加载阶段缓存的体中心点 - vtkPolyData* centers = mesh_actor_->solid_cell_centers_; + vtkPolyData* centers = ensureCellCenters(*solid_data, mesh_actor_->solid_cell_centers_); if (!centers || !centers->GetPoints()) return nullptr; diff --git a/app/render/renderStrategy/AttributeOperator.h b/app/render/renderStrategy/AttributeOperator.h index 32429c0600021129c89866e82b0147d8332710ea..3b584e0de2b5f3d12ecce51225b781daae333edc 100644 --- a/app/render/renderStrategy/AttributeOperator.h +++ b/app/render/renderStrategy/AttributeOperator.h @@ -13,6 +13,7 @@ public: AttributeOperator(MeshActor* mesh_actor_); vtkPolyDataMapper* getFaceMapper(); + vtkPolyDataMapper* getEdgeMapper(); vtkPolyDataMapper* getSolidMapper(); vtkPolyDataMapper* getGlyph3DMapper(); @@ -21,6 +22,7 @@ public: vtkCellData* getFaceCellData(); vtkPointData* getFacePointData(); + vtkCellData* getEdgeCellData(); vtkCellData* getSolidCellData(); vtkPointData* getSolidPointData(); @@ -34,6 +36,7 @@ public: double getMeshScale() const noexcept; vtkSmartPointer getFaceGlyphInput(const std::string& attr_name); + vtkSmartPointer getEdgeGlyphInput(const std::string& attr_name); vtkSmartPointer getPointGlyphInput(const std::string& attr_name); vtkSmartPointer getSolidGlyphInput(const std::string& attr_name); diff --git a/app/render/renderStrategy/IAttributeRenderStrategy.cpp b/app/render/renderStrategy/IAttributeRenderStrategy.cpp index c5d07ead25d0bf34996f6369c54a6252b0eea0b4..d2a2c91c7076a3f4dadff08e2703cf9515d4f37b 100644 --- a/app/render/renderStrategy/IAttributeRenderStrategy.cpp +++ b/app/render/renderStrategy/IAttributeRenderStrategy.cpp @@ -8,6 +8,7 @@ void IAttributeRenderStrategy::cancelActiveAttribute(AttributeOperator op) op.getFaceActor()->SetTexture(nullptr); } op.getGlyph3DActor()->SetVisibility(0); + op.getEdgeMapper()->SetScalarVisibility(0); op.getFaceMapper()->SetScalarVisibility(0); op.getSolidMapper()->SetScalarVisibility(0); }