From c89448b3edff9d2cb9cc1ae9f72f1d2323b3db86 Mon Sep 17 00:00:00 2001 From: Dtouch <1472779700@qq.com> Date: Mon, 11 Nov 2024 11:52:25 +0800 Subject: [PATCH] refactor line geometry def; solve circle & eval for polylines with bugles --- include/line.hpp | 107 ++++++++++++++++++++++++++++----------------- include/vec.hpp | 111 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 167 insertions(+), 51 deletions(-) diff --git a/include/line.hpp b/include/line.hpp index 92093d1..34cd61f 100644 --- a/include/line.hpp +++ b/include/line.hpp @@ -3,28 +3,32 @@ #include #include #include +#include +#include + +// class ILineParam { +// public: +// virtual ~ILineParam() = default; +// }; +// +// class PolylineParam : ILineParam { +// int segIdx; +// real tOnSeg; +// }; +// +// class PolynomialLineParam : ILineParam { +// real t; +// }; -class ILineParam { +class ILine { public: - virtual ~ILineParam() = default; -}; - -struct PolylineParam : ILineParam { - int segIdx; - real tOnSeg; -}; + virtual ~ILine() = default; -struct PolynomialLineParam : ILineParam { - real t; -}; + virtual Vec3 eval(const double param) const = 0; -class ILine { - public: - virtual ~ILine() = default; + virtual Vec3 tangent(const double param) const = 0; - virtual Vec3 eval(const ILineParam& param) const = 0; - virtual Vec3 tangent(const ILineParam& param) const = 0; - virtual std::unique_ptr getClosestParam(const Vec3& p) const = 0; + virtual double getClosestParam(const Vec3 &p) const = 0; }; template @@ -32,42 +36,69 @@ using PtArray = std::vector >; using Pt3Array = PtArray<3>; using Pt2Array = PtArray<2>; -template -class Polyline: public ILine { + +class Polyline : public ILine { public: - Polyline(const PtArray &points, const std::vector &bugles, bool closed = false) : points(points), - bugles(bugles), closed(closed) { + using Point = Vec<3>; + + Polyline(const Pt3Array &points, const std::vector &bugles, const Vec3 &normal, bool closed = false) + : points(points), bugles(bugles), closed(closed), normal(normal.normalize()) { assert(points.size() >= 2); if (closed) { assert(points.size() == bugles.size()); } else { - assert(points.size() - 1 == bugles.size() || points.size() == bugles.size()); + assert(points.size() - 1 == bugles.size()); + } + circleCenters.resize(bugles.size()); + thetas.resize(bugles.size()); + radii.resize(bugles.size()); + for (size_t i = 0; i < bugles.size(); ++i) { + const Point &A = points[i]; + const Point &B = points[(i + 1) % points.size()]; + Vec3 AB = B - A; + Vec3 ABNorm = AB.normalize(); + Vec3 QO = normal.cross(ABNorm) * (abs(bugles[i]) > 1 ? -1 : 1); + float theta = std::atan(bugles[i]) * 4; + float h = AB.length() * 0.5 * std::tan(theta * 0.5); + circleCenters[i] = A + AB * 0.5 + QO * h; + thetas[i] = theta; + radii[i] = (circleCenters[i] - A).length(); } } - using Point = Vec; - private: - PtArray points; - std::vector bugles; + Pt3Array points; + std::vector bugles; + Vec3 normal; bool closed; + Pt3Array circleCenters; + std::vector thetas; + std::vector radii; + public: + Vec3 eval(const real param) const override { + assert(param >= 0 && param <= bugles.size()); + int seg = static_cast(param); + real tOnSeg = param - seg; - Vec3 eval(const ILineParam& param) const override { - const PolylineParam* polyParam = dynamic_cast(¶m); // 进行类型检查 - if (!polyParam) { - throw std::invalid_argument("Invalid parameter type for Polyline::eval"); - } - // TODO: + const auto &A = points[seg]; + // const auto &B = points[(seg + 1) % points.size()]; + const auto ¢er = circleCenters[seg]; + Vec3 u = (A-center).normalize(); + Vec3 v = normal.cross(u); + + real phi = tOnSeg * thetas[seg]; + const auto &r = radii[seg]; + + return center + r * (u * std::cos(phi) + v * std::sin(phi)); } - Vec3 tangent(const ILineParam& param) const override { + Vec3 tangent(const double param) const override { // TODO: } - std::unique_ptr getClosestParam(const Vec3& p) const override { - auto closestParam = std::make_unique(); + double getClosestParam(const Vec3 &p) const override { // TODO: return closestParam; } @@ -76,8 +107,6 @@ public: points.push_back(point); } - - const Point &getPoint(size_t index) const { return points[index]; } @@ -103,6 +132,6 @@ public: } }; -class PolynomialLine: public ILine { +class PolynomialLine : public ILine { public: -}; \ No newline at end of file +}; diff --git a/include/vec.hpp b/include/vec.hpp index 9f58cdb..4b6917a 100644 --- a/include/vec.hpp +++ b/include/vec.hpp @@ -2,11 +2,11 @@ #include "real.hpp" #include #include +#include -template +template class Vec { public: - using real = float; // 根据需要定义 real 类型 std::array data; Vec() { @@ -17,24 +17,26 @@ public: std::copy(values.begin(), values.end(), data.begin()); } - Vec(const Vec& v) { + Vec(real... args) : data{static_cast(args)...} {} + + Vec(const Vec &v) { data = v.data; } - Vec& operator=(const Vec& v) { + Vec &operator=(const Vec &v) { data = v.data; return *this; } - real& operator[](size_t index) { + real &operator[](size_t index) { return data[index]; } - const real& operator[](size_t index) const { + const real &operator[](size_t index) const { return data[index]; } - Vec operator+(const Vec& v) const { + Vec operator+(const Vec &v) const { Vec result; for (size_t i = 0; i < N; ++i) { result[i] = data[i] + v[i]; @@ -42,7 +44,7 @@ public: return result; } - Vec operator-(const Vec& v) const { + Vec operator-(const Vec &v) const { Vec result; for (size_t i = 0; i < N; ++i) { result[i] = data[i] - v[i]; @@ -58,6 +60,15 @@ public: return result; } + friend Vec operator*(real s, const Vec &v) { + Vec result; + for (size_t i = 0; i < N; ++i) { + result[i] = s * v[i]; + } + return result; + } + + Vec operator/(real s) const { Vec result; for (size_t i = 0; i < N; ++i) { @@ -66,7 +77,7 @@ public: return result; } - real dot(const Vec& v) const { + real dot(const Vec &v) const { real sum = 0; for (size_t i = 0; i < N; ++i) { sum += data[i] * v[i]; @@ -82,12 +93,88 @@ public: return *this / norm(); } - Vec reflect(const Vec& n) const { + Vec reflect(const Vec &n) const { return *this - n * 2 * dot(n); } }; -template + +// specialize template class Vec<3>; +template<> +class Vec<3> { +public: + union { + std::array data; + + struct { + real x, y, z; + }; + + struct { + real u, v, w; + }; + }; + + Vec() : data{0, 0, 0} {} + + Vec(real x, real y, real z) : data{x, y, z} {} + + Vec(const Vec &v) : data{v.data[0], v.data[1], v.data[2]} {} + + Vec &operator=(const Vec &v) { + data[0] = v.data[0]; + data[1] = v.data[1]; + data[2] = v.data[2]; + return *this; + } + + real operator[](size_t index) const { + return data[index]; + } + + real &operator[](size_t index) { + return data[index]; + } + + Vec operator+(const Vec &v) const { + return {x + v.x, y + v.y, z + v.z}; + } + + Vec operator-(const Vec &v) const { + return {x - v.x, y - v.y, z - v.z}; + } + + Vec operator*(real s) const { + return {x * s, y * s, z * s}; + } + + friend Vec operator*(real s, const Vec &v) { + return {s * v.x, s * v.y, s * v.z}; + } + + + Vec operator/(real s) const { + assert(s != 0); + real inv = 1 / s; + return *this * inv; + } + + real dot(const Vec &v) const { + return x * v.x + y * v.y + z * v.z; + } + + real length() const { + return std::sqrt(dot(*this)); + } + + Vec normalize() const { + return *this / length(); + } + + Vec cross(const Vec &v) const { + return {y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x}; + } +}; using Vec2 = Vec<2>; using Vec3 = Vec<3>; @@ -141,4 +228,4 @@ using Vec3 = Vec<3>; // Vec3 reflect(const Vec3& n) const { // return *this - n * 2 * dot(n); // } -//}; \ No newline at end of file +//};