From f396c215e0f5a3373083b04db845ac6c9b0307a7 Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Thu, 12 Feb 2026 18:44:54 +0000 Subject: [PATCH] Data Exchange, STEP - Refactor pnindex handling in CreatePolyTriangulation (#1067) Separate direct node indexing and pnindex remapping into distinct code paths in StepToTopoDS_TranslateFace static helpers. Previously, the pnindex array was always allocated (even when empty) and an integer flag was checked everywhere via ternary operators, mixing two behaviors in one expression. Now the handle null state is the single source of truth: aPnindices is only allocated when NbPnindex() > 0, and all consumers check !aPnindices.IsNull() to choose the code path. Changes: - GetSimpleFaceElements/GetComplexFaceElements: guard aPnindices allocation with count > 0, convert thePnIndNb from output parameter to local variable - SetNodes: remove theNumPnindex parameter, split into two separate loops (indirection vs direct) - SetNormals: rename misleading theNumPnindex to theNbNodes - CreatePolyTriangulation: compute aNbNodes from aPnindices->Length() when non-null, remove dead aNumPnindex variable - Add GTests for StepToTopoDS_TranslateFace --- src/DataExchange/TKDESTEP/GTests/FILES.cmake | 1 + .../StepToTopoDS_TranslateFace_Test.cxx | 552 ++++++++++++++++++ .../StepToTopoDS_TranslateFace.cxx | 103 ++-- 3 files changed, 602 insertions(+), 54 deletions(-) create mode 100644 src/DataExchange/TKDESTEP/GTests/StepToTopoDS_TranslateFace_Test.cxx diff --git a/src/DataExchange/TKDESTEP/GTests/FILES.cmake b/src/DataExchange/TKDESTEP/GTests/FILES.cmake index d51e3db502..5c9e8bce83 100644 --- a/src/DataExchange/TKDESTEP/GTests/FILES.cmake +++ b/src/DataExchange/TKDESTEP/GTests/FILES.cmake @@ -14,5 +14,6 @@ set(OCCT_TKDESTEP_GTests_FILES StepTidy_PlaneReducer_Test.cxx StepTidy_Merger_Test.cxx StepTidy_VectorReducer_Test.cxx + StepToTopoDS_TranslateFace_Test.cxx StepTransientReplacements_Test.cxx ) diff --git a/src/DataExchange/TKDESTEP/GTests/StepToTopoDS_TranslateFace_Test.cxx b/src/DataExchange/TKDESTEP/GTests/StepToTopoDS_TranslateFace_Test.cxx new file mode 100644 index 0000000000..e6463872cc --- /dev/null +++ b/src/DataExchange/TKDESTEP/GTests/StepToTopoDS_TranslateFace_Test.cxx @@ -0,0 +1,552 @@ +// Copyright (c) 2025 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + +// Helper: create a CoordinatesList with given points. +static occ::handle createCoords( + const NCollection_Array1& thePoints) +{ + occ::handle> aPoints = + new NCollection_HArray1(thePoints.Lower(), thePoints.Upper()); + for (int i = thePoints.Lower(); i <= thePoints.Upper(); ++i) + { + aPoints->SetValue(i, thePoints.Value(i)); + } + occ::handle aCoords = new StepVisual_CoordinatesList(); + aCoords->Init(new TCollection_HAsciiString("coords"), aPoints); + return aCoords; +} + +// Helper: create a 2D int array for triangles (NRows x 3). +static occ::handle> createTriangles( + const NCollection_Array1>& theTriData) +{ + const int aNbTri = theTriData.Length(); + occ::handle> aTriangles = new NCollection_HArray2(1, aNbTri, 1, 3); + for (int i = 1; i <= aNbTri; ++i) + { + const NCollection_Array1& aTri = theTriData.Value(theTriData.Lower() + i - 1); + aTriangles->SetValue(i, 1, aTri.Value(aTri.Lower())); + aTriangles->SetValue(i, 2, aTri.Value(aTri.Lower() + 1)); + aTriangles->SetValue(i, 3, aTri.Value(aTri.Lower() + 2)); + } + return aTriangles; +} + +// Helper: create normals array (NRows x 3). +static occ::handle> createNormals( + const NCollection_Array1& theNorms) +{ + const int aNbNorms = theNorms.Length(); + occ::handle> aNormals = + new NCollection_HArray2(1, aNbNorms, 1, 3); + for (int i = 1; i <= aNbNorms; ++i) + { + const gp_XYZ& aN = theNorms.Value(theNorms.Lower() + i - 1); + aNormals->SetValue(i, 1, aN.X()); + aNormals->SetValue(i, 2, aN.Y()); + aNormals->SetValue(i, 3, aN.Z()); + } + return aNormals; +} + +// Helper: extract Poly_Triangulation from translated face result. +static occ::handle getMesh(const StepToTopoDS_TranslateFace& theTranslator) +{ + EXPECT_TRUE(theTranslator.IsDone()); + const TopoDS_Face& aFace = TopoDS::Face(theTranslator.Value()); + TopLoc_Location aLoc; + return BRep_Tool::Triangulation(aFace, aLoc); +} + +// Fixture providing common setup for all tests. +class StepToTopoDS_TranslateFaceTest : public testing::Test +{ +protected: + void SetUp() override + { + occ::handle aTP = new Transfer_TransientProcess(); + NCollection_DataMap, TopoDS_Shape> aMap; + myTool.Init(aMap, aTP); + myNMTool.SetActive(false); + } + + StepToTopoDS_Tool myTool; + StepToTopoDS_NMTool myNMTool; +}; + +} // namespace + +// Test: TriangulatedFace with direct node indexing (no pnindex). +TEST_F(StepToTopoDS_TranslateFaceTest, TriangulatedFace_DirectNodes) +{ + NCollection_Array1 aPoints(1, 4); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(1.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(1.0, 1.0, 0.0)); + aPoints.SetValue(4, gp_XYZ(0.0, 1.0, 0.0)); + + NCollection_Array1> aTriData(1, 2); + aTriData.ChangeValue(1) = NCollection_Array1(0, 2); + aTriData.ChangeValue(1).SetValue(0, 1); + aTriData.ChangeValue(1).SetValue(1, 2); + aTriData.ChangeValue(1).SetValue(2, 3); + aTriData.ChangeValue(2) = NCollection_Array1(0, 2); + aTriData.ChangeValue(2).SetValue(0, 1); + aTriData.ChangeValue(2).SetValue(1, 3); + aTriData.ChangeValue(2).SetValue(2, 4); + + occ::handle aTF = new StepVisual_TriangulatedFace(); + aTF->Init(new TCollection_HAsciiString("face"), + createCoords(aPoints), + 4, + nullptr, + false, + StepVisual_FaceOrSurface(), + nullptr, + createTriangles(aTriData)); + + bool aHasGeom = false; + StepToTopoDS_TranslateFace aTranslator(aTF, myTool, myNMTool, false, aHasGeom); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + EXPECT_EQ(aMesh->NbNodes(), 4); + EXPECT_EQ(aMesh->NbTriangles(), 2); + EXPECT_FALSE(aMesh->HasNormals()); + + EXPECT_NEAR(aMesh->Node(1).X(), 0.0, 1e-12); + EXPECT_NEAR(aMesh->Node(2).X(), 1.0, 1e-12); + EXPECT_NEAR(aMesh->Node(3).Y(), 1.0, 1e-12); + + int aN1, aN2, aN3; + aMesh->Triangle(1).Get(aN1, aN2, aN3); + EXPECT_EQ(aN1, 1); + EXPECT_EQ(aN2, 2); + EXPECT_EQ(aN3, 3); +} + +// Test: TriangulatedFace with pnindex remapping. +TEST_F(StepToTopoDS_TranslateFaceTest, TriangulatedFace_WithPnindex) +{ + // 4 points defined but pnindex selects only 3 of them. + NCollection_Array1 aPoints(1, 4); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(10.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(10.0, 10.0, 0.0)); + aPoints.SetValue(4, gp_XYZ(0.0, 10.0, 0.0)); + + // Pnindex: mesh nodes 1,2,3 map to coordinate indices 2,3,4. + occ::handle> aPnindex = new NCollection_HArray1(1, 3); + aPnindex->SetValue(1, 2); + aPnindex->SetValue(2, 3); + aPnindex->SetValue(3, 4); + + NCollection_Array1> aTriData(1, 1); + aTriData.ChangeValue(1) = NCollection_Array1(0, 2); + aTriData.ChangeValue(1).SetValue(0, 1); + aTriData.ChangeValue(1).SetValue(1, 2); + aTriData.ChangeValue(1).SetValue(2, 3); + + occ::handle aTF = new StepVisual_TriangulatedFace(); + aTF->Init(new TCollection_HAsciiString("face"), + createCoords(aPoints), + 4, + nullptr, + false, + StepVisual_FaceOrSurface(), + aPnindex, + createTriangles(aTriData)); + + bool aHasGeom = false; + StepToTopoDS_TranslateFace aTranslator(aTF, myTool, myNMTool, false, aHasGeom); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + EXPECT_EQ(aMesh->NbNodes(), 3); + EXPECT_EQ(aMesh->NbTriangles(), 1); + + // Node 1 should be coordinate 2 (10,0,0). + EXPECT_NEAR(aMesh->Node(1).X(), 10.0, 1e-12); + EXPECT_NEAR(aMesh->Node(1).Y(), 0.0, 1e-12); + // Node 2 should be coordinate 3 (10,10,0). + EXPECT_NEAR(aMesh->Node(2).X(), 10.0, 1e-12); + EXPECT_NEAR(aMesh->Node(2).Y(), 10.0, 1e-12); + // Node 3 should be coordinate 4 (0,10,0). + EXPECT_NEAR(aMesh->Node(3).X(), 0.0, 1e-12); + EXPECT_NEAR(aMesh->Node(3).Y(), 10.0, 1e-12); +} + +// Test: TriangulatedSurfaceSet with direct nodes (no pnindex). +TEST_F(StepToTopoDS_TranslateFaceTest, TriangulatedSurfaceSet_DirectNodes) +{ + NCollection_Array1 aPoints(1, 3); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(2.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(1.0, 2.0, 0.0)); + + NCollection_Array1> aTriData(1, 1); + aTriData.ChangeValue(1) = NCollection_Array1(0, 2); + aTriData.ChangeValue(1).SetValue(0, 1); + aTriData.ChangeValue(1).SetValue(1, 2); + aTriData.ChangeValue(1).SetValue(2, 3); + + occ::handle aTSS = new StepVisual_TriangulatedSurfaceSet(); + aTSS->Init(new TCollection_HAsciiString("surfset"), + createCoords(aPoints), + 3, + nullptr, + nullptr, + createTriangles(aTriData)); + + StepToTopoDS_TranslateFace aTranslator(aTSS, myTool, myNMTool); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + EXPECT_EQ(aMesh->NbNodes(), 3); + EXPECT_EQ(aMesh->NbTriangles(), 1); + + EXPECT_NEAR(aMesh->Node(1).X(), 0.0, 1e-12); + EXPECT_NEAR(aMesh->Node(2).X(), 2.0, 1e-12); + EXPECT_NEAR(aMesh->Node(3).Y(), 2.0, 1e-12); +} + +// Test: TriangulatedSurfaceSet with pnindex remapping. +TEST_F(StepToTopoDS_TranslateFaceTest, TriangulatedSurfaceSet_WithPnindex) +{ + NCollection_Array1 aPoints(1, 4); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(5.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(5.0, 5.0, 0.0)); + aPoints.SetValue(4, gp_XYZ(0.0, 5.0, 0.0)); + + // Pnindex selects 3 out of 4 coordinates (indices 1, 3, 4). + occ::handle> aPnindex = new NCollection_HArray1(1, 3); + aPnindex->SetValue(1, 1); + aPnindex->SetValue(2, 3); + aPnindex->SetValue(3, 4); + + NCollection_Array1> aTriData(1, 1); + aTriData.ChangeValue(1) = NCollection_Array1(0, 2); + aTriData.ChangeValue(1).SetValue(0, 1); + aTriData.ChangeValue(1).SetValue(1, 2); + aTriData.ChangeValue(1).SetValue(2, 3); + + occ::handle aTSS = new StepVisual_TriangulatedSurfaceSet(); + aTSS->Init(new TCollection_HAsciiString("surfset"), + createCoords(aPoints), + 4, + nullptr, + aPnindex, + createTriangles(aTriData)); + + StepToTopoDS_TranslateFace aTranslator(aTSS, myTool, myNMTool); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + EXPECT_EQ(aMesh->NbNodes(), 3); + + // Node 1 = coord 1 (0,0,0). + EXPECT_NEAR(aMesh->Node(1).X(), 0.0, 1e-12); + // Node 2 = coord 3 (5,5,0). + EXPECT_NEAR(aMesh->Node(2).X(), 5.0, 1e-12); + EXPECT_NEAR(aMesh->Node(2).Y(), 5.0, 1e-12); + // Node 3 = coord 4 (0,5,0). + EXPECT_NEAR(aMesh->Node(3).X(), 0.0, 1e-12); + EXPECT_NEAR(aMesh->Node(3).Y(), 5.0, 1e-12); +} + +// Test: TriangulatedFace with per-node normals. +TEST_F(StepToTopoDS_TranslateFaceTest, TriangulatedFace_WithNormals) +{ + NCollection_Array1 aPoints(1, 3); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(1.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(0.0, 1.0, 0.0)); + + NCollection_Array1 aNorms(1, 3); + aNorms.SetValue(1, gp_XYZ(0.0, 0.0, 1.0)); + aNorms.SetValue(2, gp_XYZ(0.0, 0.0, 1.0)); + aNorms.SetValue(3, gp_XYZ(0.0, 0.0, 1.0)); + + NCollection_Array1> aTriData(1, 1); + aTriData.ChangeValue(1) = NCollection_Array1(0, 2); + aTriData.ChangeValue(1).SetValue(0, 1); + aTriData.ChangeValue(1).SetValue(1, 2); + aTriData.ChangeValue(1).SetValue(2, 3); + + occ::handle aTF = new StepVisual_TriangulatedFace(); + aTF->Init(new TCollection_HAsciiString("face"), + createCoords(aPoints), + 3, + createNormals(aNorms), + false, + StepVisual_FaceOrSurface(), + nullptr, + createTriangles(aTriData)); + + bool aHasGeom = false; + StepToTopoDS_TranslateFace aTranslator(aTF, myTool, myNMTool, false, aHasGeom); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + EXPECT_TRUE(aMesh->HasNormals()); + + const gp_Dir aNormal = aMesh->Normal(1); + EXPECT_NEAR(aNormal.Z(), 1.0, 1e-12); +} + +// Test: TriangulatedFace with single normal shared by all nodes. +TEST_F(StepToTopoDS_TranslateFaceTest, TriangulatedFace_SingleNormal) +{ + NCollection_Array1 aPoints(1, 3); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(1.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(0.0, 1.0, 0.0)); + + NCollection_Array1 aNorms(1, 1); + aNorms.SetValue(1, gp_XYZ(0.0, 1.0, 0.0)); + + NCollection_Array1> aTriData(1, 1); + aTriData.ChangeValue(1) = NCollection_Array1(0, 2); + aTriData.ChangeValue(1).SetValue(0, 1); + aTriData.ChangeValue(1).SetValue(1, 2); + aTriData.ChangeValue(1).SetValue(2, 3); + + occ::handle aTF = new StepVisual_TriangulatedFace(); + aTF->Init(new TCollection_HAsciiString("face"), + createCoords(aPoints), + 3, + createNormals(aNorms), + false, + StepVisual_FaceOrSurface(), + nullptr, + createTriangles(aTriData)); + + bool aHasGeom = false; + StepToTopoDS_TranslateFace aTranslator(aTF, myTool, myNMTool, false, aHasGeom); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + EXPECT_TRUE(aMesh->HasNormals()); + + // All 3 nodes should share the same normal (0,1,0). + for (int i = 1; i <= 3; ++i) + { + const gp_Dir aNormal = aMesh->Normal(i); + EXPECT_NEAR(aNormal.X(), 0.0, 1e-12); + EXPECT_NEAR(aNormal.Y(), 1.0, 1e-12); + EXPECT_NEAR(aNormal.Z(), 0.0, 1e-12); + } +} + +// Test: Length factor scaling of coordinates. +TEST_F(StepToTopoDS_TranslateFaceTest, TriangulatedSurfaceSet_LengthFactor) +{ + NCollection_Array1 aPoints(1, 3); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(1.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(0.0, 1.0, 0.0)); + + NCollection_Array1> aTriData(1, 1); + aTriData.ChangeValue(1) = NCollection_Array1(0, 2); + aTriData.ChangeValue(1).SetValue(0, 1); + aTriData.ChangeValue(1).SetValue(1, 2); + aTriData.ChangeValue(1).SetValue(2, 3); + + occ::handle aTSS = new StepVisual_TriangulatedSurfaceSet(); + aTSS->Init(new TCollection_HAsciiString("surfset"), + createCoords(aPoints), + 3, + nullptr, + nullptr, + createTriangles(aTriData)); + + StepData_Factors aFactors; + aFactors.InitializeFactors(25.4, 1.0, 1.0); + + StepToTopoDS_TranslateFace aTranslator(aTSS, myTool, myNMTool, aFactors); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + + // Coordinates should be scaled by length factor 25.4. + EXPECT_NEAR(aMesh->Node(2).X(), 25.4, 1e-10); + EXPECT_NEAR(aMesh->Node(3).Y(), 25.4, 1e-10); +} + +// Test: ComplexTriangulatedFace with triangle strips. +TEST_F(StepToTopoDS_TranslateFaceTest, ComplexTriangulatedFace_TriangleStrips) +{ + NCollection_Array1 aPoints(1, 4); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(1.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(0.0, 1.0, 0.0)); + aPoints.SetValue(4, gp_XYZ(1.0, 1.0, 0.0)); + + // Triangle strip: [1, 2, 3, 4] produces 2 triangles. + occ::handle> aStrip = new NCollection_HArray1(1, 4); + aStrip->SetValue(1, 1); + aStrip->SetValue(2, 2); + aStrip->SetValue(3, 3); + aStrip->SetValue(4, 4); + + occ::handle>> aStrips = + new NCollection_HArray1>(1, 1); + aStrips->SetValue(1, aStrip); + + occ::handle aCTF = new StepVisual_ComplexTriangulatedFace(); + aCTF->Init(new TCollection_HAsciiString("complex_face"), + createCoords(aPoints), + 4, + nullptr, + false, + StepVisual_FaceOrSurface(), + nullptr, + aStrips, + nullptr); + + bool aHasGeom = false; + StepToTopoDS_TranslateFace aTranslator(aCTF, myTool, myNMTool, false, aHasGeom); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + EXPECT_EQ(aMesh->NbNodes(), 4); + EXPECT_EQ(aMesh->NbTriangles(), 2); +} + +// Test: ComplexTriangulatedFace with triangle fans. +TEST_F(StepToTopoDS_TranslateFaceTest, ComplexTriangulatedFace_TriangleFans) +{ + NCollection_Array1 aPoints(1, 5); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(1.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(1.0, 1.0, 0.0)); + aPoints.SetValue(4, gp_XYZ(0.0, 1.0, 0.0)); + aPoints.SetValue(5, gp_XYZ(-1.0, 0.0, 0.0)); + + // Triangle fan: [1, 2, 3, 4, 5] with center at vertex 1 produces 3 triangles. + occ::handle> aFan = new NCollection_HArray1(1, 5); + aFan->SetValue(1, 1); + aFan->SetValue(2, 2); + aFan->SetValue(3, 3); + aFan->SetValue(4, 4); + aFan->SetValue(5, 5); + + occ::handle>> aFans = + new NCollection_HArray1>(1, 1); + aFans->SetValue(1, aFan); + + occ::handle aCTF = new StepVisual_ComplexTriangulatedFace(); + aCTF->Init(new TCollection_HAsciiString("complex_face"), + createCoords(aPoints), + 5, + nullptr, + false, + StepVisual_FaceOrSurface(), + nullptr, + nullptr, + aFans); + + bool aHasGeom = false; + StepToTopoDS_TranslateFace aTranslator(aCTF, myTool, myNMTool, false, aHasGeom); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + EXPECT_EQ(aMesh->NbNodes(), 5); + EXPECT_EQ(aMesh->NbTriangles(), 3); +} + +// Test: Null input produces no result. +TEST_F(StepToTopoDS_TranslateFaceTest, NullInput_TessellatedFace) +{ + occ::handle aNullTF; + bool aHasGeom = false; + StepToTopoDS_TranslateFace aTranslator; + aTranslator.Init(aNullTF, myTool, myNMTool, false, aHasGeom); + EXPECT_FALSE(aTranslator.IsDone()); +} + +// Test: Null input for TessellatedSurfaceSet. +TEST_F(StepToTopoDS_TranslateFaceTest, NullInput_TessellatedSurfaceSet) +{ + occ::handle aNullTSS; + StepToTopoDS_TranslateFace aTranslator; + aTranslator.Init(aNullTSS, myTool, myNMTool); + EXPECT_FALSE(aTranslator.IsDone()); +} + +// Test: ComplexTriangulatedFace with strip containing degenerate triangles (duplicate indices). +TEST_F(StepToTopoDS_TranslateFaceTest, ComplexTriangulatedFace_DegenerateStrip) +{ + NCollection_Array1 aPoints(1, 4); + aPoints.SetValue(1, gp_XYZ(0.0, 0.0, 0.0)); + aPoints.SetValue(2, gp_XYZ(1.0, 0.0, 0.0)); + aPoints.SetValue(3, gp_XYZ(0.0, 1.0, 0.0)); + aPoints.SetValue(4, gp_XYZ(1.0, 1.0, 0.0)); + + // Strip with degenerate: [1, 2, 3, 3] - the second triangle (2,3,3) is degenerate. + occ::handle> aStrip = new NCollection_HArray1(1, 4); + aStrip->SetValue(1, 1); + aStrip->SetValue(2, 2); + aStrip->SetValue(3, 3); + aStrip->SetValue(4, 3); + + occ::handle>> aStrips = + new NCollection_HArray1>(1, 1); + aStrips->SetValue(1, aStrip); + + occ::handle aCTF = new StepVisual_ComplexTriangulatedFace(); + aCTF->Init(new TCollection_HAsciiString("complex_face"), + createCoords(aPoints), + 4, + nullptr, + false, + StepVisual_FaceOrSurface(), + nullptr, + aStrips, + nullptr); + + bool aHasGeom = false; + StepToTopoDS_TranslateFace aTranslator(aCTF, myTool, myNMTool, false, aHasGeom); + + occ::handle aMesh = getMesh(aTranslator); + ASSERT_FALSE(aMesh.IsNull()); + // Only 1 non-degenerate triangle from strip [1,2,3,3]. + EXPECT_EQ(aMesh->NbTriangles(), 1); +} diff --git a/src/DataExchange/TKDESTEP/StepToTopoDS/StepToTopoDS_TranslateFace.cxx b/src/DataExchange/TKDESTEP/StepToTopoDS/StepToTopoDS_TranslateFace.cxx index 7d74d109bd..86776248fc 100644 --- a/src/DataExchange/TKDESTEP/StepToTopoDS/StepToTopoDS_TranslateFace.cxx +++ b/src/DataExchange/TKDESTEP/StepToTopoDS/StepToTopoDS_TranslateFace.cxx @@ -107,15 +107,23 @@ namespace // ============================================================================ static void SetNodes(const occ::handle& theMesh, occ::handle>& theNodes, - const int theNumPnindex, occ::handle>& thePnindices, const double theLengthFactor) { - for (int aPnIndex = 1; aPnIndex <= theMesh->NbNodes(); ++aPnIndex) + if (!thePnindices.IsNull()) { - const gp_XYZ& aPoint = - theNodes->Value((theNumPnindex > 0) ? thePnindices->Value(aPnIndex) : aPnIndex); - theMesh->SetNode(aPnIndex, theLengthFactor * aPoint); + for (int aPnIndex = 1; aPnIndex <= theMesh->NbNodes(); ++aPnIndex) + { + const gp_XYZ& aPoint = theNodes->Value(thePnindices->Value(aPnIndex)); + theMesh->SetNode(aPnIndex, theLengthFactor * aPoint); + } + } + else + { + for (int aPnIndex = 1; aPnIndex <= theMesh->NbNodes(); ++aPnIndex) + { + theMesh->SetNode(aPnIndex, theLengthFactor * theNodes->Value(aPnIndex)); + } } } @@ -126,7 +134,7 @@ static void SetNodes(const occ::handle& theMesh, static void SetNormals(const occ::handle& theMesh, const occ::handle>& theNormals, const int theNormNum, - const int theNumPnindex) + const int theNbNodes) { if (theNormals->RowLength() != 3) { @@ -138,12 +146,12 @@ static void SetNormals(const occ::handle& theMesh, aNorm.SetX(theNormals->Value(1, 1)); aNorm.SetY(theNormals->Value(1, 2)); aNorm.SetZ(theNormals->Value(1, 3)); - for (int aPnIndex = 1; aPnIndex <= theNumPnindex; ++aPnIndex) + for (int aNodeIndex = 1; aNodeIndex <= theNbNodes; ++aNodeIndex) { - theMesh->SetNormal(aPnIndex, aNorm); + theMesh->SetNormal(aNodeIndex, aNorm); } } - else if (theNumPnindex == theNormNum) + else if (theNbNodes == theNormNum) { for (int aNormIndex = 1; aNormIndex <= theNormNum; ++aNormIndex) { @@ -235,21 +243,23 @@ static void GetSimpleFaceElements(const Type& theF occ::handle>& theNodes, occ::handle>& theNormals, occ::handle>& theTriangles, - int& thePnIndNb, int& theNormNb, int& theTriNb, occ::handle>& thePnindices) { - theNodes = theFace->Coordinates()->Points(); - theNormals = theFace->Normals(); - theTriangles = theFace->Triangles(); - thePnIndNb = theFace->NbPnindex(); - theNormNb = theFace->NbNormals(); - theTriNb = theFace->NbTriangles(); - thePnindices = new NCollection_HArray1(1, thePnIndNb); - for (int anIndx = 1; anIndx <= thePnIndNb; ++anIndx) + theNodes = theFace->Coordinates()->Points(); + theNormals = theFace->Normals(); + theTriangles = theFace->Triangles(); + theNormNb = theFace->NbNormals(); + theTriNb = theFace->NbTriangles(); + const int aPnIndNb = theFace->NbPnindex(); + if (aPnIndNb > 0) { - thePnindices->SetValue(anIndx, theFace->PnindexValue(anIndx)); + thePnindices = new NCollection_HArray1(1, aPnIndNb); + for (int anIndx = 1; anIndx <= aPnIndNb; ++anIndx) + { + thePnindices->SetValue(anIndx, theFace->PnindexValue(anIndx)); + } } } @@ -264,24 +274,26 @@ static void GetComplexFaceElements( occ::handle>& theNormals, occ::handle>>& theTriangleStrips, occ::handle>>& theTriangleFans, - int& thePnIndNb, int& theNormNb, int& theTriStripsNb, int& theTriFansNb, occ::handle>& thePnindices) { - theNodes = theFace->Coordinates()->Points(); - theNormals = theFace->Normals(); - theTriangleStrips = theFace->TriangleStrips(); - theTriangleFans = theFace->TriangleFans(); - thePnIndNb = theFace->NbPnindex(); - theNormNb = theFace->NbNormals(); - theTriStripsNb = theFace->NbTriangleStrips(); - theTriFansNb = theFace->NbTriangleFans(); - thePnindices = new NCollection_HArray1(1, thePnIndNb); - for (int anIndx = 1; anIndx <= thePnIndNb; ++anIndx) + theNodes = theFace->Coordinates()->Points(); + theNormals = theFace->Normals(); + theTriangleStrips = theFace->TriangleStrips(); + theTriangleFans = theFace->TriangleFans(); + theNormNb = theFace->NbNormals(); + theTriStripsNb = theFace->NbTriangleStrips(); + theTriFansNb = theFace->NbTriangleFans(); + const int aPnIndNb = theFace->NbPnindex(); + if (aPnIndNb > 0) { - thePnindices->SetValue(anIndx, theFace->PnindexValue(anIndx)); + thePnindices = new NCollection_HArray1(1, aPnIndNb); + for (int anIndx = 1; anIndx <= aPnIndNb; ++anIndx) + { + thePnindices->SetValue(anIndx, theFace->PnindexValue(anIndx)); + } } } @@ -302,9 +314,8 @@ static occ::handle CreatePolyTriangulation( occ::handle> aNodes; occ::handle> aNormals; occ::handle> aTriangles; - int aNumPnindex = 0; - int aNormNum = 0; - int aTrianNum = 0; + int aNormNum = 0; + int aTrianNum = 0; occ::handle> aPnindices; occ::handle>> aTriaStrips; @@ -316,27 +327,13 @@ static occ::handle CreatePolyTriangulation( { occ::handle aTF = occ::down_cast(theTI); - GetSimpleFaceElements(aTF, - aNodes, - aNormals, - aTriangles, - aNumPnindex, - aNormNum, - aTrianNum, - aPnindices); + GetSimpleFaceElements(aTF, aNodes, aNormals, aTriangles, aNormNum, aTrianNum, aPnindices); } else if (theTI->IsKind(STANDARD_TYPE(StepVisual_TriangulatedSurfaceSet))) { occ::handle aTSS = occ::down_cast(theTI); - GetSimpleFaceElements(aTSS, - aNodes, - aNormals, - aTriangles, - aNumPnindex, - aNormNum, - aTrianNum, - aPnindices); + GetSimpleFaceElements(aTSS, aNodes, aNormals, aTriangles, aNormNum, aTrianNum, aPnindices); } else if (theTI->IsKind(STANDARD_TYPE(StepVisual_ComplexTriangulatedFace))) { @@ -347,7 +344,6 @@ static occ::handle CreatePolyTriangulation( aNormals, aTriaStrips, aTriaFans, - aNumPnindex, aNormNum, aTrianStripsNum, aTrianFansNum, @@ -362,7 +358,6 @@ static occ::handle CreatePolyTriangulation( aNormals, aTriaStrips, aTriaFans, - aNumPnindex, aNormNum, aTrianStripsNum, aTrianFansNum, @@ -375,7 +370,7 @@ static occ::handle CreatePolyTriangulation( const bool aHasUVNodes = false; const bool aHasNormals = (aNormNum > 0); - const int aNbNodes = (aNumPnindex > 0) ? aNumPnindex : aNodes->Length(); + const int aNbNodes = !aPnindices.IsNull() ? aPnindices->Length() : aNodes->Length(); if (aTrianStripsNum == 0 && aTrianFansNum == 0) { @@ -414,7 +409,7 @@ static occ::handle CreatePolyTriangulation( aMesh = new Poly_Triangulation(aNbNodes, aNbTriaStrips + aNbTriaFans, aHasUVNodes, aHasNormals); } - SetNodes(aMesh, aNodes, aNumPnindex, aPnindices, theLocalFactors.LengthFactor()); + SetNodes(aMesh, aNodes, aPnindices, theLocalFactors.LengthFactor()); if (aHasNormals) {