#pragma once #include #include namespace internal { // 参考平面法向量固定为(0, 0, 1),以第一个顶点为二维坐标原点,以第一条边为x轴轴向 struct PE_API polyline_extrude_axis final : public extrude_axis { ~polyline_extrude_axis() override = default; double get_closest_param(Eigen::Vector3d p) const override; std::pair to_pattern_local(double t, Eigen::Vector3d p) const override; Eigen::AffineCompact3d get_local_cap_mat(double t, bool reversed) const override; aabb_t get_local_aabb() const override { aabb_t res{}; for (const auto& v : vertices) res.extend(Eigen::Vector3d{v[0], v[1], 0}); for (size_t i = 0; i < bulges.size(); ++i) { if (std::abs(bulges[i]) <= epsilon) continue; const auto& a = vertices[i]; const auto& b = vertices[i + 1]; const auto half_ab = 0.5 * (a + b); const auto bisec_vec = 0.5 * Eigen::Vector2d{a.y() - b.y(), b.x() - a.x()}; const auto center = half_ab + bisec_vec / bulges[i]; const auto ca = a - center; const auto half_theta = std::atan(bulges[i]); Eigen::Rotation2Dd rot{half_theta}; const auto mid = center + rot * ca; res.extend(Eigen::Vector3d{mid[0], mid[1], 0}); } return res; } std::vector vertices{}; // 所有顶点(圆弧段为端点) std::vector bulges{}; // bulge = tan(theta/2) }; } // namespace internal namespace detail { template <> struct hasher { size_t operator()(const internal::polyline_extrude_axis& axis) const { auto parity1 = hash_funcs(axis.vertices.begin(), axis.vertices.end()); auto parity2 = hash_funcs(axis.bulges.begin(), axis.bulges.end()); return hash_combine(size_t{0}, parity1, parity2); } }; template <> struct eq_compare { bool operator()(const internal::polyline_extrude_axis& lhs, const internal::polyline_extrude_axis& rhs) const { return eq_funcs(lhs.vertices.begin(), lhs.vertices.end(), rhs.vertices.begin()) && eq_funcs(lhs.bulges.begin(), lhs.bulges.end(), rhs.bulges.begin()); } }; } // namespace detail