2 changed files with 363 additions and 0 deletions
			
			
		@ -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
 | 
				
			|||
@ -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…
					
					
				
		Reference in new issue