ホーム > libalgo

円がかかわる交差判定・交点

概要

円がかかわる交差判定です.

実装

//@require intersection.cc
std::vector<P> crosspointCL(const C &c, const L &l) {
    std::vector<P> res;
    ld d = distanceLP(l, c.p);      // 中心と直線の距離
    if (std::abs(d - c.r) < eps) {  // 触れている
        res.push_back(projection(l, c.p));
        return res;
    }
    if (d > c.r) return res;  // 離れている
    P h = projection(l, c.p);
    P u = std::sqrt(c.r * c.r - d * d) * (l[1] - l[0]) / std::abs(l[1] - l[0]);
    res.push_back(h + u);
    res.push_back(h - u);
    return res;
}

int intersectCC(const C &c1, const C &c2) {
    ld d = std::abs(c1.p - c2.p), r1 = c1.r, r2 = c2.r;
    if (r1 + r2 < d) return 0;                   // 離れている
    if (std::abs(r1 + r2 - d) < eps) return -2;  // 外接
    if (std::abs(d + r1 - r2) < eps) return +1;  // c1 が c2 の中で内接
    if (std::abs(d + r2 - r1) < eps) return -1;  // c2 が c1 の中で内接
    if (d + r1 < r2) return +3;                  // c1 が c2 の中
    if (d + r2 < r1) return -3;                  // c2 が c1 の中
    return 2;                                    // 2つの交点を持つ
}

std::vector<P> crosspointCC(const C &c1, const C &c2) {
    std::vector<P> res;
    ld r1 = c1.r, r2 = c2.r, d = std::abs(c1.p - c2.p);
    if (std::abs(c1.p - c2.p) < 0) return res;  // 中心が同じ
    int i = intersectCC(c1, c2);
    if (i == +1 || i == -1) {  // 内接
        if (r2 < r1)
            res.push_back(c1.p + r1 / d * (c2.p - c1.p));
        else
            res.push_back(c2.p + r2 / d * (c1.p - c2.p));
        return res;
    }
    if (i == -2) {  // 外接
        res.push_back((c1.p * c1.r + c2.p * c2.r) / (c1.r + c2.r));
        return res;
    }
    if (i == 0 || i == +3 || i == -3) {  // 共通部分なし || 内部
        return res;
    }
    // 2つの交点を持つ
    P p = c1.p - c2.p;
    ld A = -2. * p.real(), B = 2 * p.imag();
    ld C = norm(c1.p) - norm(c2.p) - r1 * r1 + r2 * r2;
    return crosspointCL(c1, L(A, B, C));  // Ax + By + C = 0
}

検証

!!未検証!!