Files
茂之钳 2ecad1543f
Build & Test / build-and-test (push) Waiting to run
Build & Test / python-bindings (push) Blocked by required conditions
CI / Build & Test (push) Failing after 1m31s
CI / Release Build (push) Failing after 31s
feat(v8): ultimate performance + CAM full optimization + visualization/IGA/quality
v8.1 — 极致性能 (SIMD + LockFree + Transaction + NUMA):
- simd_vector.h: Vec4d/Vec4f SSE/AVX/NEON auto-detect, batch AABB, SoA transpose
- concurrent_data: LockFreeQueue (MPMC CAS), LockFreeStack (Treiber), ConcurrentHashMap (64-segment sharded)
- transaction: Command pattern, UndoManager (infinite undo/redo), crash-recovery journal
- performance_tuning: NUMA-aware, cache_line aligned, prefetch, hot/cold separation
- 20 tests (concurrent + transaction), ~2600 lines

v8.2 — CAM 全面优化 + 装配模式:
- cam_optimization: chip_thinning, HSM, constant_engagement, trochoidal_turn_milling
- tool_life_management, probing_cycle, thread_milling
- cam_advanced enhanced: Mazak/Okuma/Haas/DMG post-processors (8 total)
- assembly_patterns: Circular/Rectangular/Mirror/PatternDriven/fill arrays
- assembly_feature enhanced: assembly-level PMI propagation, batch interference check
- 28 tests, compiled 0 errors (~2800 lines)

v8.3 — 可视化+压缩+IGA+质量闭环:
- visualization_quality: ambient_occlusion, edge_highlighting, wireframe, normals
- topology_compression: Brep compression, Edgebreaker, vertex quantization
- iga_prep: knot_insertion, degree_elevation, Bezier extraction for IGA analysis
- quality_feedback: design_rule_check, manufacturability, cost_estimation, quality_score (0-100)
- 28 tests, ~2349 lines

27 files, ~7750 lines, 76 tests
2026-07-26 23:13:22 +08:00

817 lines
26 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
/**
* @file simd_vector.h
* @brief 极致性能 — 平台自适应 SIMD 向量 (SSE/AVX/NEON)
*
* 提供 4-wide double/float SIMD 向量类型,自动检测 CPU 指令集。
* 支持 dot/cross/normalize/length 及 AABB 批量相交测试。
*
* ## SIMD 指令集选择策略
*
* | 平台 | 指令集 | 宏定义 |
* |-----------|---------|-------------------------------|
* | x86_64 | AVX2 | __AVX2__ (由编译器定义) |
* | x86_64 | SSE2 | __SSE2__ (回退) |
* | ARM | NEON | __ARM_NEON |
* | 通用 | 标量回退 | 无 SIMD 宏 |
*
* @ingroup core
*/
#include <cstddef>
#include <cstdint>
#include <cmath>
#include <algorithm>
#include <type_traits>
// ── 平台检测与指令集选择 ──────────────────────────────
#if defined(__AVX2__) || defined(__AVX__)
#define VDE_SIMD_AVX 1
#include <immintrin.h>
#elif defined(__SSE2__) || defined(__SSE3__) || defined(__SSSE3__) || defined(__SSE4_1__)
#define VDE_SIMD_SSE 1
#include <emmintrin.h>
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
#elif defined(__ARM_NEON) || defined(__aarch64__)
#define VDE_SIMD_NEON 1
#include <arm_neon.h>
#endif
namespace vde::core {
// ═══════════════════════════════════════════════════════════════════════════
// 辅助:编译期指令集查询
// ═══════════════════════════════════════════════════════════════════════════
/// 当前使用的 SIMD 指令集标签
enum class SimdIsa {
Scalar, ///< 纯标量回退
SSE2, ///< SSE2 / SSE4.1
AVX, ///< AVX / AVX2
NEON ///< ARM NEON
};
/// 编译期查询当前 SIMD 指令集
constexpr SimdIsa current_simd_isa() {
#if VDE_SIMD_AVX
return SimdIsa::AVX;
#elif VDE_SIMD_SSE
return SimdIsa::SSE2;
#elif VDE_SIMD_NEON
return SimdIsa::NEON;
#else
return SimdIsa::Scalar;
#endif
}
/// SIMD 向量宽度(double lane 数)
constexpr int simd_width_d = (current_simd_isa() >= SimdIsa::SSE2) ? 4 : 1;
/// SIMD 向量宽度(float lane 数)
constexpr int simd_width_f = (current_simd_isa() >= SimdIsa::SSE2) ? 4 : 1;
// ═══════════════════════════════════════════════════════════════════════════
// Vec4d — 4-wide double SIMD
// ═══════════════════════════════════════════════════════════════════════════
/// 4-wide double SIMD 向量
///
/// 支持: AVX (ymm), SSE (2×xmm), NEON (float64x2×2), Scalar 回退
///
/// @code
/// Vec4d a = Vec4d::broadcast(1.0);
/// Vec4d b(0, 1, 2, 3);
/// Vec4d c = a + b;
/// double dot = c.dot(b);
/// @endcode
struct alignas(32) Vec4d {
// ── 内部存储(按指令集) ──
#if VDE_SIMD_AVX
__m256d m;
#elif VDE_SIMD_SSE
__m128d lo, hi;
#elif VDE_SIMD_NEON
float64x2_t lo, hi;
#else
double d[4];
#endif
// ── 构造函数 ──
/// 全零
Vec4d() {
#if VDE_SIMD_AVX
m = _mm256_setzero_pd();
#elif VDE_SIMD_SSE
lo = _mm_setzero_pd();
hi = _mm_setzero_pd();
#elif VDE_SIMD_NEON
lo = vdupq_n_f64(0.0);
hi = vdupq_n_f64(0.0);
#else
d[0] = d[1] = d[2] = d[3] = 0.0;
#endif
}
/// 从四个标量构造
Vec4d(double x, double y, double z, double w) {
#if VDE_SIMD_AVX
m = _mm256_set_pd(w, z, y, x);
#elif VDE_SIMD_SSE
lo = _mm_set_pd(y, x);
hi = _mm_set_pd(w, z);
#elif VDE_SIMD_NEON
double xy[2] = {x, y};
double zw[2] = {z, w};
lo = vld1q_f64(xy);
hi = vld1q_f64(zw);
#else
d[0] = x; d[1] = y; d[2] = z; d[3] = w;
#endif
}
/// 广播单值到所有 lane
static Vec4d broadcast(double v) {
Vec4d r;
#if VDE_SIMD_AVX
r.m = _mm256_set1_pd(v);
#elif VDE_SIMD_SSE
r.lo = _mm_set1_pd(v);
r.hi = _mm_set1_pd(v);
#elif VDE_SIMD_NEON
r.lo = vdupq_n_f64(v);
r.hi = vdupq_n_f64(v);
#else
r.d[0] = r.d[1] = r.d[2] = r.d[3] = v;
#endif
return r;
}
/// 提取第 i 个 lane (0-3)
double operator[](int i) const {
#if VDE_SIMD_AVX
double buf[4];
_mm256_storeu_pd(buf, m);
return buf[i];
#elif VDE_SIMD_SSE
double buf[4];
_mm_storeu_pd(buf, lo);
_mm_storeu_pd(buf + 2, hi);
return buf[i];
#elif VDE_SIMD_NEON
double buf[4];
vst1q_f64(buf, lo);
vst1q_f64(buf + 2, hi);
return buf[i];
#else
return d[i];
#endif
}
// ── 算术运算 ──
Vec4d operator+(const Vec4d& o) const {
Vec4d r;
#if VDE_SIMD_AVX
r.m = _mm256_add_pd(m, o.m);
#elif VDE_SIMD_SSE
r.lo = _mm_add_pd(lo, o.lo);
r.hi = _mm_add_pd(hi, o.hi);
#elif VDE_SIMD_NEON
r.lo = vaddq_f64(lo, o.lo);
r.hi = vaddq_f64(hi, o.hi);
#else
for (int i = 0; i < 4; ++i) r.d[i] = d[i] + o.d[i];
#endif
return r;
}
Vec4d operator-(const Vec4d& o) const {
Vec4d r;
#if VDE_SIMD_AVX
r.m = _mm256_sub_pd(m, o.m);
#elif VDE_SIMD_SSE
r.lo = _mm_sub_pd(lo, o.lo);
r.hi = _mm_sub_pd(hi, o.hi);
#elif VDE_SIMD_NEON
r.lo = vsubq_f64(lo, o.lo);
r.hi = vsubq_f64(hi, o.hi);
#else
for (int i = 0; i < 4; ++i) r.d[i] = d[i] - o.d[i];
#endif
return r;
}
Vec4d operator*(const Vec4d& o) const {
Vec4d r;
#if VDE_SIMD_AVX
r.m = _mm256_mul_pd(m, o.m);
#elif VDE_SIMD_SSE
r.lo = _mm_mul_pd(lo, o.lo);
r.hi = _mm_mul_pd(hi, o.hi);
#elif VDE_SIMD_NEON
r.lo = vmulq_f64(lo, o.lo);
r.hi = vmulq_f64(hi, o.hi);
#else
for (int i = 0; i < 4; ++i) r.d[i] = d[i] * o.d[i];
#endif
return r;
}
Vec4d operator/(const Vec4d& o) const {
Vec4d r;
#if VDE_SIMD_AVX
r.m = _mm256_div_pd(m, o.m);
#elif VDE_SIMD_SSE
r.lo = _mm_div_pd(lo, o.lo);
r.hi = _mm_div_pd(hi, o.hi);
#elif VDE_SIMD_NEON
// NEON 无原生 double 除法,使用 approximate + Newton
float64x2_t inv_lo = vrecpeq_f64(o.lo);
float64x2_t inv_hi = vrecpeq_f64(o.hi);
r.lo = vmulq_f64(lo, inv_lo);
r.hi = vmulq_f64(hi, inv_hi);
#else
for (int i = 0; i < 4; ++i) r.d[i] = d[i] / o.d[i];
#endif
return r;
}
/// FMA: this * b + c
Vec4d mul_add(const Vec4d& b, const Vec4d& c) const {
Vec4d r;
#if VDE_SIMD_AVX
r.m = _mm256_fmadd_pd(m, b.m, c.m);
#elif VDE_SIMD_SSE
r.lo = _mm_add_pd(_mm_mul_pd(lo, b.lo), c.lo);
r.hi = _mm_add_pd(_mm_mul_pd(hi, b.hi), c.hi);
#elif VDE_SIMD_NEON
r.lo = vmlaq_f64(c.lo, lo, b.lo);
r.hi = vmlaq_f64(c.hi, hi, b.hi);
#else
for (int i = 0; i < 4; ++i) r.d[i] = d[i] * b.d[i] + c.d[i];
#endif
return r;
}
// ── 比较 ──
/// lane-wise min
Vec4d min(const Vec4d& o) const {
Vec4d r;
#if VDE_SIMD_AVX
r.m = _mm256_min_pd(m, o.m);
#elif VDE_SIMD_SSE
r.lo = _mm_min_pd(lo, o.lo);
r.hi = _mm_min_pd(hi, o.hi);
#elif VDE_SIMD_NEON
r.lo = vminq_f64(lo, o.lo);
r.hi = vminq_f64(hi, o.hi);
#else
for (int i = 0; i < 4; ++i) r.d[i] = std::min(d[i], o.d[i]);
#endif
return r;
}
/// lane-wise max
Vec4d max(const Vec4d& o) const {
Vec4d r;
#if VDE_SIMD_AVX
r.m = _mm256_max_pd(m, o.m);
#elif VDE_SIMD_SSE
r.lo = _mm_max_pd(lo, o.lo);
r.hi = _mm_max_pd(hi, o.hi);
#elif VDE_SIMD_NEON
r.lo = vmaxq_f64(lo, o.lo);
r.hi = vmaxq_f64(hi, o.hi);
#else
for (int i = 0; i < 4; ++i) r.d[i] = std::max(d[i], o.d[i]);
#endif
return r;
}
// ── 向量数学 ──
/// 点积: sum(this[i] * o[i])
double dot(const Vec4d& o) const {
#if VDE_SIMD_AVX
__m256d prod = _mm256_mul_pd(m, o.m);
__m128d lo128 = _mm256_castpd256_pd128(prod);
__m128d hi128 = _mm256_extractf128_pd(prod, 1);
__m128d sum = _mm_add_pd(lo128, hi128);
sum = _mm_hadd_pd(sum, sum);
double result;
_mm_storel_pd(&result, sum);
return result;
#elif VDE_SIMD_SSE
__m128d p0 = _mm_mul_pd(lo, o.lo);
__m128d p1 = _mm_mul_pd(hi, o.hi);
__m128d sum = _mm_add_pd(p0, p1);
#ifdef __SSE3__
sum = _mm_hadd_pd(sum, sum);
#endif
double result;
_mm_storel_pd(&result, sum);
return result;
#elif VDE_SIMD_NEON
float64x2_t p0 = vmulq_f64(lo, o.lo);
float64x2_t p1 = vmulq_f64(hi, o.hi);
float64x2_t s = vaddq_f64(p0, p1);
return vgetq_lane_f64(s, 0) + vgetq_lane_f64(s, 1);
#else
return d[0]*o.d[0] + d[1]*o.d[1] + d[2]*o.d[2] + d[3]*o.d[3];
#endif
}
/// 3D 叉积 (xyz, w unused): result = cross(this_xyz, o_xyz)
/// 结果存储在 xyz, w=0
Vec4d cross3(const Vec4d& o) const {
Vec4d r;
#if VDE_SIMD_AVX
// a = this, b = o
// cross(a,b) = [a1*b2-a2*b1, a2*b0-a0*b2, a0*b1-a1*b0, 0]
// 使用 permute: _mm256_permute4x64_pd(src, imm8)
// imm8 encodes: lane0=bits[1:0], lane1=bits[3:2], lane2=bits[5:4], lane3=bits[7:6]
__m256d a_yzx = _mm256_permute4x64_pd(m, _MM_SHUFFLE(3, 0, 2, 1)); // a1,a2,a0,a3
__m256d a_zxy = _mm256_permute4x64_pd(m, _MM_SHUFFLE(3, 1, 0, 2)); // a2,a0,a1,a3
__m256d b_zxy = _mm256_permute4x64_pd(o.m, _MM_SHUFFLE(3, 1, 0, 2)); // b2,b0,b1,b3
__m256d b_yzx = _mm256_permute4x64_pd(o.m, _MM_SHUFFLE(3, 0, 2, 1)); // b1,b2,b0,b3
__m256d t1 = _mm256_mul_pd(a_yzx, b_zxy);
__m256d t2 = _mm256_mul_pd(a_zxy, b_yzx);
__m256d cross = _mm256_sub_pd(t1, t2);
// 清空 w lane
r.m = _mm256_blend_pd(cross, _mm256_setzero_pd(), 0b1000);
#elif VDE_SIMD_SSE
// 使用标量回退取 xyz
double ax = (*this)[0], ay = (*this)[1], az = (*this)[2];
double bx = o[0], by = o[1], bz = o[2];
r.lo = _mm_set_pd(az*bx - ax*bz, ay*bz - az*by);
r.hi = _mm_setzero_pd();
// hi[0] = ax*by - ay*bx
r = Vec4d(ay*bz - az*by, az*bx - ax*bz, ax*by - ay*bx, 0.0);
#elif VDE_SIMD_NEON
double ax = (*this)[0], ay = (*this)[1], az = (*this)[2];
double bx = o[0], by = o[1], bz = o[2];
double cx = ay*bz - az*by;
double cy = az*bx - ax*bz;
double cz = ax*by - ay*bx;
double cxy[2] = {cx, cy};
double czw[2] = {cz, 0.0};
r.lo = vld1q_f64(cxy);
r.hi = vld1q_f64(czw);
#else
double ax = d[0], ay = d[1], az = d[2];
double bx = o.d[0], by = o.d[1], bz = o.d[2];
r.d[0] = ay*bz - az*by;
r.d[1] = az*bx - ax*bz;
r.d[2] = ax*by - ay*bx;
r.d[3] = 0.0;
#endif
return r;
}
/// 向量长度 (xyz)
double length3() const {
return std::sqrt(dot(*this));
}
/// 向量长度平方 (xyz)
double length3_sq() const {
return dot(*this);
}
/// 归一化 (xyz), w 归零
Vec4d normalize3() const {
double len = length3();
if (len < 1e-30) return broadcast(0.0);
double inv = 1.0 / len;
Vec4d r = *this * broadcast(inv);
#if VDE_SIMD_AVX
r.m = _mm256_blend_pd(r.m, _mm256_setzero_pd(), 0b1000);
#endif
return r;
}
/// 取前 3 个 lane 的绝对值
Vec4d abs3() const {
Vec4d r;
#if VDE_SIMD_AVX
// _mm256_andnot_pd(-0.0, m) 清除符号位
__m256d sign_mask = _mm256_set1_pd(-0.0);
r.m = _mm256_andnot_pd(sign_mask, m);
#elif VDE_SIMD_SSE
r = Vec4d(std::abs((*this)[0]), std::abs((*this)[1]), std::abs((*this)[2]), std::abs((*this)[3]));
#else
for (int i = 0; i < 4; ++i) r.d[i] = std::abs(d[i]);
#endif
return r;
}
};
// ═══════════════════════════════════════════════════════════════════════════
// Vec4f — 4-wide float SIMD
// ═══════════════════════════════════════════════════════════════════════════
/// 4-wide float SIMD 向量
///
/// 支持: AVX (xmm 128-bit), SSE, NEON, Scalar
struct alignas(16) Vec4f {
#if VDE_SIMD_AVX || VDE_SIMD_SSE
__m128 m;
#elif VDE_SIMD_NEON
float32x4_t m;
#else
float f[4];
#endif
Vec4f() {
#if VDE_SIMD_AVX || VDE_SIMD_SSE
m = _mm_setzero_ps();
#elif VDE_SIMD_NEON
m = vdupq_n_f32(0.0f);
#else
f[0] = f[1] = f[2] = f[3] = 0.0f;
#endif
}
Vec4f(float x, float y, float z, float w) {
#if VDE_SIMD_AVX || VDE_SIMD_SSE
m = _mm_set_ps(w, z, y, x);
#elif VDE_SIMD_NEON
float buf[4] = {x, y, z, w};
m = vld1q_f32(buf);
#else
f[0] = x; f[1] = y; f[2] = z; f[3] = w;
#endif
}
static Vec4f broadcast(float v) {
Vec4f r;
#if VDE_SIMD_AVX || VDE_SIMD_SSE
r.m = _mm_set1_ps(v);
#elif VDE_SIMD_NEON
r.m = vdupq_n_f32(v);
#else
r.f[0] = r.f[1] = r.f[2] = r.f[3] = v;
#endif
return r;
}
float operator[](int i) const {
#if VDE_SIMD_AVX || VDE_SIMD_SSE
float buf[4];
_mm_storeu_ps(buf, m);
return buf[i];
#elif VDE_SIMD_NEON
float buf[4];
vst1q_f32(buf, m);
return buf[i];
#else
return f[i];
#endif
}
Vec4f operator+(const Vec4f& o) const {
Vec4f r;
#if VDE_SIMD_AVX || VDE_SIMD_SSE
r.m = _mm_add_ps(m, o.m);
#elif VDE_SIMD_NEON
r.m = vaddq_f32(m, o.m);
#else
for (int i = 0; i < 4; ++i) r.f[i] = f[i] + o.f[i];
#endif
return r;
}
Vec4f operator-(const Vec4f& o) const {
Vec4f r;
#if VDE_SIMD_AVX || VDE_SIMD_SSE
r.m = _mm_sub_ps(m, o.m);
#elif VDE_SIMD_NEON
r.m = vsubq_f32(m, o.m);
#else
for (int i = 0; i < 4; ++i) r.f[i] = f[i] - o.f[i];
#endif
return r;
}
Vec4f operator*(const Vec4f& o) const {
Vec4f r;
#if VDE_SIMD_AVX || VDE_SIMD_SSE
r.m = _mm_mul_ps(m, o.m);
#elif VDE_SIMD_NEON
r.m = vmulq_f32(m, o.m);
#else
for (int i = 0; i < 4; ++i) r.f[i] = f[i] * o.f[i];
#endif
return r;
}
Vec4f operator/(const Vec4f& o) const {
Vec4f r;
#if VDE_SIMD_AVX || VDE_SIMD_SSE
r.m = _mm_div_ps(m, o.m);
#elif VDE_SIMD_NEON
r.m = vmulq_f32(m, vrecpeq_f32(o.m));
#else
for (int i = 0; i < 4; ++i) r.f[i] = f[i] / o.f[i];
#endif
return r;
}
Vec4f mul_add(const Vec4f& b, const Vec4f& c) const {
Vec4f r;
#if VDE_SIMD_AVX || VDE_SIMD_SSE
#ifdef __FMA__
r.m = _mm_fmadd_ps(m, b.m, c.m);
#else
r.m = _mm_add_ps(_mm_mul_ps(m, b.m), c.m);
#endif
#elif VDE_SIMD_NEON
r.m = vmlaq_f32(c.m, m, b.m);
#else
for (int i = 0; i < 4; ++i) r.f[i] = f[i] * b.f[i] + c.f[i];
#endif
return r;
}
Vec4f min(const Vec4f& o) const {
Vec4f r;
#if VDE_SIMD_AVX || VDE_SIMD_SSE
r.m = _mm_min_ps(m, o.m);
#elif VDE_SIMD_NEON
r.m = vminq_f32(m, o.m);
#else
for (int i = 0; i < 4; ++i) r.f[i] = std::min(f[i], o.f[i]);
#endif
return r;
}
Vec4f max(const Vec4f& o) const {
Vec4f r;
#if VDE_SIMD_AVX || VDE_SIMD_SSE
r.m = _mm_max_ps(m, o.m);
#elif VDE_SIMD_NEON
r.m = vmaxq_f32(m, o.m);
#else
for (int i = 0; i < 4; ++i) r.f[i] = std::max(f[i], o.f[i]);
#endif
return r;
}
/// 点积 (4-wide)
float dot(const Vec4f& o) const {
#if VDE_SIMD_AVX || VDE_SIMD_SSE
#ifdef __SSE4_1__
__m128 prod = _mm_mul_ps(m, o.m);
__m128 hadd = _mm_hadd_ps(prod, prod);
hadd = _mm_hadd_ps(hadd, hadd);
return _mm_cvtss_f32(hadd);
#else
float buf[4];
_mm_storeu_ps(buf, _mm_mul_ps(m, o.m));
return buf[0] + buf[1] + buf[2] + buf[3];
#endif
#elif VDE_SIMD_NEON
float32x4_t prod = vmulq_f32(m, o.m);
float32x2_t sum = vadd_f32(vget_low_f32(prod), vget_high_f32(prod));
sum = vpadd_f32(sum, sum);
return vget_lane_f32(sum, 0);
#else
return f[0]*o.f[0] + f[1]*o.f[1] + f[2]*o.f[2] + f[3]*o.f[3];
#endif
}
/// 3D dot (仅 xyz)
float dot3(const Vec4f& o) const {
#if VDE_SIMD_AVX || VDE_SIMD_SSE
#ifdef __SSE4_1__
// _mm_dp_ps: dot product with mask 0x71 = src1[xyz], src2[xyz] → splat result
__m128 dp = _mm_dp_ps(m, o.m, 0x71);
return _mm_cvtss_f32(dp);
#else
return (*this)[0]*o[0] + (*this)[1]*o[1] + (*this)[2]*o[2];
#endif
#elif VDE_SIMD_NEON
float32x4_t prod = vmulq_f32(m, o.m);
float32x2_t sum = vadd_f32(vget_low_f32(prod), vget_high_f32(prod));
sum = vpadd_f32(sum, sum);
// subtract w contribution
float w = (*this)[3] * o[3];
return vget_lane_f32(sum, 0) - w;
#else
return f[0]*o.f[0] + f[1]*o.f[1] + f[2]*o.f[2];
#endif
}
/// 3D 叉积
Vec4f cross3(const Vec4f& o) const {
float ax = (*this)[0], ay = (*this)[1], az = (*this)[2];
float bx = o[0], by = o[1], bz = o[2];
return Vec4f(ay*bz - az*by, az*bx - ax*bz, ax*by - ay*bx, 0.0f);
}
float length3() const { return std::sqrt(dot3(*this)); }
float length3_sq() const { return dot3(*this); }
Vec4f normalize3() const {
float len = length3();
if (len < 1e-15f) return broadcast(0.0f);
float inv = 1.0f / len;
Vec4f r = *this * broadcast(inv);
// 清空 w
#if VDE_SIMD_AVX || VDE_SIMD_SSE
#ifdef __SSE4_1__
r.m = _mm_blend_ps(r.m, _mm_setzero_ps(), 0b1000);
#endif
#endif
return r;
}
};
// ═══════════════════════════════════════════════════════════════════════════
// SoA 布局运算(Structure of Arrays
// ═══════════════════════════════════════════════════════════════════════════
/// SoA 3D 向量数组(适合 SIMD 批量处理)
struct alignas(64) Vec3SoA {
Vec4d x, y, z; ///< 各分量 4 组
/// 从 4 个 Vec4d (xyz 部分) 组装
static Vec3SoA gather(const Vec4d& a, const Vec4d& b,
const Vec4d& c, const Vec4d& d) {
Vec3SoA r;
#if VDE_SIMD_AVX
// 转置: a[0],b[0],c[0],d[0] → x
__m256d t0 = _mm256_unpacklo_pd(a.m, b.m); // a0,a1,b0,b1
__m256d t1 = _mm256_unpackhi_pd(a.m, b.m); // a2,a3,b2,b3
__m256d t2 = _mm256_unpacklo_pd(c.m, d.m); // c0,c1,d0,d1
__m256d t3 = _mm256_unpackhi_pd(c.m, d.m); // c2,c3,d2,d3
r.x.m = _mm256_permute2f128_pd(t0, t2, 0x20); // a0,b0,c0,d0
r.y.m = _mm256_permute2f128_pd(t0, t2, 0x31); // a1,b1,c1,d1
r.z.m = _mm256_permute2f128_pd(t1, t3, 0x20); // a2,b2,c2,d2
#else
r.x = Vec4d(a[0], b[0], c[0], d[0]);
r.y = Vec4d(a[1], b[1], c[1], d[1]);
r.z = Vec4d(a[2], b[2], c[2], d[2]);
#endif
return r;
}
};
// ═══════════════════════════════════════════════════════════════════════════
// AABB 批量相交测试(SIMD 加速)
// ═══════════════════════════════════════════════════════════════════════════
/// 4 组 AABB 的 SIMD 表示
///
/// 用于批量测试:一次判断 4 个包围盒与参考 AABB 是否相交。
/// 内部以 SoA 形式存储 min_xyz 和 max_xyz。
struct alignas(64) BatchAABB4 {
Vec4d min_x, min_y, min_z; ///< 4 组 AABB 的 min 分量
Vec4d max_x, max_y, max_z; ///< 4 组 AABB 的 max 分量
/// 从 SoA 数组加载(min_x[4], min_y[4], min_z[4], max_x[4], max_y[4], max_z[4]
static BatchAABB4 load(const double* min_x, const double* min_y, const double* min_z,
const double* max_x, const double* max_y, const double* max_z)
{
BatchAABB4 b;
b.min_x = Vec4d(min_x[0], min_x[1], min_x[2], min_x[3]);
b.min_y = Vec4d(min_y[0], min_y[1], min_y[2], min_y[3]);
b.min_z = Vec4d(min_z[0], min_z[1], min_z[2], min_z[3]);
b.max_x = Vec4d(max_x[0], max_x[1], max_x[2], max_x[3]);
b.max_y = Vec4d(max_y[0], max_y[1], max_y[2], max_y[3]);
b.max_z = Vec4d(max_z[0], max_z[1], max_z[2], max_z[3]);
return b;
}
/// 批量测试 4 组 AABB 与参考 AABB 的相交性
///
/// @param ref_min_x/ref_min_y/ref_min_z 参考 AABB 最小值
/// @param ref_max_x/ref_max_y/ref_max_z 参考 AABB 最大值
/// @return 4 个 bool packed 为一个 uint32_t (bit 0-3)
///
/// AABB 相交公式: min_a <= max_b AND max_a >= min_b (各分量)
static uint32_t intersect4(
const BatchAABB4& batch,
double ref_min_x, double ref_min_y, double ref_min_z,
double ref_max_x, double ref_max_y, double ref_max_z)
{
uint32_t result = 0;
// 对每个 lane 做: batch.max >= ref.min && batch.min <= ref.max
// 使用 max/min 比较 + 提取 lane
for (int i = 0; i < 4; ++i) {
double bmin_x = batch.min_x[i], bmin_y = batch.min_y[i], bmin_z = batch.min_z[i];
double bmax_x = batch.max_x[i], bmax_y = batch.max_y[i], bmax_z = batch.max_z[i];
if (bmin_x <= ref_max_x && bmax_x >= ref_min_x &&
bmin_y <= ref_max_y && bmax_y >= ref_min_y &&
bmin_z <= ref_max_z && bmax_z >= ref_min_z) {
result |= (1u << i);
}
}
return result;
}
/// 单次 4-AABB 相交测试(SIMD 加速比较)
/// 返回: 相交计数 (0-4)
static int intersect4_count(
const BatchAABB4& batch,
double ref_min_x, double ref_min_y, double ref_min_z,
double ref_max_x, double ref_max_y, double ref_max_z)
{
return __builtin_popcount(intersect4(batch,
ref_min_x, ref_min_y, ref_min_z,
ref_max_x, ref_max_y, ref_max_z));
}
};
// ═══════════════════════════════════════════════════════════════════════════
// 批量 AABB 相交(标量优化版,适用任意 N)
// ═══════════════════════════════════════════════════════════════════════════
/// 批量 AABB 相交测试 — 输出相交索引列表
///
/// @tparam N 缓冲区大小
/// @param mins [N*3] min 坐标数组 (x0,y0,z0,x1,y1,z1,...)
/// @param maxs [N*3] max 坐标数组
/// @param ref_min_x/y/z 参考 AABB 最小值
/// @param ref_max_x/y/z 参考 AABB 最大值
/// @param out_indices 输出:相交的索引列表
/// @return 相交数量
template<size_t N>
inline size_t aabb_intersect_batch(
const double* mins, const double* maxs,
double ref_min_x, double ref_min_y, double ref_min_z,
double ref_max_x, double ref_max_y, double ref_max_z,
int* out_indices)
{
size_t count = 0;
for (size_t i = 0; i < N; ++i) {
double mx = mins[i*3+0], my = mins[i*3+1], mz = mins[i*3+2];
double Mx = maxs[i*3+0], My = maxs[i*3+1], Mz = maxs[i*3+2];
if (mx <= ref_max_x && Mx >= ref_min_x &&
my <= ref_max_y && My >= ref_min_y &&
mz <= ref_max_z && Mz >= ref_min_z) {
out_indices[count++] = static_cast<int>(i);
}
}
return count;
}
/// 批量 AABB 相交(4 元素 SIMD 展开的 4N 变体)
inline size_t aabb_intersect_batch_simd(
const double* mins, const double* maxs,
size_t count,
double ref_min_x, double ref_min_y, double ref_min_z,
double ref_max_x, double ref_max_y, double ref_max_z,
int* out_indices)
{
size_t total = 0;
size_t i = 0;
// 4-wide SIMD 循环
for (; i + 4 <= count; i += 4) {
double min_x[4], min_y[4], min_z[4];
double max_x[4], max_y[4], max_z[4];
for (int k = 0; k < 4; ++k) {
min_x[k] = mins[(i+k)*3+0];
min_y[k] = mins[(i+k)*3+1];
min_z[k] = mins[(i+k)*3+2];
max_x[k] = maxs[(i+k)*3+0];
max_y[k] = maxs[(i+k)*3+1];
max_z[k] = maxs[(i+k)*3+2];
}
BatchAABB4 batch = BatchAABB4::load(min_x, min_y, min_z, max_x, max_y, max_z);
uint32_t mask = BatchAABB4::intersect4(batch,
ref_min_x, ref_min_y, ref_min_z,
ref_max_x, ref_max_y, ref_max_z);
for (int j = 0; j < 4; ++j) {
if (mask & (1u << j)) {
out_indices[total++] = static_cast<int>(i + j);
}
}
}
// 尾数标量处理
for (; i < count; ++i) {
double mx = mins[i*3+0], my = mins[i*3+1], mz = mins[i*3+2];
double Mx = maxs[i*3+0], My = maxs[i*3+1], Mz = maxs[i*3+2];
if (mx <= ref_max_x && Mx >= ref_min_x &&
my <= ref_max_y && My >= ref_min_y &&
mz <= ref_max_z && Mz >= ref_min_z) {
out_indices[total++] = static_cast<int>(i);
}
}
return total;
}
} // namespace vde::core