bool Triangle::IntersectCylinder(const Point& c0, const Point& c1, const double radius) const { // check intersection with the edges if(SegmentSegmentDistance(p0, p1, c0, c1) < radius) return true; if(SegmentSegmentDistance(p1, p2, c0, c1) < radius) return true; if(SegmentSegmentDistance(p2, p1, c0, c1) < radius) return true; // check intersection with the inner Point n = ((p0-p1)^(p0-p2)).Normalize(); Point intersect; double origin = n|p0; double nC0 = (n|c0) - origin; double nC1 = (n|c1) - origin; if(nC0*nC1 > 0) { if(abs(nC0) < abs(nC1)) { if(abs(nC0) > radius) return false; intersect = c0 - n*nC0; } else { if(abs(nC1) > radius) return false; intersect = c1 - n*nC1; } } else { Point dir = c1 - c0; intersect = c0 + (nC0/(dir|n))*dir.Normalize(); } return IntersectPoint(intersect); }
bool CPolygonBinaryOp(const CPolygon2D &poly1, const CPolygon2D &poly2, CBinaryOp op, std::vector<CPolygon2D> &rpolys) { int n1 = poly1.getNumPoints(); int n2 = poly2.getNumPoints(); if (n1 < 3 || n2 < 3) return false; //------ // build list of node points for first polygon NodePointArray points1; NodePointMap pointMap1; { // find first point of poly1 not inside poly2 int ii = 0; for ( ; ii < n1; ++ii) { const CPoint2D &p = poly1.getPoint(ii); if (! poly2.insideEvenOdd(p)) break; } // if all inside then we are done if (ii >= n1) { if (op == CBINARY_OP_OR) rpolys.push_back(poly1); else if (op == CBINARY_OP_AND) rpolys.push_back(poly1); return true; } //---- bool inside1 = false; bool inside2 = inside1; int np = 0; for (int i = 0, i1 = ii, i2 = i1 + 1; i < n1; ++i, i1 = i2++, inside1 = inside2) { FIX_IND(i2, n1); const CPoint2D &p1 = poly1.getPoint(i1); const CPoint2D &p2 = poly1.getPoint(i2); inside2 = poly2.insideEvenOdd(p2); // find intersection points of this edge with other polygon's edges std::vector<IntersectPoint> idata; for (int j1 = n2 - 1, j2 = 0; j2 < n2; j1 = j2++) { // calc intersection (if any) const CPoint2D &p21 = poly2.getPoint(j1); const CPoint2D &p22 = poly2.getPoint(j2); CPoint2D pi; double mu1, mu2; if (! CMathGeom2D::IntersectLine(p1, p2, p21, p22, &pi, &mu1, &mu2)) continue; if (mu1 <= 0.0 || mu1 >= 1.0 || mu2 <= 0.0 || mu2 >= 1.0) continue; // save intersection data int id = CALC_ID(i1, j1, n1); idata.push_back(IntersectPoint(mu1, pi, id)); } // sort multiple intersects by mu1 std::sort(idata.begin(), idata.end()); // add intersect points uint n = idata.size(); for (uint k = 0; k < n; ++k) { NodePoint *np1 = new NodePoint(NodePoint::INTERSECT, np++, idata[k].id, idata[k].p); points1.push_back(np1); pointMap1[idata[k].id] = np1; } // add end of line NodePoint *np1 = new NodePoint((inside2 ? NodePoint::INSIDE : NodePoint::OUTSIDE), np++, 0, p2); points1.push_back(np1); } } //----- // build list of node points for second polygon NodePointArray points2; NodePointMap pointMap2; { // find first point of poly2 not inside poly1 int ii = 0; for ( ; ii < n1; ++ii) { const CPoint2D &p = poly2.getPoint(ii); if (! poly1.insideEvenOdd(p)) break; } // if all inside then we are done if (ii >= n1) { if (op == CBINARY_OP_OR) rpolys.push_back(poly2); else if (op == CBINARY_OP_AND) rpolys.push_back(poly2); return true; } //---- bool inside1 = false; bool inside2 = inside1; int np = 0; for (int i = 0, i1 = ii, i2 = i1 + 1; i < n2; ++i, i1 = i2++, inside1 = inside2) { FIX_IND(i2, n2); const CPoint2D &p1 = poly2.getPoint(i1); const CPoint2D &p2 = poly2.getPoint(i2); inside2 = poly1.insideEvenOdd(p2); // find intersection points of this edge with other polygon's edges std::vector<IntersectPoint> idata; for (int j1 = n1 - 1, j2 = 0; j2 < n1; j1 = j2++) { int id = CALC_ID(j1, i1, n1); // skip if no intersection (faster ?) NodePointMap::const_iterator p = pointMap1.find(id); if (p == pointMap1.end()) continue; // calc intersection const CPoint2D &p21 = poly1.getPoint(j1); const CPoint2D &p22 = poly1.getPoint(j2); CPoint2D pi; double mu1, mu2; bool rc = CMathGeom2D::IntersectLine(p1, p2, p21, p22, &pi, &mu1, &mu2); assert(rc && mu1 > 0.0 && mu1 < 1.0 && mu2 > 0.0 && mu2 < 1.0); idata.push_back(IntersectPoint(mu1, pi, id)); } // sort multiple intersects by mu1 std::sort(idata.begin(), idata.end()); // add intersect points uint n = idata.size(); for (uint k = 0; k < n; ++k) { NodePoint *np1 = new NodePoint(NodePoint::INTERSECT, np++, idata[k].id, idata[k].p); points2.push_back(np1); pointMap2[idata[k].id] = np1; } // add end of line NodePoint *np1 = new NodePoint((inside2 ? NodePoint::INSIDE : NodePoint::OUTSIDE), np++, 0, p2); points2.push_back(np1); } } //----- // Connect Intersections between shapes assert(pointMap1.size() == pointMap2.size()); NodePointMap::iterator pm1, pm2; for (pm1 = pointMap1.begin(), pm2 = pointMap1.end(); pm1 != pm2; ++pm1) { NodePoint *np1 = (*pm1).second; NodePointMap::iterator pm = pointMap2.find(np1->id); assert(pm != pointMap2.end()); NodePoint *np2 = (*pm).second; np1->ip = np2; np2->ip = np1; } //----- // build list of points for boolean op if (op == CBINARY_OP_OR) { CPolygon2D rpoly; while (CPolygonOrOp(points1, points2, rpoly)) rpolys.push_back(rpoly); } else if (op == CBINARY_OP_AND) { CPolygon2D rpoly; while (CPolygonAndOp(points1, points2, rpoly)) rpolys.push_back(rpoly); } else if (op == CBINARY_OP_XOR) { CPolygon2D rpoly; while (CPolygonXorOp(points1, points2, rpoly)) rpolys.push_back(rpoly); } else if (op == CBINARY_OP_NOT) { CPolygon2D rpoly; while (CPolygonXorOp(points2, points1, rpoly)) rpolys.push_back(rpoly); } return true; }