BUG: Surface extraction filters discard source length units
I maintainer di solito rispondono entro 3 giorni
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- Mezza giornata
- Idoneità per principianti
- 72/100
Direzione di ricerca
Inizia dal codice di preflight di ExtractTripleLinesFilter.cpp (intorno alle righe 162-166) e di ExtractInternalSurfacesFromTriangleGeometryFilter.cpp (intorno alle righe 180-187), dove le geometrie di output vengono create senza un'unità di origine. Riporta getUnits() della geometria di input su ciascun output, quindi crea il file JunctionLengthUnitsTest.cpp suggerito ed esegui le voci CTest JunctionLengthUnits_. Il lavoro è completato quando entrambi i controlli sulle unità riportano Micrometer e i controlli numerici esistenti continuano a superare il test.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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.
- Lingua principale
- C++
- Stelle
- 18
- Fork
- 15
- Merge medio
- 3g 22h
- PR unite (30g)
- 20
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di BlueQuartzSoftware/simplnx
-
bug Filter
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
BlueQuartzSoftware/simplnx#1860 · 1 commento ·
I maintainer di solito rispondono entro 3 giorni
-
documentation
Difficoltà 1/5 1-3 ore Idoneità per principianti 88/100
BlueQuartzSoftware/simplnx#1847 ·
I maintainer di solito rispondono entro 3 giorni
-
documentation
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
BlueQuartzSoftware/simplnx#1846 ·
I maintainer di solito rispondono entro 3 giorni
-
bug Filter
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
BlueQuartzSoftware/simplnx#1844 ·
I maintainer di solito rispondono entro 3 giorni
-
bug Filter
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
BlueQuartzSoftware/simplnx#1843 ·
I maintainer di solito rispondono entro 3 giorni
Tutte le issue di BlueQuartzSoftware/simplnx
Issue simili
-
[Bug] [Go] Ack returns nil when the server answers with a non-OK statusForse già presa @leizhiyuan l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
apache/rocketmq-clients#1465 ·
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
KhronosGroup/Vulkan-Tutorial#534 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
I maintainer di solito rispondono entro 2 giorni
-
bug IO
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
MrNeRF/LichtFeld-Studio#3824 ·
I maintainer di solito rispondono entro 1 giorno
-
pnnx: manual tanh GELU fusion loses the approximation modeForse già presa @ktz03 l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
Tencent/ncnn#7175 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno