diff --git a/src/axom/quest/MeshClipper.cpp b/src/axom/quest/MeshClipper.cpp index c312d322e3..0780cdf71a 100644 --- a/src/axom/quest/MeshClipper.cpp +++ b/src/axom/quest/MeshClipper.cpp @@ -237,8 +237,8 @@ void globalReduce(axom::Array& values, int reduceOp) axom::mpi_traits::type, reduceOp, MPI_COMM_WORLD); -#endif } +#endif void MeshClipper::accumulateClippingStats(conduit::Node& curStats, const conduit::Node& newStats) { diff --git a/src/axom/quest/io/STEPReader.cpp b/src/axom/quest/io/STEPReader.cpp index 81fb049a7f..264dc35c1c 100644 --- a/src/axom/quest/io/STEPReader.cpp +++ b/src/axom/quest/io/STEPReader.cpp @@ -123,7 +123,7 @@ class StepFileProcessor return bbox; } - /// Helper class to convert faces of CAD mesh to valid NURBSPatch instances + /// Helper class to convert the face geometry of CAD mesh to valid NURBSPatch instances /// The constructor converts the surface to a clamped (non-periodic) representation, if necessary class PatchProcessor { @@ -142,8 +142,8 @@ class StepFileProcessor const opencascade::handle& getSurface() const { return m_surface; } - /// Returns a representation of the surface as an axom::primal::NURBSPatch - NPatch nurbsPatch() const + /// Returns a representation of the surface geometry as an axom::primal::NURBSPatch + NPatch nurbsPatchGeometry() const { // Check if the surface is periodic in u or v const bool isUPeriodic = m_surface->IsUPeriodic(); @@ -679,7 +679,13 @@ class StepFileProcessor PatchProcessor patchProcessor(bsplineSurface, m_verbose); - patches[patchIndex] = patchProcessor.nurbsPatch(); + patches[patchIndex] = patchProcessor.nurbsPatchGeometry(); + + // If the face is flipped in opencascade, we need to flip the primal primitive too + if(face.Orientation() == TopAbs_REVERSED) + { + patches[patchIndex].reverseOrientation_u(); + } PatchData& patchData = m_patchData[patchIndex]; patchData.patchIndex = patchIndex; @@ -931,24 +937,11 @@ class StepFileProcessor } } - // Ensure that the trimming curves form ccw loops - if(patch.isTrimmed()) + // If the face is flipped, then the trimming curves all need to be reversed too + if(patch.isTrimmed() && + TopoDS::Face(faceExp.Current()).Orientation() == TopAbs_Orientation::TopAbs_REVERSED) { - // Evaluate the signed area over the patch trimming curves - constexpr int n_quad_pts = 20; - auto area = primal::evaluate_vector_line_integral( - patch.getTrimmingCurves(), - [](PointType x) -> VectorType { - return primal::Vector({-0.5 * x[1], 0.5 * x[0]}); - }, - n_quad_pts); - - // Signed areas should be positive - if(area < 0) - { - patch.reverseOrientation_u(); - patch.reverseTrimmingCurves(); - } + patch.reverseTrimmingCurves(); } } } @@ -1147,6 +1140,8 @@ class PatchTriangulator { TopoDS_Face face = TopoDS::Face(faceExp.Current()); + const bool isReversed = (face.Orientation() == TopAbs_Orientation::TopAbs_REVERSED); + // Create a triangulation of this patch TopLoc_Location loc; opencascade::handle triangulation = BRep_Tool::Triangulation(face, loc); @@ -1167,6 +1162,11 @@ class PatchTriangulator int n1, n2, n3; triangle.Get(n1, n2, n3); + if(isReversed) + { + std::swap(n1, n3); + } + gp_Pnt p1 = triangulation->Node(n1).Transformed(trsf); gp_Pnt p2 = triangulation->Node(n2).Transformed(trsf); gp_Pnt p3 = triangulation->Node(n3).Transformed(trsf); @@ -1200,6 +1200,8 @@ class PatchTriangulator { TopoDS_Face face = TopoDS::Face(faceExp.Current()); + const bool isReversed = (face.Orientation() == TopAbs_Orientation::TopAbs_REVERSED); + // Get the underlying surface of the face opencascade::handle surface = BRep_Tool::Surface(face); @@ -1237,6 +1239,11 @@ class PatchTriangulator int n1, n2, n3; triangle.Get(n1, n2, n3); + if(isReversed) + { + std::swap(n1, n3); + } + gp_Pnt p1 = triangulation->Node(n1).Transformed(trsf); gp_Pnt p2 = triangulation->Node(n2).Transformed(trsf); gp_Pnt p3 = triangulation->Node(n3).Transformed(trsf);