#pragma once #include "common.hpp" #include "vec.hpp" #include #include #include #include #include #include #include #include // class ILineParam { // public: // virtual ~ILineParam() = default; // }; // // class PolylineParam : ILineParam { // int segIdx; // real tOnSeg; // }; // // class PolynomialLineParam : ILineParam { // real t; // }; struct ClosestDescOnSeg { real t; real dis; ClosestDescOnSeg(real _t, real _dis) : t(_t), dis(_dis) {} ClosestDescOnSeg() : t(0), dis(std::numeric_limits::max()) {} }; class ILine { public: int aaa; virtual ~ILine() = default; virtual Vec3 eval(real param) = 0; virtual Vec3 der1(real param) = 0; virtual Vec3 der2(real param) = 0; virtual ClosestDescOnSeg getClosestParam(const Vec3 &p) = 0; }; template // Vec2 or Vec3 struct CircularArc { VecType center; real radius; real theta; real h = -1; // straight line for h <= 0. VecType u; VecType v; VecType inCircleDir; PtBoundaryRelation inCircleCheck(const VecType &pt) const { real d = (pt - center).norm(); return d < radius ? Inside : d > radius ? Outside : OnBoundary; } }; ; struct AA { int a; int b; void print() const { std::cout << a << " " << b << std::endl; } }; const real DISC_ARC_ANGLE = std::numbers::pi * 0.125; class Polyline : public ILine { public: using Point = Vec3; Polyline(Pt3Array points, std::vector bugles, const Vec3 &normal, bool closed = false) : _points(std::move(points)), _bugles(std::move(bugles)), _closed(closed), _normal(normal.normalize()) { assert(_points.size() >= 2); if (closed) { assert(_points.size() == _points.size()); } else { assert(_points.size() - 1 == _points.size()); } circularArcs.resize(_bugles.size()); } [[nodiscard]] const Pt3Array &getPoints() const { return _points; } [[nodiscard]] const std::vector &getBugles() const { return _bugles; } [[nodiscard]] const Vec3 &getNormal() const { return _normal; } [[nodiscard]] bool isClosed() const { return _closed; } [[nodiscard]] const std::vector> &getCircularArcs() const { return circularArcs; } private: Pt3Array _points; std::vector _bugles; Vec3 _normal; bool _closed; std::vector> circularArcs; public: void initSegInfo() { for (size_t i = 0; i < _bugles.size(); ++i) { const Point &A = _points[i]; const Point &B = _points[(i + 1) % _points.size()]; Vec3 ABHalf = (B - A) * 0.5; Vec3 ABNorm = ABHalf.normalize(); real theta = std::atan(_bugles[i]) * 4; circularArcs[i].inCircleDir = _normal.cross(ABNorm) * (abs(_bugles[i]) > 1 ? -1 : 1); circularArcs[i].h = ABHalf.norm() * std::tan(theta * 0.5); circularArcs[i].center = A + ABHalf + circularArcs[i].inCircleDir * circularArcs[i].h; circularArcs[i].theta = theta; circularArcs[i].radius = (circularArcs[i].center - A).norm(); circularArcs[i].u = (A - circularArcs[i].center).normalize(); circularArcs[i].v = _normal.cross(circularArcs[i].u); } } Vec3 eval(real param) override { if (circularArcs.empty()) initSegInfo(); int seg = static_cast(param); real tOnSeg = param - seg; const auto &arc = circularArcs[seg]; real phi = tOnSeg * arc.theta; return arc.center + arc.radius * (arc.u * std::cos(phi) + arc.v * std::sin(phi)); } Vec3 der1(real param) override { if (circularArcs.empty()) initSegInfo(); int seg = static_cast(param); real tOnSeg = param - seg; const auto &arc = circularArcs[seg]; real phi = tOnSeg * arc.theta; return arc.radius * (arc.u * -std::sin(phi) + arc.v * std::cos(phi)); } Vec3 der2(real param) override { if (circularArcs.empty()) initSegInfo(); int seg = static_cast(param); real tOnSeg = param - seg; const auto &arc = circularArcs[seg]; real phi = tOnSeg * arc.theta; return -arc.radius * (arc.u * std::cos(phi) + arc.v * std::cos(phi)); } // ClosestDescOnSeg getClosestParam(const Vec3 &p) override { // real closestDis = std::numeric_limits::max(); // real closestParam; // for (int i = 0; i < _bugles.size(); ++i) { // const Vec3 &A = _points[i]; // const Vec3 &B = _points[(i + 1) % _points.size()]; // const auto &arc = circularArcs[i]; // real dis2Seg = segPtDist(p, A, B).dis; // if (dis2Seg - arc.h > closestDis) // continue; // if ((A - p).norm() < closestDis) { // closestDis = (A - p).norm(); // closestParam = i; // } // if ((B - p).norm() < closestDis) { // closestDis = (B - p).norm(); // closestParam = i + 1; // } // int segInsertedCnt = arc.theta / DISC_ARC_ANGLE; // for (int j = 0; j < segInsertedCnt; ++j) { // real insertParam = i + j * DISC_ARC_ANGLE / arc.theta; // const Vec3 insertPt = eval(insertParam); // real dis2InsertPt = (p - insertPt).norm(); // if (dis2InsertPt < closestDis) { // closestDis = dis2InsertPt; // closestParam = insertParam; // } // } // } // // TODO: 为了鲁棒和精度,应该在每个可能最近的seg上做newton iteration // int seg = static_cast(closestParam); // // Q = arc.center + arc.radius * (arc.u * std::cos(phi) + arc.v * // // std::sin(phi)) d2 = (Q - p)^2 // Vec3 q = eval(closestParam); // Vec3 qDer1 = der1(closestParam); // Vec3 qDer2 = der2(closestParam); // real lDer1 = (q - p).dot(qDer1); // int iter = 0; // while (fabs(lDer1) > std::numeric_limits::epsilon() * 1e6) { // closestParam -= lDer1 / (qDer1.dot(qDer1) + (q - p).dot(qDer2)); // -der1 / der2 // q = eval(closestParam); // qDer1 = der1(closestParam); // qDer2 = der2(closestParam); // lDer1 = (q - p).dot(qDer1); // printf("After iter %d, dL is %lf\n", iter, lDer1); // if (closestParam < seg - std::numeric_limits::epsilon()) { // closestParam = seg; // closestDis = (_points[seg] - p).norm(); // break; // } // if (closestParam > seg + 1 + std::numeric_limits::epsilon()) { // closestParam = seg + 1; // closestDis = (_points[(seg + 1) % _points.size()] - p).norm(); // break; // } // closestDis = (q - p).norm(); // iter++; // } // return {closestParam, closestDis}; // } ClosestDescOnSeg getClosestParam(const Vec3 &p) override { ClosestDescOnSeg closestDes{}; for (int i = 0; i < _bugles.size(); ++i) { const Vec3 &a = _points[i]; const Vec3 &b = _points[(i + 1) % _points.size()]; const CircularArc &arc = circularArcs[i]; const Vec3 &o = arc.center; // p 到圆弧平面的投影 const Vec3 projPt = p - _normal.dot(p - a) * _normal; // projPt到圆的最近点 const Vec3 clsPtOnCircle = o + arc.radius * (projPt - o).normalize(); if ((clsPtOnCircle - a).dot(arc.inCircleDir) > 0) { // 在圆弧上 real dis = (p - clsPtOnCircle).norm(); if (dis < closestDes.dis) { closestDes.dis = dis; Vec3 oa = a - o; Vec3 oClsPt = clsPtOnCircle - o; real R2 = arc.radius * arc.radius; real cosTheta = (oa).dot(oClsPt) / R2; real theta = std::acos(cosTheta); // [0, pi] if ((oa.cross(oClsPt)).dot(_normal) < 0) { theta = 2 * std::numbers::pi - theta; } closestDes.t = i + theta / arc.theta; } continue; } real paDis = (p - a).norm(); real pbDis = (p - b).norm(); if (paDis < closestDes.dis) { closestDes.dis = paDis; closestDes.t = i; } else { closestDes.dis = pbDis; closestDes.t = i + 1; } } return closestDes; } void print() const { if (_closed) std::cout << "Closed Polyline: \n"; else std::cout << "Open Polyline: \n"; std::cout << "Points: {\n"; for (int i = 0; i < _points.size(); ++i) { std::cout << _points[i].x() << ", " << _points[i].y() << ", " << _points[i].z() << ">"; if (i != _points.size() - 1) std::cout << ", "; } std::cout << "}\n"; std::cout << "的可变参数Bugles: {\n"; for (int i = 0; i < _bugles.size(); ++i) { std::cout << _bugles[i]; if (i != _bugles.size() - 1) std::cout << ", "; } std::cout << "}\n"; } static ClosestDescOnSeg segPtDist(const Vec3 &p, const Vec3 &A, const Vec3 &B) { Vec3 AB = B - A; Vec3 AP = p - A; real h = std::clamp(AP.dot(AB) / AB.dot(AB), 0., 1.); return {h, (AP - AB * h).norm()}; } static ClosestDescOnSeg segPtDist(const Vec2 &p, const Vec2 &A, const Vec2 &B) { Vec2 AB = B - A; Vec2 AP = p - A; real h = std::clamp(AP.dot(AB) / AB.dot(AB), 0., 1.); return {h, (AP - AB * h).norm()}; } }; class HelixLine : public ILine { public: Vec3 eval(real param) override { return {}; }; Vec3 der1(real param) override { return {}; }; Vec3 der2(real param) override { return {}; }; ClosestDescOnSeg getClosestParam(const Vec3 &p) override { return {}; }; private: Vec3 axisStart, axisDir; real advanceLen, advancePerRound; real startTheta; // 轴线起始时在螺旋投影(圆)上的参数 }; class PolynomialLine : public ILine { public: Vec3 eval(real param) override { return {}; }; Vec3 der1(real param) override { return {}; }; Vec3 der2(real param) override { return {}; }; ClosestDescOnSeg getClosestParam(const Vec3 &p) override { return {}; }; };