Browse Source

ruff init surface integral module

wch
mckay 5 days ago
parent
commit
3154fe8fc3
  1. 69
      surface_integral/interface/SurfaceIntegrator.hpp
  2. 294
      surface_integral/src/SurfaceIntegrator.cpp

69
surface_integral/interface/SurfaceIntegrator.hpp

@ -0,0 +1,69 @@
#pragma once
#include <primitive_process/interface/base/subface.hpp>
namespace internal
{
// 每个活动子面应具有以下结构
struct parametric_plane {
stl_vector_mp<Eigen::Vector2d> chain_vertices{}; // 链顶点
flat_index_group chains{}; // 链组
stl_vector_mp<uint32_t> singularity_vertices{}; // 奇异顶点,即链的交点
stl_vector_mp<uint32_t> polar_vertices{}; // 极性顶点,即两个连接顶点周围的最小/最大 x/y
stl_vector_mp<uint32_t> parallel_start_vertices{}; // 平行起始顶点,即边 {v, v + 1} 平行于 x/y 轴
};
class SurfaceAreaCalculator
{
public:
// 构造函数,接受对 subface 的引用
explicit SurfaceAreaCalculator(const subface& surface);
[[deprecated("Use calculate_new() instead")]]
SurfaceAreaCalculator(const subface& surface,
const stl_vector_map<double>& u_breaks,
double umin,
double umax,
double vmin,
double vmax);
SurfaceAreaCalculator(const subface& surface, const parametric_plane& uv_plane);
// 设置 u_breaks(裁剪/分割线)
void set_ubreaks(const stl_vector_map<double>& u_breaks);
// 计算面积主函数
template <typename Func>
double calculate(Func&& func, int gauss_order = 3) const;
private:
const subface& m_surface; // 引用原始曲面
stl_vector_map<double> m_u_breaks; // 分割线信息(可选)
parametric_plane m_uv_plane;
double Umin = 0.0; // 参数域范围
double Umax = 1.0;
double Vmin = 0.0;
double Vmax = 1.0;
// 私有辅助函数(可扩展)
template <typename Func>
double SurfaceAreaCalculator::GaussIntegrate1D(double a, double b, Func&& func, int q) const;
// 直线u=u_val与边界的交点
std::vector<double> FindVerticalIntersectionsOCCT(double u_val,
const std::vector<Handle(Geom2d_Curve)>& edges,
double v_min,
double v_max);
bool IsPointInsideDomain(double u,
double v,
const std::vector<Handle(Geom2d_Curve)>& outerEdges,
const std::vector<Handle(Geom2d_Curve)>& innerEdges,
double u_min,
double u_max,
double v_min,
double v_max);
double integrate_over_uv(int num_samples) const;
};
} // namespace internal

294
surface_integral/src/SurfaceIntegrator.cpp

@ -0,0 +1,294 @@
#include "surface_integral.hpp" // Replace with your actual header path
#include <Eigen/Geometry> // For vector and cross product operations
#include <cmath> // For math functions like sqrt
namespace internal
{
// Constructor 1: Initialize only with a reference to the surface
SurfaceAreaCalculator::SurfaceAreaCalculator(const subface& surface) : m_surface(surface) {}
// Constructor 2: Initialize with surface and u-breaks (e.g., trimming curves)
SurfaceAreaCalculator::SurfaceAreaCalculator(const subface& surface,
const stl_vector_map<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)
{
}
SurfaceAreaCalculator::SurfaceAreaCalculator(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()) {
// 初始化为第一个点的坐标
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);
}
}
// 转换为 vector 并排序(set 默认是有序的)
m_u_breaks = std::vector<double>(unique_u_values.begin(), unique_u_values.end());
}
// Set u-breaks (optional trimming or partitioning lines)
void SurfaceAreaCalculator::set_ubreaks(const stl_vector_map<double>& u_breaks) { m_u_breaks = u_breaks; }
// Main entry point to compute surface area
template <typename Func>
double SurfaceAreaCalculator::calculate(Func&& func, int gauss_order) const
{
// 在u方向进行高斯积分
auto u_integrand = [&](double u) {
// 对每个u,找到v方向的精确交点
std::vector<double> v_breaks = {self.Vmin, self.Vmax};
auto outer_intersections = FindVerticalIntersectionsOCCT(u, self.outerEdges, self.Vmin, self.Vmax);
v_breaks.insert(v_breaks.end(), outer_intersections.begin(), outer_intersections.end());
auto inner_intersections = FindVerticalIntersectionsOCCT(u, self.innerEdges, self.Vmin, self.Vmax);
v_breaks.insert(v_breaks.end(), inner_intersections.begin(), inner_intersections.end());
// 排序并去重
sort_and_unique_with_tol(v_breaks, 1e-6);
// 在v方向进行高斯积分
auto v_integrand = [&](double v) {
// 判断点是否在有效域内
if (IsPointInsideself(u,
v,
self.outerEdges,
self.innerEdges,
self.Umin,
self.Umax,
self.Vmin,
self.Vmax)) {
try {
gp_Pnt p;
gp_Vec dU, dV;
surface->D1(u, v, p, dU, dV);
const double jacobian = dU.Crossed(dV).Magnitude();
return func(u, v, p, dU, dV) * jacobian;
} catch (...) {
return 0.0; // 跳过奇异点
}
}
return 0.0; // 点不在有效域内
};
double v_integral = 0.0;
for (size_t i = 0; i < v_breaks.size() - 1; ++i) {
double a = v_breaks[i];
double b = v_breaks[i + 1];
// 检查区间中点是否有效
double mid_v = (a + b) / 2.0;
if (IsPointInsideself(u,
mid_v,
self.outerEdges,
self.innerEdges,
self.Umin,
self.Umax,
self.Vmin,
self.Vmax)) {
v_integral += GaussIntegrate1D(a, b, v_integrand, gauss_order);
} else {
std::cout << "uv out of domain: (" << u << "," << mid_v << ")" << std::endl;
}
}
return v_integral;
};
// 在u方向积分
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 = FindVerticalIntersectionsOCCT(mid_u, self.outerEdges, self.Vmin, self.Vmax);
if (!v_intersections.empty()) { // 确保该u区间有有效区域
double integralp = GaussIntegrate1D(a, b, u_integrand, gauss_order);
integral += integralp;
std::cout << "integral " << i << ": " << integralp << std::endl;
}
}
return integral;
}
// 在区间[a,b]上进行高斯积分采样
template<typename Func>
double SurfaceAreaCalculator::GaussIntegrate1D(double a, double b, Func&& func, int q) const {
double sum = 0.0;
for (int i = 0; i < q; ++i) {
double x=a+(b-a)*GaussQuad::x(q, i);
double w=GaussQuad::w(q, i);
sum += w * func(x);
}
return sum * (b-a);
}
// 直线u=u_val与边界的交点
std::vector<double> SurfaceAreaCalculator::FindVerticalIntersectionsOCCT(
double u_val,
const std::vector<Handle(Geom2d_Curve)>& edges,
double v_min,
double v_max)
{
std::vector<double> intersections;
// 创建垂直线(u=u_val)
gp_Lin2d vertical_line(gp_Pnt2d(u_val, v_min), gp_Dir2d(0, 1));
Handle(Geom2d_Line) hVerticalLine = new Geom2d_Line(vertical_line);
for (const auto& edge : edges) {
if (edge.IsNull()) {
continue;
}
// 使用Geom2dAPI_InterCurveCurve求交
Geom2dAPI_InterCurveCurve intersector(edge, hVerticalLine);
if (intersector.NbPoints() > 0) {
for (int i = 1; i <= intersector.NbPoints(); ++i) {
gp_Pnt2d pt = intersector.Point(i);
double v = pt.Y();
if (v >= v_min && v <= v_max) {
intersections.push_back(v);
}
}
}
// 补充采样法确保可靠性
Geom2dAdaptor_Curve adaptor(edge);
double first = adaptor.FirstParameter();
double last = adaptor.LastParameter();
const int samples = 20;
gp_Pnt2d prev_p;
adaptor.D0(first, prev_p);
double prev_v = prev_p.Y();
for (int i = 1; i <= samples; ++i) {
double param = first + i * (last - first) / samples;
gp_Pnt2d curr_p;
adaptor.D0(param, curr_p);
double curr_v = curr_p.Y();
if ((prev_v - u_val) * (curr_v - u_val) <= 0) {
// 牛顿迭代法
double t = param - (last - first)/samples;
for (int iter = 0; iter < 5; ++iter) {
gp_Pnt2d p;
gp_Vec2d deriv;
adaptor.D1(t, p, deriv);
if (std::abs(p.X() - u_val) < Precision::Confusion()) {
if (p.Y() >= v_min && p.Y() <= v_max) {
intersections.push_back(p.Y());
}
break;
}
t -= (p.X() - u_val) / deriv.X();
}
}
prev_v = curr_v;
}
}
// 去重排序
std::sort(intersections.begin(), intersections.end());
intersections.erase(std::unique(intersections.begin(), intersections.end()), intersections.end());
return intersections;
}
// Private method: Numerical integration over the UV parameter domain
double SurfaceAreaCalculator::integrate_over_uv(int num_samples) const
{
double area = 0.0;
double du = 1.0 / num_samples;
double dv = 1.0 / num_samples;
// Fetch evaluators for point and derivative calculation
auto point_func = m_surface.fetch_point_by_param_evaluator();
auto solver_func = m_surface.fetch_solver_evaluator();
for (int i = 0; i < num_samples; ++i) {
double u = (i + 0.5) * du; // Midpoint sampling in u-direction
for (int j = 0; j < num_samples; ++j) {
double v = (j + 0.5) * dv; // Midpoint sampling in v-direction
// Evaluate the surface point at (u, v)
Eigen::Vector4d pt = point_func(Eigen::Vector2d(u, v));
// Get constraint and solve intermediate result
auto constraint = m_surface.fetch_curve_constraint_evaluator(internal::parameter_v_t{}, v)(u);
auto result = std::get<internal::parametric_equation_intermediate>(solver_func(std::move(constraint)));
// Extract partial derivatives ∂S/∂u and ∂S/∂v
Eigen::Vector3d dSdu = result.grad_f.col(0);
Eigen::Vector3d dSdv = result.grad_f.col(1);
// Compute the differential area element (cross product norm)
double dA = dSdu.cross(dSdv).norm();
// Accumulate area using numerical integration
area += dA * du * dv;
}
}
return area;
}
} // namespace internal
Loading…
Cancel
Save