圆是否相交

whether circles intersect or not

本文关键字:是否      更新时间:2023-10-16

我有一个矩阵,看起来像这样:

0 0 1
0 0 2
0 2 1.5

表示圆的(X, Y, R)(首先是圆心,其次是半径)

这个矩阵是动态创建的,所以它可以有你想要的所有大小,只要输入它的1。

我需要找出这些圆是否相交,我这样做:

 for( int i = 0; i < n; i++ ) {
    dis_x = fabs(*(matrix + (i+1) * 3 + 0) - *(matrix + i * 3 + 0));
    dis_y = fabs(*(matrix + (i+1) * 3 + 1) - *(matrix + i * 3 + 1));
    hypotenuse = sqrt( pow(dis_x,2) + pow(dis_y,2) );
    radius_i = *(matrix + i * 3 + 2);
    radius_i_plus_1 = *(matrix + (i+1) * 3 + 2);
    sum_of_radius = radius_i_plus_1 + radius_i;
    if( sum_of_radius >= hypotenuse && hypotenuse != 0) {
        *(array_of_numbers_of_circles + i * 2 + 0) = i + 1;
        *(array_of_numbers_of_circles + i * 2 + 1) = i + 2;
    }
}

如果我用上面的例子,我将看到:2 3

但是我需要:

1 3
2 3

换句话说,我需要比较所有元素,包括第一个元素与最后一个元素(如果大小为3)和所有元素:第二个元素与第四个元素(如果大小为4+)

提前感谢!

count = 0;
for( int i = 0; i < n-1; i++ ) {
  for( int j= i + 1;  j < n ; j++) {
    dis_x = *(matrix + j * 3 + 0) - *(matrix + i * 3 + 0); // no need for fabs
    dis_y = *(matrix + j * 3 + 1) - *(matrix + i * 3 + 1);
    // use squared form, use multiplication rather than pow
    hypSquared = dis_x * dis_x + dis_y * dis_y; 
    radius_i = *(matrix + i * 3 + 2);
    radius_j = *(matrix + j * 3 + 2);
    sum_of_radius = radius_i + radius_j;
    diff_of_radius = radius_i - radius_j;
    // compare square of radius to the square of hyp. Eliminates call to sqrt()
    if( sum_of_radius * sum_of_radius >= hypSquared
     && diff_of_radius * diff_of_radius < hypSquared  ) {
        *(array_of_numbers_of_circles + count * 2 + 0) = i + 1;
        *(array_of_numbers_of_circles + count * 2 + 1) = j + 2;
        ++count;
    }
}

这个怎么样:

struct circle
{
    double x, y, r;
    bool empty() { return x==0.0 && y==0.0 && r==0.0; }
};
circle matrix[] = {
    {0, 0, 1},
    {0, 0, 2},
    {0, 2, 1.5},
    {0,0,0}  // end marker
};
bool intersect(circle &c1, circle &c2)
{
    double dx = c2.x - c1.x;
    double dy = c2.y - c1.y;
    double dist = sqrt(dx*dx + dy*dy);
    double sumRad = c2.r + c1.r;
    bool yes = false;
    if (sumRad >= dist)
    {
        double minR = c1.r;
        double maxR = c2.r;
        if (minR > maxR) std::swap(minR, maxR);
        if (dist + minR >= maxR || (dist == 0.0 && minR == maxR))
            yes = true;
    }
    return yes;
}
void test()
{
    std::vector<std::pair<int, int>> result;
    for (int i=0; !matrix[i].empty(); i++)
        for (int j=i+1; !matrix[j].empty(); j++)
            if (intersect(matrix[i], matrix[j]))
                result.push_back(std::pair<int, int>(i+1,j+1));
    for (int i =0; i < result.size(); i++)
        printf("%d %dn", result[i].first, result[i].second);
}

执行test()的输出为:

1 3
2 3

我倾向于这样做。首先是创建一个Circle类

class Circle 
{
public:
    friend std::ostream &operator<<(std::ostream &out, const Circle &c) 
        { return out << '(' << c.x << ", " << c.y << ", " << c.r << ')'; };
    friend std::istream &operator>>(std::istream &in, Circle &c) 
        { return in >> c.x >> c.y >> c.r; };
    bool intersects(const Circle &c2) const;
private:
    float x, y, r;
};
bool Circle::intersects(const Circle &c2) const
{
    float dist_squared = (x-c2.x)*(x-c2.x)+(y-c2.y)*(y-c2.y);
    if ((r-c2.r)*(r-c2.r) > dist_squared)
        return false;
    return (r+c2.r)*(r+c2.r) >= dist_squared;
}

注意,这个类包括它自己的流插入器和提取器,以及一个成员函数intersects,它告诉我们是否有两个Circle类实例相交。显然,这里省略了所有的错误检查,但它给出了该技术的本质。

我将在下面的完整程序中展示如何使用它。该程序使用c++ 2011功能,使其相当紧凑,但它们不是使用Circle类所必需的。

#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
#include <algorithm>
//  the above Circle code would go here...
int main()
{
    std::ifstream in("circles.txt");
    std::vector<Circle> circles;
    std::copy(std::istream_iterator<Circle>(in), 
        std::istream_iterator<Circle>(), 
        std::back_inserter(circles));
    for (auto i : circles)
        for (auto j : circles)
            if (i.intersects(j))
                std::cout << i << " intersects " << j << std::endl;
    return 0;
}

如果文件circles.txt是一个包含给定输入的文本文件:

0 0 1
0 0 2
0 2 1.5

输出为:

(0, 0, 1) intersects (0, 0, 1)
(0, 0, 1) intersects (0, 2, 1.5)
(0, 0, 2) intersects (0, 0, 2)
(0, 0, 2) intersects (0, 2, 1.5)
(0, 2, 1.5) intersects (0, 0, 1)
(0, 2, 1.5) intersects (0, 0, 2)
(0, 2, 1.5) intersects (0, 2, 1.5)

注意这个版本报告每个圆与自己相交。技术上是正确的,但可能不是很有用!当然,可以重写驱动程序代码,去掉c++ 11的特性,并提供一些替代形式的输出。一种方法是将以下代码替换为上面代码中嵌套的for循环:

for (int i = 0; i < circles.size(); ++i)
    for (int j = i+1; j < circles.size(); ++j)
        if (circles[i].intersects(circles[j]))
            std::cout << i+1 << " " << j+1 << std::endl;

这样做会产生以下输出:

1 3
2 3