Browse Source

refactor(integrator_t): streamline constructors and enhance integration methods

- Simplified and unified constructors for `integrator_t` to improve usability and maintainability.
- Enhanced `find_v_intersections_at_u` with robust handling of vertical edges and improved numerical stability.
- Refactored `is_point_inside_domain` to reuse existing intersection logic, eliminating code duplication.
- Adjusted interface to align with revised expectations around `parametric_plane_t`, which previously caused inconsistencies.
- Extended design to support multi-face integration (previously limited to single face); volume-related logic temporarily commented out for clarity.

This version is compilable, but not yet runnable due to nullptr issues in primitive_process during object creation. Integration framework is now structurally ready for multi-surface extension once initialization is fixed.
feat-integrator
mckay 4 months ago
parent
commit
4a7ad26da1
  1. 86
      surface_integral/interface/SurfaceIntegrator.hpp
  2. 326
      surface_integral/src/SurfaceIntegrator.cpp

86
surface_integral/interface/SurfaceIntegrator.hpp

@ -3,64 +3,70 @@
#include <base/subface.hpp> #include <base/subface.hpp>
#include <process.hpp> #include <process.hpp>
#include <container/stl_alias.hpp> #include <container/stl_alias.hpp>
#include <container/wrapper/flat_index_group.hpp> #include <container/wrapper/flat_index_group.hpp>
namespace internal namespace internal
{ {
// 每个活动子面应具有以下结构 /**
struct parametric_plane { * @brief Numerical integrator for parametric surfaces with trimming curves.
stl_vector_mp<Eigen::Vector2d> chain_vertices{}; // 链顶点 *
flat_index_group chains{}; // 链组 * This class computes integrals (e.g., area, mass, etc.) over trimmed parametric surfaces
stl_vector_mp<uint32_t> singularity_vertices{}; // 奇异顶点,即链的交点 * by subdividing the parameter domain and applying Gaussian quadrature.
stl_vector_mp<uint32_t> polar_vertices{}; // 极性顶点,即两个连接顶点周围的最小/最大 x/y *
stl_vector_mp<uint32_t> parallel_start_vertices{}; // 平行起始顶点,即边 {v, v + 1} 平行于 x/y 轴 * The integrator does not own the input data; it holds const references to ensure zero-copy semantics.
}; * Users must ensure that the lifetime of input data exceeds that of the integrator.
*/
class SI_API integrator_t class SI_API integrator_t
{ {
public: public:
// 构造函数,接受对 subface 的引用 /**
explicit integrator_t(const subface& surface); * @note This constructor does not copy the data; it stores const references.
[[deprecated("Use calculate_new() instead")]] integrator_t(const subface& surface, * The caller is responsible for ensuring the validity of the referenced data
const stl_vector_mp<double>& u_breaks, * throughout the lifetime of this integrator.
double umin, */
double umax, integrator_t(const stl_vector_mp<object_with_index_mapping<subface>>& surfaces,
double vmin, const flat_hash_map_mp<uint32_t, parametric_plane_t>& uv_planes)
double vmax); : m_surfaces(surfaces), m_uv_planes(uv_planes)
integrator_t(const subface& surface, const parametric_plane& uv_plane); {
}
/// Default destructor
~integrator_t() = default;
// 设置 u_breaks(裁剪/分割线)
void set_ubreaks(const stl_vector_mp<double>& u_breaks);
// 计算面积主函数
template <typename Func> template <typename Func>
double calculate(Func&& func, int gauss_order = 3) const; double calculate(int gauss_order, Func&& func) const;
double compute_volume(int gauss_order = 4) const;
template <typename Func>
double calculate_one_subface(const subface& subface,
const parametric_plane_t& param_plane,
int gauss_order,
Func&& func) const;
private: private:
const subface& m_surface; // 引用原始曲面 /// Non-owning reference to the list of subfaces
stl_vector_mp<double> m_u_breaks; // 分割线信息(可选) const stl_vector_mp<object_with_index_mapping<subface>>& m_surfaces;
parametric_plane m_uv_plane;
double Umin = 0.0; // 参数域范围 /// Non-owning reference to the map of parametric planes (ID -> parametric_plane_t)
double Umax = 1.0; const flat_hash_map_mp<uint32_t, parametric_plane_t>& m_uv_planes;
double Vmin = 0.0;
double Vmax = 1.0; stl_vector_mp<double> compute_u_breaks(const parametric_plane_t& param_plane, double u_min, double u_max);
// 私有辅助函数 stl_vector_mp<double> find_v_intersections_at_u(const subface& subface,
// 直线u=u_val与边界的交点 const parametric_plane_t& param_plane,
std::vector<double> find_vertical_intersections(double u_val) const; double u_val) const;
bool is_point_inside_domain(double u, double v) const; bool is_point_inside_domain(const subface& subface, const parametric_plane_t& param_plane, double u, double v) const;
bool is_u_near_singularity(double u, double tol = 1e-6) const; bool is_u_near_singularity(double u, double tol = 1e-6) const;
void sort_and_unique_with_tol(std::vector<double>& vec, double epsilon = 1e-8) const;
};
void sort_and_unique_with_tol(stl_vector_mp<double>& vec, double epsilon = 1e-8) const;
};
SI_API double newton_method(const std::function<internal::implicit_equation_intermediate(double)>& F, double newton_method(const std::function<implicit_equation_intermediate(double)>& F,
double v_initial, double v_initial,
double tolerance = 1e-8, double tolerance = 1e-8,
int max_iterations = 100); int max_iterations = 100);

326
surface_integral/src/SurfaceIntegrator.cpp

@ -8,111 +8,53 @@
namespace internal namespace internal
{ {
// Constructor 1: Initialize only with a reference to the surface // Main entry point to compute surface area
integrator_t::integrator_t(const subface& surface) : m_surface(surface) {} // Main entry point to compute surface area
template <typename Func>
// Constructor 2: Initialize with surface and u-breaks (e.g., trimming curves) double integrator_t::calculate(int gauss_order, Func&& func) const
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)
{ {
if (!uv_plane.chain_vertices.empty()) { total_integral = 0.0;
// 初始化为第一个点的坐标 for (const auto& [subface_index, param_plane] : m_uv_planes) {
double min_u = uv_plane.chain_vertices[0].x(); const auto& subface = m_subfaces[subface_index].object_ptr.get();
double max_u = uv_plane.chain_vertices[0].x(); total_integral += calculate_one_subface(subface, param_plane, gauss_order, std::forward<Func>(func));
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);
} }
} return total_integral;
// 转换为 vector 并排序(set 默认是有序的)
m_u_breaks = stl_vector_mp<double>(unique_u_values.begin(), unique_u_values.end());
} }
// 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> 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_surface.fetch_solver_evaluator(); auto solver = subface.fetch_solver_evaluator();
// 在u方向进行高斯积分 // Gaussian integration in u direction
auto u_integrand = [&](double u) { auto u_integrand = [&](double u) {
// 对每个u,找到v方向的精确交点 // Find exact v intersections for each u
std::vector<double> v_breaks = find_vertical_intersections(u); std::vector<double> v_breaks = find_vertical_intersections(u);
// 在v方向进行高斯积分 // Gaussian integration in v direction
auto v_integrand = [&](double v) { auto v_integrand = [&](double v) {
// 判断点是否在有效域内 // Check if point is inside domain
if (is_point_inside_domain(u, v)) { if (is_point_inside_domain(subface, param_plane, u, v)) {
try { try {
// 获取两个方向的 evaluator // Get evaluators for both directions
auto eval_du = m_surface.fetch_curve_constraint_evaluator(parameter_v_t{}, v); // 固定 v,变 u → 得到 ∂/∂u auto eval_du = subface.fetch_curve_constraint_evaluator(parameter_v_t{}, v); // Fix v, vary u → ∂/∂u
auto eval_dv = m_surface.fetch_curve_constraint_evaluator(parameter_u_t{}, u); // 固定 u,变 v → 得到 ∂/∂v 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_u = eval_du(u); // f(u,v), grad_f = ∂r/∂u
auto res_v = eval_dv(v); // f(u,v), grad_f = ∂r/∂v 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 dU = res_u.grad_f.template head<3>(); // ∂r/∂u
Eigen::Vector3d dV = res_v.grad_f.template head<3>(); // ∂r/∂v Eigen::Vector3d dV = res_v.grad_f.template head<3>(); // ∂r/∂v
// ✅ 计算面积元:||dU × dV|| // Area element: ||dU × dV||
Eigen::Vector3d cross = dU.cross(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; return func(u, v, p, dU, dV) * jacobian;
} catch (...) { } 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; 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 a = v_breaks[i];
double b = v_breaks[i + 1]; double b = v_breaks[i + 1];
// 检查区间中点是否有效 // Check midpoint validity
double mid_v = (a + b) / 2.0; 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); v_integral += integrate_1D(a, b, v_integrand, gauss_order);
} else { } else {
std::cout << "uv out of domain: (" << u << "," << mid_v << ")" << std::endl; 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; return v_integral;
}; };
// 在u方向积分 // Integrate in u direction
const auto& u_breaks = compute_u_breaks(param_plane);
double integral = 0.0; double integral = 0.0;
for (size_t i = 0; i < u_breaks.size() - 1; ++i) { for (size_t i = 0; i < u_breaks.size() - 1; ++i) {
double a = u_breaks[i]; double a = u_breaks[i];
double b = u_breaks[i + 1]; double b = u_breaks[i + 1];
// 检查区间中点是否有效
double mid_u = (a + b) / 2.0; double mid_u = (a + b) / 2.0;
auto v_intersections = find_vertical_intersections(mid_u, self.outerEdges, self.Vmin, self.Vmax); 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)); 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 类中添加: // 在 integrator_t 类中添加:
/*
double integrator_t::compute_volume(int gauss_order) const double integrator_t::compute_volume(int gauss_order) const
{ {
double total_volume = 0.0; double total_volume = 0.0;
@ -163,7 +105,7 @@ double integrator_t::compute_volume(int gauss_order) const
// 内层:对 v 积分 // 内层:对 v 积分
auto v_integrand = [&](double v) -> double { auto v_integrand = [&](double v) -> double {
if (!is_point_inside_domain(u, v)) { if (!is_point_inside_domain(subface, u, v)) {
return 0.0; return 0.0;
} }
@ -193,7 +135,7 @@ double integrator_t::compute_volume(int gauss_order) const
double a = v_breaks[i]; double a = v_breaks[i];
double b = v_breaks[i + 1]; double b = v_breaks[i + 1];
double mid_v = (a + b) / 2.0; 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); 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 // 乘以 1/3
return std::abs(total_volume) / 3.0; 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; stl_vector_mp<double> intersections;
std::vector<int32_t> uPositionFlags;
uPositionFlags.reserve(m_uv_plane.chain_vertices.size()); // Iterate over each boundary chain
for (const auto& chain : param_plane.chain_vertices) {
std::transform(m_uv_plane.chain_vertices.begin(), const size_t n_vertices = chain.size();
m_uv_plane.chain_vertices.end(), if (n_vertices < 2) continue; // Skip degenerate chains
std::back_inserter(uPositionFlags),
[&](const auto& currentVertex) { // Iterate over each edge in the chain (including closing edge if desired)
double uDifference = currentVertex.x() - u_val; for (size_t i = 0; i < n_vertices; ++i) {
if (uDifference < 0) return -1; // 在参考值左侧 size_t j = (i + 1) % n_vertices; // Next vertex index (wraps around for closed chain)
if (uDifference > 0) return 1; // 在参考值右侧
return 0; // 等于参考值 const Eigen::Vector2d& v1 = chain[i]; // Current vertex: (u1, v1)
}); const Eigen::Vector2d& v2 = chain[j]; // Next vertex: (u2, v2)
uint32_t group_idx = 0; double u1 = v1.x(), v1_val = v1.y();
for (uint32_t element_idx = 0; element_idx < m_uv_plane.chains.index_group.size() - 1; element_idx++) { double u2 = v2.x(), v2_val = v2.y();
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]) { // Classify position relative to u = u_val: -1 (left), 0 (on), +1 (right)
uint32_t vertex_idx1 = m_uv_plane.chains.index_group[element_idx]; const double eps = 1e-12;
uint32_t vertex_idx2 = m_uv_plane.chains.index_group[element_idx + 1]; auto sign_cmp = [u_val, eps](double u) -> int {
if (uPositionFlags[vertex_idx1] * uPositionFlags[vertex_idx2] <= 0) { if (u < u_val - eps) return -1;
auto v1 = m_uv_plane.chain_vertices[vertex_idx1], v2 = m_uv_plane.chain_vertices[vertex_idx2]; if (u > u_val + eps) return 1;
if (v1.x() != v2.x()) { return 0;
// "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); // Then use it
auto solver_evaluator = m_surface.fetch_solver_evaluator(); 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 { auto target_function = [&](double v) -> internal::implicit_equation_intermediate {
constraint_curve_intermediate temp_res = curve_evaluator(v); constraint_curve_intermediate temp_res = curve_evaluator(v);
auto full_res = solver_evaluator(std::move(temp_res)); 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); 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); double v_solution = newton_method(target_function, v_initial);
intersections.push_back(v_solution); intersections.push_back(v_solution);
} else { } catch (...) {
intersections.push_back(v1.y()); // If Newton's method fails (e.g., divergence), fall back to linear approximation
intersections.push_back(v2.y()); intersections.push_back(v_initial);
} }
} }
} }
} }
// 去重排序 // Final step: sort and remove duplicates within tolerance
sort_and_unique_with_tol(intersections); if (!intersections.empty()) {
sort_and_unique_with_tol(intersections, 1e-8);
}
return intersections; 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 NOTE: when v_intersect - v < threshold, further checks are required to accurately determine if the intersection point lies
precisely on the boundary segment. 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(); auto intersections = find_v_intersections_at_u(subface, param_plane, u);
uint32_t group_idx = 0, intersection_count = 0; const double tol_near = 1e-8;
for (uint32_t element_idx = 0; element_idx < m_uv_plane.chains.index_group.size() - 1; element_idx++) { const double tol_above = 1e-12;
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;
}
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
} }
/*
case v1.x() == v2.x() == u, do not count as intersection.but will cout in next iteration
*/
} }
} return (count % 2) == 1;
return intersection_count % 2 == 1; // in domain
} }
bool integrator_t::is_u_near_singularity(double u, double tol) const 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; 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; if (vec.empty()) return;

Loading…
Cancel
Save