|
|
@ -11,6 +11,7 @@ |
|
|
|
#include <limits.h> |
|
|
|
#include <limits> |
|
|
|
#include <vector> |
|
|
|
#include "aabb.hpp" |
|
|
|
|
|
|
|
// class ILineParam {
|
|
|
|
// public:
|
|
|
@ -26,12 +27,19 @@ |
|
|
|
// real t;
|
|
|
|
// };
|
|
|
|
|
|
|
|
struct ClosestDescOnSeg { |
|
|
|
struct ClosestDescOnLine { |
|
|
|
real t; |
|
|
|
real dis; |
|
|
|
ClosestDescOnSeg(real _t, real _dis) : t(_t), dis(_dis) {} |
|
|
|
ClosestDescOnSeg() : t(0), dis(std::numeric_limits<real>::max()) {} |
|
|
|
ClosestDescOnLine(real _t, real _dis) : t(_t), dis(_dis) {} |
|
|
|
ClosestDescOnLine() : t(0), dis(std::numeric_limits<real>::max()) {} |
|
|
|
}; |
|
|
|
|
|
|
|
struct ClosestDescOnProfile : public ClosestDescOnLine { |
|
|
|
int i; // line idx
|
|
|
|
ClosestDescOnProfile(real _t, real _dis, int _i) : ClosestDescOnLine(_t, _dis), i(_i) {} |
|
|
|
ClosestDescOnProfile() : i(-1) {} |
|
|
|
}; |
|
|
|
|
|
|
|
// vscode C++ override跳转插件
|
|
|
|
class ILine { |
|
|
|
public: |
|
|
@ -43,29 +51,34 @@ public: |
|
|
|
ILine(ILine &&) = default; |
|
|
|
ILine &operator=(ILine &&) = default; |
|
|
|
|
|
|
|
virtual Vec3 eval(real t) const = 0; |
|
|
|
[[nodiscard]] virtual Vec3 eval(real t) const = 0; |
|
|
|
|
|
|
|
virtual Vec3 der1(real t) const = 0; |
|
|
|
[[nodiscard]] virtual Vec3 der1(real t) const = 0; |
|
|
|
|
|
|
|
virtual Vec3 der2(real t) const = 0; |
|
|
|
[[nodiscard]] virtual Vec3 der2(real t) const = 0; |
|
|
|
|
|
|
|
virtual Vec3 tangent(real t) const = 0; |
|
|
|
[[nodiscard]] virtual Vec3 tangent(real t) const = 0; |
|
|
|
|
|
|
|
virtual Vec3 normal(real t, const Vec3 &tan = -1.) const = 0; |
|
|
|
[[nodiscard]] virtual Vec3 normal(real t, const Vec3 &tan = -1.) const = 0; |
|
|
|
|
|
|
|
virtual ClosestDescOnSeg getClosestParam(const Vec3 &p) const = 0; |
|
|
|
[[nodiscard]] virtual ClosestDescOnLine getClosestParam(const Vec3 &p) const = 0; |
|
|
|
|
|
|
|
[[nodiscard]] virtual bool isEndParam(real t) const = 0; |
|
|
|
|
|
|
|
[[nodiscard]] virtual real startT() const = 0; |
|
|
|
[[nodiscard]] virtual real endT() const = 0; |
|
|
|
|
|
|
|
[[nodiscard]] virtual AABB getAABB() const = 0; |
|
|
|
}; |
|
|
|
|
|
|
|
inline static ClosestDescOnSeg segPtDist(const Vec3 &p, const Vec3 &A, const Vec3 &B) { |
|
|
|
inline static ClosestDescOnLine 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()}; |
|
|
|
} |
|
|
|
|
|
|
|
inline static ClosestDescOnSeg segPtDist(const Vec2 &p, const Vec2 &A, const Vec2 &B) { |
|
|
|
inline static ClosestDescOnLine 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.); |
|
|
@ -109,6 +122,12 @@ public: |
|
|
|
} |
|
|
|
circularArcs.resize(_bugles.size()); |
|
|
|
initSegInfo(); |
|
|
|
for (size_t i = 0; i < _bugles.size(); ++i) { |
|
|
|
AABB tmp{_points[i], _points[i]}; |
|
|
|
tmp.extend(AABB{_points[(i + 1) % _points.size()], _points[(i + 1) % _points.size()]}); |
|
|
|
tmp.expand(circularArcs[i].radius - circularArcs[i].h); |
|
|
|
aabb.extend(tmp); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] const Pt3Array &getPoints() const { return _points; } |
|
|
@ -123,6 +142,9 @@ public: |
|
|
|
return circularArcs; |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] real startT() const override { return 0; }; |
|
|
|
[[nodiscard]] real endT() const override { return static_cast<real>(_bugles.size()); }; |
|
|
|
|
|
|
|
protected: |
|
|
|
Pt3Array _points; |
|
|
|
std::vector<real> _bugles; |
|
|
@ -130,6 +152,8 @@ protected: |
|
|
|
bool _closed; |
|
|
|
std::vector<CircularArc<Vec3>> circularArcs; |
|
|
|
|
|
|
|
AABB aabb; |
|
|
|
|
|
|
|
public: |
|
|
|
void initSegInfo() { |
|
|
|
for (size_t i = 0; i < _bugles.size(); ++i) { |
|
|
@ -138,7 +162,7 @@ public: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Vec3 eval(real t) const override { |
|
|
|
[[nodiscard]] Vec3 eval(real t) const override { |
|
|
|
// if (circularArcs.empty())
|
|
|
|
// initSegInfo();
|
|
|
|
int seg = static_cast<int>(t); |
|
|
@ -151,7 +175,7 @@ public: |
|
|
|
return arc.center + arc.radius * (arc.u * std::cos(phi) + arc.v * std::sin(phi)); |
|
|
|
} |
|
|
|
|
|
|
|
Vec3 der1(real t) const override { |
|
|
|
[[nodiscard]] Vec3 der1(real t) const override { |
|
|
|
int seg = static_cast<int>(t); |
|
|
|
if (isEqual(_bugles[seg], 0)) { |
|
|
|
return _points[(seg + 1) % _points.size()] - _points[seg]; |
|
|
@ -162,7 +186,7 @@ public: |
|
|
|
return arc.radius * (arc.u * -std::sin(phi) + arc.v * std::cos(phi)); |
|
|
|
} |
|
|
|
|
|
|
|
Vec3 der2(real t) const override { |
|
|
|
[[nodiscard]] Vec3 der2(real t) const override { |
|
|
|
int seg = static_cast<int>(t); |
|
|
|
if (isEqual(_bugles[seg], 0)) { |
|
|
|
int aaa = 1; |
|
|
@ -245,14 +269,14 @@ public: |
|
|
|
// return {closestParam, closestDis};
|
|
|
|
// }
|
|
|
|
|
|
|
|
ClosestDescOnSeg getClosestParam(const Vec3 &p) const override { |
|
|
|
ClosestDescOnSeg closestDes{}; |
|
|
|
[[nodiscard]] ClosestDescOnLine getClosestParam(const Vec3 &p) const override { |
|
|
|
ClosestDescOnLine closestDes{}; |
|
|
|
for (int i = 0; i < _bugles.size(); ++i) { |
|
|
|
const Vec3 &a = _points[i]; |
|
|
|
const Vec3 &b = _points[(i + 1) % _points.size()]; |
|
|
|
if (isEqual(_bugles[i], 0)) { |
|
|
|
// 点到线段最近距离
|
|
|
|
ClosestDescOnSeg segPtDistRes = segPtDist(p, a, b); |
|
|
|
ClosestDescOnLine segPtDistRes = segPtDist(p, a, b); |
|
|
|
if (segPtDistRes.dis < closestDes.dis) { |
|
|
|
closestDes = segPtDistRes; |
|
|
|
closestDes.t = i + segPtDistRes.t; |
|
|
@ -320,6 +344,8 @@ public: |
|
|
|
return t < EPS_END_PARAM || t > static_cast<real>(_bugles.size()) - EPS_END_PARAM; |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] AABB getAABB() const override { return aabb; } |
|
|
|
|
|
|
|
private: |
|
|
|
void initCircularArcInfo(const Vec3 &a, const Vec3 &b, real bugle, const Vec3 &refNormal, |
|
|
|
CircularArc<Vec3> &res) { |
|
|
@ -365,25 +391,30 @@ public: |
|
|
|
real _4pi2r = PI2 * PI2 * _r; |
|
|
|
// _k = _4pi2r / (advancePerRound * advancePerRound + _4pi2r * _r);
|
|
|
|
_arcDeltaMaxFactor = _4pi2r / (advancePerRound * advancePerRound + _4pi2r * _r) * ONE_EIGHT; |
|
|
|
|
|
|
|
// init aabb
|
|
|
|
aabb.extend(_axisStart); |
|
|
|
aabb.extend(axisEnd); |
|
|
|
aabb.extend(r); |
|
|
|
} |
|
|
|
Vec3 eval(real t) const override { |
|
|
|
[[nodiscard]] Vec3 eval(real t) const override { |
|
|
|
real theta = _frequency * t; |
|
|
|
return _axisStart + _axisDir * t + (_u * std::cos(theta) + _v * std::sin(theta)) * _r; |
|
|
|
}; |
|
|
|
|
|
|
|
Vec3 der1(real param) const override { |
|
|
|
[[nodiscard]] Vec3 der1(real param) const override { |
|
|
|
real theta = _frequency * param; |
|
|
|
return _axisDir + _2pir_p * (_v * std::cos(theta) - _u * std::sin(theta)); |
|
|
|
}; |
|
|
|
|
|
|
|
Vec3 der2(real param) const override { |
|
|
|
[[nodiscard]] Vec3 der2(real param) const override { |
|
|
|
real theta = _frequency * param; |
|
|
|
return -_4pi2r_p2 * (_u * std::cos(theta) + _v * std::sin(theta)); |
|
|
|
}; |
|
|
|
|
|
|
|
Vec3 tangent(real t) const override { return der1(t).normalize(); } |
|
|
|
[[nodiscard]] Vec3 tangent(real t) const override { return der1(t).normalize(); } |
|
|
|
|
|
|
|
Vec3 normal(real t, const Vec3 &tan = -1.) const override { |
|
|
|
[[nodiscard]] Vec3 normal(real t, const Vec3 &tan = -1.) const override { |
|
|
|
Vec3 der2Vec = this->der2(t); |
|
|
|
if (tan == -1.) { |
|
|
|
Vec3 realTan = tangent(t); |
|
|
@ -392,15 +423,20 @@ public: |
|
|
|
return (der2Vec - der2Vec.dot(tan) * tan).normalize(); |
|
|
|
} |
|
|
|
|
|
|
|
ClosestDescOnSeg getClosestParam(const Vec3 &p) const override { |
|
|
|
[[nodiscard]] real startT() const override { return 0; } |
|
|
|
[[nodiscard]] real endT() const override { return 1; } |
|
|
|
|
|
|
|
[[nodiscard]] AABB getAABB() const override { return aabb; } |
|
|
|
|
|
|
|
ClosestDescOnLine getClosestParam(const Vec3 &p) const override { |
|
|
|
// discretization and traversal
|
|
|
|
real startT = 0; |
|
|
|
real endT = SEG_T; |
|
|
|
auto segCount = static_cast<size_t>(std::ceil(_advanceLen / SEG_T)); |
|
|
|
std::vector<ClosestDescOnSeg> sampledSegs(segCount + 2); // 加上首尾
|
|
|
|
std::vector<ClosestDescOnLine> sampledSegs(segCount + 2); // 加上首尾
|
|
|
|
std::vector<Vec3> samplePoints(segCount + 2); |
|
|
|
|
|
|
|
ClosestDescOnSeg closestSampleDes; |
|
|
|
ClosestDescOnLine closestSampleDes; |
|
|
|
for (size_t i = 0; i < segCount; ++i, startT = endT, endT += SEG_T) { |
|
|
|
real sampledT = fmin(startT + SEG_T_HALF, _advanceLen); |
|
|
|
samplePoints[i] = eval(sampledT); |
|
|
@ -474,6 +510,7 @@ private: |
|
|
|
real _r, _2pir_p, _4pi2r_p2, _arcDeltaMaxFactor; |
|
|
|
const int SEG_PER_ROUND = 12; |
|
|
|
const real SEG_T, SEG_T_HALF; |
|
|
|
AABB aabb; |
|
|
|
}; |
|
|
|
|
|
|
|
class SingleLine : public ILine { |
|
|
@ -507,5 +544,5 @@ public: |
|
|
|
|
|
|
|
Vec3 normal(real t, const Vec3 &tan = -1.) const override { return {}; } |
|
|
|
|
|
|
|
ClosestDescOnSeg getClosestParam(const Vec3 &p) const override { return {}; }; |
|
|
|
ClosestDescOnLine getClosestParam(const Vec3 &p) const override { return {}; }; |
|
|
|
}; |
|
|
|