@ -8,6 +8,37 @@
namespace internal
{
integrator_t ( const stl_vector_mp < object_with_index_mapping < subface > > & surfaces ,
const flat_hash_map_mp < uint32_t , parametric_plane_t > & uv_planes )
: m_subfaces ( surfaces ) , m_uv_planes ( uv_planes )
{
std : : cout < < " Integrator initialized with " < < surfaces . size ( ) < < " subfaces. " < < std : : endl ;
std : : cout < < " m_uv_planes size: " < < m_uv_planes . size ( ) < < std : : endl ;
// calculate chain bbox
for ( int subface_index = 0 ; subface_index < m_subfaces . size ( ) ; + + subface_index ) {
if ( m_uv_planes . find ( subface_index ) ! = m_uv_planes . end ( ) ) {
const auto & param_plane = m_uv_planes . at ( subface_index ) ;
auto & chain_bboxs = m_chain_bboxes_hash [ subface_index ] ;
chain_bboxes . clear ( ) ;
chain_bboxs . reverse ( chain_vertices . size ( ) ) ;
for ( const auto & chain : param_plane . chain_vertices ) {
Eigen : : AlignedBox2d bbox ;
bbox . setEmpty ( ) ;
if ( ! chain . empty ( ) ) {
for ( const auto & pt : chain ) {
bbox . extend ( pt ) ;
}
}
chain_bboxes . push_back ( bbox ) ;
}
}
}
m_chain_bboxes_hash
}
double integrator_t : : calculate (
int gauss_order ,
double ( * func ) ( double u , double v , const Eigen : : Vector3d & p , const Eigen : : Vector3d & dU , const Eigen : : Vector3d & dV ) ) const
@ -40,33 +71,32 @@ double integrator_t::calculate_one_subface(
// Gaussian integration in u direction
auto u_integrand = [ & ] ( double u ) {
// Find exact v intersections for each u
stl_vector_mp < double > v_breaks = find_v_intersections_at_u ( subface , param_plane , u , true , v_min , v_max ) ;
stl_vector_mp < double > v_intersections ;
stl_vector_mp < uint16_t > intersected_chains ;
find_v_intersections_at_u ( subface , param_plane , u , v_min , v_max , v_intersections , intersected_chains ) ;
// Gaussian integration in v direction
auto v_integrand = [ & ] ( double v ) {
// Check if point is inside domain
if ( is_point_inside_domain ( subface , param_plane , u , v ) ) {
try {
// Get evaluators for both directions
auto eval_du = subface . fetch_curve_constraint_evaluator ( parameter_v_t { } , v ) ; // Fix v, vary u → ∂/∂u
auto eval_dv = subface . fetch_curve_constraint_evaluator ( parameter_u_t { } , u ) ; // Fix u, vary v → ∂/∂v
auto res_u = eval_du ( u ) ; // f(u,v), grad_f = ∂r/∂u
auto res_v = eval_dv ( v ) ; // f(u,v), grad_f = ∂r/∂v
Eigen : : Vector3d p = res_u . f . template head < 3 > ( ) ; // Point (x,y,z)
Eigen : : Vector3d dU = res_u . grad_f . template head < 3 > ( ) ; // ∂r/∂u
Eigen : : Vector3d dV = res_v . grad_f . template head < 3 > ( ) ; // ∂r/∂v
// Area element: ||dU × dV||
Eigen : : Vector3d cross = dU . cross ( dV ) ;
double jacobian = cross . norm ( ) ; // Jacobian (area scaling factor)
return func ( u , v , p , dU , dV ) * jacobian ;
} catch ( . . . ) {
return 0.0 ; // Skip singular points
}
try {
// Get evaluators for both directions
auto eval_du = subface . fetch_curve_constraint_evaluator ( parameter_v_t { } , v ) ; // Fix v, vary u → ∂/∂u
auto eval_dv = subface . fetch_curve_constraint_evaluator ( parameter_u_t { } , u ) ; // Fix u, vary v → ∂/∂v
auto res_u = eval_du ( u ) ; // f(u,v), grad_f = ∂r/∂u
auto res_v = eval_dv ( v ) ; // f(u,v), grad_f = ∂r/∂v
Eigen : : Vector3d p = res_u . f . template head < 3 > ( ) ; // Point (x,y,z)
Eigen : : Vector3d dU = res_u . grad_f . template head < 3 > ( ) ; // ∂r/∂u
Eigen : : Vector3d dV = res_v . grad_f . template head < 3 > ( ) ; // ∂r/∂v
// Area element: ||dU × dV||
Eigen : : Vector3d cross = dU . cross ( dV ) ;
double jacobian = cross . norm ( ) ; // Jacobian (area scaling factor)
return func ( u , v , p , dU , dV ) * jacobian ;
} catch ( . . . ) {
return 0.0 ; // Skip singular points
}
return 0.0 ; // Point not in domain
} ;
double v_integral = 0.0 ;
@ -76,7 +106,7 @@ double integrator_t::calculate_one_subface(
// Check midpoint validity
double mid_v = ( a + b ) / 2.0 ;
if ( is_point _inside_domain ( subface , param_plane , u , mid_v ) ) {
if ( is_edge _inside_domain ( subface , param_plane , u , mid_v ) ) {
v_integral + = integrate_1D ( a , b , v_integrand , gauss_order ) ;
} else {
std : : cout < < " uv out of domain: ( " < < u < < " , " < < mid_v < < " ) " < < std : : endl ;
@ -94,7 +124,9 @@ double integrator_t::calculate_one_subface(
double b = u_breaks [ i + 1 ] ;
double mid_u = ( a + b ) / 2.0 ;
auto v_intersections = find_v_intersections_at_u ( subface , param_plane , mid_u , true , v_min , v_max ) ;
stl_vector_mp < double > v_intersections ;
stl_vector_mp < uint16_t > intersected_chains ;
find_v_intersections_at_u ( subface , param_plane , mid_u , v_min , v_max , v_intersections , intersected_chains ) ;
if ( ! v_intersections . empty ( ) ) {
integral + = integrate_1D ( a , b , u_integrand , gauss_order , is_u_near_singularity ( mid_u ) ) ;
@ -133,28 +165,37 @@ stl_vector_mp<double> integrator_t::compute_u_breaks(const parametric_plane_t& p
return stl_vector_mp < double > ( break_set . begin ( ) , break_set . end ( ) ) ;
}
stl_vector_mp < double > integrator_t : : find_v_intersections_at_u ( const subface & subface ,
void integrator_t : : find_v_intersections_at_u ( const subface & subface ,
const parametric_plane_t & param_plane ,
const stl_vector_mp < Eigen : : AlignedBox2d > & chain_bboxs ,
double u_val ,
bool if_add_boundary ,
double v_min ,
double v_max
double v_max ,
stl_vector_mp < double > & intersections ,
stl_vector_mp < uint16_t > & intersected_chains
) const
{
stl_vector_mp < double > intersections ;
if ( if_add_boundary ) {
intersections . push_back ( v_min ) ;
intersections . push_back ( v_max ) ;
}
intersections . clear ( ) ;
intersected_chains . clear ( ) ;
uint16_t chain_idx = 0 ;
// Iterate over each boundary chain
for ( const auto & chain : param_plane . chain_vertices ) {
const size_t n_vertices = chain . size ( ) - 1 ;
if ( n_vertices < 2 ) {
std : : cout < < " Warning: Degenerate chain with less than 2 vertices. " < < std : : endl ;
chain_idx + + ;
continue ; // Skip degenerate chains
}
// filter bbox
if ( chain_bbox [ chain_idx ] . isEmpty ( )
| | ( chain_bbox [ chain_idx ] . x ( ) < u_val - 1e-8 | | chain_bbox [ chain_idx ] . x ( ) > u_val + 1e-8 ) ) {
chain_idx + + ;
continue ;
}
// Iterate over each edge in the chain (including closing edge if desired)
for ( size_t i = 0 ; i < n_vertices ; + + i ) {
const Eigen : : Vector2d & v1 = chain [ i ] ; // Current vertex: (u1, v1)
@ -182,6 +223,8 @@ stl_vector_mp<double> integrator_t::find_v_intersections_at_u(const subface&
if ( pos1 = = 0 & & pos2 = = 0 ) {
intersections . push_back ( v1_val ) ;
intersections . push_back ( v2_val ) ;
intersected_chains . push_back ( chain_idx ) ;
intersected_chains . push_back ( chain_idx ) ;
}
// Case 3: One endpoint on u = u_val or segment crosses u = u_val
else if ( std : : abs ( u1 - u2 ) < eps ) {
@ -189,6 +232,8 @@ stl_vector_mp<double> integrator_t::find_v_intersections_at_u(const subface&
if ( pos1 = = 0 | | pos2 = = 0 ) {
intersections . push_back ( v1_val ) ;
intersections . push_back ( v2_val ) ;
intersected_chains . push_back ( chain_idx ) ;
intersected_chains . push_back ( chain_idx ) ;
}
} else {
// General case: non-vertical segment crossing u = u_val
@ -211,48 +256,37 @@ stl_vector_mp<double> integrator_t::find_v_intersections_at_u(const subface&
try {
double v_solution = newton_method ( target_function , v_initial ) ;
intersections . push_back ( v_solution ) ;
intersected_chains . push_back ( chain_idx ) ;
} catch ( . . . ) {
// If Newton's method fails (e.g., divergence), fall back to linear approximation
intersections . push_back ( v_initial ) ;
intersected_chains . push_back ( chain_idx ) ;
}
}
}
chain_idx + + ;
}
// Final step: sort and remove duplicates within tolerance
if ( ! intersections . empty ( ) ) { sort_and_unique_with_tol ( intersections , 1e-8 ) ; }
//if (!intersections.empty()) { sort_and_unique_with_tol(intersections, 1e-8); }
return intersections ;
}
/*
point ( u , v ) is inside the domain by ray - casting algorithm
To determine whether a point ( u , v ) is inside or outside a domain by counting the intersections of a vertical ray starting
from the point and extending upwards ,
NOTE : when v_intersect - v < threshold , further checks are required to accurately determine if the intersection point lies
precisely on the boundary segment .
*/
bool integrator_t : : is_point_inside_domain ( const subface & subface ,
const parametric_plane_t & param_plane ,
double u ,
double v ) const
bool is_edge_inside_domain ( const stl_vector_mp < stl_vector_mp < uint16_t > > & chain_group_indices ,
uint16_t chain_idx1 ,
uint16_t chain_idx2 ) const
{
auto intersections = find_v_intersections_at_u ( subface , param_plane , u , false ) ;
const double tol_near = 1e-8 ;
const double tol_above = 1e-12 ;
uint32_t count = 0 ;
for ( double v_int : intersections ) {
double diff = v_int - v ;
if ( diff > tol_above ) {
count + + ;
} else if ( std : : abs ( diff ) < tol_near ) {
return true ; // on boundary → inside
}
const auto & group1 = chain_group_indices [ chain_idx1 ] ;
const auto & group2 = chain_group_indices [ chain_idx2 ] ;
if ( group1 . find ( chain_idx2 ) ! = group1 . end ( ) & & group2 . find ( chain_idx1 ) ! = group2 . end ( ) ) {
return true ;
}
return ( count % 2 ) = = 1 ;
return false ;
}
bool integrator_t : : is_u_near_singularity ( double u , double tol ) const { return false ; }
void integrator_t : : sort_and_unique_with_tol ( stl_vector_mp < double > & vec , double epsilon ) const