圆圈是否相交

时间:2014-03-30 21:33:07

标签: c++ arrays algorithm loops

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

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

提前谢谢你!

3 个答案:

答案 0 :(得分: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;
    }

}

答案 1 :(得分:1)

这个怎么样:

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

答案 2 :(得分:1)

我倾向于像这样接近它。首先是创建一个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