Browse Source

uniform interface for extrusion with 2 axis types

master
gjj 4 months ago
parent
commit
4adfc33da8
  1. 126
      include/solid.hpp

126
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 <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
*/
@ -46,16 +36,17 @@ protected:
// / (std::numbers::pi * 2);
// }
// template <typename AxisLineType>
class ExtrudedSolidPolyline : public IExtrudedSolidBase<Polyline> {
private:
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;
std::vector<Pt2Array> _localProfiles2D;
std::vector<std::vector<CircularArc<Vec2>>> _localArcs2d;
Vec3 _biNormal;
public:
ExtrudedSolidPolyline(std::vector<Polyline> profiles, Polyline axis, real rScale)
: IExtrudedSolidBase(std::move(profiles), std::move(axis), rScale) {
Vec3 _biNormalStartPt;
IExtrudedSolidBase(std::vector<Polyline> 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<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:
virtual std::array<Vec3, 3> 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<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) {
// 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<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(
// 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<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)};
}
};

Loading…
Cancel
Save