From 4adfc33da8008865063dba02461ab41c78818922 Mon Sep 17 00:00:00 2001 From: gjj Date: Fri, 22 Nov 2024 17:07:24 +0800 Subject: [PATCH] uniform interface for extrusion with 2 axis types --- include/solid.hpp | 126 +++++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 57 deletions(-) diff --git a/include/solid.hpp b/include/solid.hpp index ab45504..e9c3c4f 100644 --- a/include/solid.hpp +++ b/include/solid.hpp @@ -24,16 +24,6 @@ inline Vec2 get2DRepOf3DDir(const Vec3 &dir, const Vec3 &u, const Vec3 &v) { return Vec2{dir.dot(u), dir.dot(v)}.normalize(); } -template -class IExtrudedSolidBase : public ISolid { -protected: - std::vector _profiles; // TODO: may be replaced by const ref to profile - AxisLineType _axis; - real _rScale; - IExtrudedSolidBase(std::vector profiles, AxisLineType axis, real rScale) - : _profiles(std::move(profiles)), _axis(std::move(axis)), _rScale(rScale) {} -}; - /** * calculate winding number of a point w.r.t. a segment ab */ @@ -46,16 +36,17 @@ protected: // / (std::numbers::pi * 2); // } -// template -class ExtrudedSolidPolyline : public IExtrudedSolidBase { -private: +template +class IExtrudedSolidBase : public ISolid { +protected: + std::vector _profiles; // TODO: may be replaced by const ref to profile + AxisLineType _axis; + real _rScale; std::vector _localProfiles2D; std::vector>> _localArcs2d; - Vec3 _biNormal; - -public: - ExtrudedSolidPolyline(std::vector profiles, Polyline axis, real rScale) - : IExtrudedSolidBase(std::move(profiles), std::move(axis), rScale) { + Vec3 _biNormalStartPt; + IExtrudedSolidBase(std::vector profiles, AxisLineType axis, real rScale) + : _profiles(std::move(profiles)), _axis(std::move(axis)), _rScale(rScale) { assert(!_profiles.empty()); for (const auto &_profile : _profiles) { assert(_profile.isClosed()); @@ -63,8 +54,7 @@ public: // project profile at st point to 2D Vec3 tangent = _axis.der1(0).normalize(); Vec3 normal = _axis.der2(0).normalize(); - _biNormal = tangent.cross(normal); - assert(_biNormal.isParallel(_axis.getNormal())); + _biNormalStartPt = tangent.cross(normal); Vec3 q = _axis.eval(0); size_t profileCount = _profiles.size(); _localProfiles2D.resize(profileCount); @@ -77,11 +67,11 @@ public: for (int j = 0; j < segCount; ++j) { // TODO: _localProfiles2D[i][j] = - get2DRepOf3DPt(profile.getPoints()[j] - q, normal, _biNormal, q); + get2DRepOf3DPt(profile.getPoints()[j] - q, normal, _biNormalStartPt, q); auto &arc2d = _localArcs2d[i][j]; const auto &arc3d = profile.getCircularArcs()[j]; - arc2d.center = get2DRepOf3DPt(arc3d.center - q, normal, _biNormal, q); - arc2d.inCircleDir = get2DRepOf3DDir(arc3d.inCircleDir, normal, _biNormal); + arc2d.center = get2DRepOf3DPt(arc3d.center - q, normal, _biNormalStartPt, q); + arc2d.inCircleDir = get2DRepOf3DDir(arc3d.inCircleDir, normal, _biNormalStartPt); arc2d.radius = arc3d.radius; arc2d.theta = arc3d.theta; arc2d.h = arc3d.h; @@ -95,7 +85,7 @@ public: auto t = closestDescToAxis.t; Vec3 q = _axis.eval(t); // closest point on axis Vec3 qp = p - q; - auto TBN = getTBN(p, q, closestDescToAxis); + auto TBN = getTBN(p, q, closestDescToAxis.t); const Vec3 &tangent = TBN[0]; const Vec3 &normal = TBN[1]; const Vec3 &biNormal = TBN[2]; @@ -120,22 +110,9 @@ public: return closestDescToProfile.dis * static_cast(ptProfileRelation); } - std::array getTBN(const Vec3 &p, const Vec3 &q, const ClosestDescOnSeg &closestDesc) { - real t = closestDesc.t; - if (std::abs(t - std::round(t)) < EPS) { - // 端点处 - // p到圆弧平面的投影 - Vec3 projPt = p - _biNormal.dot(p - q) * _biNormal; - Vec3 normal = (q - projPt).normalize(); - if (normal.dot(_axis.der2(t)) < 0) { - normal = -normal; - } - return {normal.cross(_biNormal), normal, _biNormal}; - } - return {_axis.der1(t).normalize(), _axis.der1(t).normalize(), _biNormal}; - } - private: + virtual std::array getTBN(const Vec3 &p, const Vec3 &q, real t) = 0; + inline ClosestDescOnSeg disProfile2D(const Vec2 &p2D) { ClosestDescOnSeg closestDescToProfile{}; for (int i = 0; i < _localArcs2d.size(); ++i) { @@ -302,24 +279,6 @@ private: return {1, pbDis}; } - bool isOn2DPolyline(const Vec2 &p2D, const Pt2Array &profile2D, - const std::vector> &arcs2d) { - size_t segCount = arcs2d.size(); - for (int i = 0; i < segCount; ++i) { - const Vec2 &a = profile2D[i]; - const Vec2 &b = profile2D[(i + 1) % segCount]; - if (arcs2d[i].h <= EPS) { - //line segment - if (isPointOnSegment(p2D, a, b)) { - return true; - } - continue; - } - } - // TODO: 没写完,但是暂时用不到 - return true; - } - static bool isPointOnSegment(const Vec2 &p, const Vec2 &a, const Vec2 &b) { // check collinearity double crossProduct = (p[1] - a[1]) * (b[0] - a[0]) - (p[0] - a[0]) * (b[1] - a[1]); @@ -332,6 +291,46 @@ private: && p[1] >= std::min(a[1], b[1]) && p[1] <= std::max(a[1], b[1])); } + // bool isOn2DPolyline(const Vec2 &p2D, const Pt2Array &profile2D, + // const std::vector> &arcs2d) { + // size_t segCount = arcs2d.size(); + // for (int i = 0; i < segCount; ++i) { + // const Vec2 &a = profile2D[i]; + // const Vec2 &b = profile2D[(i + 1) % segCount]; + // if (arcs2d[i].h <= EPS) { + // //line segment + // if (isPointOnSegment(p2D, a, b)) { + // return true; + // } + // continue; + // } + // } + // // TODO: 没写完,但是暂时用不到 + // return true; + // } +}; + +class ExtrudedSolidPolyline : public IExtrudedSolidBase { +public: + ExtrudedSolidPolyline(std::vector profiles, Polyline axis, real rScale = 1.0) + : IExtrudedSolidBase(std::move(profiles), std::move(axis), rScale) { + assert(_biNormalStartPt.isParallel(_axis.getNormal())); + } + + std::array getTBN(const Vec3 &p, const Vec3 &q, real t) override { + if (std::abs(t - std::round(t)) < EPS) { + // 端点处 + // p到圆弧平面的投影 + Vec3 projPt = p - _biNormalStartPt.dot(p - q) * _biNormalStartPt; + Vec3 normal = (q - projPt).normalize(); + if (normal.dot(_axis.der2(t)) < 0) { + normal = -normal; + } + return {normal.cross(_biNormalStartPt), normal, _biNormalStartPt}; + } + return {_axis.der1(t).normalize(), _axis.der1(t).normalize(), _biNormalStartPt}; + } + // real wnCircularArc( // const Vec3 &p, const Vec3 &a, const Vec3 &b, const Vec3 &plgNormal, const Polyline::CircularArc &arc, int dir) // { @@ -364,3 +363,16 @@ private: // return arc.center + arc.radius * (arc.u * std::cos(phi) + arc.v * std::sin(phi)); // } }; + +class ExtrudedSolidHelixLine : public IExtrudedSolidBase { +public: + ExtrudedSolidHelixLine(std::vector profiles, HelixLine axis, real rScale = 1.0) + : IExtrudedSolidBase(std::move(profiles), std::move(axis), rScale) {} + + std::array getTBN([[maybe_unused]] const Vec3 &a, [[maybe_unused]] const Vec3 &b, + real t) override { + Vec3 tangent = _axis.der1(t).normalize(); + Vec3 normal = _axis.der1(t).normalize(); + return {tangent, normal, tangent.cross(normal)}; + } +};