Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

BUG: Surface extraction filters discard source length units

Abierto Apto para principiantes
#1,813 0 comentarios 0 reacciones 0 asignados Ver en GitHub

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
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
cpp
Área
backend

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

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.

Lenguaje dominante
C++
Estrellas
18
Forks
15
Merge medio
5 d 1 h
PR fusionados (30 d)
22

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de BlueQuartzSoftware/simplnx

Todos los issues de BlueQuartzSoftware/simplnx

Issues similares

Más issues de C++

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.