diff --git a/.clang-tidy b/.clang-tidy index eaa025e..08c49ec 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,9 +1,12 @@ Checks: " -*, bugprone-*, + -bugprone-easily-swappable-parameters, performance-*, readability-*, + -readability-braces-around-statements, misc-*, + -misc-non-private-member-variables-in-classes, clang-analyzer-*, clang-diagnostic-*, cppcoreguidelines-*, @@ -16,6 +19,7 @@ Checks: " -modernize-use-trailing-return-type, -cppcoreguidelines-magic-numbers, -cppcoreguidelines-init-variables, + -cppcoreguidelines-pro-type-member-init, " WarningsAsErrors: '' diff --git a/include/common.hpp b/include/common.hpp index 64c79b5..0be5879 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -1,8 +1,14 @@ #pragma once +#include "real.hpp" +#include +#include enum PtBoundaryRelation { Inside = -1, OnBoundary, Outside = 1 }; -bool isEqual(double a, double b) { +const real PI = std::numbers::pi; +const real PI2 = 2 * PI; +const real EPS = std::numeric_limits::epsilon() * 1e2; +inline bool isEqual(double a, double b) { // TODO return a == b; } \ No newline at end of file diff --git a/include/line.hpp b/include/line.hpp index c0214af..29aa4f8 100644 --- a/include/line.hpp +++ b/include/line.hpp @@ -34,6 +34,7 @@ struct ClosestDescOnSeg { class ILine { public: + int aaa; virtual ~ILine() = default; virtual Vec3 eval(real param) = 0; @@ -50,7 +51,7 @@ struct CircularArc { VecType center; real radius; real theta; - real h; + real h = -1; // straight line for h <= 0. VecType u; VecType v; VecType inCircleDir; @@ -61,6 +62,12 @@ struct CircularArc { }; ; +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 { @@ -87,6 +94,10 @@ public: [[nodiscard]] bool isClosed() const { return _closed; } + [[nodiscard]] const std::vector> &getCircularArcs() const { + return circularArcs; + } + private: Pt3Array _points; std::vector _bugles; @@ -143,90 +154,128 @@ public: 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 { - real closestDis = std::numeric_limits::max(); - real closestParam; + ClosestDescOnSeg closestDes{}; 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; + 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; } - } - // 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 (abs(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; + 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; } - closestDis = (q - p).norm(); - iter++; } - return {closestParam, closestDis}; + return closestDes; } - const std::vector> &getCircularArcs() const { return circularArcs; } - void print() const { if (_closed) - printf("Closed Polyline: \n"); + std::cout << "Closed Polyline: \n"; else - printf("Open Polyline: \n"); - printf("Points: {\n"); + std::cout << "Open Polyline: \n"; + std::cout << "Points: {\n"; for (int i = 0; i < _points.size(); ++i) { - printf("<%lf, %lf, %lf>", _points[i].x(), _points[i].y(), _points[i].z()); + std::cout << _points[i].x() << ", " << _points[i].y() << ", " << _points[i].z() << ">"; if (i != _points.size() - 1) - printf(", "); + std::cout << ", "; } - std::cout << "}" << std::endl; - printf("Bugles: {\n"); + std::cout << "}\n"; + std::cout << "的可变参数Bugles: {\n"; for (int i = 0; i < _bugles.size(); ++i) { - printf("%lf", _bugles[i]); + std::cout << _bugles[i]; if (i != _bugles.size() - 1) - printf(", "); + std::cout << ", "; } - std::cout << "}" << std::endl; + std::cout << "}\n"; } - static ClosestDescOnSeg segPtDist(const Vec3 &p, const Vec3 &A, const Vec3 &B) { Vec3 AB = B - A; Vec3 AP = p - A; diff --git a/include/solid.hpp b/include/solid.hpp index 5c4fde9..701f1cf 100644 --- a/include/solid.hpp +++ b/include/solid.hpp @@ -2,7 +2,10 @@ #include "common.hpp" #include "real.hpp" +#include +#include #include +#include #include "vec.hpp" #include "line.hpp" @@ -12,88 +15,110 @@ public: virtual real sdf(const Vec3 &p) = 0; }; - -Vec2 get2DRepOf3DPt(const Vec3 &pt3D, const Vec3 &u, const Vec3 &v, const Vec3 &localO) { +inline 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)}; } -Vec2 get2DRepOf3DDir(const Vec3 &dir, const Vec3 &u, const Vec3 &v) { +inline Vec2 get2DRepOf3DDir(const Vec3 &dir, const Vec3 &u, const Vec3 &v) { return Vec2{dir.dot(u), dir.dot(v)}.normalize(); } class IExtrudedSolid : public ISolid { public: - Polyline _profile; // TODO: may be replaced by const ref to profile + std::vector _profiles; // TODO: may be replaced by const ref to profile real _rScale; - -public: - IExtrudedSolid(Polyline profile, real rScale) : _profile(std::move(profile)), _rScale(rScale) {} + IExtrudedSolid(std::vector profiles, real rScale) + : _profiles(std::move(profiles)), _rScale(rScale) {} }; /** * calculate winding number of a point w.r.t. a segment ab */ -real unsignedWindingNumberSegment(const Vec3 &p, const Vec3 &a, const Vec3 &b, - const Vec3 &refNormal) { - Vec3 pa = a - p; - Vec3 pb = b - p; - return std::acos(std::clamp(pa.dot(pb) / (pa.norm() * pb.norm()), static_cast(-1.), - static_cast(1.))) - / (std::numbers::pi * 2); -} +// inline real unsignedWindingNumberSegment(const Vec3 &p, const Vec3 &a, const Vec3 &b, +// const Vec3 &refNormal) { +// Vec3 pa = a - p; +// Vec3 pb = b - p; +// return std::acos(std::clamp(pa.dot(pb) / (pa.norm() * pb.norm()), static_cast(-1.), +// static_cast(1.))) +// / (std::numbers::pi * 2); +// } class ExtrudedSolidPolyline : public IExtrudedSolid { private: Polyline _axis; - Pt2Array _localProfile2D; - std::vector> _localArcs2d; + std::vector _localProfiles2D; + std::vector>> _localArcs2d; // Pt2Array _localCircleCenter2D; // Pt2Array _localInCircleDir; public: - ExtrudedSolidPolyline(Polyline profile, Polyline axis, real rScale) - : IExtrudedSolid(std::move(profile), rScale), _axis(std::move(axis)) { - assert(_profile.isClosed()); + ExtrudedSolidPolyline(std::vector profiles, Polyline axis, real rScale) + : IExtrudedSolid(std::move(profiles), rScale), _axis(std::move(axis)) { + assert(!_profiles.empty()); + for (const auto &_profile : _profiles) { + 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); - int segCount = _profile.getPoints().size(); - _localProfile2D.resize(segCount); - _localArcs2d.resize(segCount); - // _localInCircleDir.resize(segCount); - // _localCircleCenter2D.resize(segCount); - for (int i = 0; i < segCount; ++i) { - _localProfile2D[i] = get2DRepOf3DPt(_profile.getPoints()[i] - Q, N, B, Q); - auto &arc2d = _localArcs2d[i]; - const auto &arc3d = _profile.getCircularArcs()[i]; - arc2d.center = get2DRepOf3DPt(arc3d.center - Q, N, B, Q); - arc2d.inCircleDir = get2DRepOf3DDir(arc3d.inCircleDir, N, B); - arc2d.radius = arc3d.radius; + size_t profileCount = _profiles.size(); + _localProfiles2D.resize(profileCount); + _localArcs2d.resize(profileCount); + for (int i = 0; i < _profiles.size(); ++i) { + const auto &profile = _profiles[i]; + size_t segCount = profile.getPoints().size(); + _localProfiles2D[i].resize(segCount); + _localArcs2d[i].resize(segCount); + for (int j = 0; j < segCount; ++j) { + // TODO: + _localProfiles2D[i][j] = get2DRepOf3DPt(profile.getPoints()[j] - Q, N, B, Q); + auto &arc2d = _localArcs2d[i][j]; + const auto &arc3d = profile.getCircularArcs()[j]; + arc2d.center = get2DRepOf3DPt(arc3d.center - Q, N, B, Q); + arc2d.inCircleDir = get2DRepOf3DDir(arc3d.inCircleDir, N, B); + arc2d.radius = arc3d.radius; + arc2d.theta = arc3d.theta; + arc2d.h = arc3d.h; + } } } real sdf(const Vec3 &p) override { - ClosestDescOnSeg closestDesc = _axis.getClosestParam(p); + ClosestDescOnSeg closestDescToAxis = _axis.getClosestParam(p); // TNB coordinate system - auto t = closestDesc.t; + auto t = closestDescToAxis.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 p2D = get2DRepOf3DPt(QP, N, B, Q); - // TODO: to test if p2D is in _localProfile2D - // for (auto i = 0; i < _localProfile2D.size(); ++i) { - // } - PtBoundaryRelation ptProfileRelation = getPtProfileRelation(p2D); - if (ptProfileRelation == OnBoundary) { - return 0; // TODO: 判断OnBoundary的过程可以加一点容差 + // PMC + PtBoundaryRelation ptProfileRelation = Inside; + for (int i = 0; i < _localArcs2d.size(); ++i) { + PtBoundaryRelation relationTmp = + getPtProfileRelation(p2D, _localProfiles2D[i], _localArcs2d[i]); + if (relationTmp == OnBoundary) { + return 0; // TODO: 判断OnBoundary的过程可以加一点容差 + } + if ((relationTmp == Outside && i == 0) || (relationTmp == Inside && i != 0)) { + ptProfileRelation = Outside; + break; + } } - ClosestDescOnSeg closestDescOnProfile = distance2Profile2D(p2D); - return closestDescOnProfile.dis * static_cast(ptProfileRelation); + // distance + ClosestDescOnSeg closestDescToProfile{}; + for (int i = 0; i < _localArcs2d.size(); ++i) { + ClosestDescOnSeg closestDescTemp = + distance2Profile2D(p2D, _localProfiles2D[i], _localArcs2d[i]); + if (closestDescTemp.dis < closestDescToProfile.dis) { + closestDescToProfile = closestDescTemp; + } + } + return closestDescToProfile.dis * static_cast(ptProfileRelation); } private: @@ -103,19 +128,18 @@ private: * out + in = in * out + out = out */ - PtBoundaryRelation getPtProfileRelation(const Vec2 &p2D) { - assert(_profile.isClosed()); - - int segCount = _profile.getBugles().size(); + static PtBoundaryRelation getPtProfileRelation(const Vec2 &p2D, const Pt2Array &profile2D, + const std::vector> &arcs2d) { + size_t segCount = arcs2d.size(); // 先判断是否在outline上 // 顺便判断点-扇的位置关系 bool inFan = false; int onLinesegButHasBugle = -1; for (int i = 0; i < segCount; ++i) { - const Vec2 &a = _localProfile2D[i]; - const Vec2 &b = _localProfile2D[(i + 1) % segCount]; - if (_profile.getBugles()[i] == 0) { - //line segment + const Vec2 &a = profile2D[i]; + const Vec2 &b = profile2D[(i + 1) % segCount]; + if (arcs2d[i].h <= EPS) { + //straight line segment if (isPointOnSegment(p2D, a, b)) { return OnBoundary; } @@ -125,9 +149,9 @@ private: onLinesegButHasBugle = i; break; } - const auto &arc = _profile.getCircularArcs()[i]; - real po = (p2D - _localArcs2d[i].center).norm(); - if ((p2D - a).dot(_localArcs2d[i].inCircleDir) > 0) { + const auto &arc = arcs2d[i]; + real po = (p2D - arc.center).norm(); + if ((p2D - a).dot(arc.inCircleDir) > 0) { if (po == arc.radius) { return OnBoundary; } @@ -151,13 +175,13 @@ private: int majorityIn = 0; // 在多边形内的射线计数 int majorityOut = 0; // 在多边形外的射线计数 for (int rayIdx = 0; rayIdx < numRays; ++rayIdx) { - double angle = (2.0 * std::numbers::pi * rayIdx) / numRays; + double angle = (PI2 * rayIdx) / numRays; Vec2 rayDir(cos(angle), sin(angle)); int crossings = 0; for (int i = 0; i < segCount; ++i) { - const Vec2 &a = _localProfile2D[i]; - const Vec2 &b = _localProfile2D[(i + 1) % segCount]; + const Vec2 &a = profile2D[i]; + const Vec2 &b = profile2D[(i + 1) % segCount]; assert(isPointOnSegment(p, a, b)); // if (isPointOnSegment(p2D, a, b)) // { @@ -195,23 +219,20 @@ private: if (onLinesegButHasBugle != -1) { // 需要特殊考虑的情况 // 从p2D向inCircle方向前进一小步 - Vec2 samplePt = p2D - + _localArcs2d[onLinesegButHasBugle].center - * std::numeric_limits::epsilon() * 1e6; + Vec2 samplePt = p2D + arcs2d[onLinesegButHasBugle].inCircleDir * EPS; return !ptInPolygon(samplePt) ? Inside : Outside; // 取反 } return ptInPolygon(p2D) ^ inFan ? Inside : Outside; - // TODO: 返回on的情况 } - ClosestDescOnSeg distance2Profile2D(const Vec2 &p2D) { - // TODO: 2D 下点到圆弧的距离应该可以直接算,不用这么迭代! - assert(_profile.isClosed()); + static ClosestDescOnSeg distance2Profile2D(const Vec2 &p2D, const Pt2Array &profile2D, + const std::vector> &arcs2d) { + size_t segCount = arcs2d.size(); + assert(profile2D.size() == segCount); ClosestDescOnSeg res{}; - for (int i = 0; i < _localArcs2d.size(); ++i) { + for (int i = 0; i < segCount; ++i) { auto disDesc = - distance2Arc2D(p2D, _localProfile2D[i], - _localProfile2D[(i + 1) % _localArcs2d.size()], _localArcs2d[i]); + distance2Arc2D(p2D, profile2D[i], profile2D[(i + 1) % segCount], arcs2d[i]); if (res.dis > disDesc.dis) { res.dis = disDesc.dis; res.t = i + disDesc.t; @@ -220,20 +241,20 @@ private: return res; } - ClosestDescOnSeg distance2Arc2D(const Vec2 &p2D, const Vec2 &a, const Vec2 &b, - const CircularArc &arc) { + static ClosestDescOnSeg distance2Arc2D(const Vec2 &p2D, const Vec2 &a, const Vec2 &b, + const CircularArc &arc) { const Vec2 ¢er = arc.center; Vec2 op = p2D - center; Vec2 q = center + arc.radius * op.normalize(); // closest pt on circle - Vec2 oq = q - center; - Vec2 oa = a - center; // 判断q是否在弧上 if ((q - a).dot(arc.inCircleDir) > 0) { // 计算参数 - real normMulti = arc.radius * oq.norm(); - real cosTheta = (oa).dot(oq) / normMulti; - real sinTheta = (oa).cross(oq) / normMulti; - return {atan2(sinTheta, cosTheta), (p2D - q).norm()}; + Vec2 oq = q - center; + Vec2 oa = a - center; + real R2 = arc.radius * arc.radius; + real cosTheta = (oa).dot(oq) / R2; + real sinTheta = (oa).cross(oq) / R2; + return {atan2(sinTheta, cosTheta) / arc.theta, (p2D - q).norm()}; } real paDis = (a - p2D).norm(); @@ -243,12 +264,13 @@ private: return {1, pbDis}; } - bool isOn2DPolyline(const Vec2 &p2D) { - int segCount = _profile.getBugles().size(); + bool isOn2DPolyline(const Vec2 &p2D, const Pt2Array &profile2D, + const std::vector> &arcs2d) { + size_t segCount = arcs2d.size(); for (int i = 0; i < segCount; ++i) { - const Vec2 &a = _localProfile2D[i]; - const Vec2 &b = _localProfile2D[(i + 1) % segCount]; - if (_profile.getBugles()[i] == 0) { + 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; @@ -256,13 +278,16 @@ private: continue; } } + // TODO: 没写完,但是暂时用不到 + return true; } - 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 double crossProduct = (p[1] - a[1]) * (b[0] - a[0]) - (p[0] - a[0]) * (b[1] - a[1]); - if (!isEqual(crossProduct, 0)) + if (!isEqual(crossProduct, 0)) { return false; // Not collinear + } // Check if point is within segment bounds return (p[0] >= std::min(a[0], b[0]) && p[0] <= std::max(a[0], b[0]) diff --git a/require.md b/require.md index 212725a..d3f6449 100644 --- a/require.md +++ b/require.md @@ -77,4 +77,224 @@ virtual CPmSolid * create_face_helix(const PMSoft::CPMGePoint3DArray &pt3d, BOOL handiness, double radius, double pitch); -``` \ No newline at end of file +``` + + + + + + + + + + +////////////////////////////////////////////////////////////////////////// + /// 体生成 + ////////////////////////////////////////////////////////////////////////// + // 两截面蒙皮(生成台体) + virtual CPmSolid * create_by_faces_to_skin(PmDbPolyline * pStartPoly, PmDbPolyline * pEndPoly, PMSoft::CPMGeVector3D normal/*,BOOL bIsFace*/) override; + + // 多截面蒙皮(截面的边均为线段) + virtual CPmSolid * create_by_faces_to_skin(const CArray &jmsPts3d, BOOL bIsFace) override; + + // 多截面蒙皮(截面的边可能存在凸度) + virtual CPmSolid * create_by_faces_to_skin(const CArray &jmPt3d, const CArray &jmbulge, + CArray &normalArr, const PMSoft::CPMGePoint3DArray &pathPt3d, BOOL bIsFace) override; + + CPmSolid * create_by_faces_to_skin(const CArray &jmsPts3d, const CArray &jmsBulges, + const CArray &normalArr, BOOL bIsFace); + + // 多线段蒙皮(线段不含弧) + CPmSolid * createFacesBySkinWithSegs(const CArray &segs, BOOL bIsFace); + + virtual CPmSolid * createBox(const PMSoft::CPMGePoint3D& p,double xLen,double yLen,double zLen); + virtual CPmSolid * createTorus(const PMSoft::CPMGePoint3D& p, double majorRadius, double minorRadius); + virtual CPmSolid * createSphere(const PMSoft::CPMGePoint3D& p, double radius); + void CreateCircPoints(int nNum, const PMSoft::CPMGePoint3D& pt, const PMSoft::CPMGePoint3D& ptCent, PMSoft::CPMGePoint3DArray& ptCircArr); + CPmSolid * CreateBall(const PMSoft::CPMGePoint3D& ptCent, double dRadius, PMSoft::PMBoolean3d::Ent3dData& drawData); + CPmSolid * CreateBall(const PMSoft::CPMGePoint3D& ptCent, double dRadius); + CPmSolid * CreateBall(const PMSoft::CPMGePoint3D& ptCent, double dRadius, double dHeight); + CPmSolid * CreateBall(const PMSoft::CPMGePoint3D& ptCent, double dRadius, double dHeight, PMSoft::PMBoolean3d::Ent3dData& drawData); + virtual CPmSolid * CreateBallBoard(const PMSoft::CPMGePoint3D& ptCent, double dHeight, double dRadius, double dBoardHeight); + virtual CPmSolid * createPipe(const PMSoft::CPMGePoint3D& axisStart, PMSoft::CPMGePoint3D& axisEnd, + const PMSoft::CPMGeVector3D& baseNormal, + double dblOuterRadius, double dblInnerRadius); + virtual CPmSolid * createCone(const PMSoft::CPMGePoint3D& axisStart, const PMSoft::CPMGePoint3D& axisEnd, + double radius1, double radius2); + virtual CPmSolid * createEllipsoid(const PMSoft::CPMGePoint3D &basept,double height,double radius1,double radius2,double radius3); + virtual CPmSolid * createPyramid(const PMSoft::CPMGePoint3DArray &Pt3d, const PMSoft::CPMGeVector3D &plgNormal, + const PMSoft::CPMGePoint3D &apex); + virtual CPmSolid * createPyramid(const PMSoft::CPMGePoint3DArray &Pt3d, const PMSoft::CPMGeVector3D &plgNormal, + const PMSoft::CPMGePoint3DArray &apexs); + virtual CPmSolid * createHelix(const PMSoft::CPMGePoint3DArray &pt3d, + const PmGeDoubleArray bulges, + const PMSoft::CPMGePoint3D &axis_start, + const PMSoft::CPMGePoint3D &axis_end, + const PMSoft::CPMGeVector3D &start_dir, + BOOL handiness, + double radius, + double pitch); + virtual CPmSolid * createHelix(const PMSoft::CPMGePoint3DArray &pt3d, + const PmGeDoubleArray bulges, + const PMSoft::CPMGeVector3D &FaceNormal, + const PMSoft::CPMGePoint3D &axis_start, + const PMSoft::CPMGePoint3D &axis_end, + const PMSoft::CPMGeVector3D &start_dir, + BOOL handiness, + double radius, + double pitch, + BOOL bIsFace = FALSE); + + virtual CPmSolid * create_face_helix(const PMSoft::CPMGePoint3DArray &pt3d, + const PmGeDoubleArray bulges, + const PMSoft::CPMGePoint3D &axis_start, + const PMSoft::CPMGePoint3D &axis_end, + const PMSoft::CPMGeVector3D &start_dir, + BOOL handiness, + double radius, + double pitch); + + /** + * @brief 截面绕轴旋转生成体 + * + * + * @note : + * @param : 截面、基点、轴向量、旋转角度 + * @return: + * @author: csl + * @date : [11/7/2022] + */ + virtual CPmSolid * createSolidByFaceAroundAxis(const PMSoft::CPMGePoint3DArray &pt3d, const PmGeDoubleArray &bulges, const PMSoft::CPMGeVector3D &plgNormal, + const PMSoft::CPMGePoint3D &apex, const PMSoft::CPMGeVector3D &axis, + double angle) override; + + virtual CPmSolid * createSphereFace(const PMSoft::CPMGePoint3D& p, double radius); + + virtual CPmSolid * create_face_cylinder_cone(const PMSoft::CPMGePoint3D& axisStart, const PMSoft::CPMGePoint3D& axisEnd, double radius1, double radius2, double start = 0, double end = 360); + + virtual CPmSolid * extrudeAdvance(PmDbPolyline * pExtrudePoly, + const PMSoft::CPMGePoint3D &fixedPt, + const PMSoft::CPMGeVector3D &plgNormal, + const PMSoft::CPMGeVector3D &extusionVector, + double scaleFactor, + double twistAngle); + + virtual CPmSolid * extrudeAlongPath(const PMSoft::CPMGePoint3DArray &pt3d, + const PmGeDoubleArray &bulge, + PMSoft::CPMGeVector3D normal, + PmDbPolyline * path, + BOOL IsInteset = FALSE) override; + + /** + * @brief 带洞截面沿路径拉伸 + * + * + * @note : + * @param : 截面必须共面,数组首个元素必须为外包,其余元素为内部洞;拉伸路径可以闭合 + * @return: + * @author: csl + * @date : [11/7/2022] + */ + virtual CPmSolid * extrudeAlongPath(const CArray & polys, + PmDbPolyline * path) override; + + virtual BOOL GetExtents(const CPmSolid *pEntity, PmExtents& extents); + + virtual InterferenceType checkInterferenceType(const CPmSolid* Ent,const CPmSolid* otherEnt,double dTol = 0.01); + + virtual CPmSolid * extrude(const PMSoft::CPMGePoint3DArray &pt3d, const PmGeDoubleArray &bulge, const PMSoft::CPMGePoint3D &fixedPt, const PMSoft::CPMGeVector3D &plgNormal, const PMSoft::CPMGeVector3D &extusionVector, double scaleFactor, double twistAngle) override; + CPmSolid * extrude(const PMSoft::CPMGePoint3DArray & pt3d, const PmGeDoubleArray & bulge, const PMSoft::CPMGePoint3D &fixedPt, const PMSoft::CPMGeVector3D &extusionVector); + + virtual CPmSolid * extrude(PmDbPolyline * pExtrudePoly, + const PMSoft::CPMGePoint3D &fixedPt, + const PMSoft::CPMGeVector3D &plgNormal, + const PMSoft::CPMGeVector3D &extusionVector, + double scaleFactor, + double twistAngle); + + // (新弧形) 面拉伸为柱类体测试接口 + PMSoft::PMBoolean3d::CCylinderLikeBody * extrudeCylinderBodyTest(const PMSoft::OdexBase2d::PmDbPLine& plSection, const PMSoft::CPMGeVector3D& vecExtru); + PMSoft::PMBoolean3d::CCylinderLikeBody * extrudeCylinderBodyTest(const PMSoft::CPMGePoint3DArray& pts, const PMSoft::PmGeDoubleArray& bulges, const PMSoft::CPMGeVector3D& vecNormal, const PMSoft::CPMGeVector3D& vecExtru); + + /** + * @brief 带洞截面拉伸 + * + * + * @note : + * @param : 数组首个元素必须为外包,其余元素为内部洞 + * @return: + * @author: csl + * @date : [11/7/2022] + */ + virtual CPmSolid * extrude(const CArray & polys, + const PMSoft::CPMGePoint3D &fixedPt, + const PMSoft::CPMGeVector3D &plgNormal, + const PMSoft::CPMGeVector3D &extusionVector, + double scaleFactor = 1.0, + double twistAngle = 0.0) override; + + /** + * @brief 多段拉伸生成完整体(适用构造柱马牙槎) + * + * + * @note : 只在自主布尔中实现,ACIS未实现 + * @param : polys为各段拉伸的起始截面,vctsExtru为每段拉伸的拉伸向量 + * 截面与向量的数量应该相同,且至少为2个 + * @return: + * @author: csl + * @date : [9/25/2023] + */ + virtual CPmSolid * extrudeStepByStep(const CArray & polys, const CArray & vctsExtru) override; + + + virtual CPmSolid * CreateFaceBody_extrude(const PMSoft::CPMGePoint3DArray & pt3d, const PmGeDoubleArray & bugle, const PMSoft::CPMGeVector3D &plgNormal, double dLength); + + virtual CPmSolid * CreateFaceBody_extrude(const PMSoft::CPMGePoint3DArray & pt3d,const PmGeDoubleArray & bugle,const PMSoft::CPMGeVector3D &plgNormal,const PMSoft::CPMGeVector3D &extrudeVec); + + virtual CPmSolid * CreateFaceBody_extrude(PmDbPolyline * ply, const PMSoft::CPMGeVector3D &plgNormal, const PMSoft::CPMGeVector3D & extrudeVec); + + virtual CPmSolid * CreateFaceBody(const PMSoft::CPMGePoint3DArray & pt3d,const PmGeDoubleArray & bulge,const PMSoft::CPMGeVector3D &plgNormal); + + virtual CPmSolid * CreateFaceBody(const PmDbPolyline * pFacePolyLine); + //生成自身带洞的面 + virtual CPmSolid * CreateFaceBody(const CArray & pFacePolyLineArr) override; + + virtual CPmSolid * CreateFaceBody_extrudeAlongPath(const PMSoft::CPMGePoint3DArray & pt3d,const PmGeDoubleArray &bulge,PMSoft::CPMGeVector3D normal,PmDbPolyline* path,BOOL IsInteset = FALSE) override; + + virtual void getSliceFace(CPmSolid * &pEntity,const PMSoft::CPMGePoint3D & pt, const PMSoft::CPMGeVector3D & normal, double dTol); + + virtual CPmSolid* CreateBodyBySliceFace(CPmSolid * pEntity,const PMSoft::CPMGePoint3D & pt, const PMSoft::CPMGeVector3D & normal, double dExtrudeDis); + + virtual BOOL GetEntity_AllFaces(CPmSolid * &pEntity);// 体构件转化为面构件 + /// 隐藏不需要的面(适用人防墙业务) + virtual BOOL UnHookSpecialFaces(CPmSolid *& pSolid, CArray & brds); + virtual BOOL UnHookSpecialFaces(CPmSolid *& pSolid, CArray & brds, BOOL bNeedTransf); + /// 隐藏单面(适用人防墙业务),向量即为面法向量 + virtual BOOL UnHookSingleFace(CPmSolid *& pSolid, const CGeBorder & brd, const PMSoft::CPMGeVector3D & normal); + ////////////////////////////////////////////////////////////////////////// + /// 其他 + ////////////////////////////////////////////////////////////////////////// + virtual BOOL AddEntityToDbs(const CPMSolidArr & EntArr,CPM3dEntDataArr & entDataArr,CString & strACISFilePath); + + BOOL RemoveVertexNotNeed(PMSoft::CPMGePoint3DArray & PtArr,PmGeDoubleArray & BulgeArr,int & iSize_Pt,int & iSize_Bulge); + + /***************************************************************************************************************************************************/ + virtual BOOL getCentroid(CPmSolid *pEntity, PMSoft::CPMGePoint3D ¢roid); + + + //describe:获取所需实体的所有符合条件面,判断条件为实体面的法向量和传入向量符合条件 + //notice:bGetOrMove,获取符合条件的还是去除符合条件的;bStrict,绝对符合条件还是接近条件(e.g 绝对条件为(线/面)同向时,接近条件为锐角;绝对条件为noZ时,接近条件为非xy平面) + //return: + // + //author:csl + //date:2022/9/14 + virtual BOOL GetFaceSuitVec(CPmSolid *& pSolid, FaceNormalType normalType, BOOL bGetOrMove, BOOL bStrict, const PMSoft::CPMGeVector3D & vctNormalStd, const PMSoft::CPMGeTol& tol = PMSoft::CPMGeTol::gTol) override; + + // 一组实体 向 指定面进行投影 + virtual CPmSolid * CreateEntShadow(const CPMSolidArr & entArr, const PMSoft::CPMGePlane & plane) override; + + // 将面实体拆分,每个面作为一个Solid,放在结果数组中。!内存需要调用方管理 + virtual BOOL SplitFacesSolid(const CPmSolid * pFacesSolid, CPMSolidArr & facesSplitResult) override; + + // 将面Solid转化为体Solid(原始面组必须能构成单个完整体,不能多面,也不能缺面) + virtual BOOL createBodyByFaces(CPmSolid *& pSolid) override; \ No newline at end of file