점이 회전 된 사각형 안에 있는지 어떻게 효율적으로 확인합니까?


11

C # 또는 C ++를 사용하여 2D 점이 P2D 회전 사각형 안에 있는지 여부를 가장 효율적으로 확인할 수있는 방법은 XYZW무엇입니까?

현재 내가하고있는 일은 Real Time Collision Detection 책에있는 "point in triangle"알고리즘 을 사용하고 두 번 실행합니다 (사각형을 구성하는 두 개의 삼각형, XYZ 및 XZW).

bool PointInTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
 // Compute vectors        
 Vector2 v0 = C - A;
 Vector2 v1 = B - A;
 Vector2 v2 = P - A;

 // Compute dot products
 float dot00 = Vector2.Dot(v0, v0);
 float dot01 = Vector2.Dot(v0, v1);
 float dot02 = Vector2.Dot(v0, v2);
 float dot11 = Vector2.Dot(v1, v1);
 float dot12 = Vector2.Dot(v1, v2);

 // Compute barycentric coordinates
 float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
 float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
 float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

 // Check if point is in triangle
 if(u >= 0 && v >= 0 && (u + v) < 1)
    { return true; } else { return false; }
}


bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
 if(PointInTriangle(X,Y,Z,P)) return true;
 if(PointInTriangle(X,Z,W,P)) return true;
 return false;
}

그러나 나는 더 깨끗하고 빠른 방법이있을 수 있다고 생각합니다. 특히 수학 연산 수를 줄입니다.


점이 많거나 직사각형이 많습니까? 그런 작은 작업을 최적화하기 전에 스스로에게 물어보아야 할 첫 번째 질문입니다.
sam hocevar

좋은 지적. 나는 매우 많은 수의 포인트를 가지지 만 더 많은 직사각형을 확인할 것입니다.
Louis15

회전 된 사각형에 대한 점의 거리를 찾는 방법에 대한 관련 질문 . 이것은 거리가 0 인 경우에만 확인되는 축퇴입니다. 물론 여기에 적용되지 않는 최적화가있을 것입니다.
Anko

사각형의 참조 프레임으로 점을 회전시키는 것을 고려 했습니까?
Richard Tingle

@RichardTingle 실제로 나는 처음에하지 않았다. 나중에 나는 그것이 아래에 주어진 대답 중 하나와 관련이 있다고 생각하기 때문에 그렇게했습니다. 그러나 명확히하기 위해 : 점을 사각형의 참조 프레임으로 회전시킨 후 max.x, min.x 등의 논리적 비교만으로 포함을 확인해야합니까?
Louis15

답변:


2

쉽고 간단한 최적화는 다음과 같이 최종 조건을 변경하는 것입니다 PointInTriangle.

bool PointInRectangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P) {
  ...
  if(u >= 0 && v >= 0 && u <= 1 && v <= 1)
      { return true; } else { return false; }
  }
}

코드는 PointInRectangle이미 이미 많았 (u + v) < 1으며, 사각형의 "두 번째"삼각형이 아닌지 확인 하는 조건 이있었습니다.

또는 isLeft(페이지의 첫 번째 코드 예제, 크게 설명) 테스트를 4 번 수행하고 모두 동일한 부호 (점이 시계 방향인지 반 시계 방향인지에 따라 다름)로 결과를 반환하는지 확인할 수 있습니다. 안에있을 지점. 이것은 다른 볼록 다각형에도 적용됩니다.

float isLeft( Point P0, Point P1, Point P2 )
{
    return ( (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y) );
}
bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
    return (isLeft(X, Y, P) > 0 && isLeft(Y, Z, P) > 0 && isLeft(Z, W, P) > 0 && isLeft(W, X, p) > 0);
}

훌륭한. 나는 당신의 제안을 더 좋아하는지, 나의 것보다 정말로 빠르고 훨씬 우아하거나, PointInTri 코드가 쉽게 PointInRec가 될 수 있음을 알았다면 더 잘 모르겠습니다! 감사합니다
Louis15

isLeft방법의 경우 +1 삼각대 기능이 필요하지 않으므로 Vector2.Dot속도가 빨라집니다.
Anko

Btw, 주 함수 내에 직접 isLeft를 포함시키고 "&&"연산자를 "||"로 대체하여 코드를 조정할 수 없었습니다 (테스트하지 않았으며이 컴퓨터에 방법이 없음). 역 논리? public static bool PointInRectangle(Vector2 P, Vector2 X, Vector2 Y, Vector2 Z, Vector2 W) { return !(( (Y.x - X.x) * (P.y - X.y) - (P.x - X.x) * (Y.y - X.y) ) < 0 || ( (Z.x - Y.x) * (P.y - Y.y) - (P.x - Y.x) * (Z.y - Y.y) ) < 0 || ( (W.x - Z.x) * (P.y - Z.y) - (P.x - Z.x) * (W.y - Z.y) ) < 0 || ( (X.x - W.x) * (P.y - W.y) - (P.x - W.x) * (X.y - W.y) ) < 0 ); }
Louis15

1
@ Louis15 나는 당신이 &&와 || 하나의 부정적인 / 긍정적 인 것이 발견되면 (또는 다른 이유가 있었으면) 더 이상의 진술 실행을 중단 할 것입니다. isLeft컴파일러를 인라인으로 선언 하면 컴파일러가 비슷한 작업을 수행 할 수 있습니다 (컴파일러를 작성하는 엔지니어가 CPU를 가장 잘 알고 옵션 중 가장 빠른 옵션을 선택하기 때문에 가능할 것입니다).
wondra

8

편집 : OPs 의견은 임의의 2D 점이 회전 및 / 또는 움직이는 사각형 내에 있는지 여부를 확인하기 위해 알고리즘을 개선하기 위해 제안 된 음의 원형 경계 검사의 효율성에 회의적이었습니다. 내 2D 게임 엔진 (OpenGL / C ++)에서 약간의 문제를 해결하면서 OP의 현재 사각형 내 체크 알고리즘 (및 변형)에 대해 알고리즘의 성능 벤치 마크를 제공하여 답변을 보완합니다.

나는 원래 알고리즘을 제자리에 두는 것을 제안했지만 (거의 최적 임), 단순한 게임 논리를 통해 단순화했다 : (1) 원래 사각형 주위에 사전 처리 된 원을 사용; (2) 거리 점검을하고 해당 지점이 해당 원 안에 있는지 확인하십시오. (3) OP 또는 기타 간단한 알고리즘을 사용하십시오 (다른 답변에서 제공하는 isLeft 알고리즘을 권장합니다). 내 제안의 논리는 점이 원 안에 있는지 확인하는 것이 회전 된 사각형이나 다른 다각형의 경계 검사보다 훨씬 효율적이라는 것입니다.

벤치 마크 테스트의 초기 시나리오는 약 20 개의 회전 / 이동 사각형으로 채워지는 제한된 공간에서 많은 수의 나타나고 사라지는 점 (모든 게임 루프에서 위치가 변경되는 점)을 실행하는 것입니다. 설명을 위해 비디오 ( youtube 링크 )를 게시했습니다 . 매개 변수 : 무작위로 나타나는 점의 수, 숫자 또는 사각형을 확인하십시오. 다음 매개 변수를 사용하여 벤치마킹합니다.

OFF : 원 경계 네거티브 검사없이 OP에서 제공하는 간단한 알고리즘

ON : 사각형 주위에서 처리 된 (경계) 원을 첫 번째 제외 확인으로 사용

ON + Stack : 스택 의 루프 내에서 런타임에 원 경계 만들기

ON + 제곱 거리 : 더 비싼 제곱근 알고리즘 (Pieter Geerkens)을 사용하지 않도록 제곱 거리를 추가 최적화로 사용합니다.

다음은 루프를 반복하는 데 걸리는 시간을 보여줌으로써 다양한 알고리즘의 다양한 성능을 요약 입니다.

여기에 이미지 설명을 입력하십시오

x 축은 더 많은 점을 추가하여 루프를 느리게하여 복잡성을 증가시킵니다. (예를 들어, 20 개의 사각형이있는 신뢰할 수있는 공간에서 1000 개의 무작위로 나타나는 점 검사에서 루프는 알고리즘을 20000 번 반복하고 호출합니다.) y 축은 고해상도를 사용하여 전체 루프를 완료하는 데 걸리는 시간 (ms)을 나타냅니다. 성능 타이머. 부드러운 애니메이션을 보간하기 위해 높은 fps를 사용하지 않고 게임이 때때로 '견고한'것처럼 보일 수 있기 때문에 20ms 이상은 괜찮은 게임에 문제가 될 것입니다.

결과 1 : 루프 내에서 빠른 네거티브 검사를 수행하는 사전 처리 된 순환 바운드 알고리즘은 일반 알고리즘 (검사없이 원래 루프 시간의 5 %)에 비해 성능이 1900 % 향상됩니다. 결과는 루프 내 반복 횟수에 대략 비례하므로 10 또는 10000 개의 무작위로 나타나는 점을 검사해도 문제가되지 않습니다. 따라서,이 예시에서, 성능 손실을 느끼지 않으면 서 객체의 수를 안전하게 10k로 증가시킬 수있다.

결과 2 : 알고리즘이 더 빠르지 만 메모리 집약적 일 수 있다고 이전 의견에서 제안했습니다. 그러나 사전 처리 된 원 크기의 부동 소수점을 저장하는 데 4 바이트 만 소요됩니다. OP가 100000+ 개체를 동시에 실행할 계획이 아니라면 실제 문제는 아닙니다. 대안적이고 메모리 효율적인 접근 방식은 루프 내 스택의 원 최대 크기를 계산하여 반복 할 때마다 범위를 벗어나도록하여 속도를 알 수없는 메모리 사용량이 거의없는 것입니다. 실제로 결과는이 방법이 사전 처리 된 원 크기를 사용하는 것보다 실제로 느리다는 것을 보여 주지만 여전히 약 1150 % (즉, 원래 처리 시간의 8 %)의 상당한 성능 향상을 보여줍니다.

결과 3 : 실제 거리 대신 제곱 거리를 사용하여 계산적으로 비싼 제곱근 연산을 수행하여 결과 1 알고리즘을 추가로 개선합니다. 이것은 단지 성능을 엄격하게 향상시킵니다 (2400 %). (참고 : 나는 비슷하지만 약간 더 나쁜 결과를 가진 제곱근 근사에 대해 사전 처리 된 배열에 대한 해시 테이블을 시도합니다)

결과 4 : 사각형의 이동 / 충돌을 추가로 확인합니다. 그러나 논리적 검사는 본질적으로 동일하게 유지되므로 기본 결과 (예상대로)는 변경되지 않습니다.

결과 5 : 사각형의 수를 변경하고 공간이 채워지지 않을수록 알고리즘이 훨씬 효율적으로된다는 것을 알았습니다 (데모에는 표시되지 않음). 원과 물체의 경계 사이의 작은 공간 내에 점이 나타날 확률이 줄어들 기 때문에 결과도 다소 기대됩니다. 다른 극단적 인 경우, 동일한 좁은 공간 내에서 직사각형의 수를 100으로 늘리고 루프 내에서 런타임에 크기를 동적으로 변경하려고합니다 (sin (반복자)). 성능이 570 % (또는 원래 루프 시간의 15 %) 증가해도 여전히 성능이 우수합니다.

결과 6 : 여기에 제안 된 대체 알고리즘을 테스트하고 성능에 약간의 차이가 있지만 크게 차이는 없습니다 (2 %). 흥미롭고 더 간단한 IsLeft 알고리즘은 17 % (원래 계산 시간의 85 %)의 성능 향상으로 매우 잘 수행되지만 빠른 네거티브 체크 알고리즘의 효율성에 거의 미치지 않습니다.

제 요점은 특히 경계와 충돌 이벤트를 다룰 때 린 디자인과 게임 로직을 고려하는 것입니다. OPs 전류 알고리즘은 이미 상당히 효율적이며 추가 최적화는 기본 개념 자체를 최적화하는 것만 큼 중요하지 않습니다. 또한 알고리즘의 효율성이 결정적으로 결정되므로 게임의 범위와 목적을 전달하는 것이 좋습니다.

평범한 코드를 보는 것만으로 실제 런타임 성능에 대한 진실을 밝힐 수 없으므로 게임 디자인 단계에서 복잡한 알고리즘을 벤치마킹하려고 항상 제안합니다. 예를 들어, 마우스 커서가 사각형 안에 있는지 아닌지, 또는 대부분의 객체가 이미 닿았는지 여부를 테스트하려는 경우 제안 된 알고리즘이 필요하지 않을 수도 있습니다. 점 점검의 대부분이 사각형 내에 있으면 알고리즘의 효율성이 떨어집니다. (그러나, 2 차 네거티브 체크로 '내부 원'경계를 설정할 수 있습니다.) 원 / 구 경계 체크는 자연스럽게 그들 사이에 약간의 공간이있는 많은 수의 물체의 적절한 충돌 감지에 매우 유용합니다 .

Rec Points  Iter    OFF     ON     ON_Stack     ON_SqrDist  Ileft Algorithm (Wondra)
            (ms)    (ms)    (ms)    (ms)        (ms)        (ms)
20  10      200     0.29    0.02    0.04        0.02        0.17
20  100     2000    2.23    0.10    0.20        0.09        1.69
20  1000    20000   24.48   1.25    1.99        1.05        16.95
20  10000   200000  243.85  12.54   19.61       10.85       160.58

나는 특이한 접근 방식을 좋아하고 Da Vinci 참조를 좋아했지만 반경을 제외하고는 원을 다루는 것이 그렇게 효율적이라고 생각하지 않습니다. 또한 모든 사각형이 미리 고정되고 알려진 경우에만이 솔루션이 합리적입니다.
Louis15

사각형의 위치는 고정 될 필요가 없습니다. 상대 좌표를 사용하십시오. 이것도 생각하십시오. 회전 여부와 상관없이 반경이 동일하게 유지됩니다.
Majte

이것은 훌륭한 답변입니다. 내가 생각하지 않았기 때문에 더 나은. 실제 거리 대신 제곱 거리를 사용하는 것으로 충분하므로 제곱근을 계산할 필요가 없습니다.
Pieter Geerkens

빠른 양성 / 음성 테스트를위한 흥미로운 알고리즘! 문제는 사전 처리 된 경계 원 (및 너비)을 저장하기위한 추가 메모리 일 수 있으며, 휴리스틱은 좋지만 사용이 제한되어 있습니다. 주로 메모리가 중요하지 않은 경우 (대형 오브젝트의 정적 크기 사각형 = 스프라이트 게임 오브젝트) 전처리 할 시간이 있습니다.
wondra

편집 + 추가 벤치 마크 테스트.
Majte

2

4 개의 점으로 사각형을 정의하면 사다리꼴을 만들 수 있습니다. 그러나 x, y, 너비, 높이 및 중간 주위의 회전으로 정의하는 경우 사각형의 역 회전 (동일한 원점 주위)으로 확인하는 점을 회전 한 다음 확인하십시오. 원래 사각형에서.


흠, 제안에 감사하지만, 회전하고 역 회전하는 것은 그렇게 효율적이지 않습니다. 실제로 그것은 내 솔루션만큼 효과적이지 않을 것입니다-wondra 's는 말할 것도 없습니다
Louis15

행렬을 사용하여 3D 점을 회전시키는 것은 6 곱하기와 3 더하기, 하나의 함수 호출입니다. @wondra의 솔루션은 최상의 수준이지만 의도는 훨씬 명확하지 않습니다. DRY 위반으로 유지 보수 오류에 더 취약합니다.
Pieter Geerkens

@Pieter Geerkens의 주장에 따르면, 내 솔루션 중 어떤 것이 DRY를 위반합니까 (DRY는 주요 프로그래밍 원칙 중 하나입니까? 지금까지 들어 본 적이 없습니다)? 그리고 가장 중요한 것은 해당 솔루션에 어떤 오류가 있습니까? 항상 배울 준비가되었습니다.
wondra

@wondra : DRY = 스스로 반복하지 마십시오. 코드 스 니펫은 표준 행렬 응용 프로그램 대 벡터 방법을 호출하는 대신 기능이 코드에 나타나는 모든 곳에서 벡터 곱셈으로 행렬의 세부 사항을 코딩하는 것을 제안합니다.
Pieter Geerkens

@PieterGeerkens of-course 그것은 그것의 일부만을 제안합니다-1) 당신은 명시 적으로 행렬을 가지고 있지 않습니다 (각 쿼리마다 새로운 행렬을 할당하면 성능이 어려울 것입니다) 2) 나는 특정 경우의 곱셈을 사용합니다. 하나. 낮은 수준의 작동이며 예기치 않은 동작을 방지하기 위해 캡슐화 된 상태로 유지해야합니다.
wondra

1

나는 이것을 벤치마킹 할 시간이 없었지만, 직사각형을 x와 y 범위에서 축 정렬 된 사각형으로 변환하는 변환 행렬을 0에서 1까지 저장하는 것이 좋습니다. 사각형의 한 모서리를 (0,0)으로, 반대쪽 모서리를 (1,1)로 변환합니다.

사각형이 많이 움직이고 충돌이 거의 확인되지 않으면 비용이 많이 들지만, 사각형 업데이트보다 검사가 훨씬 많으면 적어도 두 개의 삼각형에 대한 테스트 방법보다 빠릅니다. 6 개의 내적은 하나의 행렬 곱셈으로 대체되기 때문입니다

그러나 항상이 알고리즘의 속도는 수행 할 검사 종류에 따라 크게 달라집니다. 대부분의 포인트가 간단한 거리 확인 (예 : (point.x-firstCorner.x)> aLargeDistance)을 수행하는 사각형에 가깝지 않은 경우 속도가 크게 증가 할 수 있지만 거의 모든 경우에 속도가 느려질 수 있습니다. 점은 사각형 안에 있습니다.

편집 : 이것은 내 Rectangle 클래스의 모습입니다.

class Rectangle
{
public:
    Matrix3x3 _transform;

    Rectangle()
    {}

    void setCorners(Vector2 p_a, Vector2 p_b, Vector2 p_c)
    {
        // create a matrix from the two edges of the rectangle
        Vector2 edgeX = p_b - p_a;
        Vector2 edgeY = p_c - p_a;

        // and then create the inverse of that matrix because we want to 
        // transform points from world coordinates into "rectangle coordinates".
        float scaling = 1/(edgeX._x*edgeY._y - edgeY._x*edgeX._y);

        _transform._columns[0]._x = scaling * edgeY._y;
        _transform._columns[0]._y = - scaling * edgeX._y;
        _transform._columns[1]._x = - scaling * edgeY._x;
        _transform._columns[1]._y = scaling * edgeX._x;

        // the third column is the translation, which also has to be transformed into "rectangle space"
        _transform._columns[2]._x = -p_a._x * _transform._columns[0]._x - p_a._y * _transform._columns[1]._x;
        _transform._columns[2]._y = -p_a._x * _transform._columns[0]._y - p_a._y * _transform._columns[1]._y;
    }

    bool isInside(Vector2 p_point)
    {
        Vector2 test = _transform.transform(p_point);
        return  (test._x>=0)
                && (test._x<=1)
                && (test._y>=0)
                && (test._y<=1);
    }
};

이것은 내 벤치 마크의 전체 목록입니다.

#include <cstdlib>
#include <math.h>
#include <iostream>

#include <sys/time.h>

using namespace std;

class Vector2
{
public:
    float _x;
    float _y;

    Vector2()
    :_x(0)
    ,_y(0)
    {}

    Vector2(float p_x, float p_y)
        : _x (p_x)
        , _y (p_y)
        {}

    Vector2 operator-(const Vector2& p_other) const
    {
        return Vector2(_x-p_other._x, _y-p_other._y);
    }

    Vector2 operator+(const Vector2& p_other) const
    {
        return Vector2(_x+p_other._x, _y+p_other._y);
    }

    Vector2 operator*(float p_factor) const
    {
        return Vector2(_x*p_factor, _y*p_factor);
    }

    static float Dot(Vector2 p_a, Vector2 p_b)
    {
        return (p_a._x*p_b._x + p_a._y*p_b._y);
    }
};

bool PointInTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
 // Compute vectors        
 Vector2 v0 = C - A;
 Vector2 v1 = B - A;
 Vector2 v2 = P - A;

 // Compute dot products
 float dot00 = Vector2::Dot(v0, v0);
 float dot01 = Vector2::Dot(v0, v1);
 float dot02 = Vector2::Dot(v0, v2);
 float dot11 = Vector2::Dot(v1, v1);
 float dot12 = Vector2::Dot(v1, v2);

 // Compute barycentric coordinates
 float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
 float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
 float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

 // Check if point is in triangle
 if(u >= 0 && v >= 0 && (u + v) < 1)
    { return true; } else { return false; }
}


bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
 if(PointInTriangle(X,Y,Z,P)) return true;
 if(PointInTriangle(X,Z,W,P)) return true;
 return false;
}

class Matrix3x3
{
public:
    Vector2 _columns[3];

    Vector2 transform(Vector2 p_in)
    {
        return _columns[0] * p_in._x + _columns[1] * p_in._y + _columns[2];
    }
};

class Rectangle
{
public:
    Matrix3x3 _transform;

    Rectangle()
    {}

    void setCorners(Vector2 p_a, Vector2 p_b, Vector2 p_c)
    {
        // create a matrix from the two edges of the rectangle
        Vector2 edgeX = p_b - p_a;
        Vector2 edgeY = p_c - p_a;

        // and then create the inverse of that matrix because we want to 
        // transform points from world coordinates into "rectangle coordinates".
        float scaling = 1/(edgeX._x*edgeY._y - edgeY._x*edgeX._y);

        _transform._columns[0]._x = scaling * edgeY._y;
        _transform._columns[0]._y = - scaling * edgeX._y;
        _transform._columns[1]._x = - scaling * edgeY._x;
        _transform._columns[1]._y = scaling * edgeX._x;

        // the third column is the translation, which also has to be transformed into "rectangle space"
        _transform._columns[2]._x = -p_a._x * _transform._columns[0]._x - p_a._y * _transform._columns[1]._x;
        _transform._columns[2]._y = -p_a._x * _transform._columns[0]._y - p_a._y * _transform._columns[1]._y;
    }

    bool isInside(Vector2 p_point)
    {
        Vector2 test = _transform.transform(p_point);
        return  (test._x>=0)
                && (test._x<=1)
                && (test._y>=0)
                && (test._y<=1);
    }
};

void runTest(float& outA, float& outB)
{
    Rectangle r;
    r.setCorners(Vector2(0,0.5), Vector2(0.5,1), Vector2(0.5,0));

    int numTests = 10000;

    Vector2 points[numTests];

    Vector2 cornerA[numTests];
    Vector2 cornerB[numTests];
    Vector2 cornerC[numTests];
    Vector2 cornerD[numTests];

    bool results[numTests];
    bool resultsB[numTests];

    for (int i=0; i<numTests; ++i)
    {
        points[i]._x = rand() / ((float)RAND_MAX);
        points[i]._y = rand() / ((float)RAND_MAX);

        cornerA[i]._x = rand() / ((float)RAND_MAX);
        cornerA[i]._y = rand() / ((float)RAND_MAX);

        Vector2 edgeA;
        edgeA._x = rand() / ((float)RAND_MAX);
        edgeA._y = rand() / ((float)RAND_MAX);

        Vector2 edgeB;
        edgeB._x = rand() / ((float)RAND_MAX);
        edgeB._y = rand() / ((float)RAND_MAX);

        cornerB[i] = cornerA[i] + edgeA;
        cornerC[i] = cornerA[i] + edgeB;
        cornerD[i] = cornerA[i] + edgeA + edgeB;
    }

    struct timeval start, end;

    gettimeofday(&start, NULL);
    for (int i=0; i<numTests; ++i)
    {
        r.setCorners(cornerA[i], cornerB[i], cornerC[i]);
        results[i] = r.isInside(points[i]);
    }
    gettimeofday(&end, NULL);
    float elapsed = (end.tv_sec - start.tv_sec)*1000;
    elapsed += (end.tv_usec - start.tv_usec)*0.001;
    outA += elapsed;

    gettimeofday(&start, NULL);
    for (int i=0; i<numTests; ++i)
    {
        resultsB[i] = PointInRectangle(cornerA[i], cornerB[i], cornerC[i], cornerD[i], points[i]);
    }
    gettimeofday(&end, NULL);
    elapsed = (end.tv_sec - start.tv_sec)*1000;
    elapsed += (end.tv_usec - start.tv_usec)*0.001;
    outB += elapsed;
}

/*
 * 
 */
int main(int argc, char** argv) 
{
    float a = 0;
    float b = 0;

    for (int i=0; i<5000; i++)
    {
        runTest(a, b);
    }

    std::cout << "Result: " << a << " / " << b << std::endl;

    return 0;
}

코드는 확실히 아름답지는 않지만 주요 버그는 즉시 보지 않습니다. 해당 코드를 사용하면 사각형이 각 검사 사이에서 이동하면 솔루션이 약 두 배 빠릅니다. 움직이지 않으면 코드가 5 배 이상 빠릅니다.

코드가 어떻게 사용되는지 알고 있다면 변환과 수표를 두 차원으로 분리하여 속도를 조금 높일 수도 있습니다. 예를 들어 레이싱 게임에서는 많은 장애물이 차 앞이나 뒤에있을 것이기 때문에 운전 방향을 가리키는 좌표를 먼저 확인하는 것이 더 빠를 것입니다.


흥미롭지 만 점에 매트릭스 회전을 적용해야한다는 것을 잊지 마십시오. 게임 엔진에 행렬 썩음 연산이 있으며 나중에 알고리즘을 벤치마킹 할 수 있습니다. 마지막 코멘트와 관련하여. 그런 다음 '내부 원'도 정의하고 위에서 설명한 것처럼 점이 내부 원 외부와 외부 원 내부에 있는지 이중 네거티브 검사를 수행 할 수 있습니다.
Majte

그렇습니다. 대부분의 점이 삼각형의 중간에 가까워지면 도움이 될 것입니다. 나는 직사각형 레이스 트랙과 같은 상황을 상상하고 있었다. 이 경우 모든 검사는 사각형의 경계에 가까우며 원 검사는 성능을 떨어 뜨릴 수 있습니다. 물론, 그것은 구성된 예이지만 실제로 일어날 수있는 일이라고 말하고 싶습니다.
Lars Kokemohr

그런 일이 일어날 수 있습니다 알고리즘에 반하는 좋은 점이 무엇인지 궁금합니다. 결국 그것은 당신의 목적에 달려 있습니다. 시간이 있다면 OPs 게시물을 사용하여 코드를 게시 할 수 있으며 알고리즘을 벤치 마크 할 수 있습니까? 직감이 맞는지 봅시다. IsLeft 알고리즘에 대한 귀하의 아이디어의 성과가 궁금합니다.
Majte
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.