BUG: Surface extraction filters discard source length units
Los mantenedores suelen responder en 4 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- Medio día
- Aptitud para principiantes
- 72/100
Línea de trabajo
Empieza en el código de preflight de ExtractTripleLinesFilter.cpp (alrededor de las líneas 162-166) y en ExtractInternalSurfacesFromTriangleGeometryFilter.cpp (alrededor de las líneas 180-187), donde las geometrías de salida se crean sin unidad de origen. Traslada getUnits() de la geometría de entrada a cada salida y luego crea el JunctionLengthUnitsTest.cpp sugerido. Después ejecuta las entradas de CTest JunctionLengthUnits_. Está terminado cuando ambas comprobaciones de unidades informan Micrometer y las comprobaciones numéricas existentes siguen pasando.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Problem
ExtractTripleLinesFilter and ExtractInternalSurfacesFromTriangleGeometryFilter discard the source Triangle Geometry's length units at commit fe6c4a15e5a5bffef2523f52cec01be33b1e62a9. A Micrometer input produces Meter output even though extraction retains the numeric vertex coordinates. Both filters complete successfully.
| Operation | Numeric output verified | Expected units | Actual units |
|---|---|---|---|
| Extract Triple Lines | One edge from (10,20,30) to (10,20,34), two vertices, NumFeatures=3 |
Micrometer (6) | Meter (10) |
| Extract Internal Surfaces, Node Type Range | Three original triangles, five original vertices | Micrometer (6) | Meter (10) |
| Extract Internal Surfaces, Face Labels | Three original triangles, five original vertices | Micrometer (6) | Meter (10) |
Consumers that use the unit metadata can therefore interpret the unchanged coordinates at the wrong physical scale.
Steps to Reproduce
- At the commit above, create a Triangle Geometry with units
IGeometry::LengthUnit::Micrometerand these five vertices:(10,20,30),(10,20,34),(11,20,32),(10,21,32),(9,19,32). - Set triangle connectivity to
(0,1,2),(0,1,3),(0,1,4). Set the corresponding two-component int32 Face Labels to(1,2),(2,3),(1,3). Set all five int8 Node Types to3. - Run Extract Triple Lines with those arrays, Copy Node Types enabled, Include Exterior Triple Lines disabled, and a new output geometry. The expected result is the shared edge
(0,1)with unchanged endpoints and Micrometer units. - On a fresh copy of the explicitly constructed input, run Extract Internal Surfaces From Triangle Geometry with Node Type Range
[0,8]. On another fresh input, repeat with the Face Labels criterion. All three faces satisfy both criteria. - Check output geometry counts, coordinates, connectivity, and
getUnits(). The numeric checks pass, but all three unit checks report Meter instead of Micrometer.
The verification below constructs every input in memory; it requires no downloaded dataset.
Cause
The preflight implementations create new output geometries without transferring the source unit:
-
ExtractTripleLinesFilter.cpp, lines 162-166:
auto createGeometryAction = std::make_unique<CreateEdgeGeometryAction>(pTripleLineGeometryPath, 0, 0, pVertexDataName, pEdgeDataName, EdgeGeom::k_SharedVertexListName, EdgeGeom::k_SharedEdgeListName); -
ExtractInternalSurfacesFromTriangleGeometryFilter.cpp, lines 180-187:
auto createInternalTrianglesAction = std::make_unique<CreateTriangleGeometryAction>(internalTrianglesGeomPath, numFaces, numVertices, vertexDataName, faceDataName, TriangleGeom::k_SharedVertexListName, TriangleGeom::k_SharedFacesListName);
The new geometries inherit the default LengthUnit::Meter. Neither extraction algorithm transfers the source units. Triple-line extraction copies the original coordinates directly, and internal-surface extraction copies the selected coordinates through its vertex remap. No coordinate conversion accounts for the change in unit metadata.
Verification Unit Test
Suggested test file: src/Plugins/SimplnxCore/test/JunctionLengthUnitsTest.cpp, registered in that directory's ${PLUGIN_NAME}UnitTest_SRCS list. The complete source below was compiled and executed in a small standalone Catch2 harness that linked the existing production SimplnxCore.lib and simplnx.lib built from the reported commit. It loaded byte-identical copies of those builds' SimplnxCore.simplnx and simplnx.dll. No filter or algorithm source was replaced or modified.
#include "SimplnxCore/Filters/ExtractInternalSurfacesFromTriangleGeometryFilter.hpp"
#include "SimplnxCore/Filters/ExtractTripleLinesFilter.hpp"
#include "simplnx/DataStructure/AttributeMatrix.hpp"
#include "simplnx/DataStructure/DataArray.hpp"
#include "simplnx/DataStructure/DataStore.hpp"
#include "simplnx/DataStructure/DataStructure.hpp"
#include "simplnx/DataStructure/Geometry/EdgeGeom.hpp"
#include "simplnx/DataStructure/Geometry/TriangleGeom.hpp"
#include "simplnx/Filter/Arguments.hpp"
#include "simplnx/Parameters/ChoicesParameter.hpp"
#include "simplnx/UnitTest/UnitTestCommon.hpp"
#include <catch2/catch.hpp>
#include <any>
#include <array>
#include <memory>
#include <vector>
using namespace nx::core;
namespace
{
const DataPath k_InputPath({"TriangleGeom"});
const DataPath k_OutputPath({"Extracted"});
const DataPath k_NodeTypesPath({"TriangleGeom", "Vertex Data", "NodeTypes"});
const DataPath k_FaceLabelsPath({"TriangleGeom", "Face Data", "FaceLabels"});
constexpr std::array<float32, 15> k_Vertices = {10, 20, 30, 10, 20, 34, 11, 20, 32, 10, 21, 32, 9, 19, 32};
constexpr std::array<IGeometry::MeshIndexType, 9> k_Triangles = {0, 1, 2, 0, 1, 3, 0, 1, 4};
constexpr std::array<int32, 6> k_FaceLabels = {1, 2, 2, 3, 1, 3};
void CreateJunctionMesh(DataStructure& dataStructure)
{
auto* geometry = TriangleGeom::Create(dataStructure, k_InputPath.getTargetName());
REQUIRE(geometry != nullptr);
geometry->setUnits(IGeometry::LengthUnit::Micrometer);
auto* vertices = Float32Array::Create(dataStructure, TriangleGeom::k_SharedVertexListName, std::make_unique<DataStore<float32>>(ShapeType{5}, ShapeType{3}, 0.0f), geometry->getId());
REQUIRE(vertices != nullptr);
for(usize i = 0; i < k_Vertices.size(); i++)
{
(*vertices)[i] = k_Vertices[i];
}
geometry->setVertices(*vertices);
auto* faces = UInt64Array::Create(dataStructure, TriangleGeom::k_SharedFacesListName, std::make_unique<DataStore<IGeometry::MeshIndexType>>(ShapeType{3}, ShapeType{3}, 0), geometry->getId());
REQUIRE(faces != nullptr);
for(usize i = 0; i < k_Triangles.size(); i++)
{
(*faces)[i] = k_Triangles[i];
}
geometry->setFaceList(*faces);
auto* vertexData = AttributeMatrix::Create(dataStructure, "Vertex Data", ShapeType{5}, geometry->getId());
REQUIRE(vertexData != nullptr);
geometry->setVertexAttributeMatrix(*vertexData);
auto* nodeTypes = Int8Array::Create(dataStructure, "NodeTypes", std::make_unique<DataStore<int8>>(ShapeType{5}, ShapeType{1}, 3), vertexData->getId());
REQUIRE(nodeTypes != nullptr);
auto* faceData = AttributeMatrix::Create(dataStructure, "Face Data", ShapeType{3}, geometry->getId());
REQUIRE(faceData != nullptr);
geometry->setFaceAttributeMatrix(*faceData);
auto* faceLabels = Int32Array::Create(dataStructure, "FaceLabels", std::make_unique<DataStore<int32>>(ShapeType{3}, ShapeType{2}, 0), faceData->getId());
REQUIRE(faceLabels != nullptr);
for(usize i = 0; i < k_FaceLabels.size(); i++)
{
(*faceLabels)[i] = k_FaceLabels[i];
}
}
} // namespace
TEST_CASE("SimplnxCore::ExtractTripleLinesFilter: Preserve source length units", "[SimplnxCore][ExtractTripleLinesFilter][JunctionLengthUnits]")
{
UnitTest::LoadPlugins();
DataStructure dataStructure;
CreateJunctionMesh(dataStructure);
ExtractTripleLinesFilter filter;
auto args = filter.getDefaultArguments();
args.insertOrAssign(ExtractTripleLinesFilter::k_TriangleGeometryPath_Key, std::make_any<DataPath>(k_InputPath));
args.insertOrAssign(ExtractTripleLinesFilter::k_FaceLabelsArrayPath_Key, std::make_any<DataPath>(k_FaceLabelsPath));
args.insertOrAssign(ExtractTripleLinesFilter::k_NodeTypesArrayPath_Key, std::make_any<DataPath>(k_NodeTypesPath));
args.insertOrAssign(ExtractTripleLinesFilter::k_CreatedTripleLineGeometryPath_Key, std::make_any<DataPath>(k_OutputPath));
auto preflight = filter.preflight(dataStructure, args);
SIMPLNX_RESULT_REQUIRE_VALID(preflight.outputActions);
auto execution = filter.execute(dataStructure, args);
SIMPLNX_RESULT_REQUIRE_VALID(execution.result);
const auto& input = dataStructure.getDataRefAs<TriangleGeom>(k_InputPath);
const auto& output = dataStructure.getDataRefAs<EdgeGeom>(k_OutputPath);
REQUIRE(output.getNumberOfEdges() == 1);
REQUIRE(output.getNumberOfVertices() == 2);
REQUIRE((*output.getEdges())[0] == 0);
REQUIRE((*output.getEdges())[1] == 1);
for(usize i = 0; i < 6; i++)
{
REQUIRE((*output.getVertices())[i] == k_Vertices[i]);
}
const auto& numFeatures = dataStructure.getDataRefAs<Int8Array>(k_OutputPath.createChildPath("Edge Data").createChildPath("NumFeatures"));
REQUIRE(numFeatures[0] == 3);
REQUIRE(input.getUnits() == IGeometry::LengthUnit::Micrometer);
CHECK(static_cast<uint32>(output.getUnits()) == static_cast<uint32>(input.getUnits()));
}
TEST_CASE("SimplnxCore::ExtractInternalSurfacesFromTriangleGeometryFilter: Preserve source length units", "[SimplnxCore][ExtractInternalSurfacesFromTriangleGeometryFilter][JunctionLengthUnits]")
{
UnitTest::LoadPlugins();
const auto criterionMode = GENERATE(ChoicesParameter::ValueType{0}, ChoicesParameter::ValueType{1});
CAPTURE(criterionMode);
DataStructure dataStructure;
CreateJunctionMesh(dataStructure);
ExtractInternalSurfacesFromTriangleGeometryFilter filter;
auto args = filter.getDefaultArguments();
args.insertOrAssign(ExtractInternalSurfacesFromTriangleGeometryFilter::k_SelectedTriangleGeometryPath_Key, std::make_any<DataPath>(k_InputPath));
args.insertOrAssign(ExtractInternalSurfacesFromTriangleGeometryFilter::k_CreatedTriangleGeometryPath_Key, std::make_any<DataPath>(k_OutputPath));
args.insertOrAssign(ExtractInternalSurfacesFromTriangleGeometryFilter::k_CriterionMode_Key, std::make_any<ChoicesParameter::ValueType>(criterionMode));
args.insertOrAssign(ExtractInternalSurfacesFromTriangleGeometryFilter::k_NodeTypesPath_Key, std::make_any<DataPath>(k_NodeTypesPath));
args.insertOrAssign(ExtractInternalSurfacesFromTriangleGeometryFilter::k_FaceLabelsPath_Key, std::make_any<DataPath>(k_FaceLabelsPath));
auto preflight = filter.preflight(dataStructure, args);
SIMPLNX_RESULT_REQUIRE_VALID(preflight.outputActions);
auto execution = filter.execute(dataStructure, args);
SIMPLNX_RESULT_REQUIRE_VALID(execution.result);
const auto& input = dataStructure.getDataRefAs<TriangleGeom>(k_InputPath);
const auto& output = dataStructure.getDataRefAs<TriangleGeom>(k_OutputPath);
REQUIRE(output.getNumberOfFaces() == 3);
REQUIRE(output.getNumberOfVertices() == 5);
for(usize i = 0; i < k_Vertices.size(); i++)
{
REQUIRE((*output.getVertices())[i] == k_Vertices[i]);
}
for(usize i = 0; i < k_Triangles.size(); i++)
{
REQUIRE((*output.getFaces())[i] == k_Triangles[i]);
}
REQUIRE(input.getUnits() == IGeometry::LengthUnit::Micrometer);
CHECK(static_cast<uint32>(output.getUnits()) == static_cast<uint32>(input.getUnits()));
}
The standalone harness registered one CTest entry per filter and was run sequentially with:
ctest --test-dir <repro-build> -C Release -R "^JunctionLengthUnits_" -j 1 --output-on-failure --timeout 30
Observed output, with local path prefixes omitted:
1/2 Test #1: JunctionLengthUnits_TripleLines ........***Failed
JunctionLengthUnitsTest.cpp(103): failed: static_cast<uint32>(output.getUnits()) == static_cast<uint32>(input.getUnits()) for: 10 == 6
Failed 1 test case, failed 1 assertion.
2/2 Test #2: JunctionLengthUnits_InternalSurfaces ...***Failed
JunctionLengthUnitsTest.cpp(139): failed: static_cast<uint32>(output.getUnits()) == static_cast<uint32>(input.getUnits()) for: 10 == 6 with 1 message: 'criterionMode := 0'
JunctionLengthUnitsTest.cpp(139): failed: static_cast<uint32>(output.getUnits()) == static_cast<uint32>(input.getUnits()) for: 10 == 6 with 1 message: 'criterionMode := 1'
Failed 1 test case, failed 2 assertions.
0% tests passed, 2 tests failed out of 2
After registering the same source in the standard SimplnxCore test target, these commands select only these two test cases:
cmake --build <in-core-build> --config Release --target SimplnxCoreUnitTest
ctest --test-dir <in-core-build> -C Release -R "^SimplnxCore::(ExtractTripleLinesFilter|ExtractInternalSurfacesFromTriangleGeometryFilter): Preserve source length units$" -j 1 --output-on-failure
The executed evidence is from the standalone harness, not a build of the modified standard test target.
Proposed Fix
In ExtractTripleLines::operator(), transfer triangleGeom.getUnits() to tripleLineGeom after obtaining the input and output geometry references. In ExtractInternalSurfacesFromTriangleGeometry::operator(), transfer the same source property to internalTriangleGeom. Preserve the coordinate values and existing extraction criteria. Add nondefault-unit regression coverage beside the numeric checks.
Prepare the library fix on a separate branch. No fix has been applied or tested for this report.
Notes
Executed on Windows, MSVC 19.44, Release, in-core configuration (SIMPLNX_TEST_ALGORITHM_PATH=0). This report does not claim OOC-store or cross-platform verification.
The affected filter and algorithm files, geometry-action headers, and geometry unit default are byte-identical at current public develop, 84c66066a26b9e098ab58748dc2f8e7bee8b01e9. Execution evidence remains from the pinned commit above.
Related unit-loss reports #1784, #1792, and #1796 cover other geometry producers and copy paths. Their bodies and comments were checked; neither extraction filter above is included. Searches for the filter names and length-unit terms found no existing issue covering these two paths.
- Lenguaje dominante
- C++
- Estrellas
- 18
- Forks
- 15
- Merge medio
- 5 d 1 h
- PR fusionados (30 d)
- 22
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de BlueQuartzSoftware/simplnx
-
bug Filter
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
BlueQuartzSoftware/simplnx#1891 ·
Los mantenedores suelen responder en 4 días
-
DOC: Compute Feature Phases Binary describes a per-Cell output, but writes one value per FeatureAbiertodocumentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
BlueQuartzSoftware/simplnx#1886 ·
Los mantenedores suelen responder en 4 días
-
bug Filter
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
BlueQuartzSoftware/simplnx#1860 · 1 comentario ·
Los mantenedores suelen responder en 4 días
-
documentation
Dificultad 1/5 1-3 horas Aptitud para principiantes 88/100
BlueQuartzSoftware/simplnx#1847 ·
Los mantenedores suelen responder en 4 días
-
documentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
BlueQuartzSoftware/simplnx#1846 ·
Los mantenedores suelen responder en 4 días
Todos los issues de BlueQuartzSoftware/simplnx
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
espressif/esp-matter#1913 ·
-
bug priority: low
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
chipsalliance/verible#2644 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
grafana/pyroscope-dotnet#470 ·
Los mantenedores suelen responder en 1 día
-
documentation P5 XS
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
open-astro/AlpacaBridge#1848 ·
Los mantenedores suelen responder en 1 día