Simple Kreis/Rechteck kollisionsüberprüfung!
-
ja, da hab ich wohl geschlampt :p - geht so wohl doch besser:
inline int sqr(const int x){ return x*x; } inline bool intersectsCircleLineX(const circle &c, const int x, const int y1,const int y2) { register int r2; return (r2=sqr(c.r)-sqr(c.x-x))>=0&&((r2-sqr(c.y-y1))*(r2-sqr(c.y-y2))<=0||((c.y-y1)*(c.y-y2)<=0&&r2-sqr(c.y-y1)<=0)); } inline bool intersectsCircleLineY(const circle &c, const int x1, const int x2,const int y) { register int r2; return (r2=sqr(c.r)-sqr(c.y-y))>=0&&((r2-sqr(c.x-x1))*(r2-sqr(c.x-x2))<=0||((c.x-x1)*(c.x-x2)<=0&&r2-sqr(c.x-x1)<=0)); } bool intersectsCircleRect(const rect &r, const circle &c) { return intersectsCircleLineX(c,r.x,r.y,r.y+r.height)|| intersectsCircleLineX(c,r.x+r.width,r.y,r.y+r.height)|| intersectsCircleLineY(c,r.x,r.x+r.width,r.y)|| intersectsCircleLineY(c,r.x,r.x+r.width,r.y+r.height); }
-
Wieder geschlampt? Mit den selben Koordianten gehts noch immer nicht und obwohl sich kreis und Rect schneiden sagt er "no collision"
-
dann liegt der fehler diesmal nicht bei mir...
-
doch, könnte sogar sein, dass der fehler bei dir liegt, die sache mit dem schneidend er linie mit dem kreis sieht mir sehr abenteuerlich aus
@threadersteller ich muss das ganze heute abend mal machen, ma schaun ob ichs heute noch poste...
-
also wenn ich diese funktion mit eben diesen beispieldaten füttere liefert sie mir hier true zurück, so wie es sein soll
die idee des schnitttests ist eigentlich simpel; erst wird geprüft, ob die geraden, die das rechteck definieren, dem kreis überhaupt nah genug kommen; wenn das der fall ist, gibt es zwei möglichkeiten für den schnitt, endweder liegt ein endpunkt im kreis und einer ausserhalb oder beide liegen ausserhalb (ich teste nur einen punkt, denn falls der andere punkt innen liegt, kommen wir gar nicht soweit) aber auf verschiedenen seiten der gerade y=circle_.y bzw. x=circle_.x
-
hi,
hier das testprogramm:
int MIN(int x, int y) { return (x < y) ? x : y; } inline int abs (int value) { return ((value < 0) ? -value : value); } struct RECTANGLE { unsigned int x; // upper left unsigned int y; unsigned int width; // lower right unsigned int height; }; struct CIRCLE { unsigned int x; unsigned int y; unsigned int r; }; inline int sqr(const int x){ return x*x; } inline bool intersectsCircleLineX(const CIRCLE &c, const int x, const int y1,const int y2) { register int r2; return (r2=sqr(c.r)-sqr(c.x-x))>=0&&((r2-sqr(c.y-y1))*(r2-sqr(c.y-y2))<=0||((c.y-y1)*(c.y-y2)<=0&&r2-sqr(c.y-y1)<=0)); } inline bool intersectsCircleLineY(const CIRCLE &c, const int x1, const int x2,const int y) { register int r2; return (r2=sqr(c.r)-sqr(c.y-y))>=0&&((r2-sqr(c.x-x1))*(r2-sqr(c.x-x2))<=0||((c.x-x1)*(c.x-x2)<=0&&r2-sqr(c.x-x1)<=0)); } bool intersectsCircleRect(const RECTANGLE &r, const CIRCLE &c) { return intersectsCircleLineX(c,r.x,r.y,r.y+r.height)|| intersectsCircleLineX(c,r.x+r.width,r.y,r.y+r.height)|| intersectsCircleLineY(c,r.x,r.x+r.width,r.y)|| intersectsCircleLineY(c,r.x,r.x+r.width,r.y+r.height); } #define WIN32_LEAN_AND_MEAN #include <windows.h> #include "resource.h" const char name[] = "SplashScreen"; const unsigned long window_style = WS_SYSMENU | WS_MINIMIZEBOX | WS_OVERLAPPED; HBITMAP g_hBitmap; /////////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK WndProc(HWND hWnd, unsigned int message, unsigned int wParam, long lParam) { switch(message) { case WM_CREATE: { RECT rc = {0, 0, 640, 480}; ::AdjustWindowRectEx (&rc, window_style, false, 0); int centerX = (::GetSystemMetrics(SM_CXFULLSCREEN)/2) - (abs(rc.left)+rc.right )/2; int centerY = (::GetSystemMetrics(SM_CYFULLSCREEN)/2) - (abs(rc.top )+rc.bottom)/2; ::MoveWindow (hWnd, centerX, centerY, (rc.right - rc.left), (rc.bottom - rc.top), true); g_hBitmap = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP1)); } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hDC, hBitmapDC; HBITMAP hOldBitmap; BITMAP bm; hDC = BeginPaint(hWnd, &ps); //-- Create a DC for the bitmap and select it // into the created DC. hBitmapDC = CreateCompatibleDC(hDC); hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, (HBITMAP)g_hBitmap); //-- Display the bitmap into window GetObject((HBITMAP)g_hBitmap, sizeof(BITMAP), &bm); BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hBitmapDC, 0, 0, SRCCOPY); //-- Delete the temporary bitmap DC SelectObject(hBitmapDC, hOldBitmap); DeleteDC(hBitmapDC); EndPaint(hWnd, &ps); HDC hdc = GetDC(hWnd); CIRCLE c; c.x = 100; c.y = 100; c.r = 50; RECTANGLE rc; rc.x = 145; rc.y = 0; rc.width = 60; rc.height = 150; Ellipse(hdc, c.x - c.r, c.y - c.r, c.x + c.r, c.y + c.r); Rectangle(hdc, rc.x, rc.y, rc.width+rc.x, rc.height+rc.y); ReleaseDC(hWnd, hdc); if( intersectsCircleRect(rc, c) ) MessageBoxA(hWnd, "COLLISION", "Notify", MB_OK|MB_ICONINFORMATION); else MessageBoxA(hWnd, "NO COLLISION", "Notify", MB_OK|MB_ICONINFORMATION); } break; case WM_DESTROY: { if(g_hBitmap) DeleteObject(g_hBitmap); PostQuitMessage(0); } break; } return DefWindowProc(hWnd, message, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { // Läuft die Anwendung schon? HANDLE isRunning = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READONLY, 0, 32, name); if (isRunning && ::GetLastError () == ERROR_ALREADY_EXISTS) { ::MessageBox (NULL, "Läuft schon!", "", MB_OK); return 0; } MSG msg; HWND hWnd; WNDCLASSEX wc; wc.cbSize = sizeof(wc); wc.style = CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = name; wc.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)); RegisterClassEx(&wc); hWnd = CreateWindowEx(NULL, name, name, window_style, 0, 0, 640, 480, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, iCmdShow); UpdateWindow(hWnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } ::UnregisterClass (name, hInstance); return (int) msg.wParam; }
-
Vieleicht hilft dir das HIER weiter
-
Eigentlich sollte das nicht all zu schwer sein:
2 Rechteck stoßen zusammen wenn ihre Projektion auf die X Axe und die Y Axe überlappen:
A 0AA00 A 0AA00 0 00000 B 000BB B 000BB 0AABB
Nein, keine überlappt
A 00AA0 A 00AA0 0 00000 B 000BB B 000BB 00ACB
Nein, nur die X Axe
0 00000 0 00000 A 00AA0 C 00ACB B 000BB 00ACB
Ja, X Axe und Y Axe.
Dieser Trick funz auch ganz ähnlich mit Kreisen, nur muss du hier die Seiten des Rechtecks einzeln betrachten, und jeweils die "Breite" des Kreises mit gleicher X oder Y Koordinate. Beispiel für:
00000 00A00 0AAA0 00ABB 000BB
Erste vertikale Seite:
| 0 00000 0 00A00 A 0AAA0 B 00ABB B 000BB
Zweite vertikale Seite:
| 0 00000 0 00A00 0 0AAA0 B 00ABB B 000BB
Erste horizontale Seite:
00000 00A00 0AAA0 -00ABB 000BB 00ABB
Zweite horizontale Seite:
00000 00A00 0AAA0 00ABB -000BB 000BB
Und ein Beipiel von es eine Kollision gibt:
00000 00A00 0AACB 00ABB 00000
Erste vertikale Seite:
| 0 00000 0 00ABB C 0AACB B 00ABB 0 00000
Zweite vertikale Seite:
| 0 00000 B 00ABB B 0AACB B 00ABB 0 000B0
Erste horizontale Seite:
00000 -00ABB 0AACB 00ABB 00000 00ABB
Zweite horizontale Seite:
00000 00ABB 0AACB -00ABB 00000 00ABB
Einziges Problem: Es werden nur die Ränder des Rechtecks getestet, wenn der Kreis komplet im Rechteck liegt wird diese Methode fehlschlagen. Allerdings kann diesen Fall ja sehr einfach einzeln behandlen, man braucht nur den Kreis viereckig zu machen. Also aus:
00000 00A00 0AAA0 00A00 00000
wird
00000 0AAA0 0AAA0 0AAA0 00000
und schon musst du nur 2 Rechtecke testen.
Keine Ahnung ob man das besser hin kriegen könnte.
-
tja... damit gehts...
inline int sqr(const int x){ return x*x; } inline bool intersectsCircleLineX(const CIRCLE &c, const int x, const int y1,const int y2) { int r2=sqr(c.r)-sqr(c.x-x); int aa=r2-sqr(c.y-y1); int bb=r2-sqr(c.y-y2); int cc=(c.y-y1); int dd=(c.y-y2); return (r2>=0)&&((aa*bb<=0)||((cc*dd<=0)&&(aa<=0))); // return ((r2=sqr(c.r)-sqr(c.x-x))>=0)&&(((r2-sqr(c.y-y1))*(r2-sqr(c.y-y2))<=0)||(((c.y-y1)*(c.y-y2)<=0)&&(r2-sqr(c.y-y1)<=0))); } inline bool intersectsCircleLineY(const CIRCLE &c, const int x1, const int x2,const int y) { int r2=sqr(c.r)-sqr(c.y-y); int aa=r2-sqr(c.x-x1); int bb=r2-sqr(c.x-x2); int cc=(c.x-x1); int dd=(c.x-x2); return (r2>=0)&&((aa*bb<=0)||((cc*dd<=0)&&(aa<=0))); // return (r2=sqr(c.r)-sqr(c.y-y))>=0&&((r2-sqr(c.x-x1))*(r2-sqr(c.x-x2))<=0||((c.x-x1)*(c.x-x2)<=0&&r2-sqr(c.x-x1)<=0)); } bool intersectsCircleRect(const RECTANGLE &r, const CIRCLE &c) { return intersectsCircleLineX(c,r.x,r.y,r.y+r.height)|| intersectsCircleLineX(c,r.x+r.width,r.y,r.y+r.height)|| intersectsCircleLineY(c,r.x,r.x+r.width,r.y)|| intersectsCircleLineY(c,r.x,r.x+r.width,r.y+r.height); }
das ist derselbe algorithmus - k.A. wieso es nicht in einer zeile geht... für hinweise bin ich dankbar
-
oh na klar... das alte unsigned/signed problem...
inline int sqr(const int x){ return x*x; } inline bool intersectsCircleLineX(const CIRCLE &c, const int x, const int y1,const int y2) { register int r2; return ((r2=sqr(c.r)-sqr(c.x-x))>=0)&&(((r2-sqr(c.y-y1))*(r2-sqr(c.y-y2))<=0)||(((int)(c.y-y1)*(int)(c.y-y2)<=0)&&(r2-sqr(c.y-y1)<=0))); } inline bool intersectsCircleLineY(const CIRCLE &c, const int x1, const int x2,const int y) { register int r2; return ((r2=sqr(c.r)-sqr(c.y-y))>=0)&&(((r2-sqr(c.x-x1))*(r2-sqr(c.x-x2))<=0)||(((int)(c.x-x1)*(int)(c.x-x2)<=0)&&(r2-sqr(c.x-x1)<=0))); } bool intersectsCircleRect(const RECTANGLE &r, const CIRCLE &c) { return intersectsCircleLineX(c,r.x,r.y,r.y+r.height)|| intersectsCircleLineX(c,r.x+r.width,r.y,r.y+r.height)|| intersectsCircleLineY(c,r.x,r.x+r.width,r.y)|| intersectsCircleLineY(c,r.x,r.x+r.width,r.y+r.height); }
ich hatte es mit den definitionen, die oben angegeben waren getestet - und die waren signed; die windows strukturen benutzen aber unsigned - also hatten wir beide recht