ฉันจะคำนวณระยะห่างระหว่างจุดและสี่เหลี่ยมผืนผ้าที่จัดแนวแกนได้อย่างไร


29

ฉันมีรูปสี่เหลี่ยมผืนผ้า 2 มิติที่มี x, ตำแหน่ง y, ความสูงและความกว้างและมีตำแหน่งที่อยู่ใกล้เคียงแบบสุ่ม

มีวิธีการตรวจสอบว่าจุดนี้อาจชนกับสี่เหลี่ยมถ้ามันใกล้กว่าระยะทางที่กำหนดหรือไม่ ลองจินตนาการถึงรัศมีที่มองไม่เห็นนอกจุดที่ชนกับสี่เหลี่ยมดังกล่าว ฉันมีปัญหากับเรื่องนี้เพียงเพราะมันไม่ใช่สแควร์!

คำตอบ:


26

ถ้า(x,y)เป็นจุดศูนย์กลางของสี่เหลี่ยมระยะห่างจากจุดหนึ่ง(px,py)ไปยังเส้นขอบของสี่เหลี่ยมสามารถคำนวณได้ดังนี้

dx = max(abs(px - x) - width / 2, 0);
dy = max(abs(py - y) - height / 2, 0);
return dx * dx + dy * dy;

หากระยะทางกำลังสองนั้นเป็นศูนย์ก็หมายความว่าจุดนั้นสัมผัสหรืออยู่ภายในสี่เหลี่ยม


6
สำหรับคนอื่นที่สงสัย (x, y) เป็นศูนย์กลางของสี่เหลี่ยมผืนผ้าไม่ใช่มุม
Greg Rozmarynowycz

2
ขออภัยสำหรับความคิดเห็นเก่า แต่สมการนี้จะถือว่าสี่เหลี่ยมผืนผ้าอยู่ในแนวเดียวกันหรือไม่?
BitNinja

1
@ BitNinja ใช่นั่นคือสิ่งที่คำถามถือว่า ถ้ามันไม่ได้จัดแนวแกนอัลกอริทึมที่เร็วที่สุด / ง่ายที่สุดจะขึ้นอยู่กับวิธีการจัดเก็บข้อมูลสี่เหลี่ยมผืนผ้า
sam hocevar

พูดว่าจุดคือ (4: 4) สี่เหลี่ยมอยู่ที่ (5: 5) โดยมีความกว้าง / ความสูง (5: 5) รหัสของคุณจะอ้างว่าเป็นจุดที่สัมผัสหรืออยู่ภายในสี่เหลี่ยมผืนผ้า แต่เห็นได้ชัดว่าข้างนอก
LRN

@LRN สี่เหลี่ยมผืนผ้าที่อยู่กึ่งกลางที่ (5: 5) มีความกว้าง / ความสูง (5: 5) มีช่วงตั้งแต่ (2.5: 2.5) ถึง (7.5: 7.5) จุด (4: 4) อยู่ในสี่เหลี่ยมนั้น
sam hocevar

11

ฉันถือว่าสี่เหลี่ยมผืนผ้าของคุณอยู่ในแนวแกน

คุณเพียงแค่ต้อง "ยึด" จุดเข้าไปในสี่เหลี่ยมแล้วคำนวณระยะทางจากจุดยึด

จุด = (px, py), สี่เหลี่ยมผืนผ้า = (rx, ry, แบนด์วิดท์, rheight) // (มุมบนซ้าย, ขนาด)

function pointRectDist (px, py, rx, ry, rwidth, rheight)
{
    var cx = Math.max(Math.min(px, rx+rwidth ), rx);
    var cy = Math.max(Math.min(py, ry+rheight), ry);
    return Math.sqrt( (px-cx)*(px-cx) + (py-cy)*(py-cy) );
}

3

คุณต้องใช้การชนกันของวงกลมสี่เหลี่ยมสำหรับสิ่งนี้ มีคำถามที่คล้ายกันใน Stack Overflow

ศูนย์กลางของวงกลมของคุณจะเป็นจุดที่สงสัยและรัศมีจะเป็นระยะทางที่คุณต้องการตรวจสอบ


3

หากคุณกำลังพยายามหาระยะทางจากจุดหนึ่งไปยังอีกมุมหนึ่งของสี่เหลี่ยมการทำงานกับเก้าภูมิภาคที่สร้างโดยสี่เหลี่ยมอาจเป็นวิธีที่เร็วที่สุด:

function pointRectangleDistance(x, y, x1, y1, x2, y2) {
    var dx, dy;
    if (x < x1) {
        dx = x1 - x;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else if (x > x2) {
        dx = x - x2;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else {
        if (y < y1) {
            return y1 - y;
        }
        else if (y > y2) {
            return y - y2;
        }
        else {
            return 0.0; // inside the rectangle or on the edge
        }
    }
}

2

[แก้ไขคำตอบตามความคิดเห็น]

ถ้าคุณต้องการดูว่าจุดนั้นอยู่ในหน่วย 10 หน่วยถ้าสี่เหลี่ยมสีเทาในภาพด้านล่างคุณตรวจสอบว่าจุดนั้นอยู่ในรูปใด

  1. สี่เหลี่ยมผืนผ้าสีแดง
  2. สี่เหลี่ยมผืนผ้าสีน้ำเงิน
  3. วงกลมสีเขียวอันใดอันหนึ่ง (รัศมี 10)

ป้อนคำอธิบายรูปภาพที่นี่

inside=false;

bluerect.x=oldrect.x-10;
bluerect.y=oldrect.y;
bluerect.width=oldrect.width;
bluerect.height=oldrect.height+20;

if(  point.x >=bluerect && point.x <=redrect.x+bluerect.width &&
     point.y >=bluerect && point.y <=redrect.y+bluerect.height){
         //now point is side the blue rectangle
         inside=true;
}

redrect.x=oldrect.x;
redrect.y=oldrect.y-10;
redrect.width=oldrect.width+20;
redrect.height=oldrect.height;

if(  point.x >=redrect&& point.x <=redrect.x+redrect.width &&
     point.y >=redrect&& point.y <=redrect.y+redrect.height){
         //now point is side the redrectangle
         inside=true;
}


d1= distance(point, new point(oldrect.x, oldrect.y)) //calculate distance between point and (oldrect.x, oldrect.y)
d2= distance(point, new point(oldrect.x+10, oldrect.y))
d3= distance(point, new point(oldrect.x, oldrect.y+10))
d4= distance(point, new point(oldrect.x+10, oldrect.y+10))
if (d1 < 10 || d2 <10 || d3 < 10 || d4 <10){
    inside=true;
}

//inside is now true if the point is within 10 units of rectangle

วิธีการนี้มีความซับซ้อนเล็กน้อย วิธีการที่คล้ายกันซึ่งหลีกเลี่ยงการทดสอบทั้ง 4 มุมโดยการใช้ symmetry สี่เหลี่ยมผืนผ้านั้นมีการบันทึกไว้ที่ stackoverflow


ในทิศทางแนวทแยงนี้จะให้ผลบวกที่ผิดพลาดกับคะแนนที่เป็นเช่น ห่างออกไป 11 หน่วย
Eric B

รูปภาพที่อัปเดตนั้นผิดปกติจริง ๆ แล้วมันแสดงให้เห็นถึงกรณีข้อผิดพลาดและทำให้มันถูกต้อง จุดสีเขียวนั้นอาจอยู่ห่างออกไปมากกว่า 10 ยูนิตและอยู่ภายในสี่เหลี่ยมด้านนอกนั้น
Eric B

เฮ้ @EricB ฉันได้แก้ไขข้อผิดพลาดที่คุณได้ชี้ไปแล้วการเลิกทำการ downvote ของคุณล่ะ?
เคน

คำตอบของคุณจะไม่ให้ผลลัพธ์ที่ไม่ถูกต้องอีกต่อไปดังนั้นฉันจึงลบ downvote แต่ก็ไม่ใช่วิธีที่ดีที่สุดเลย ทำไมไม่ลองทดสอบดูว่าศูนย์กลางอยู่ภายในสี่เหลี่ยมหรือไม่และถ้าส่วนของสี่บรรทัดตัดกันวงกลม? การสร้างรูปสี่เหลี่ยมผืนผ้าและวงกลมใหม่เหล่านี้ไม่จำเป็น คำตอบของคุณยังไม่ได้ให้ระยะทางจริงจากจุดไปยังสี่เหลี่ยมผืนผ้า
Eric B

คำตอบนี้น่ากลัวจริงๆ เพิ่ม 12, การสร้างวัตถุ 4, การทดสอบ 12, รากที่ 4 สำหรับงานที่ต้องใช้รหัส 3 บรรทัด
sam hocevar

-2

คุณสามารถใช้สิ่งนี้: ป้อนคำอธิบายรูปภาพที่นี่


วิธีนี้ดูเหมือนซับซ้อนโดยไม่จำเป็น การค้นหา x1 และ y1 ไม่จำเป็นต้องแก้ปัญหานี้
Eric B

ในความเป็นจริงมันไม่ได้ตอบสนองความต้องการในการค้นหาการชนกันภายในระยะทางที่กำหนด มันเป็นวิธีที่ไม่ดีในการตรวจสอบว่าจุดนั้นอยู่ภายในสี่เหลี่ยมหรือไม่
Eric B

การวัดระยะทางมีอยู่แล้วโดยปริยาย if (d2 <10 * 10) {/ * ภายใน 10 หน่วยวัด * /}
AlexanderBrevig
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.