@@ -570,20 +570,30 @@ bool isLayerElementOk(Mesh* m, Entity* e)
570570 if (type == apf::Mesh::PRISM)
571571 return isPrismOk (m, e);
572572 if (type == apf::Mesh::QUAD) {
573- // For 2D boundary layer meshes, check if quad is non-degenerate
574- // A quad is OK if it has positive area (non-inverted)
573+ // Check if quad is non-degenerate without assuming a specific embedding.
574+ // The quad is considered valid if its two sub-triangles have non-zero area
575+ // and consistent orientation.
576+
575577 Entity* v[4 ];
576578 m->getDownward (e, 0 , v);
577579 Vector p[4 ];
578580 for (int i = 0 ; i < 4 ; ++i)
579581 m->getPoint (v[i], 0 , p[i]);
580582
581- // Check both triangulation diagonals for positive area
582- Vector d1 = apf::cross (p[1 ] - p[0 ], p[2 ] - p[0 ]);
583- Vector d2 = apf::cross (p[2 ] - p[0 ], p[3 ] - p[0 ]);
583+ // Form two triangles sharing a diagonal
584+ Vector n1 = apf::cross (p[1 ] - p[0 ], p[2 ] - p[0 ]);
585+ Vector n2 = apf::cross (p[2 ] - p[0 ], p[3 ] - p[0 ]);
586+
587+ double a1 = n1.getLength ();
588+ double a2 = n2.getLength ();
589+
590+ // Reject degenerate triangles
591+ const double eps = 1e-14 ;
592+ if (a1 < eps || a2 < eps)
593+ return false ;
584594
585- // If both triangles have positive area in same direction, quad is OK
586- return (d1[ 2 ] > 0 && d2[ 2 ] > 0 ) || (d1[ 2 ] < 0 && d2[ 2 ] < 0 ) ;
595+ // Check consistent orientation (normals point in the same general direction)
596+ return (n1 * n2) > eps * a1 * a2 ;
587597 }
588598 abort ();
589599 return false ;
0 commit comments