@ -8,111 +8,53 @@
namespace internal
{
// Constructor 1: Initialize only with a reference to the surface
integrator_t : : integrator_t ( const subface & surface ) : m_surface ( surface ) { }
// Constructor 2: Initialize with surface and u-breaks (e.g., trimming curves)
integrator_t : : integrator_t ( const subface & surface ,
const stl_vector_mp < double > & u_breaks ,
double umin ,
double umax ,
double vmin ,
double vmax )
: m_surface ( surface ) , m_u_breaks ( u_breaks ) , Umin ( umin ) , Umax ( umax ) , Vmin ( vmin ) , Vmax ( vmax )
{
}
integrator_t : : integrator_t ( const subface & surface , const parametric_plane & uv_plane )
: m_surface ( surface ) , m_uv_plane ( uv_plane ) , Umin ( 0.0 ) , Umax ( 0.0 ) , Vmin ( 0.0 ) , Vmax ( 0.0 )
// Main entry point to compute surface area
// Main entry point to compute surface area
template < typename Func >
double integrator_t : : calculate ( int gauss_order , Func & & func ) const
{
if ( ! uv_plane . chain_vertices . empty ( ) ) {
// 初始化为第一个点的坐标
double min_u = uv_plane . chain_vertices [ 0 ] . x ( ) ;
double max_u = uv_plane . chain_vertices [ 0 ] . x ( ) ;
double min_v = uv_plane . chain_vertices [ 0 ] . y ( ) ;
double max_v = uv_plane . chain_vertices [ 0 ] . y ( ) ;
// 遍历所有链顶点
for ( const auto & pt : uv_plane . chain_vertices ) {
double u = pt . x ( ) ;
double v = pt . y ( ) ;
if ( u < min_u ) min_u = u ;
if ( u > max_u ) max_u = u ;
if ( v < min_v ) min_v = v ;
if ( v > max_v ) max_v = v ;
}
Umin = min_u ;
Umax = max_u ;
Vmin = min_v ;
Vmax = max_v ;
} else {
// 没有顶点时使用默认范围 [0, 1] × [0, 1]
Umin = 0.0 ;
Umax = 1.0 ;
Vmin = 0.0 ;
Vmax = 1.0 ;
}
std : : set < uint32_t > unique_vertex_indices ;
// 插入所有类型的顶点索引
unique_vertex_indices . insert ( uv_plane . singularity_vertices . begin ( ) , uv_plane . singularity_vertices . end ( ) ) ;
unique_vertex_indices . insert ( uv_plane . polar_vertices . begin ( ) , uv_plane . polar_vertices . end ( ) ) ;
unique_vertex_indices . insert ( uv_plane . parallel_start_vertices . begin ( ) , uv_plane . parallel_start_vertices . end ( ) ) ;
std : : set < double > unique_u_values ;
for ( uint32_t idx : unique_vertex_indices ) {
if ( idx < uv_plane . chain_vertices . size ( ) ) {
double u = uv_plane . chain_vertices [ idx ] . x ( ) ;
unique_u_values . insert ( u ) ;
}
total_integral = 0.0 ;
for ( const auto & [ subface_index , param_plane ] : m_uv_planes ) {
const auto & subface = m_subfaces [ subface_index ] . object_ptr . get ( ) ;
total_integral + = calculate_one_subface ( subface , param_plane , gauss_order , std : : forward < Func > ( func ) ) ;
}
// 转换为 vector 并排序(set 默认是有序的)
m_u_breaks = stl_vector_mp < double > ( unique_u_values . begin ( ) , unique_u_values . end ( ) ) ;
return total_integral ;
}
// Set u-breaks (optional trimming or partitioning lines)
void integrator_t : : set_ubreaks ( const stl_vector_mp < double > & u_breaks ) { m_u_breaks = u_breaks ; }
// Main entry point to compute surface area
template < typename Func >
double integrator_t : : calculate ( Func & & func , int gauss_order ) const
double integrator_t : : calculate_one_subface ( const subface & subface , const parametric_plane_t & param_plane , int gauss_order , Func & & func ) const
{
auto solver = m_sur face. fetch_solver_evaluator ( ) ;
// 在u方向进行高斯积分
auto solver = subface . fetch_solver_evaluator ( ) ;
// Gaussian integration in u direction
auto u_integrand = [ & ] ( double u ) {
// 对每个u,找到v方向的精确交点
// Find exact v intersections for each u
std : : vector < double > v_breaks = find_vertical_intersections ( u ) ;
// 在v方向进行高斯积分
// Gaussian integration in v direction
auto v_integrand = [ & ] ( double v ) {
// 判断点是否在有效域内
if ( is_point_inside_domain ( u , v ) ) {
// Check if point is inside domain
if ( is_point_inside_domain ( subface , param_plane , u , v ) ) {
try {
// 获取两个方向的 evaluator
auto eval_du = m_sur face. fetch_curve_constraint_evaluator ( parameter_v_t { } , v ) ; // 固定 v,变 u → 得到 ∂/∂u
auto eval_dv = m_sur face. fetch_curve_constraint_evaluator ( parameter_u_t { } , u ) ; // 固定 u,变 v → 得到 ∂/∂v
// 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 > ( ) ; // 点坐标 (x,y,z)
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
// ✅ 计算面积元: ||dU × dV||
// Area element: ||dU × dV||
Eigen : : Vector3d cross = dU . cross ( dV ) ;
double jacobian = cross . norm ( ) ; // 雅可比行列式(面积缩放因子)
double jacobian = cross . norm ( ) ; // Jacobian (area scaling factor)
return func ( u , v , p , dU , dV ) * jacobian ;
} catch ( . . . ) {
return 0.0 ; // 跳过奇异点
return 0.0 ; // Skip singular points
}
}
return 0.0 ; // 点不在有效域内
return 0.0 ; // Point not in domain
} ;
double v_integral = 0.0 ;
@ -120,9 +62,9 @@ double integrator_t::calculate(Func&& func, int gauss_order) const
double a = v_breaks [ i ] ;
double b = v_breaks [ i + 1 ] ;
// 检查区间中点是否有效
// Check midpoint validity
double mid_v = ( a + b ) / 2.0 ;
if ( is_point_inside_domain ( u , mid_v ) ) {
if ( is_point_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 ;
@ -132,18 +74,17 @@ double integrator_t::calculate(Func&& func, int gauss_order) const
return v_integral ;
} ;
// 在u方向积分
// Integrate in u direction
const auto & u_breaks = compute_u_breaks ( param_plane ) ;
double integral = 0.0 ;
for ( size_t i = 0 ; i < u_breaks . size ( ) - 1 ; + + i ) {
double a = u_breaks [ i ] ;
double b = u_breaks [ i + 1 ] ;
// 检查区间中点是否有效
double mid_u = ( a + b ) / 2.0 ;
auto v_intersections = find_vertical_intersections ( mid_u , self . outerEdges , self . Vmin , self . Vmax ) ;
if ( ! v_intersections . empty ( ) ) { // 确保该u区间有有效区域
if ( ! v_intersections . empty ( ) ) {
integral + = integrate_1D ( a , b , u_integrand , gauss_order , is_u_near_singularity ( mid_u ) ) ;
}
}
@ -152,6 +93,7 @@ double integrator_t::calculate(Func&& func, int gauss_order) const
}
// 在 integrator_t 类中添加:
/*
double integrator_t : : compute_volume ( int gauss_order ) const
{
double total_volume = 0.0 ;
@ -163,7 +105,7 @@ double integrator_t::compute_volume(int gauss_order) const
// 内层:对 v 积分
auto v_integrand = [ & ] ( double v ) - > double {
if ( ! is_point_inside_domain ( u , v ) ) {
if ( ! is_point_inside_domain ( subface , u , v ) ) {
return 0.0 ;
}
@ -193,7 +135,7 @@ double integrator_t::compute_volume(int gauss_order) const
double a = v_breaks [ i ] ;
double b = v_breaks [ i + 1 ] ;
double mid_v = ( a + b ) / 2.0 ;
if ( is_point_inside_domain ( u , mid_v ) ) {
if ( is_point_inside_domain ( subface , u , mid_v ) ) {
v_integral + = integrate_1D ( a , b , v_integrand , gauss_order ) ;
}
}
@ -214,56 +156,126 @@ double integrator_t::compute_volume(int gauss_order) const
// 乘以 1/3
return std : : abs ( total_volume ) / 3.0 ;
} */
/**
* @ brief Compute the u - parameter breakpoints for integration .
* @ note The function currently uses std : : set for uniqueness and sorting ,
* but floating - point precision may cause near - duplicate values to be
* treated as distinct . A tolerance - based comparison is recommended .
* TODO : Use a tolerance - based approach to avoid floating - point precision issues
* when inserting u - values ( e . g . , merge values within 1e-12 ) .
*/
stl_vector_mp < double > compute_u_breaks (
const parametric_plane_t & param_plane ,
double u_min ,
double u_max )
{
std : : set < double > break_set ;
// Insert domain boundaries
break_set . insert ( u_min ) ;
break_set . insert ( u_max ) ;
// Insert u-values from special vertices (e.g., trimming curve vertices)
for ( size_t i = 0 ; i < param_plane . chain_vertices . size ( ) ; + + i ) {
const auto & vertices = param_plane . chain_vertices [ i ] ;
auto & vertex_flags = param_plane . vertex_special_flags [ i ] ;
for ( size_t j = 0 ; j < vertices . size ( ) ; + + j ) {
if ( vertex_flags [ j ] ) { break_set . insert ( vertices [ j ] . x ( ) ) ; } // Special vertex u
}
}
// Return as vector (sorted and unique due to set)
return stl_vector_mp < double > ( break_set . begin ( ) , break_set . end ( ) ) ;
}
// 直线u=u_val与边界的交点
std : : vector < double > integrator_t : : find_vertical_intersections ( double u_val ) const
stl_vector_mp < double > integrator_t : : find_v_intersections_at_u (
const subface & subface ,
const parametric_plane_t & param_plane ,
double u_val ) const
{
std : : vector < double > intersections ;
std : : vector < int32_t > uPositionFlags ;
uPositionFlags . reserve ( m_uv_plane . chain_vertices . size ( ) ) ;
std : : transform ( m_uv_plane . chain_vertices . begin ( ) ,
m_uv_plane . chain_vertices . end ( ) ,
std : : back_inserter ( uPositionFlags ) ,
[ & ] ( const auto & currentVertex ) {
double uDifference = currentVertex . x ( ) - u_val ;
if ( uDifference < 0 ) return - 1 ; // 在参考值左侧
if ( uDifference > 0 ) return 1 ; // 在参考值右侧
return 0 ; // 等于参考值
} ) ;
uint32_t group_idx = 0 ;
for ( uint32_t element_idx = 0 ; element_idx < m_uv_plane . chains . index_group . size ( ) - 1 ; element_idx + + ) {
if ( element_idx > m_uv_plane . chains . start_indices [ group_idx + 1 ] ) group_idx + + ;
if ( element_idx + 1 < m_uv_plane . chains . start_indices [ group_idx + 1 ] ) {
uint32_t vertex_idx1 = m_uv_plane . chains . index_group [ element_idx ] ;
uint32_t vertex_idx2 = m_uv_plane . chains . index_group [ element_idx + 1 ] ;
if ( uPositionFlags [ vertex_idx1 ] * uPositionFlags [ vertex_idx2 ] < = 0 ) {
auto v1 = m_uv_plane . chain_vertices [ vertex_idx1 ] , v2 = m_uv_plane . chain_vertices [ vertex_idx2 ] ;
if ( v1 . x ( ) ! = v2 . x ( ) ) {
// "The line segment is vertical (u₁ == u₂), so there is no unique v value corresponding to the given u."
double v_initial = v1 . y ( ) + ( v2 . y ( ) - v1 . y ( ) ) * ( u_val - v1 . x ( ) ) / ( v2 . x ( ) - v1 . x ( ) ) ;
auto curve_evaluator = m_surface . fetch_curve_constraint_evaluator ( parameter_u_t { } , u_val ) ;
auto solver_evaluator = m_surface . fetch_solver_evaluator ( ) ;
auto target_function = [ & ] ( double v ) - > internal : : implicit_equation_intermediate {
constraint_curve_intermediate temp_res = curve_evaluator ( v ) ;
auto full_res = solver_evaluator ( std : : move ( temp_res ) ) ;
// ensure solver_eval returns implicit_equation_intermediate)
return std : : get < internal : : implicit_equation_intermediate > ( full_res ) ;
} ;
stl_vector_mp < double > intersections ;
// Iterate over each boundary chain
for ( const auto & chain : param_plane . chain_vertices ) {
const size_t n_vertices = chain . size ( ) ;
if ( n_vertices < 2 ) continue ; // Skip degenerate chains
// Iterate over each edge in the chain (including closing edge if desired)
for ( size_t i = 0 ; i < n_vertices ; + + i ) {
size_t j = ( i + 1 ) % n_vertices ; // Next vertex index (wraps around for closed chain)
const Eigen : : Vector2d & v1 = chain [ i ] ; // Current vertex: (u1, v1)
const Eigen : : Vector2d & v2 = chain [ j ] ; // Next vertex: (u2, v2)
double u1 = v1 . x ( ) , v1_val = v1 . y ( ) ;
double u2 = v2 . x ( ) , v2_val = v2 . y ( ) ;
// Classify position relative to u = u_val: -1 (left), 0 (on), +1 (right)
const double eps = 1e-12 ;
auto sign_cmp = [ u_val , eps ] ( double u ) - > int {
if ( u < u_val - eps ) return - 1 ;
if ( u > u_val + eps ) return 1 ;
return 0 ;
} ;
// Then use it
int pos1 = sign_cmp ( u1 ) ;
int pos2 = sign_cmp ( u2 ) ;
// Case 1: Both endpoints on the same side (and not on the line) → no intersection
if ( pos1 * pos2 > 0 ) {
continue ;
}
// Case 2: Both endpoints lie exactly on u = u_val → add both v-values
if ( pos1 = = 0 & & pos2 = = 0 ) {
intersections . push_back ( v1_val ) ;
intersections . push_back ( v2_val ) ;
}
// Case 3: One endpoint on u = u_val or segment crosses u = u_val
else if ( std : : abs ( u1 - u2 ) < eps ) {
// Vertical segment: if aligned with u_val, treat as overlapping
if ( pos1 = = 0 | | pos2 = = 0 ) {
intersections . push_back ( v1_val ) ;
intersections . push_back ( v2_val ) ;
}
}
else {
// General case: non-vertical segment crossing u = u_val
// Compute linear interpolation parameter t
double t = ( u_val - u1 ) / ( u2 - u1 ) ;
double v_initial = v1_val + t * ( v2_val - v1_val ) ; // Initial guess for v
// Fetch evaluators from subface for constraint solving
auto curve_evaluator = subface . fetch_curve_constraint_evaluator ( parameter_u_t { } , u_val ) ;
auto solver_evaluator = subface . fetch_solver_evaluator ( ) ;
// Define target function: v ↦ residual of implicit equation
auto target_function = [ & ] ( double v ) - > internal : : implicit_equation_intermediate {
constraint_curve_intermediate temp_res = curve_evaluator ( v ) ;
auto full_res = solver_evaluator ( std : : move ( temp_res ) ) ;
return std : : get < internal : : implicit_equation_intermediate > ( full_res ) ;
} ;
// Refine solution using Newton-Raphson method
try {
double v_solution = newton_method ( target_function , v_initial ) ;
intersections . push_back ( v_solution ) ;
} else {
intersections . push_back ( v1 . y ( ) ) ;
intersections . push_back ( v2 . y ( ) ) ;
} catch ( . . . ) {
// If Newton's method fails (e.g., divergence), fall back to linear approximation
intersections . push_back ( v_initial ) ;
}
}
}
}
// 去重排序
sort_and_unique_with_tol ( intersections ) ;
// Final step: sort and remove duplicates within tolerance
if ( ! intersections . empty ( ) ) {
sort_and_unique_with_tol ( intersections , 1e-8 ) ;
}
return intersections ;
}
@ -274,65 +286,35 @@ std::vector<double> integrator_t::find_vertical_intersections(double u_val) cons
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 ( double u , double v ) const
bool integrator_t : : is_point_inside_domain (
const subface & subface ,
const parametric_plane_t & param_plane ,
double u ,
double v ) const
{
bool is_implicit_equation_intermediate = m_surface . is_implicit_equation_intermediate ( ) ;
uint32_t group_idx = 0 , intersection_count = 0 ;
for ( uint32_t element_idx = 0 ; element_idx < m_uv_plane . chains . index_group . size ( ) - 1 ; element_idx + + ) {
if ( element_idx > m_uv_plane . chains . start_indices [ group_idx + 1 ] ) group_idx + + ;
if ( element_idx + 1 < m_uv_plane . chains . start_indices [ group_idx + 1 ] ) {
uint32_t vertex_idx1 = m_uv_plane . chains . index_group [ element_idx ] ;
uint32_t vertex_idx2 = m_uv_plane . chains . index_group [ element_idx + 1 ] ;
auto v1 = m_uv_plane . chain_vertices [ vertex_idx1 ] , v2 = m_uv_plane . chain_vertices [ vertex_idx2 ] ;
if ( ( v1 . x ( ) < = u & & v2 . x ( ) > u ) | | ( v2 . x ( ) < u & & v1 . x ( ) > = u ) ) {
double v_initial = v1 . y ( ) + ( v2 . y ( ) - v1 . y ( ) ) * ( u - v1 . x ( ) ) / ( v2 . x ( ) - v1 . x ( ) ) ;
if ( v_initial - v > = 1e-6 ) {
intersection_count + + ;
} else if ( std : : abs ( v_initial - v ) < 1e-6 ) {
// Only use Newton's method for implicit surfaces (scalar equation)
// Newton requires f(v) and df/dv as scalars — only implicit provides this.
// Skip parametric surfaces (vector residual) — treat initial guess as final
if ( is_implicit_equation_intermediate ) {
auto curve_evaluator = m_surface . fetch_curve_constraint_evaluator ( parameter_u_t { } , u ) ;
auto solver_evaluator = m_surface . fetch_solver_evaluator ( ) ;
auto target_function = [ & ] ( double v ) - > internal : : implicit_equation_intermediate {
constraint_curve_intermediate temp_res = curve_evaluator ( v ) ;
auto full_res = solver_evaluator ( std : : move ( temp_res ) ) ;
// ensure solver_eval returns implicit_equation_intermediate)
return std : : get < internal : : implicit_equation_intermediate > ( full_res ) ;
} ;
double v_solution = newton_method ( target_function , v_initial ) ;
if ( std : : abs ( v_solution - v ) > 0 ) { intersection_count + + ; }
}
else {
continue ;
}
}
}
/*
case v1 . x ( ) = = v2 . x ( ) = = u , do not count as intersection . but will cout in next iteration
*/
auto intersections = find_v_intersections_at_u ( subface , param_plane , u ) ;
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
}
}
return intersection_count % 2 = = 1 ; // in domain
return ( count % 2 ) = = 1 ;
}
bool integrator_t : : is_u_near_singularity ( double u , double tol ) const
{
for ( auto idx : m_uv_plane . singularity_vertices ) {
double singular_u = m_uv_plane . chain_vertices [ idx ] . x ( ) ;
if ( std : : abs ( u - singular_u ) < tol ) { return true ; }
}
// 可扩展:判断是否靠近极点、极性顶点等
for ( auto idx : m_uv_plane . polar_vertices ) {
double polar_u = m_uv_plane . chain_vertices [ idx ] . x ( ) ;
if ( std : : abs ( u - polar_u ) < tol ) { return true ; }
}
return false ;
}
void integrator_t : : sort_and_unique_with_tol ( std : : vector < double > & vec , double epsilon ) const
void integrator_t : : sort_and_unique_with_tol ( stl_vector_mp < double > & vec , double epsilon ) const
{
if ( vec . empty ( ) ) return ;