จะคำนวณพื้นที่ที่มีรูปร่างผิดปกติได้อย่างไร?


17

ฉันมีห้องวัตถุที่กำหนดโดยชุดของส่วนของเส้นที่วนลูปที่ฉันต้องคำนวณพื้นที่ คลาสสามารถอธิบายได้ดังต่อไปนี้ (ในรหัสเทียม):

class Point {
    float x; 
    float y;
    ...
    float distanceFrom(Point p);
}

class Segment {
    Point start;
    Point end;
    ...
    float length();
}

class Room {
    List<Segment> walls;
    ...
    float area();
}

ผนังของห้องไม่สามารถตัดกันได้ทุกที่ แต่ที่จุดสิ้นสุดของเซกเมนต์และ "sub-loops" ที่สร้างขึ้นจะถูกแยกออกเป็นห้องใหม่ การแก้ปัญหาไม่จำเป็นต้องแม่นยำอย่างสมบูรณ์ (ยอมรับข้อผิดพลาด 10%) และไม่คำนวณบ่อยมาก (<1 / s)


7
มันจะเหมาะสมกว่าที่RoomจะมีรายการของPoints แล้วรับส่วนด้วยการเชื่อมต่อแต่ละจุดเข้าด้วยกันแล้ววนกลับเข้าไปใหม่ มิฉะนั้นด้วยการตั้งค่าปัจจุบันของคุณมันตะวันออกมากที่จะได้รับค่าที่ไม่ถูกต้อง (เช่นห้องที่ไม่มีคนอยู่ห้องที่มีผนังตรงกลางเป็นต้น) นี่จะเป็นตัวเลือกที่ดีที่สุด
MCMastery

อีกตัวเลือกหนึ่งคือสามเหลี่ยมด้านบนและคำนวณพื้นที่ของสามเหลี่ยมแต่ละอัน ส่วนที่ยากคือสมการ ทำได้ แต่ไม่สวยเสมอไป คำตอบเชือกผูกรองเท้ายังดีกว่า
Draco18 ไม่ไว้วางใจ SE

@MCMastery ว่าการแก้ปัญหาจะไม่ทำงานตามที่ต้องการRooms จะเสร็จสมบูรณ์เสมอและที่ไม่อาจเป็นกรณีที่หากมีการสร้างผู้เล่นRooms ใช้Segments นอกจากนี้ฟังก์ชั่นปิดห้องยังง่ายต่อการกำหนด (เพียงวนผ่านSegments และตรวจสอบให้แน่ใจว่าพวกเขาสร้างห้อง)

คำตอบ:


31

คุณสามารถใช้สูตรเชือกผูกรองเท้าของเกาส์ได้ :

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

A = 0

for (i = 0; i < points.length; i++) do

    A += points[i].x * points[(i + 1) % points.length].y - points[i].y * points[(i + 1) % points.length].x

end

A /= 2

2
ฉันมักจะใช้มันเพื่อคำนวณผลคูณของเวกเตอร์สองตัวที่ไม่เคยรู้มาก่อนมันถูกเรียกว่าอัลกอริทึมเชือกผูกรองเท้า
Sidar

3
โปรดทราบว่าสิ่งนี้สามารถขยายได้เพื่อคำนวณปริมาตรของวัตถุ 3 มิติที่ผิดปกติซึ่งทำจากรูปสามเหลี่ยมและสามารถพิจารณาได้ในกรณีที่ไม่สำคัญของทฤษฎีบทพื้นฐานของแคลคูลัส
Dietrich Epp

5
พื้นที่ที่นี่ถูกเซ็นชื่อ ผ่านจุดต่าง ๆ ในทิศทางอื่นและสุดท้ายAจะถูกทำให้ไร้ผล A = |A|อาจจำเป็นต้องa ด้วยรหัสพื้นที่เชิงลบสามารถค้นหาพื้นที่ในโดนัทที่ผิดปกติโดยใช้รายการจุดภายในและภายนอก (หนึ่งในลำดับที่ตรงข้าม)
chux - Reinstate Monica

6
เพราะแน่นอนว่าเกาส์หรือออยเลอร์มีสูตรสำหรับมัน
corsiKa

0

เราสามารถใช้วิธีมอนติคาร์โล

วาดสี่เหลี่ยมรอบรูปร่างโดยพลการ ใช้แหล่ง PRNG ที่กระจายอย่างสม่ำเสมอเช่น mersenne twister แล้วผูกเอาท์พุตด้วยความยาว X, Y ของสี่เหลี่ยมโดยใช้ฟังก์ชันโมดูโล นับจำนวน ของคะแนนสุ่มที่ลงจอดอยู่ในรูปร่างของคุณ หารด้วยจำนวนคะแนนทั้งหมดที่สร้าง คูณผลหารหารด้วยพื้นที่ของสี่เหลี่ยม ด้วยการวนซ้ำแต่ละครั้งคุณจะเข้าหาพื้นที่จริง อัลกอริธึมนั้นมีความน่าขันและสามารถใช้ในการคำนวณ 'ปริมาตร' รูปร่างตามอำเภอใจได้ตราบใดที่คุณสามารถกำหนดได้ว่าพิกัด R ^ N ตกอยู่ในขอบเขต R ^ N ของรูปร่างหรือไม่

.

ที่นี่มีใครบางคนกำลังใช้วิธีนี้ค้นหาพื้นที่วงกลมจากนั้นใช้สิ่งนั้นในการคำนวณ pi https://www.youtube.com/watch?v=VJTFfIqO4TU


2
-1: คุณไม่ต้องการใช้โมดูโล่เพื่อให้อยู่ในช่วงคุณต้องการใช้การแจกแจงแบบเดียวกันหรือการแจกแจงแบบอื่นการทำแบบโมดูโล่นั้นมีปัญหาทางสถิติทุกประเภท
user1997744

12
วิธีนี้อาจเป็นประโยชน์เมื่อเราไม่มีรูปหลายเหลี่ยมที่เรียบง่าย แต่มีรูปร่างที่ค่อนข้างชัดเจนซึ่งมีเส้นขอบที่ยากต่อการแสดงออกเช่นเศษส่วนหรือเศษซากเมทัลล์ สำหรับกรณีของรูปหลายเหลี่ยมดังในคำถาม แต่ดูเหมือนว่ามันจะมีราคาแพงโดยไม่จำเป็น
DMGregory

@DMGregory ชี้ว่านี่ไม่ใช่สิ่งที่ฉันกำลังมองหา อย่างไรก็ตามฉันคิดว่ามันสมควรได้รับ +1 ในกรณีที่มีคนอื่นต้องการ

สิ่งนี้น่าสนใจ แต่ค่าใช้จ่ายในการทดสอบรวมจะไม่ถูกห้ามหรือไม่ คือถ้าคุณมีรูปร่างที่ซับซ้อนเพียงพอที่จะรับประกันวิธีการนี้การทดสอบแบบรวมจะไม่แพงเลยดังนั้นคุณไม่ต้องการทำแบบทดสอบหลาย ๆ แบบเลยเหรอ? (สมมติว่ามีรูปหลายเหลี่ยม)
Mattia

Ok modulo เป็นปัญหาแน่นอน แต่มันเป็นทางออกที่ง่าย สิ่งที่เราได้รับอย่างแท้จริงคือสุ่ม P = 1/2 บิต 0/1 ดังนั้นสิ่งที่เราได้คือการกระจายตัวของตัวเลขอย่างสม่ำเสมอ สำหรับ 3 บิตจาก 0 ถึง 7 การทำแรนด์% 5 หากตัวเลขสุ่มใช้ค่า 6 หรือ 7 จะได้รับการแมปเป็น 1 หรือ 2 ทำให้มีผลเพิ่มความถี่ 1,2 ทำให้การแจกแจงไม่สม่ำเสมอ เพื่อหลีกเลี่ยงการที่คุณต้องการบางสิ่งบางอย่างเช่นเครื่องรัฐที่หมุนแผนที่เช่น 6,7 แผนที่ไป 1,2 จากนั้นเป็น 3,4 จากนั้น 5,0 และมันจะดำเนินต่อไป เราสามารถทิ้ง 6,7 เมื่อใดก็ตามที่พวกเขาขึ้นมา อย่างไรก็ตามนั่นเป็นปัญหาการใช้งานห้องสมุด
FranG

-1

วิธีอื่น: อย่า

แทน:

while (Segments.Count > 3)
{
    Segment A = Segments[Segments.Count - 2];
    Segment B = Segments[Segments.Count - 1];
    Segment C = new Segment(B.End, A.Start);
    Triangle T = new Triangle(A, B, C);
    Segments[Segments.Count - 2] = C;
    Segments.RemoveAt(Segments.Count - 1);
    if (B is inside the new shape Segments)
        Area -= T.Area;
    else
        Area += T.Area;
}
Area += new Triangle(Segments[0], Segments[1], Segments[2]).Area;

โดยทั่วไปลพบุรีสามเหลี่ยม พื้นที่ของรูปสามเหลี่ยมนั้นเรียบง่ายและในการทำเช่นนั้นเราจึงลดจำนวนส่วนที่เหลือลงทีละส่วน ทำซ้ำจนกระทั่งสิ่งที่เหลืออยู่คือรูปสามเหลี่ยม


2
สูตรเชือกผูกรองเท้าของเกาส์เป็นแบบย่อสำหรับสิ่งนี้ที่ลดลงครึ่งหนึ่งหรือสามในจำนวนการคำนวณ ทำให้เป็นไปได้.
Pieter Geerkens
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.