मैं कैसे बता सकता हूं कि 2 डी यूक्लिडियन स्पेस में एक सर्कल और एक आयत प्रतिच्छेद है या नहीं? (यानी क्लासिक 2 डी ज्यामिति)
मैं कैसे बता सकता हूं कि 2 डी यूक्लिडियन स्पेस में एक सर्कल और एक आयत प्रतिच्छेद है या नहीं? (यानी क्लासिक 2 डी ज्यामिति)
जवाबों:
केवल दो मामले हैं जब सर्कल आयत के साथ प्रतिच्छेद करते हैं:
ध्यान दें कि इससे आयत को अक्ष-समानांतर होने की आवश्यकता नहीं है।
(इसे देखने का एक तरीका: यदि किसी भी किनारे में वृत्त का कोई बिंदु नहीं है (यदि सभी किनारे सर्कल के बाहर "पूरी तरह से" हैं), तो एकमात्र तरीका सर्कल अभी भी बहुभुज को काट सकता है यदि यह पूरी तरह से अंदर है बहुभुज।)
उस जानकारी के साथ, निम्नलिखित की तरह कुछ काम करेंगे, जहां चक्र केंद्र है P
और त्रिज्या R
और आयत के कोने है A
, B
, C
, D
इसी क्रम (पूरा नहीं हुआ कोड) में:
def intersect(Circle(P, R), Rectangle(A, B, C, D)):
S = Circle(P, R)
return (pointInRectangle(P, Rectangle(A, B, C, D)) or
intersectCircle(S, (A, B)) or
intersectCircle(S, (B, C)) or
intersectCircle(S, (C, D)) or
intersectCircle(S, (D, A)))
यदि आप कोई भी ज्यामिति लिख रहे हैं तो संभवतः आपके पुस्तकालय में उपरोक्त कार्य पहले से हैं। अन्यथा, pointInRectangle()
कई तरीकों से लागू किया जा सकता है; बहुभुज तरीकों में से कोई भी सामान्य बिंदु काम करेगा, लेकिन एक आयत के लिए आप बस जांच सकते हैं कि क्या यह काम करता है:
0 ≤ AP·AB ≤ AB·AB and 0 ≤ AP·AD ≤ AD·AD
और intersectCircle()
इसे लागू करना भी आसान है: एक तरीका यह होगा कि जाँच करें कि क्या सीधा से P
लाइन का पैर काफी करीब है और एंडपॉइंट्स के बीच है, और एंडपॉइंट्स को अन्यथा जांचें।
शांत बात यह है कि एक ही विचार न केवल आयतों के लिए बल्कि किसी भी साधारण बहुभुज के साथ एक सर्कल के चौराहे के लिए काम करता है - यहां तक कि उत्तल होना भी नहीं है!
यहाँ है कि मैं यह कैसे करेंगे:
bool intersects(CircleType circle, RectType rect)
{
circleDistance.x = abs(circle.x - rect.x);
circleDistance.y = abs(circle.y - rect.y);
if (circleDistance.x > (rect.width/2 + circle.r)) { return false; }
if (circleDistance.y > (rect.height/2 + circle.r)) { return false; }
if (circleDistance.x <= (rect.width/2)) { return true; }
if (circleDistance.y <= (rect.height/2)) { return true; }
cornerDistance_sq = (circleDistance.x - rect.width/2)^2 +
(circleDistance.y - rect.height/2)^2;
return (cornerDistance_sq <= (circle.r^2));
}
यहां देखिए यह कैसे काम करता है:
लाइनों की पहली जोड़ी चक्र के केंद्र और आयत के केंद्र के बीच x और y अंतर के पूर्ण मूल्यों की गणना करती है। इससे चार चतुर्भुज नीचे गिर जाते हैं, जिससे गणना चार बार नहीं करनी पड़ती है। छवि उस क्षेत्र को दिखाती है जिसमें सर्कल का केंद्र अब झूठ होना चाहिए। ध्यान दें कि केवल एकल चतुर्थांश दिखाया गया है। आयत ग्रे क्षेत्र है, और लाल सीमा महत्वपूर्ण क्षेत्र को रेखांकित करती है जो आयत के किनारों से बिल्कुल एक त्रिज्या है। चौराहे पर होने के लिए सर्कल का केंद्र इस लाल सीमा के भीतर होना चाहिए।
लाइनों की दूसरी जोड़ी उन आसान मामलों को खत्म करती है जहां सर्कल आयत (किसी भी दिशा में) से काफी दूर है कि कोई चौराहा संभव नहीं है। यह छवि में हरे क्षेत्र से मेल खाती है।
तीसरी जोड़ी रेखाएं आसान मामलों को संभालती हैं जहां सर्कल आयत के करीब (दोनों दिशा में) पर्याप्त है कि एक चौराहे की गारंटी है। यह छवि में नारंगी और ग्रे वर्गों से मेल खाती है। ध्यान दें कि तर्क करने के लिए यह कदम चरण 2 के बाद होना चाहिए।
शेष पंक्तियाँ उस कठिन मामले की गणना करती हैं जहाँ वृत्त आयत के कोने को काट सकता है। हल करने के लिए, सर्कल और कोने के केंद्र से दूरी की गणना करें और फिर सत्यापित करें कि दूरी सर्कल के त्रिज्या से अधिक नहीं है। यह गणना उन सभी हलकों के लिए गलत है, जिनका केंद्र लाल छायांकित क्षेत्र के भीतर है और उन सभी मंडलियों के लिए सही है, जिनका केंद्र सफेद छायांकित क्षेत्र में है।
;)
circleDistance_x = abs(circle.x - (rect.x-rect.w/2)); circleDistance_y = abs(circle.y - (rect.y-rect.h/2));
यहाँ एक और समाधान है जो लागू करने के लिए बहुत सरल है (और बहुत तेज़ है, भी)। यह सभी चौराहों को पकड़ लेगा, जिसमें जब गोला पूरी तरह से आयत में प्रवेश कर गया है।
// clamp(value, min, max) - limits value to the range min..max
// Find the closest point to the circle within the rectangle
float closestX = clamp(circle.X, rectangle.Left, rectangle.Right);
float closestY = clamp(circle.Y, rectangle.Top, rectangle.Bottom);
// Calculate the distance between the circle's center and this closest point
float distanceX = circle.X - closestX;
float distanceY = circle.Y - closestY;
// If the distance is less than the circle's radius, an intersection occurs
float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
return distanceSquared < (circle.Radius * circle.Radius);
किसी भी सभ्य गणित पुस्तकालय के साथ, जिसे 3 या 4 पंक्तियों में छोटा किया जा सकता है।
आपका गोला और रेक्ट इंटरसेक्ट IIF
सर्कल-सेंटर के बीच की दूरी और आपकी आयत के एक शीर्ष पर आपके गोले के त्रिज्या से छोटा होता है
या
सर्कल-सेंटर के बीच की दूरी और आपकी रेक्ट के एक किनारे से आपके गोले के त्रिज्या से छोटा होता है। [ बिंदु-रेखा दूरी ])
या
सर्कल केंद्र रेती के अंदर है
पॉइंट-पॉइंट दूरी के :
P1 = [X1, y1] P2 = [x2, y2] दूरी = sqrt (abs (X1 - x2) + abs (y1-y2))
बिंदु-लाइन दूरी:
L1 = [X1, y1], L2 = [x2, y2] (आपकी पंक्ति के दो बिंदु, यानी शीर्ष बिंदु) P1 = [px, py] कुछ बिंदु दूरी d = abs ((x2-X1) (y1-py) - (X1-px) (y2-y1) / दूरी (L1, L2)
रेक्ट के अंदर सर्कल सेंटर:
एक सेपरेटिंग ऐक्सप्रैस aproach लें: यदि किसी लाइन पर मौजूद कोई प्रक्षेपण मौजूद है जो आयत को बिंदु से अलग करता है, तो वे प्रतिच्छेद नहीं करते हैं
आप अपनी आयत के किनारों के समानांतर रेखाओं पर बिंदु को प्रोजेक्ट कर सकते हैं और फिर आसानी से निर्धारित कर सकते हैं कि क्या वे प्रतिच्छेद करते हैं। यदि वे सभी 4 अनुमानों पर प्रतिच्छेद नहीं करते हैं, तो वे (बिंदु और आयत) प्रतिच्छेद नहीं कर सकते हैं।
आपको केवल आंतरिक उत्पाद (x = [X1, x2], y = [y1, y2], x * y = X1 * y1 + x2 * y2) की आवश्यकता है
आपका परीक्षण ऐसा लगेगा:
// आयत किनारों: टीएल (ऊपर बाएं), टीआर (ऊपर दाएं), बीएल (नीचे बाएं), बीआर (नीचे दाएं) // पॉइंट टू टेस्ट: पीओआई अलग = गलत उदाहरण के लिए {{TL, TR}, {BL, BR}, {TL, BL}, {TR-BR}} // किनारों पर D = बढ़त [0] - बढ़त [1] इनरप्रोड = डी * पीओआई Interval_min = min (D * edge [0], D * edge [1]) Interval_max = max (D * edge [0], D * edge [1]) यदि नहीं (Interval_min P इनरप्रोड val Interval_max) अलग = सत्य विराम // पाश के लिए अंत अगर अंत के लिए अंत अगर (अलग-अलग सच है) वापसी "कोई चौराहा" नहीं अन्य वापसी "चौराहे" अगर अंत
यह एक अक्ष-संरेखित आयत नहीं मानता है और उत्तल सेटों के बीच चौराहों के परीक्षण के लिए आसानी से विस्तार योग्य है।
यह सबसे तेज़ उपाय है:
public static boolean intersect(Rectangle r, Circle c)
{
float cx = Math.abs(c.x - r.x - r.halfWidth);
float xDist = r.halfWidth + c.radius;
if (cx > xDist)
return false;
float cy = Math.abs(c.y - r.y - r.halfHeight);
float yDist = r.halfHeight + c.radius;
if (cy > yDist)
return false;
if (cx <= r.halfWidth || cy <= r.halfHeight)
return true;
float xCornerDist = cx - r.halfWidth;
float yCornerDist = cy - r.halfHeight;
float xCornerDistSq = xCornerDist * xCornerDist;
float yCornerDistSq = yCornerDist * yCornerDist;
float maxCornerDistSq = c.radius * c.radius;
return xCornerDistSq + yCornerDistSq <= maxCornerDistSq;
}
निष्पादन के आदेश पर ध्यान दें, और आधी चौड़ाई / ऊंचाई पूर्व-गणना है। इसके अलावा कुछ घड़ी चक्रों को बचाने के लिए स्क्वेरिंग "मैन्युअल रूप से" की जाती है।
सबसे सरल समाधान जो मैं लेकर आया हूं वह बहुत सीधा है।
यह सर्कल के निकटतम आयत में बिंदु को खोजने के द्वारा काम करता है, फिर दूरी की तुलना करता है।
आप कुछ कार्यों के साथ यह सब कर सकते हैं, और यहां तक कि sqrt फ़ंक्शन से भी बच सकते हैं।
public boolean intersects(float cx, float cy, float radius, float left, float top, float right, float bottom)
{
float closestX = (cx < left ? left : (cx > right ? right : cx));
float closestY = (cy < top ? top : (cy > bottom ? bottom : cy));
float dx = closestX - cx;
float dy = closestY - cy;
return ( dx * dx + dy * dy ) <= radius * radius;
}
और बस! उपरोक्त समाधान एक्स-अक्ष के साथ दुनिया के ऊपरी बाएं हिस्से में एक मूल मानता है जो नीचे इंगित करता है।
यदि आप एक बढ़ते सर्कल और आयत के बीच टकराव से निपटने के लिए समाधान चाहते हैं, तो यह कहीं अधिक जटिल है और मेरा एक और उत्तर में कवर किया गया है।
वास्तव में, यह बहुत अधिक सरल है। आपको केवल दो चीजों की जरूरत है।
सबसे पहले, आपको सर्कल केंद्र से आयत की प्रत्येक पंक्ति तक चार ऑर्थोगोनल दूरी खोजने की आवश्यकता है । तब आपका वृत्त आयत को नहीं काटेगा, यदि उनमें से कोई तीन वृत्त त्रिज्या से बड़ा है।
दूसरा, आपको सर्कल केंद्र और आयत केंद्र के बीच की दूरी खोजने की आवश्यकता है, फिर आप सर्कल आयत के अंदर नहीं होंगे यदि दूरी आयत विकर्ण की लंबाई के आधे से बड़ा है।
सौभाग्य!
यहाँ एक गोला और एक गैर-अक्ष संरेखित बॉक्स के बीच टकराव को हल करने के लिए मेरा सी कोड है। यह मेरे स्वयं के पुस्तकालय दिनचर्या के एक जोड़े पर निर्भर करता है, लेकिन यह कुछ के लिए उपयोगी साबित हो सकता है। मैं इसे एक गेम में इस्तेमाल कर रहा हूं और यह पूरी तरह से काम करता है।
float physicsProcessCollisionBetweenSelfAndActorRect(SPhysics *self, SPhysics *actor)
{
float diff = 99999;
SVector relative_position_of_circle = getDifference2DBetweenVectors(&self->worldPosition, &actor->worldPosition);
rotateVector2DBy(&relative_position_of_circle, -actor->axis.angleZ); // This aligns the coord system so the rect becomes an AABB
float x_clamped_within_rectangle = relative_position_of_circle.x;
float y_clamped_within_rectangle = relative_position_of_circle.y;
LIMIT(x_clamped_within_rectangle, actor->physicsRect.l, actor->physicsRect.r);
LIMIT(y_clamped_within_rectangle, actor->physicsRect.b, actor->physicsRect.t);
// Calculate the distance between the circle's center and this closest point
float distance_to_nearest_edge_x = relative_position_of_circle.x - x_clamped_within_rectangle;
float distance_to_nearest_edge_y = relative_position_of_circle.y - y_clamped_within_rectangle;
// If the distance is less than the circle's radius, an intersection occurs
float distance_sq_x = SQUARE(distance_to_nearest_edge_x);
float distance_sq_y = SQUARE(distance_to_nearest_edge_y);
float radius_sq = SQUARE(self->physicsRadius);
if(distance_sq_x + distance_sq_y < radius_sq)
{
float half_rect_w = (actor->physicsRect.r - actor->physicsRect.l) * 0.5f;
float half_rect_h = (actor->physicsRect.t - actor->physicsRect.b) * 0.5f;
CREATE_VECTOR(push_vector);
// If we're at one of the corners of this object, treat this as a circular/circular collision
if(fabs(relative_position_of_circle.x) > half_rect_w && fabs(relative_position_of_circle.y) > half_rect_h)
{
SVector edges;
if(relative_position_of_circle.x > 0) edges.x = half_rect_w; else edges.x = -half_rect_w;
if(relative_position_of_circle.y > 0) edges.y = half_rect_h; else edges.y = -half_rect_h;
push_vector = relative_position_of_circle;
moveVectorByInverseVector2D(&push_vector, &edges);
// We now have the vector from the corner of the rect to the point.
float delta_length = getVector2DMagnitude(&push_vector);
float diff = self->physicsRadius - delta_length; // Find out how far away we are from our ideal distance
// Normalise the vector
push_vector.x /= delta_length;
push_vector.y /= delta_length;
scaleVector2DBy(&push_vector, diff); // Now multiply it by the difference
push_vector.z = 0;
}
else // Nope - just bouncing against one of the edges
{
if(relative_position_of_circle.x > 0) // Ball is to the right
push_vector.x = (half_rect_w + self->physicsRadius) - relative_position_of_circle.x;
else
push_vector.x = -((half_rect_w + self->physicsRadius) + relative_position_of_circle.x);
if(relative_position_of_circle.y > 0) // Ball is above
push_vector.y = (half_rect_h + self->physicsRadius) - relative_position_of_circle.y;
else
push_vector.y = -((half_rect_h + self->physicsRadius) + relative_position_of_circle.y);
if(fabs(push_vector.x) < fabs(push_vector.y))
push_vector.y = 0;
else
push_vector.x = 0;
}
diff = 0; // Cheat, since we don't do anything with the value anyway
rotateVector2DBy(&push_vector, actor->axis.angleZ);
SVector *from = &self->worldPosition;
moveVectorBy2D(from, push_vector.x, push_vector.y);
}
return diff;
}
कल्पना करने के लिए, अपने कीबोर्ड के नंबरपैड को लें। यदि कुंजी '5' आपकी आयत का प्रतिनिधित्व करता है, तो सभी कुंजियाँ 1-9 उन 9 आयतों को दर्शाती हैं, जो आपकी आयत को बनाने वाली रेखाओं से विभाजित होती हैं (5 अंदर की ओर होती हैं।)
1) यदि वृत्त का केंद्र चतुर्थांश में है (यानी आयत के अंदर) तो दो आकृतियाँ प्रतिच्छेद करती हैं।
उस रास्ते से, दो संभावित मामले हैं: क) सर्कल आयत के दो या अधिक पड़ोसी किनारों के साथ प्रतिच्छेदन करता है। b) सर्कल आयत के एक किनारे के साथ प्रतिच्छेद करता है।
पहला मामला सरल है। यदि सर्कल आयत के दो पड़ोसी किनारों के साथ प्रतिच्छेदन करता है, तो इसमें उन दो किनारों को जोड़ने वाला कोने होना चाहिए। (वह, या उसका केंद्र चतुर्थांश 5 में है, जिसे हमने पहले ही कवर कर लिया है। यह भी ध्यान दें कि वृत्त जहां दो चक्रों के साथ घूमता है) आयत के किनारों के करता है)
2) यदि आयताकार का कोई भी कोने A, B, C, D सर्कल के अंदर स्थित है, तो दो आकृतियाँ प्रतिच्छेद करती हैं।
दूसरा मामला पेचीदा है। हमें इस बात पर ध्यान देना चाहिए कि यह तभी हो सकता है जब वृत्त का केंद्र 2, 4, 6 या 8 में से किसी एक में निहित हो (वास्तव में, यदि केंद्र 1, 3, 7, 8 में से किसी एक पर है) संबंधित कोने इसके निकटतम बिंदु होंगे।)
अब हमारे पास यह मामला है कि सर्कल का केंद्र 'एज' क्वैडेंट्स में से एक में है, और यह केवल इसी एज के साथ इंटरसेक्ट करता है। फिर, किनारे पर बिंदु जो सर्कल के केंद्र के सबसे करीब है, सर्कल के अंदर झूठ होना चाहिए।
3) प्रत्येक रेखा के लिए AB, BC, CD, DA, वृत्त के केंद्र P के माध्यम से लंबवत रेखाओं p (AB, P), p (BC, P), p (CD, P), p (DA, P) का निर्माण करें। प्रत्येक लंबवत रेखा, यदि मूल किनारे वाला चौराहा सर्कल के अंदर है, तो दो आकृतियाँ प्रतिच्छेद करती हैं।
इस अंतिम चरण के लिए एक शॉर्टकट है। यदि वृत्त का केंद्र चतुर्थांश 8 में है और किनारे AB शीर्ष छोर है, तो चौराहे के बिंदु पर A और B का y- समन्वय होगा और केंद्र P का x- समन्वय होगा।
आप चार लाइन चौराहों का निर्माण कर सकते हैं और जांच सकते हैं कि क्या वे अपने संबंधित किनारों पर स्थित हैं, या यह पता करें कि कौन सा चतुर्थांश पी है और संबंधित चौराहे की जांच करें। दोनों को एक ही बूलियन समीकरण को सरल बनाना चाहिए। इस बात से सावधान रहें कि ऊपर दिए गए चरण 2 ने 'कोने' के चतुर्थांशों में से एक में P होने से इंकार नहीं किया; यह सिर्फ एक चौराहे की तलाश में था।
संपादित करें: जैसा कि यह पता चला है, मैंने सरल तथ्य को अनदेखा कर दिया है कि # 2 ऊपर # 3 का एक सबकेस है। आखिरकार, कोने भी किनारों पर स्थित हैं। महान विवरण के लिए नीचे देखें @ श्रीवत्सआर का उत्तर। और इस बीच, ऊपर # 2 को भूल जाइए जब तक आप एक त्वरित लेकिन निरर्थक जाँच नहीं चाहते।
यह फ़ंक्शन सर्कल और रेक्टेंगल के बीच टकरावों (चौराहों) का पता लगाता है। वह अपने जवाब में ई। जैम विधि की तरह काम करता है, लेकिन यह आयत के सभी कोणों के लिए टकराव का पता लगाता है (न केवल सही कोने तक)।
ध्यान दें:
aRect.origin.x और aRect.origin.y आयत के निचले बाएँ कोण के निर्देशांक हैं!
aCircle.x और aCircle.y सर्किल सेंटर के निर्देशांक हैं!
static inline BOOL RectIntersectsCircle(CGRect aRect, Circle aCircle) {
float testX = aCircle.x;
float testY = aCircle.y;
if (testX < aRect.origin.x)
testX = aRect.origin.x;
if (testX > (aRect.origin.x + aRect.size.width))
testX = (aRect.origin.x + aRect.size.width);
if (testY < aRect.origin.y)
testY = aRect.origin.y;
if (testY > (aRect.origin.y + aRect.size.height))
testY = (aRect.origin.y + aRect.size.height);
return ((aCircle.x - testX) * (aCircle.x - testX) + (aCircle.y - testY) * (aCircle.y - testY)) < aCircle.radius * aCircle.radius;
}
मेरे पास एक विधि है जो यदि आवश्यक न हो तो महंगे पाइथागोरस से बचती है - यानी। जब आयत और सर्कल के बाउंडिंग बक्सों को काटना नहीं है।
और यह गैर-यूक्लिडियन के लिए भी काम करेगा:
class Circle {
// create the bounding box of the circle only once
BBox bbox;
public boolean intersect(BBox b) {
// test top intersect
if (lat > b.maxLat) {
if (lon < b.minLon)
return normDist(b.maxLat, b.minLon) <= normedDist;
if (lon > b.maxLon)
return normDist(b.maxLat, b.maxLon) <= normedDist;
return b.maxLat - bbox.minLat > 0;
}
// test bottom intersect
if (lat < b.minLat) {
if (lon < b.minLon)
return normDist(b.minLat, b.minLon) <= normedDist;
if (lon > b.maxLon)
return normDist(b.minLat, b.maxLon) <= normedDist;
return bbox.maxLat - b.minLat > 0;
}
// test middle intersect
if (lon < b.minLon)
return bbox.maxLon - b.minLon > 0;
if (lon > b.maxLon)
return b.maxLon - bbox.minLon > 0;
return true;
}
}
dLat=(lat-circleY); dLon=(lon-circleX); normed=dLat*dLat+dLon*dLon
:। यदि आप उस मानदंड विधि का उपयोग करते हैं normedDist = dist*dist;
, तो आपको सर्कल के लिए बनाने की आवश्यकता होगीमैंने आकार के साथ काम के लिए वर्ग बनाया है आशा है कि आप आनंद लेंगे
public class Geomethry {
public static boolean intersectionCircleAndRectangle(int circleX, int circleY, int circleR, int rectangleX, int rectangleY, int rectangleWidth, int rectangleHeight){
boolean result = false;
float rectHalfWidth = rectangleWidth/2.0f;
float rectHalfHeight = rectangleHeight/2.0f;
float rectCenterX = rectangleX + rectHalfWidth;
float rectCenterY = rectangleY + rectHalfHeight;
float deltax = Math.abs(rectCenterX - circleX);
float deltay = Math.abs(rectCenterY - circleY);
float lengthHypotenuseSqure = deltax*deltax + deltay*deltay;
do{
// check that distance between the centerse is more than the distance between the circumcircle of rectangle and circle
if(lengthHypotenuseSqure > ((rectHalfWidth+circleR)*(rectHalfWidth+circleR) + (rectHalfHeight+circleR)*(rectHalfHeight+circleR))){
//System.out.println("distance between the centerse is more than the distance between the circumcircle of rectangle and circle");
break;
}
// check that distance between the centerse is less than the distance between the inscribed circle
float rectMinHalfSide = Math.min(rectHalfWidth, rectHalfHeight);
if(lengthHypotenuseSqure < ((rectMinHalfSide+circleR)*(rectMinHalfSide+circleR))){
//System.out.println("distance between the centerse is less than the distance between the inscribed circle");
result=true;
break;
}
// check that the squares relate to angles
if((deltax > (rectHalfWidth+circleR)*0.9) && (deltay > (rectHalfHeight+circleR)*0.9)){
//System.out.println("squares relate to angles");
result=true;
}
}while(false);
return result;
}
public static boolean intersectionRectangleAndRectangle(int rectangleX, int rectangleY, int rectangleWidth, int rectangleHeight, int rectangleX2, int rectangleY2, int rectangleWidth2, int rectangleHeight2){
boolean result = false;
float rectHalfWidth = rectangleWidth/2.0f;
float rectHalfHeight = rectangleHeight/2.0f;
float rectHalfWidth2 = rectangleWidth2/2.0f;
float rectHalfHeight2 = rectangleHeight2/2.0f;
float deltax = Math.abs((rectangleX + rectHalfWidth) - (rectangleX2 + rectHalfWidth2));
float deltay = Math.abs((rectangleY + rectHalfHeight) - (rectangleY2 + rectHalfHeight2));
float lengthHypotenuseSqure = deltax*deltax + deltay*deltay;
do{
// check that distance between the centerse is more than the distance between the circumcircle
if(lengthHypotenuseSqure > ((rectHalfWidth+rectHalfWidth2)*(rectHalfWidth+rectHalfWidth2) + (rectHalfHeight+rectHalfHeight2)*(rectHalfHeight+rectHalfHeight2))){
//System.out.println("distance between the centerse is more than the distance between the circumcircle");
break;
}
// check that distance between the centerse is less than the distance between the inscribed circle
float rectMinHalfSide = Math.min(rectHalfWidth, rectHalfHeight);
float rectMinHalfSide2 = Math.min(rectHalfWidth2, rectHalfHeight2);
if(lengthHypotenuseSqure < ((rectMinHalfSide+rectMinHalfSide2)*(rectMinHalfSide+rectMinHalfSide2))){
//System.out.println("distance between the centerse is less than the distance between the inscribed circle");
result=true;
break;
}
// check that the squares relate to angles
if((deltax > (rectHalfWidth+rectHalfWidth2)*0.9) && (deltay > (rectHalfHeight+rectHalfHeight2)*0.9)){
//System.out.println("squares relate to angles");
result=true;
}
}while(false);
return result;
}
}
यहाँ 100% काम करने वाला संशोधित कोड है:
public static bool IsIntersected(PointF circle, float radius, RectangleF rectangle)
{
var rectangleCenter = new PointF((rectangle.X + rectangle.Width / 2),
(rectangle.Y + rectangle.Height / 2));
var w = rectangle.Width / 2;
var h = rectangle.Height / 2;
var dx = Math.Abs(circle.X - rectangleCenter.X);
var dy = Math.Abs(circle.Y - rectangleCenter.Y);
if (dx > (radius + w) || dy > (radius + h)) return false;
var circleDistance = new PointF
{
X = Math.Abs(circle.X - rectangle.X - w),
Y = Math.Abs(circle.Y - rectangle.Y - h)
};
if (circleDistance.X <= (w))
{
return true;
}
if (circleDistance.Y <= (h))
{
return true;
}
var cornerDistanceSq = Math.Pow(circleDistance.X - w, 2) +
Math.Pow(circleDistance.Y - h, 2);
return (cornerDistanceSq <= (Math.Pow(radius, 2)));
}
बासम आलगिली
इसके लिए एक तेज़ एक-लाइन परीक्षण यहां दिया गया है:
if (length(max(abs(center - rect_mid) - rect_halves, 0)) <= radius ) {
// They intersect.
}
यह धुरी-संरेखित मामला है जहां rect_halves
आयताकार मध्य से एक कोने तक इंगित एक सकारात्मक वेक्टर है। अंदर की अभिव्यक्ति आयत में एक निकटतम बिंदु length()
से एक डेल्टा वेक्टर है center
। यह किसी भी आयाम में काम करता है।
यह कुशल है, क्योंकि:
मेरे लिए काम किया (केवल काम जब आयत का कोण 180 है)
function intersects(circle, rect) {
let left = rect.x + rect.width > circle.x - circle.radius;
let right = rect.x < circle.x + circle.radius;
let top = rect.y < circle.y + circle.radius;
let bottom = rect.y + rect.height > circle.y - circle.radius;
return left && right && bottom && top;
}
ई। के उत्तर में थोड़ा सुधार करें:
double dx = abs(circle.x - rect.x) - rect.w / 2,
dy = abs(circle.y - rect.y) - rect.h / 2;
if (dx > circle.r || dy > circle.r) { return false; }
if (dx <= 0 || dy <= 0) { return true; }
return (dx * dx + dy * dy <= circle.r * circle.r);
यह घटता है rect.w / 2
और rect.h / 2
एक बार के बजाय तीन बार तक।
उन लोगों के लिए एसक्यूएल के साथ भौगोलिक निर्देशांक में सर्कल / आयत टकराव की गणना करना है,
यह मेरा कार्यान्वयन है। ई-नाम के 11 एल्गोरिदम का सुझाव दिया एल्गोरिदम ।
इनपुट में इसे सर्कल निर्देशांक, किमी में सर्कल त्रिज्या और आयत के दो कोने निर्देशांक की आवश्यकता होती है:
CREATE OR REPLACE FUNCTION "DETECT_CIRC_RECT_COLLISION"
(
circleCenterLat IN NUMBER, -- circle Center Latitude
circleCenterLon IN NUMBER, -- circle Center Longitude
circleRadius IN NUMBER, -- circle Radius in KM
rectSWLat IN NUMBER, -- rectangle South West Latitude
rectSWLon IN NUMBER, -- rectangle South West Longitude
rectNELat IN NUMBER, -- rectangle North Est Latitude
rectNELon IN NUMBER -- rectangle North Est Longitude
)
RETURN NUMBER
AS
-- converts km to degrees (use 69 if miles)
kmToDegreeConst NUMBER := 111.045;
-- Remaining rectangle vertices
rectNWLat NUMBER;
rectNWLon NUMBER;
rectSELat NUMBER;
rectSELon NUMBER;
rectHeight NUMBER;
rectWIdth NUMBER;
circleDistanceLat NUMBER;
circleDistanceLon NUMBER;
cornerDistanceSQ NUMBER;
BEGIN
-- Initialization of remaining rectangle vertices
rectNWLat := rectNELat;
rectNWLon := rectSWLon;
rectSELat := rectSWLat;
rectSELon := rectNELon;
-- Rectangle sides length calculation
rectHeight := calc_distance(rectSWLat, rectSWLon, rectNWLat, rectNWLon);
rectWidth := calc_distance(rectSWLat, rectSWLon, rectSELat, rectSELon);
circleDistanceLat := abs( (circleCenterLat * kmToDegreeConst) - ((rectSWLat * kmToDegreeConst) + (rectHeight/2)) );
circleDistanceLon := abs( (circleCenterLon * kmToDegreeConst) - ((rectSWLon * kmToDegreeConst) + (rectWidth/2)) );
IF circleDistanceLon > ((rectWidth/2) + circleRadius) THEN
RETURN -1; -- -1 => NO Collision ; 0 => Collision Detected
END IF;
IF circleDistanceLat > ((rectHeight/2) + circleRadius) THEN
RETURN -1; -- -1 => NO Collision ; 0 => Collision Detected
END IF;
IF circleDistanceLon <= (rectWidth/2) THEN
RETURN 0; -- -1 => NO Collision ; 0 => Collision Detected
END IF;
IF circleDistanceLat <= (rectHeight/2) THEN
RETURN 0; -- -1 => NO Collision ; 0 => Collision Detected
END IF;
cornerDistanceSQ := POWER(circleDistanceLon - (rectWidth/2), 2) + POWER(circleDistanceLat - (rectHeight/2), 2);
IF cornerDistanceSQ <= POWER(circleRadius, 2) THEN
RETURN 0; -- -1 => NO Collision ; 0 => Collision Detected
ELSE
RETURN -1; -- -1 => NO Collision ; 0 => Collision Detected
END IF;
RETURN -1; -- -1 => NO Collision ; 0 => Collision Detected
END;
काम करता है, बस एक हफ्ते पहले यह पता लगा, और बस अब यह परीक्षण करने के लिए मिला है।
double theta = Math.atan2(cir.getX()-sqr.getX()*1.0,
cir.getY()-sqr.getY()*1.0); //radians of the angle
double dBox; //distance from box to edge of box in direction of the circle
if((theta > Math.PI/4 && theta < 3*Math.PI / 4) ||
(theta < -Math.PI/4 && theta > -3*Math.PI / 4)) {
dBox = sqr.getS() / (2*Math.sin(theta));
} else {
dBox = sqr.getS() / (2*Math.cos(theta));
}
boolean touching = (Math.abs(dBox) >=
Math.sqrt(Math.pow(sqr.getX()-cir.getX(), 2) +
Math.pow(sqr.getY()-cir.getY(), 2)));
def colision(rect, circle):
dx = rect.x - circle.x
dy = rect.y - circle.y
distance = (dy**2 + dx**2)**0.5
angle_to = (rect.angle + math.atan2(dx, dy)/3.1415*180.0) % 360
if((angle_to>135 and angle_to<225) or (angle_to>0 and angle_to<45) or (angle_to>315 and angle_to<360)):
if distance <= circle.rad/2.+((rect.height/2.0)*(1.+0.5*abs(math.sin(angle_to*math.pi/180.)))):
return True
else:
if distance <= circle.rad/2.+((rect.width/2.0)*(1.+0.5*abs(math.cos(angle_to*math.pi/180.)))):
return True
return False
मान लें कि आपके पास आयत के चार किनारे हैं, किनारों से सर्कल के केंद्र तक की दूरी की जांच करें, यदि इसकी कम है तो त्रिज्या, फिर आकृतियाँ प्रतिच्छेद कर रही हैं।
if sqrt((rectangleRight.x - circleCenter.x)^2 +
(rectangleBottom.y - circleCenter.y)^2) < radius
// then they intersect
if sqrt((rectangleRight.x - circleCenter.x)^2 +
(rectangleTop.y - circleCenter.y)^2) < radius
// then they intersect
if sqrt((rectangleLeft.x - circleCenter.x)^2 +
(rectangleTop.y - circleCenter.y)^2) < radius
// then they intersect
if sqrt((rectangleLeft.x - circleCenter.x)^2 +
(rectangleBottom.y - circleCenter.y)^2) < radius
// then they intersect
यदि आयत वृत्त को काटता है, तो आयत का एक या अधिक कोना बिंदु वृत्त के अंदर होना चाहिए। मान लीजिए कि एक आयत के चार बिंदु A, B, C, D हैं। उनमें से कम से कम एक चक्र को काटना चाहिए। इसलिए यदि सर्कल के केंद्र के एक बिंदु से दूरी सर्कल के त्रिज्या से कम है, तो इसे सर्कल को काटना चाहिए। दूरी पाने के लिए आप पाइथागोरस प्रमेय का उपयोग कर सकते हैं,
H^2 = A^2 + B^2
इस तकनीक की कुछ सीमाएँ हैं। लेकिन यह गेम डेवलपर्स के लिए बेहतर काम करेगा। विशेष रूप से टक्कर का पता लगाने
यह Arvo के एल्गोरिथ्म के लिए एक अच्छा अपडेट है