7b76689ea1
v11.1 — Test Infrastructure (14 files): - .github/workflows/ci.yml: Ubuntu 22.04 + GCC 11, auto ctest on push - tests/regression/: degenerate geometry, extreme coords, thin wall, large models - tests/fuzz/: SDF random CSG, random booleans, format round-trip, continuous mode - tests/benchmark/: boolean perf, MC perf, IO perf benchmarks - docs/benchmark-report.md: benchmark template v11.2 — Code Quality + Docs: - .clang-tidy: 15 check categories, 22 exclusions - .github/workflows/static-analysis.yml: clang-tidy CI scan - CODEOWNERS, SECURITY.md - docs: API overview, testing guide, contributing guide - README: module capability overview table Pending: binary formats + curve projection (retrying)
145 lines
6.1 KiB
C++
145 lines
6.1 KiB
C++
#pragma once
|
|
#include "vde/curves/nurbs_surface.h"
|
|
#include "vde/curves/nurbs_curve.h"
|
|
#include "vde/core/point.h"
|
|
#include "vde/core/aabb.h"
|
|
#include "vde/mesh/halfedge_mesh.h"
|
|
#include <optional>
|
|
#include <vector>
|
|
#include <utility>
|
|
|
|
namespace vde::brep {
|
|
|
|
/// A p-curve: 2D curve in the parameter space of a surface
|
|
/// We reuse NurbsCurve with Z=0 — only X (u) and Y (v) are meaningful.
|
|
using PCurve = curves::NurbsCurve;
|
|
|
|
/// Trimming loop: closed contour in parameter space (u, v)
|
|
/// An outer loop defines the boundary; inner loops define holes.
|
|
struct TrimLoop {
|
|
std::vector<PCurve> p_curves; ///< parameter-space curves forming the loop
|
|
bool is_outer = true; ///< true = outer boundary, false = hole
|
|
};
|
|
|
|
/// A trimmed surface: base NURBS surface + trimming loops in parameter space
|
|
///
|
|
/// Point classification: a parameter (u, v) is INSIDE if it lies within
|
|
/// the outer loop AND outside all inner loops.
|
|
///
|
|
/// This is the fundamental B-Rep primitive used by all industrial CAD kernels
|
|
/// (Parasolid, ACIS, CGM).
|
|
///
|
|
/// @ingroup brep
|
|
struct TrimmedSurface {
|
|
curves::NurbsSurface base_surface; ///< Underlying geometry
|
|
std::vector<TrimLoop> loops; ///< Trimming loops (first = outer boundary if marked)
|
|
|
|
/// Evaluate the surface at (u, v).
|
|
/// Returns the 3D point only if (u, v) is inside the trimmed region.
|
|
/// @return Point3D if inside, std::nullopt if outside
|
|
[[nodiscard]] std::optional<core::Point3D> evaluate(double u, double v) const;
|
|
|
|
/// Check if a parameter point is inside the trimmed region
|
|
[[nodiscard]] bool is_inside(double u, double v) const;
|
|
|
|
/// Compute winding number of point (u,v) relative to a loop
|
|
/// Positive = inside (for counter-clockwise outer loop), 0 = outside
|
|
[[nodiscard]] int winding_number(double u, double v, const TrimLoop& loop) const;
|
|
|
|
/// Find the closest point on the boundary to (u,v) — for points outside trimmed region
|
|
[[nodiscard]] core::Point3D closest_boundary_point(double u, double v) const;
|
|
|
|
/// Get the axis-aligned bounding box of the trimmed surface
|
|
[[nodiscard]] core::AABB3D bounds() const;
|
|
|
|
/// Tessellate the trimmed surface to a triangle mesh
|
|
/// Uses adaptive grid sampling with inside/outside testing
|
|
/// @param deflection chord-height tolerance for tessellation
|
|
/// @return HalfedgeMesh containing the triangulated trimmed surface
|
|
[[nodiscard]] mesh::HalfedgeMesh to_mesh(double deflection = 0.01) const;
|
|
|
|
/// Create an untrimmed surface (full parameter domain)
|
|
static TrimmedSurface from_surface(const curves::NurbsSurface& surf);
|
|
|
|
/// Create a rectangular trimmed surface
|
|
static TrimmedSurface from_rect(const curves::NurbsSurface& surf,
|
|
double u0, double u1, double v0, double v1);
|
|
|
|
/// Create a trimmed surface with a circular hole
|
|
static TrimmedSurface from_rect_with_hole(const curves::NurbsSurface& surf,
|
|
double u0, double u1, double v0, double v1,
|
|
double hole_uc, double hole_vc, double hole_r,
|
|
int hole_segments = 32);
|
|
|
|
/// Create a trimmed surface for a cylinder side patch
|
|
/// u ranges [u0, u1] along circumference, v ranges [v0, v1] along height
|
|
static TrimmedSurface from_cylinder_patch(const curves::NurbsSurface& cyl_surf,
|
|
double u0, double u1, double v0, double v1);
|
|
|
|
/// Create a trimmed surface for a sphere patch
|
|
static TrimmedSurface from_sphere_patch(const curves::NurbsSurface& sphere_surf,
|
|
double u0, double u1, double v0, double v1);
|
|
};
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// 曲面偏移
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
/// 自交区域描述
|
|
struct SelfIntersectionRegion {
|
|
std::pair<double, double> u_range; ///< 自交区域在 u 参数方向的范围
|
|
std::pair<double, double> v_range; ///< 自交区域在 v 参数方向的范围
|
|
std::string intersection_type; ///< "overlap" 或 "tangent_crossing"
|
|
};
|
|
|
|
/// 曲面偏移结果
|
|
struct OffsetResult {
|
|
curves::NurbsSurface offset_surface; ///< 偏移后的曲面
|
|
bool has_self_intersection = false; ///< 是否检测到自交
|
|
std::vector<SelfIntersectionRegion> self_intersection_regions; ///< 自交区域
|
|
TrimmedSurface offset_trimmed; ///< 自动裁剪后的偏移曲面
|
|
};
|
|
|
|
/**
|
|
* @brief 沿法向偏移曲面
|
|
*
|
|
* 使用控制点偏移法(Greville 横坐标评估法向)构造偏移曲面。
|
|
* 这是工业中 Parasolid/ACIS 的常用近似方法,精确偏移仅对可展曲面成立。
|
|
*
|
|
* 自动检测自交区域并构建裁剪曲面。
|
|
*
|
|
* @param surface 原始 NURBS 曲面
|
|
* @param distance 偏移距离(正 = 法向正方向,负 = 反向)
|
|
* @return OffsetResult 包含偏移曲面 + 自交信息 + 裁剪曲面
|
|
*/
|
|
[[nodiscard]] OffsetResult offset_surface(
|
|
const curves::NurbsSurface& surface, double distance);
|
|
|
|
/**
|
|
* @brief 检测曲面自交区域
|
|
*
|
|
* 通过网格采样 + 空间哈希检测参数域中不同位置映射到
|
|
* 同一 3D 空间的区域。
|
|
*
|
|
* @param surface 待检测曲面
|
|
* @param grid_res 采样网格分辨率(默认 50)
|
|
* @return 自交区域列表
|
|
*/
|
|
[[nodiscard]] std::vector<SelfIntersectionRegion> detect_self_intersections(
|
|
const curves::NurbsSurface& surface, int grid_res = 50);
|
|
|
|
/**
|
|
* @brief 从裁剪曲面中移除自交区域
|
|
*
|
|
* 将检测到的自交区域作为内部孔洞裁剪掉。
|
|
*
|
|
* @param ts 原始裁剪曲面
|
|
* @param regions 自交区域列表
|
|
* @return 移除自交区域后的裁剪曲面
|
|
*/
|
|
[[nodiscard]] TrimmedSurface trim_self_intersections(
|
|
const TrimmedSurface& ts,
|
|
const std::vector<SelfIntersectionRegion>& regions);
|
|
|
|
} // namespace vde::brep
|