#pragma once #include #include #include #include class ISolid { public: virtual ~ISolid() = default; virtual real sdf(const Vec3 &p) = 0; }; Vec2 get2DRepOf3DPt(const Vec3 &pt3D, const Vec3 &u, const Vec3 &v, const Vec3 &localO) { Vec3 OP = pt3D - localO; return {OP.dot(u), OP.dot(v)}; } class IExtrudedSolid : public ISolid { public: Polyline _profile; real _rScale; public: IExtrudedSolid(Polyline profile, real rScale) : _profile(std::move(profile)), _rScale(rScale) { } }; /** * calculate winding number of a point w.r.t. a segment ab */ real wnSegment(const Vec3 &p, const Vec3 &a, const Vec3 &b, const Vec3 &refNormal) { Vec3 pa = a - p; Vec3 pb = b - p; real wn = std::acos(std::clamp(pa.dot(pb) / (pa.norm() * pb.norm()), static_cast(-1.), static_cast(1.))); return wn * (refNormal.dot(pa.cross(pb)) > 0 ? 1 : -1); } class ExtrudedSolidPolyline : public IExtrudedSolid { private: Polyline _axis; Pt2Array _localProfile2D; public: ExtrudedSolidPolyline(Polyline profile, Polyline axis, real rScale) : IExtrudedSolid(std::move(profile), rScale), _axis(std::move(axis)) { assert(_profile.isClosed()); // TODO: project profile at st point to 2D Vec3 T = _axis.der1(0).normalize(); Vec3 N = _axis.der2(0).normalize(); Vec3 B = T.cross(N); Vec3 Q = _axis.eval(0); for (const auto &P: _profile.getPoints()) { Vec3 QP = P - Q; auto uv = get2DRepOf3DPt(QP, N, B, Q); // test it { } _localProfile2D.emplace_back(uv.u(), uv.v()); } } real sdf(const Vec3 &p) override { ClosestDescOnSeg closestDesc = _axis.getClosestParam(p); // TNB coordinate system auto t = closestDesc.t; Vec3 T = _axis.der1(t).normalize(); Vec3 N = _axis.der2(t).normalize(); Vec3 B = T.cross(N); Vec3 Q = _axis.eval(t); Vec3 QP = p - Q; auto uv = get2DRepOf3DPt(QP, N, B, Q); //test it { } // TODO: to test if uv is in _localProfile2D for (auto i = 0; i < _localProfile2D.size(); ++i) { } return 0; } private: real wnCircularArc(const Vec3& p, const Vec3& a, const Vec3& b, const Vec3& refNormal, const Polyline::CircularArc& arc) { Vec3 pa = a - p; Vec3 pb = b - p; real wn = std::acos(std::clamp(pa.dot(pb) / (pa.norm() * pb.norm()), static_cast(-1.), static_cast(1.))); real dir = refNormal.dot(pb.cross(pa)) > 0 ? 1 : -1; // 注意这里是pb x pa, 不是pa x pb auto inOutCircle = arc.inCircleCheck(p); if (inOutCircle == OnBoundary) { // TODO } return (inOutCircle - wn) * dir; } }; class ExtrudedSolidPolynomialLine : public IExtrudedSolid { protected: PolynomialLine _axis; };