Browse Source

2D PMC for polyline

master
gjj 1 year ago
parent
commit
55407ee6e4
  1. 4
      include/common.hpp
  2. 2
      include/line.hpp
  3. 115
      include/solid.hpp
  4. 28
      require.md

4
include/common.hpp

@ -5,3 +5,7 @@ enum PtBoundaryRelation {
OnBoundary, OnBoundary,
Outside = -1 Outside = -1
}; };
bool isEqual(double a, double b) {
// TODO
return a == b; }

2
include/line.hpp

@ -99,8 +99,6 @@ public:
circularArcs[i].h = ABHalf.norm() * std::tan(theta * 0.5); circularArcs[i].h = ABHalf.norm() * std::tan(theta * 0.5);
circularArcs[i].center = A + ABHalf + QONorm * circularArcs[i].h; circularArcs[i].center = A + ABHalf + QONorm * circularArcs[i].h;
circularArcs[i].theta = theta; circularArcs[i].theta = theta;
Vec3 a;
a = ABHalf.cross(QONorm);
circularArcs[i].radius = (circularArcs[i].center - A).norm(); circularArcs[i].radius = (circularArcs[i].center - A).norm();
circularArcs[i].u = (A - circularArcs[i].center).normalize(); circularArcs[i].u = (A - circularArcs[i].center).normalize();
circularArcs[i].v = ABNorm.cross(circularArcs[i].u); circularArcs[i].v = ABNorm.cross(circularArcs[i].u);

115
include/solid.hpp

@ -30,18 +30,18 @@ public:
/** /**
* calculate winding number of a point w.r.t. a segment ab * 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) { real unsignedWindingNumberSegment(const Vec3 &p, const Vec3 &a, const Vec3 &b, const Vec3 &refNormal) {
Vec3 pa = a - p; Vec3 pa = a - p;
Vec3 pb = b - p; Vec3 pb = b - p;
real wn = std::acos(std::clamp(pa.dot(pb) / (pa.norm() * pb.norm()), static_cast<real>(-1.), return std::acos(std::clamp(pa.dot(pb) / (pa.norm() * pb.norm()), static_cast<real>(-1.),
static_cast<real>(1.))); static_cast<real>(1.))) / (std::numbers::pi * 2);
return wn * (refNormal.dot(pa.cross(pb)) > 0 ? 1 : -1);
} }
class ExtrudedSolidPolyline : public IExtrudedSolid { class ExtrudedSolidPolyline : public IExtrudedSolid {
private: private:
Polyline _axis; Polyline _axis;
Pt2Array _localProfile2D; Pt2Array _localProfile2D;
Pt2Array _localCircleCenter2D;
public: public:
ExtrudedSolidPolyline(Polyline profile, Polyline axis, real rScale) : IExtrudedSolid(std::move(profile), rScale), ExtrudedSolidPolyline(Polyline profile, Polyline axis, real rScale) : IExtrudedSolid(std::move(profile), rScale),
@ -52,13 +52,9 @@ public:
Vec3 N = _axis.der2(0).normalize(); Vec3 N = _axis.der2(0).normalize();
Vec3 B = T.cross(N); Vec3 B = T.cross(N);
Vec3 Q = _axis.eval(0); Vec3 Q = _axis.eval(0);
for (const auto &P: _profile.getPoints()) { for (int i = 0; i < _profile.getPoints().size(); ++i) {
Vec3 QP = P - Q; _localProfile2D.emplace_back(get2DRepOf3DPt(_profile.getPoints()[i] - Q, N, B, Q));
auto uv = get2DRepOf3DPt(QP, N, B, Q); _localCircleCenter2D.emplace_back(get2DRepOf3DPt(_profile.getCircularArcs()[i].center - Q, N, B, Q));
// test it
{
}
_localProfile2D.emplace_back(uv.u(), uv.v());
} }
} }
@ -80,18 +76,103 @@ public:
} }
return 0; return 0;
} }
private: private:
real wnCircularArc(const Vec3& p, const Vec3& a, const Vec3& b, const Vec3& refNormal, const Polyline::CircularArc& arc) { /**
* in + in = out
* in + out = in
* out + in = in
* out + out = out
*/
bool isInside2DPolyline(const Polyline& outline, const Vec3& p3D, const Vec2& p2D) {
assert(outline.isClosed());
int intersectionCount = 0, segCount = outline.getBugles().size();
int onSegIdx = -1;
constexpr int numRays = 3; // 射线数量
int majorityIn = 0; // 在多边形内的射线计数
int majorityOut = 0; // 在多边形外的射线计数
for (int rayIdx = 0; rayIdx < numRays && onSegIdx == -1; ++rayIdx) {
double angle = (2.0 * std::numbers::pi * 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];
if (isPointOnSegment(p2D, a, b)) {
onSegIdx = i;
break;
}
// 使用向量方法计算射线和边的交点
double dx1 = b[0] - a[0];
double dy1 = b[1] - a[1];
double dx2 = rayDir[0];
double dy2 = rayDir[1];
double determinant = dx1 * dy2 - dy1 * dx2;
// 如果determinant为0,则射线和边平行,不计算交点
if (isEqual(determinant, 0)) continue;
double t1 = ((p2D[0] - a[0]) * dy2 - (p2D[1] - a[1]) * dx2) / determinant;
double t2 = ((p2D[0] - a[0]) * dy1 - (p2D[1] - a[1]) * dx1) / determinant;
// 检查交点是否在边上(0 <= t1 <= 1)且射线上(t2 >= 0)
if (t1 >= 0 && t1 <= 1 && t2 >= 0) {
crossings++;
}
}
if (crossings % 2 == 0) {
majorityOut++;
} else {
majorityIn++;
}
}
// 判断是否在扇内
bool inFan = false;
for (int i = 0; i < segCount; ++i) {
const Vec2& a = _localProfile2D[i];
const Vec2& b = _localProfile2D[(i + 1) % segCount];
real po = (p2D - _localCircleCenter2D[i]).norm();
if (po == _profile.getCircularArcs()[i].radius) {
// TODO
}
if ((po < _profile.getCircularArcs()[i].radius) {
if ((p2D - a).dot(b - a) > 0) {
inFan = true;
break;
}
}
}
}
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)) 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]) &&
p[1] >= std::min(a[1], b[1]) && p[1] <= std::max(a[1], b[1]));
}
real wnCircularArc(const Vec3 &p, const Vec3 &a, const Vec3 &b, const Vec3 &plgNormal,
const Polyline::CircularArc &arc, int dir) {
Vec3 pa = a - p; Vec3 pa = a - p;
Vec3 pb = b - p; Vec3 pb = b - p;
real wn = std::acos(std::clamp(pa.dot(pb) / (pa.norm() * pb.norm()), static_cast<real>(-1.), real wn = std::acos(std::clamp(pa.dot(pb) / (pa.norm() * pb.norm()), static_cast<real>(-1.),
static_cast<real>(1.))); static_cast<real>(1.))) / (std::numbers::pi * 2);
real dir = refNormal.dot(pb.cross(pa)) > 0 ? 1 : -1; // 注意这里是pb x pa, 不是pa x pb
auto inOutCircle = arc.inCircleCheck(p); auto inOutCircle = arc.inCircleCheck(p);
if (inOutCircle == OnBoundary) { if (inOutCircle == PtBoundaryRelation::Outside || pa.cross(pb).dot(plgNormal) < 0) {
// TODO // outside
// pa.cross(pb).dot(plgNormal) 不会 == 0
return -wn * dir;
} }
return (inOutCircle - wn) * dir; if (inOutCircle == PtBoundaryRelation::Inside) {
return wn * dir;
}
return 0;
} }
}; };

28
require.md

@ -0,0 +1,28 @@
```C++
/**
* @brief 带洞截面沿路径拉伸
* @note :
* @param : 截面必须共面,数组首个元素必须为外包,其余元素为内部洞;拉伸路径可以闭合
* @return:
* @author: csl
* @date : [11/7/2022]
*/
virtual CPmSolid * extrudeAlongPath(const CArray<PmDbPolyline *> & polys,
PmDbPolyline * path) override;
```
```C++
/**
* @brief 带洞截面拉伸
* @note :
* @param : 数组首个元素必须为外包,其余元素为内部洞
* @return:
* @author: csl
* @date : [11/7/2022]
*/
virtual CPmSolid * extrude(const CArray<PmDbPolyline *> & polys,
const PMSoft::CPMGePoint3D &fixedPt, // ?
const PMSoft::CPMGeVector3D &plgNormal,
const PMSoft::CPMGeVector3D &extusionVector, // ? 没有路径吗
double scaleFactor = 1.0,
double twistAngle = 0.0) override;
```
Loading…
Cancel
Save