|
@ -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(); |
|
|
return Vec2{dir.dot(u), dir.dot(v)}.normalize(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
template <typename AxisLineType> |
|
|
|
|
|
class IExtrudedSolidBase : public ISolid { |
|
|
|
|
|
protected: |
|
|
|
|
|
std::vector<Polyline> _profiles; // TODO: may be replaced by const ref to profile
|
|
|
|
|
|
AxisLineType _axis; |
|
|
|
|
|
real _rScale; |
|
|
|
|
|
IExtrudedSolidBase(std::vector<Polyline> 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 |
|
|
* calculate winding number of a point w.r.t. a segment ab |
|
|
*/ |
|
|
*/ |
|
@ -46,16 +36,17 @@ protected: |
|
|
// / (std::numbers::pi * 2);
|
|
|
// / (std::numbers::pi * 2);
|
|
|
// }
|
|
|
// }
|
|
|
|
|
|
|
|
|
// template <typename AxisLineType>
|
|
|
template <typename AxisLineType> |
|
|
class ExtrudedSolidPolyline : public IExtrudedSolidBase<Polyline> { |
|
|
class IExtrudedSolidBase : public ISolid { |
|
|
private: |
|
|
protected: |
|
|
|
|
|
std::vector<Polyline> _profiles; // TODO: may be replaced by const ref to profile
|
|
|
|
|
|
AxisLineType _axis; |
|
|
|
|
|
real _rScale; |
|
|
std::vector<Pt2Array> _localProfiles2D; |
|
|
std::vector<Pt2Array> _localProfiles2D; |
|
|
std::vector<std::vector<CircularArc<Vec2>>> _localArcs2d; |
|
|
std::vector<std::vector<CircularArc<Vec2>>> _localArcs2d; |
|
|
Vec3 _biNormal; |
|
|
Vec3 _biNormalStartPt; |
|
|
|
|
|
IExtrudedSolidBase(std::vector<Polyline> profiles, AxisLineType axis, real rScale) |
|
|
public: |
|
|
: _profiles(std::move(profiles)), _axis(std::move(axis)), _rScale(rScale) { |
|
|
ExtrudedSolidPolyline(std::vector<Polyline> profiles, Polyline axis, real rScale) |
|
|
|
|
|
: IExtrudedSolidBase(std::move(profiles), std::move(axis), rScale) { |
|
|
|
|
|
assert(!_profiles.empty()); |
|
|
assert(!_profiles.empty()); |
|
|
for (const auto &_profile : _profiles) { |
|
|
for (const auto &_profile : _profiles) { |
|
|
assert(_profile.isClosed()); |
|
|
assert(_profile.isClosed()); |
|
@ -63,8 +54,7 @@ public: |
|
|
// project profile at st point to 2D
|
|
|
// project profile at st point to 2D
|
|
|
Vec3 tangent = _axis.der1(0).normalize(); |
|
|
Vec3 tangent = _axis.der1(0).normalize(); |
|
|
Vec3 normal = _axis.der2(0).normalize(); |
|
|
Vec3 normal = _axis.der2(0).normalize(); |
|
|
_biNormal = tangent.cross(normal); |
|
|
_biNormalStartPt = tangent.cross(normal); |
|
|
assert(_biNormal.isParallel(_axis.getNormal())); |
|
|
|
|
|
Vec3 q = _axis.eval(0); |
|
|
Vec3 q = _axis.eval(0); |
|
|
size_t profileCount = _profiles.size(); |
|
|
size_t profileCount = _profiles.size(); |
|
|
_localProfiles2D.resize(profileCount); |
|
|
_localProfiles2D.resize(profileCount); |
|
@ -77,11 +67,11 @@ public: |
|
|
for (int j = 0; j < segCount; ++j) { |
|
|
for (int j = 0; j < segCount; ++j) { |
|
|
// TODO:
|
|
|
// TODO:
|
|
|
_localProfiles2D[i][j] = |
|
|
_localProfiles2D[i][j] = |
|
|
get2DRepOf3DPt(profile.getPoints()[j] - q, normal, _biNormal, q); |
|
|
get2DRepOf3DPt(profile.getPoints()[j] - q, normal, _biNormalStartPt, q); |
|
|
auto &arc2d = _localArcs2d[i][j]; |
|
|
auto &arc2d = _localArcs2d[i][j]; |
|
|
const auto &arc3d = profile.getCircularArcs()[j]; |
|
|
const auto &arc3d = profile.getCircularArcs()[j]; |
|
|
arc2d.center = get2DRepOf3DPt(arc3d.center - q, normal, _biNormal, q); |
|
|
arc2d.center = get2DRepOf3DPt(arc3d.center - q, normal, _biNormalStartPt, q); |
|
|
arc2d.inCircleDir = get2DRepOf3DDir(arc3d.inCircleDir, normal, _biNormal); |
|
|
arc2d.inCircleDir = get2DRepOf3DDir(arc3d.inCircleDir, normal, _biNormalStartPt); |
|
|
arc2d.radius = arc3d.radius; |
|
|
arc2d.radius = arc3d.radius; |
|
|
arc2d.theta = arc3d.theta; |
|
|
arc2d.theta = arc3d.theta; |
|
|
arc2d.h = arc3d.h; |
|
|
arc2d.h = arc3d.h; |
|
@ -95,7 +85,7 @@ public: |
|
|
auto t = closestDescToAxis.t; |
|
|
auto t = closestDescToAxis.t; |
|
|
Vec3 q = _axis.eval(t); // closest point on axis
|
|
|
Vec3 q = _axis.eval(t); // closest point on axis
|
|
|
Vec3 qp = p - q; |
|
|
Vec3 qp = p - q; |
|
|
auto TBN = getTBN(p, q, closestDescToAxis); |
|
|
auto TBN = getTBN(p, q, closestDescToAxis.t); |
|
|
const Vec3 &tangent = TBN[0]; |
|
|
const Vec3 &tangent = TBN[0]; |
|
|
const Vec3 &normal = TBN[1]; |
|
|
const Vec3 &normal = TBN[1]; |
|
|
const Vec3 &biNormal = TBN[2]; |
|
|
const Vec3 &biNormal = TBN[2]; |
|
@ -120,22 +110,9 @@ public: |
|
|
return closestDescToProfile.dis * static_cast<int>(ptProfileRelation); |
|
|
return closestDescToProfile.dis * static_cast<int>(ptProfileRelation); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::array<Vec3, 3> 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: |
|
|
private: |
|
|
|
|
|
virtual std::array<Vec3, 3> getTBN(const Vec3 &p, const Vec3 &q, real t) = 0; |
|
|
|
|
|
|
|
|
inline ClosestDescOnSeg disProfile2D(const Vec2 &p2D) { |
|
|
inline ClosestDescOnSeg disProfile2D(const Vec2 &p2D) { |
|
|
ClosestDescOnSeg closestDescToProfile{}; |
|
|
ClosestDescOnSeg closestDescToProfile{}; |
|
|
for (int i = 0; i < _localArcs2d.size(); ++i) { |
|
|
for (int i = 0; i < _localArcs2d.size(); ++i) { |
|
@ -302,24 +279,6 @@ private: |
|
|
return {1, pbDis}; |
|
|
return {1, pbDis}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool isOn2DPolyline(const Vec2 &p2D, const Pt2Array &profile2D, |
|
|
|
|
|
const std::vector<CircularArc<Vec2>> &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) { |
|
|
static bool isPointOnSegment(const Vec2 &p, const Vec2 &a, const Vec2 &b) { |
|
|
// check collinearity
|
|
|
// check collinearity
|
|
|
double crossProduct = (p[1] - a[1]) * (b[0] - a[0]) - (p[0] - a[0]) * (b[1] - a[1]); |
|
|
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])); |
|
|
&& 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<CircularArc<Vec2>> &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<Polyline> { |
|
|
|
|
|
public: |
|
|
|
|
|
ExtrudedSolidPolyline(std::vector<Polyline> profiles, Polyline axis, real rScale = 1.0) |
|
|
|
|
|
: IExtrudedSolidBase(std::move(profiles), std::move(axis), rScale) { |
|
|
|
|
|
assert(_biNormalStartPt.isParallel(_axis.getNormal())); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::array<Vec3, 3> 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(
|
|
|
// real wnCircularArc(
|
|
|
// const Vec3 &p, const Vec3 &a, const Vec3 &b, const Vec3 &plgNormal, const Polyline::CircularArc &arc, int dir)
|
|
|
// 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));
|
|
|
// return arc.center + arc.radius * (arc.u * std::cos(phi) + arc.v * std::sin(phi));
|
|
|
// }
|
|
|
// }
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
class ExtrudedSolidHelixLine : public IExtrudedSolidBase<HelixLine> { |
|
|
|
|
|
public: |
|
|
|
|
|
ExtrudedSolidHelixLine(std::vector<Polyline> profiles, HelixLine axis, real rScale = 1.0) |
|
|
|
|
|
: IExtrudedSolidBase(std::move(profiles), std::move(axis), rScale) {} |
|
|
|
|
|
|
|
|
|
|
|
std::array<Vec3, 3> 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)}; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|