From e8f17a88ccb96891b9c2ff98466fdb8657c3cfd5 Mon Sep 17 00:00:00 2001 From: Young <2109190674@qq.com> Date: Mon, 24 Aug 2026 16:14:19 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix(renderStrategy):=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E8=BE=B9=E5=B1=9E=E6=80=A7=E6=B8=B2=E6=9F=93=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/model/QModelQuery.cpp | 4 +-- app/render/MeshActor.cpp | 9 +++++- app/render/MeshActor.h | 2 ++ .../renderStrategy/AttriRenderStrategyRGB.cpp | 14 +++++++-- .../AttriRenderStrategyScalar.cpp | 17 +++++++++- .../AttriRenderStrategyVector.cpp | 11 ++++++- .../renderStrategy/AttributeOperator.cpp | 31 +++++++++++++++++++ app/render/renderStrategy/AttributeOperator.h | 3 ++ .../IAttributeRenderStrategy.cpp | 1 + 9 files changed, 85 insertions(+), 7 deletions(-) diff --git a/app/model/QModelQuery.cpp b/app/model/QModelQuery.cpp index 244d61d..6e962f4 100644 --- a/app/model/QModelQuery.cpp +++ b/app/model/QModelQuery.cpp @@ -45,7 +45,7 @@ void appendAttributeInfo( item["type"] = static_cast(type); item["typeName"] = type_name; item["attrType"] = attr_type; - item["renderable"] = type != Element::Type::Edge; + item["renderable"] = true; item["componentCount"] = component_count; out.append(item); } @@ -524,4 +524,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 a3c53aa..4c56217 100644 --- a/app/render/MeshActor.cpp +++ b/app/render/MeshActor.cpp @@ -60,7 +60,7 @@ void addPointAttributes( } } -// 将面属性或体属性写入对应 VTK 数据对象的 CellData。 +// 将边、面或体属性写入对应 VTK 数据对象的 CellData。 void addCellAttributes( vtkCellData& cell_data, const std::map>& attributes, @@ -204,6 +204,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 @@ -229,6 +231,11 @@ void MeshActor::loadModelData(const MeshDataVtk& model_data) // 单元中心点只和几何拓扑有关,在加载数据时统一计算并缓存,属性渲染阶段直接复用。 { + vtkNew edge_centers; + edge_centers->SetInputData(edge_poly); + edge_centers->Update(); + edge_cell_centers_->DeepCopy(edge_centers->GetOutput()); + vtkNew face_centers; face_centers->SetInputData(face_poly); face_centers->Update(); diff --git a/app/render/MeshActor.h b/app/render/MeshActor.h index 7de0994..9ec799c 100644 --- a/app/render/MeshActor.h +++ b/app/render/MeshActor.h @@ -102,6 +102,8 @@ private: vtkNew face_data_; vtkNew edge_data_; + // 缓存边单元中心点,供边向量 glyph 复用。 + vtkNew edge_cell_centers_; // 缓存面单元中心点。 vtkNew face_cell_centers_; // 缓存体单元中心点。 diff --git a/app/render/renderStrategy/AttriRenderStrategyRGB.cpp b/app/render/renderStrategy/AttriRenderStrategyRGB.cpp index ae3af54..d20df4e 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 2687020..d5ea311 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 130026f..ab242e0 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 6733ed3..d1ef191 100644 --- a/app/render/renderStrategy/AttributeOperator.cpp +++ b/app/render/renderStrategy/AttributeOperator.cpp @@ -123,6 +123,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 +156,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(); @@ -229,6 +239,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 = 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_; diff --git a/app/render/renderStrategy/AttributeOperator.h b/app/render/renderStrategy/AttributeOperator.h index 32429c0..3b584e0 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 c5d07ea..d2a2c91 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); } -- Gitee From ca77e95d2c43c93c369347f02dd7ac3002724b58 Mon Sep 17 00:00:00 2001 From: Young <2109190674@qq.com> Date: Wed, 26 Aug 2026 14:55:03 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix(renderStrategy):=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=97=A0=E7=94=A8=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/AttributeRenderPanel.qml | 8 ++------ app/model/QModelQuery.cpp | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/AttributeRenderPanel.qml b/app/AttributeRenderPanel.qml index 6cc3ca4..94e6a99 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 6e962f4..ae0ca21 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"] = true; item["componentCount"] = component_count; out.append(item); } -- Gitee From d956ca597379070c8d4583e04008de6d39ddbbaa Mon Sep 17 00:00:00 2001 From: Young <2109190674@qq.com> Date: Sat, 29 Aug 2026 18:29:46 +0800 Subject: [PATCH 3/3] =?UTF-8?q?refactor(AttributeRender):=20=E6=87=92?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E5=B9=B6=E5=A4=8D=E7=94=A8=E8=BE=B9=E9=9D=A2?= =?UTF-8?q?=E4=BD=93=E5=8D=95=E5=85=83=E4=B8=AD=E5=BF=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/render/MeshActor.cpp | 24 ++++------------- app/render/MeshActor.h | 11 ++++---- .../renderStrategy/AttributeOperator.cpp | 27 ++++++++++++++----- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/app/render/MeshActor.cpp b/app/render/MeshActor.cpp index 4c56217..92113c6 100644 --- a/app/render/MeshActor.cpp +++ b/app/render/MeshActor.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -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()); @@ -229,24 +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 edge_centers; - edge_centers->SetInputData(edge_poly); - edge_centers->Update(); - edge_cell_centers_->DeepCopy(edge_centers->GetOutput()); - - 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 9ec799c..f8ec72e 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,12 +103,10 @@ private: vtkNew face_data_; vtkNew edge_data_; - // 缓存边单元中心点,供边向量 glyph 复用。 - vtkNew edge_cell_centers_; - // 缓存面单元中心点。 - 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/AttributeOperator.cpp b/app/render/renderStrategy/AttributeOperator.cpp index d1ef191..d37de0c 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] {}; @@ -226,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; @@ -249,8 +265,8 @@ vtkSmartPointer AttributeOperator::getEdgeGlyphInput(const std::str if (!array) return nullptr; - // 边向量位于线段中心,直接复用模型加载阶段缓存的中心点。 - vtkPolyData* centers = mesh_actor_->edge_cell_centers_; + // 边向量位于线段中心,首次请求时计算并缓存中心点。 + vtkPolyData* centers = ensureCellCenters(*edge_data, mesh_actor_->edge_cell_centers_); if (!centers || !centers->GetPoints()) return nullptr; @@ -311,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; -- Gitee