54 lines
1.4 KiB
C++
54 lines
1.4 KiB
C++
#pragma once
|
|
|
|
#include "../Eigen/Dense"
|
|
#include <cmath>
|
|
|
|
namespace OpticsFEM {
|
|
|
|
// SBC face normal for 3D first-order Nedelec scatter (FemType=4).
|
|
// Matches MATLAB assembly_inc.m / assembly_out.m:
|
|
// inc -> [0,0,1]
|
|
// out, domain==3 -> [0,0,-1]
|
|
// other out -> normalize([sum(x)/3, sum(y)/3, 0]) from tet vertices
|
|
// Fallback when the reference formula is degenerate:
|
|
// 1) mesh NormOfFace(domain) if non-zero
|
|
// 2) geometric normal from the boundary triangle
|
|
inline Eigen::Vector3d computeScatterSBCNormal(
|
|
bool isInc,
|
|
int boundaryDomain,
|
|
const double tetX[4],
|
|
const double tetY[4],
|
|
const Eigen::Vector3d& faceP0,
|
|
const Eigen::Vector3d& faceP1,
|
|
const Eigen::Vector3d& faceP2,
|
|
const Eigen::Vector3d* meshNormFallback = nullptr)
|
|
{
|
|
using Eigen::Vector3d;
|
|
|
|
if (isInc)
|
|
return Vector3d(0.0, 0.0, 1.0);
|
|
|
|
// Prefer mesh NormOfFace (matches MATLAB assembly_out / assembly_inc).
|
|
if (meshNormFallback != nullptr && meshNormFallback->norm() >= 1e-30)
|
|
return (*meshNormFallback) / meshNormFallback->norm();
|
|
|
|
if (boundaryDomain == 3)
|
|
return Vector3d(0.0, 0.0, -1.0);
|
|
|
|
Vector3d n(
|
|
(tetX[0] + tetX[1] + tetX[2] + tetX[3]) / 3.0,
|
|
(tetY[0] + tetY[1] + tetY[2] + tetY[3]) / 3.0,
|
|
0.0);
|
|
const double len = n.norm();
|
|
if (len >= 1e-30)
|
|
return n / len;
|
|
|
|
const Vector3d geo = (faceP1 - faceP0).cross(faceP2 - faceP0);
|
|
if (geo.norm() >= 1e-30)
|
|
return geo.normalized();
|
|
|
|
return Vector3d(0.0, 0.0, -1.0);
|
|
}
|
|
|
|
} // namespace OpticsFEM
|