Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

BUG: Surface extraction filters discard source length units

Aperta Adatta ai principianti
#1,813 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

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
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
cpp
Ambito
backend

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

bug

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

  1. At the commit above, create a Triangle Geometry with units IGeometry::LengthUnit::Micrometer and these five vertices: (10,20,30), (10,20,34), (11,20,32), (10,21,32), (9,19,32).
  2. 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 to 3.
  3. 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.
  4. 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.
  5. 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

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di BlueQuartzSoftware/simplnx

Tutte le issue di BlueQuartzSoftware/simplnx

Issue simili

Altre issue su C++

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.