#pragma once #include "clipper2/clipper.h" using namespace Clipper2Lib; class PointInPolygonTester { private: // 将 double 坐标转换为 int64_t(Clipper2 使用整数坐标) Point64 toPoint64(double x, double y, double scale = 100.0) { return Point64( static_cast(x * scale), static_cast(y * scale) ); } public: BOOL isPointInCurvePath(double x, double y, Clipper2Lib::Path64& curvePath, int scale = 100); // 方法1:判断单个点 void getPolygonPath(CCurve& curve, Clipper2Lib::Path64& curvePath, int scale = 100); bool isPointInPolygon(double x, double y, const std::vector>& polygon); // 方法2:判断点是否在多边形内或边界上 PointInPolygonResult detailedPointTest(double x, double y, const std::vector>& polygon); // 方法3:批量判断点 std::vector batchTestPoints(const std::vector>& points, const std::vector>& polygon); // 方法4:带孔的多边形判断 bool isPointInPolygonWithHoles(double x, double y, const std::vector>& outerPolygon, const std::vector>>& holes); // 方法5:使用 PolyTree 进行复杂判断 bool isPointInComplexPolygon(double x, double y, const Paths64& polygons); //enum class PointInPolygonResult { // Inside, // Outside, // OnBoundary //}; }; /*一些网上ai生成的算法测试,不太好用*/ typedef struct _tPoint2D { double x0, y0; _tPoint2D() : x0(0), y0(0) {} _tPoint2D(double x_, double y_) : x0(x_), y0(y_) {} _tPoint2D operator+(const _tPoint2D& other) const { return _tPoint2D(x0 + other.x0, y0 + other.y0); } _tPoint2D operator-(const _tPoint2D& other) const { return _tPoint2D(x0 - other.x0, y0 - other.y0); } _tPoint2D operator*(double scalar) const { return _tPoint2D(x0 * scalar, y0 * scalar); } double length() const { return std::sqrt(x0 * x0 + y0 * y0); } _tPoint2D normalize() const { double len = length(); if (len == 0) return _tPoint2D(0, 0); return _tPoint2D(x0 / len, y0 / len); } // 为了方便输出 void print() const { std::cout << "(" << x0 << ", " << y0 << ")"; } } tPoint2D; class ParallelPolylineGenerator //这个不好用 { public: // 连接类型枚举 enum class JoinType { MITER, // 斜接连接 ROUND, // 圆角连接 BEVEL // 斜角连接(平头) }; // 端点类型枚举 enum class EndType { BUTT, // 平头端点 SQUARE, // 方形端点 ROUND // 圆角端点 }; private: // 计算点到直线的垂直向量 tPoint2D perpendicularVector(const tPoint2D& p1, const tPoint2D& p2, double distance) { tPoint2D dir = p2 - p1; double len = dir.length(); if (len == 0) return tPoint2D(0, 0); // 垂直向量(旋转90度) tPoint2D perp = tPoint2D(-dir.y0, dir.x0); perp = perp.normalize(); return perp * distance; } // 计算两条直线的交点 bool lineIntersection(const tPoint2D& p1, const tPoint2D& p2, const tPoint2D& p3, const tPoint2D& p4, tPoint2D& result) { double denom = (p4.y0 - p3.y0) * (p2.x0 - p1.x0) - (p4.x0 - p3.x0) * (p2.y0 - p1.y0); if (std::abs(denom) < 1e-10) return false; double ua = ((p4.x0 - p3.x0) * (p1.y0 - p3.y0) - (p4.y0 - p3.y0) * (p1.x0 - p3.x0)) / denom; result.x0 = p1.x0 + ua * (p2.x0 - p1.x0); result.y0 = p1.y0 + ua * (p2.y0 - p1.y0); return true; } // 计算向量夹角(0-180度) double angleBetweenVectors(const tPoint2D& v1, const tPoint2D& v2) { double dot = v1.x0 * v2.x0 + v1.y0 * v2.y0; double len1 = v1.length(); double len2 = v2.length(); if (len1 == 0 || len2 == 0) return 0; double cosAngle = dot / (len1 * len2); cosAngle = max(-1.0, min(1.0, cosAngle)); return std::acos(cosAngle) * 180.0 / PI; } // 计算折线在顶点处的夹角 double calculateAngle(const tPoint2D& prev, const tPoint2D& curr, const tPoint2D& next) { tPoint2D v1 = prev - curr; tPoint2D v2 = next - curr; return angleBetweenVectors(v1, v2); } // 生成圆弧点 std::vector generateArcPoints(const tPoint2D& center, double radius, double startAngle, double endAngle, int segments = 8) { std::vector points; // 确保角度递增 if (endAngle < startAngle) { endAngle += 2 * PI; } double angleStep = (endAngle - startAngle) / segments; for (int i = 1; i < segments; i++) { double angle = startAngle + angleStep * i; double x = center.x0 + std::cos(angle) * radius; double y = center.y0 + std::sin(angle) * radius; points.push_back(tPoint2D(x, y)); } return points; } // 检查线段是否相交 bool segmentsIntersect(const tPoint2D& p1, const tPoint2D& p2, const tPoint2D& p3, const tPoint2D& p4) { auto orientation = [](const tPoint2D& p, const tPoint2D& q, const tPoint2D& r) -> double { return (q.y0 - p.y0) * (r.x0 - q.x0) - (q.x0 - p.x0) * (r.y0 - q.y0); }; auto onSegment = [](const tPoint2D& p, const tPoint2D& q, const tPoint2D& r) -> bool { return q.x0 <= max(p.x0, r.x0) && q.x0 >= min(p.x0, r.x0) && q.y0 <= max(p.y0, r.y0) && q.y0 >= min(p.y0, r.y0); }; double o1 = orientation(p1, p2, p3); double o2 = orientation(p1, p2, p4); double o3 = orientation(p3, p4, p1); double o4 = orientation(p3, p4, p2); // 一般情况 if (o1 * o2 < 0 && o3 * o4 < 0) return true; // 特殊情况:共线 if (o1 == 0 && onSegment(p1, p3, p2)) return true; if (o2 == 0 && onSegment(p1, p4, p2)) return true; if (o3 == 0 && onSegment(p3, p1, p4)) return true; if (o4 == 0 && onSegment(p3, p2, p4)) return true; return false; } // 检查路径是否自相交 bool checkSelfIntersection(const std::vector& path) { if (path.size() < 4) return false; for (size_t i = 0; i < path.size() - 3; i++) { for (size_t j = i + 2; j < path.size() - 1; j++) { if (segmentsIntersect(path[i], path[i + 1], path[j], path[j + 1])) { return true; } } } return false; } // 修复自相交 std::vector fixSelfIntersection(const std::vector& original, const std::vector& parallel, double distance, JoinType joinType, double miterLimit) { std::vector fixedPath; if (parallel.size() < 2) return parallel; // 保留第一个点 fixedPath.push_back(parallel[0]); // 重新计算连接点,对于锐角使用斜角连接 for (size_t i = 1; i < original.size() - 1; i++) { tPoint2D prev = original[i - 1]; tPoint2D curr = original[i]; tPoint2D next = original[i + 1]; double angle = calculateAngle(prev, curr, next); // 计算偏移点 tPoint2D offsetPrev = curr + perpendicularVector(curr, prev, -distance); tPoint2D offsetNext = curr + perpendicularVector(curr, next, distance); if (angle < 90.0) { // 锐角:强制使用斜角连接 fixedPath.push_back(offsetPrev); fixedPath.push_back(offsetNext); } else { // 钝角或直角:根据连接类型处理 tPoint2D miterPoint; if (lineIntersection(offsetPrev, offsetPrev + (prev - curr), offsetNext, offsetNext + (next - curr), miterPoint)) { // 检查斜接长度 double miterLength = (miterPoint - curr).length(); double miterRatio = miterLength / std::abs(distance); if (joinType == JoinType::MITER && miterRatio <= miterLimit) { fixedPath.push_back(miterPoint); } else { fixedPath.push_back(offsetPrev); fixedPath.push_back(offsetNext); } } else { fixedPath.push_back(offsetPrev); fixedPath.push_back(offsetNext); } } } // 添加最后一个点 fixedPath.push_back(parallel.back()); return fixedPath; } public: // 生成平行折线的主函数 std::vector createParallelPolyline(const std::vector& original, double distance, JoinType joinType = JoinType::MITER, EndType endType = EndType::BUTT, double miterLimit = 2.0, int roundSegments = 8) { if (original.size() < 2) return {}; std::vector parallel; size_t n = original.size(); // 1. 生成所有偏移点 std::vector offsetPoints(n); // 第一个点 if (n > 1) { tPoint2D dir = original[1] - original[0]; dir = dir.normalize(); tPoint2D perp = tPoint2D(-dir.y0, dir.x0); offsetPoints[0] = original[0] + perp * distance; } // 中间点 for (size_t i = 1; i < n - 1; i++) { tPoint2D prevDir = (original[i - 1] - original[i]).normalize(); tPoint2D nextDir = (original[i + 1] - original[i]).normalize(); tPoint2D perpPrev = tPoint2D(-prevDir.y0, prevDir.x0); tPoint2D perpNext = tPoint2D(-nextDir.y0, nextDir.x0); // 平均垂直向量 tPoint2D perpAvg = (perpPrev + perpNext).normalize(); offsetPoints[i] = original[i] + perpAvg * distance; } // 最后一个点 if (n > 1) { tPoint2D dir = original[n - 1] - original[n - 2]; dir = dir.normalize(); tPoint2D perp = tPoint2D(-dir.y0, dir.x0); offsetPoints[n - 1] = original[n - 1] + perp * distance; } // 2. 处理端点 if (endType == EndType::BUTT) { parallel.push_back(offsetPoints[0]); } else if (endType == EndType::SQUARE) { // 方形端点:延长半个距离 if (n > 1) { tPoint2D dir = original[0] - original[1]; dir = dir.normalize() * std::abs(distance) * 0.5; parallel.push_back(offsetPoints[0] + dir); } } else if (endType == EndType::ROUND) { // 圆角端点:添加圆弧 parallel.push_back(offsetPoints[0]); if (n > 1) { tPoint2D dir = (original[1] - original[0]).normalize(); double startAngle = std::atan2(dir.y0, dir.x0) + PI/2; double endAngle = startAngle + PI/2; auto arcPoints = generateArcPoints(original[0], std::abs(distance), startAngle, endAngle, roundSegments); parallel.insert(parallel.end(), arcPoints.begin(), arcPoints.end()); } } // 3. 处理连接点 for (size_t i = 1; i < n - 1; i++) { double angle = calculateAngle(original[i - 1], original[i], original[i + 1]); // 计算两个偏移方向 tPoint2D perpPrev = perpendicularVector(original[i], original[i - 1], distance); tPoint2D perpNext = perpendicularVector(original[i], original[i + 1], distance); tPoint2D offsetPrev = original[i] + perpPrev; tPoint2D offsetNext = original[i] + perpNext; if (joinType == JoinType::BEVEL || angle < 45.0) { // 斜角连接或锐角:直接连接 parallel.push_back(offsetPrev); parallel.push_back(offsetNext); } else if (joinType == JoinType::MITER) { // 计算斜接点 tPoint2D miterPoint; if (lineIntersection(offsetPrev, offsetPrev + (original[i - 1] - original[i]), offsetNext, offsetNext + (original[i + 1] - original[i]), miterPoint)) { // 检查斜接限制 double miterLength = (miterPoint - original[i]).length(); double miterRatio = miterLength / std::abs(distance); if (miterRatio <= miterLimit) { parallel.push_back(miterPoint); } else { // 超过限制,使用斜角连接 parallel.push_back(offsetPrev); parallel.push_back(offsetNext); } } else { parallel.push_back(offsetPrev); parallel.push_back(offsetNext); } } else if (joinType == JoinType::ROUND) { // 圆角连接 parallel.push_back(offsetPrev); if (angle < 180.0 && std::abs(distance) > 0) { // 计算圆弧 tPoint2D center = original[i]; double radius = std::abs(distance); tPoint2D dir1 = (original[i - 1] - original[i]).normalize(); tPoint2D dir2 = (original[i + 1] - original[i]).normalize(); double startAngle = std::atan2(dir1.y0, dir1.x0) + PI/2; double endAngle = std::atan2(dir2.y0, dir2.x0) + PI/2; // 根据角度调整分段数 int segments = max(3, static_cast(angle / 30.0)); segments = min(segments, roundSegments); auto arcPoints = generateArcPoints(center, radius, startAngle, endAngle, segments); parallel.insert(parallel.end(), arcPoints.begin(), arcPoints.end()); } parallel.push_back(offsetNext); } } // 4. 处理最后一个点之前的连接 if (n > 1) { parallel.push_back(offsetPoints[n - 2]); } // 5. 处理终点 if (endType == EndType::BUTT) { parallel.push_back(offsetPoints[n - 1]); } else if (endType == EndType::SQUARE) { parallel.push_back(offsetPoints[n - 1]); if (n > 1) { tPoint2D dir = original[n - 1] - original[n - 2]; dir = dir.normalize() * std::abs(distance) * 0.5; parallel.push_back(offsetPoints[n - 1] + dir); } } else if (endType == EndType::ROUND) { parallel.push_back(offsetPoints[n - 1]); } // 6. 检查并修复自相交 if (checkSelfIntersection(parallel)) { std::cout << "Warning: Self-intersection detected, applying fix..." << std::endl; parallel = fixSelfIntersection(original, parallel, distance, joinType, miterLimit); } return parallel; } // 打印点集 //void printPoints(const std::vector& points, const std::string& name) { // std::cout << "\n" << name << " (" << points.size() << " points):" << std::endl; // for (size_t i = 0; i < points.size(); i++) { // std::cout << " " << i << ": (" << points[i].x0 << ", " << points[i].y0 << ")" << std::endl; // } //} // 生成平行折线(简化接口) std::vector createParallel(const std::vector& original, double distance, bool miterJoin = true, bool roundEnds = false) { JoinType joinType = miterJoin ? JoinType::MITER : JoinType::BEVEL; EndType endType = roundEnds ? EndType::ROUND : EndType::BUTT; return createParallelPolyline(original, distance, joinType, endType, 2.0, 8); } }; extern AFX_EXT_API void makeCurveParallelSimple(CCurve& inCurve, double offset, CCurveEx& outCurve); extern AFX_EXT_API void makeCurveParallel(CCurve& inCurve, double offset, CCurveEx& outCurve); extern AFX_EXT_API void offsetCurveWithClipper3(CCurve& inCurve, double offset, CCurveEx& outCurve);//不好用 extern AFX_EXT_API void offsetCurveWithClipper2(CCurve& inCurve, double offset, CCurveEx& outCurve); //不好用