【问题标题】:whether circles intersect or not圆是否相交
【发布时间】:2014-03-30 21:33:07
【问题描述】:

我有一个矩阵,如下所示:

0 0 1
0 0 2
0 2 1.5

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

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

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

 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+)

提前谢谢你!

【问题讨论】:

  • 那么你需要一个嵌套循环。只需与每一对圆相交。还是太慢了?
  • 你想要像for( int i = 0; i &lt; n; i++ ) { for( int j = i + 1; j &lt; n; j++ ) { test if circle i and circle j intersect } }这样的东西
  • 您还应该检查半径的差异是否小于中心之间的距离。如果差值大于距离,则循环嵌套。
  • @Salixalba,是的,但我需要计算 dis_x、dis_y 等等……我该怎么做? *(matrix + ?*3 + 0) - *(matrix + ?*3 + 0) 中会有什么?谢谢!
  • @KonstantinRasskazov 这是一种奇怪的做法。通常您会将matrix 定义为二维数组:int matrix[n][3]。然后就是dis_x = fabs(matrix[i][0] - matrix[j][0]) 等等。

标签: c++ arrays algorithm loops


【解决方案1】:
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;
    }

}

【讨论】:

  • 您已经忘记了一个圆圈大部分位于另一个圆圈内的情况。见stackoverflow.com/questions/8367512/…
  • 你需要比较abs(r1 - r2)r1 + r2之间的中心距离。
  • 感谢您接受我的回答。我必须说其他答案更好,类或结构将使进一步的工作更好。
【解决方案2】:

这个怎么样:

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 %d\n", result[i].first, result[i].second);
}

执行 test() 的输出是:

1 3
2 3

【讨论】:

    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多