简体   繁体   English

多边形区域(递归使用Python)

[英]Area of a polygon (Recursively using Python)

I'm trying a solve an exercise from Exploring Python book. 我正在尝试解决探索Python书籍的练习。 But, I guess I don't understand concept of the recursion. 但是,我想我不明白递归的概念。 I've written some Recursively function. 我写了一些递归函数。 Therefore I know some of the aspects. 因此我知道一些方面。 But, I don't have enough experience. 但是,我没有足够的经验。 And I've stopped to study programming about one year. 而且我已经停止学习大约一年的编程。

Anyway, let me give you the full question: 无论如何,让我给你一个完整的问题:

A polygon can be represented by a list of (x, y) pairs where each pair is a tuple: [ (x1, y1), (x2, y2), (x3, y3) , ... (xn, yn)]. 多边形可以由(x,y)对列表表示,其中每对是元组:[(x1,y1),(x2,y2),(x3,y3),...(xn,yn)] 。 Write a recursive function to compute the area of a polygon. 编写递归函数来计算多边形的面积。 This can be accomplished by “cutting off” a triangle, using the fact that a triangle with corners (x1, y1), (x2, y2), (x3, y3) has area (x1y1 + x2y2 + x3y2 – y1x2 –y2x3 – y3x1) / 2. 这可以通过“切断”三角形来实现,使用具有角(x1,y1),(x2,y2),(x3,y3)的三角形具有面积(x1y1 + x2y2 + x3y2-y1x2-y2x3)的事实。 y3x1)/ 2。

Despite the fact that, the question already gave the formula, I used another formula. 尽管问题已经给出了公式,但我使用了另一个公式。 Because, I made some research about area of a polygon. 因为,我对多边形的面积做了一些研究。 And if you look at here the formula is different. 如果你看这里的公式是不同的。

And describing my program step by step would be better, in order to explain what I want. 一步一步地描述我的程序会更好,以便解释我想要的东西。 OK, I had to declare global scopes, because of recursion: 好的,我必须声明全局范围,因为递归:

area = 0
x = [0] * 3
y = [0] * 3 

And then, I created a recursively function. 然后,我创建了一个递归函数。 Zero is always returned by this function as a result. 因此,此函数始终返回零。 So my real problem is this: 所以我真正的问题是:

def areaofpolygon(polygon, i):
    global area, x, y # My variables 
    try: # I prefered using try statement from using if-else statements. So it is the easier I guess.
        x[i], y[i] = polygon[i] # X and Y coordinates from tuple
        area += (x[i]*y[i+1] - x[i+1]*y[i]) #My formula
    except IndexError:
        return area/2

    areaofpolygon(polygon, i+1)   # Here, this is my weird recursion

And my main function: 而我的主要功能:

  def main():
      mypolygon = [(1,2), (2,5), (1,4)] # I declared polygon as tuples
      # I called my function and started to count from zero, and the result will be prompted.
      print(areaofpolygon(mypolygon,0))

      return 0
  if __name__ == '__main__':
      main()

And here is my full code without comments: 这是我的完整代码没有评论:

'''
Created on Feb 24, 2012

@author: msarialp
'''
area = 0
x = [0] * 3
y = [0] * 3
def areaofpolygon(polygon, i):
    global area, x, y
    try:
        x[i], y[i] = polygon[i]
        area += (x[i]*y[i+1] - x[i+1]*y[i])
    except IndexError:
        return area/2

    areaofpolygon(polygon, i+1)   
def main():
    mypolygon = [(1,2), (2,5), (1,4)]
    print(areaofpolygon(mypolygon,0))

    return 0
if __name__ == '__main__':
    main()

EDIT One 编辑一

After reading your answers, I've understood what was wrong with my code. 阅读完答案后,我明白了我的代码出了什么问题。 So I decided to share last version of my program in order to get some other helps. 所以我决定分享我的程序的最新版本,以获得一些其他的帮助。 Again, I had to declare global variables. 同样,我必须声明全局变量。 How can I apply ( lop_triangle ) function from senderle 如何从senderle应用(lop_triangle)函数

area = 0
x = [0] * 3
y = [0] * 3

My function that divides tuple and to get x and y coordinates. 我的函数分割元组并获得x和y坐标。

def sides_of_polygon(polygon, i):
    global x, y
    try:
        x[i], y[i] = polygon[i]
        return sides_of_polygon(polygon, i+1)
    except IndexError:
        return x, y

My function calculate area of polygon( Same as before ) 我的函数计算多边形的面积(与之前相同)

def area_of_polygon(x, y, i):
    global area
    try:
        area += x[i]*y[i+1] - x[i+1]*y[i]
        return area_of_polygon(x, y, i+1)
    except IndexError:
        return area/2.0

My main function... 我的主要功能......

def main():
    mypolygon = [(1,2), (2,5), (1,4)]
    dx, dy = sides_of_polygon(mypolygon, 0)
    print(area_of_polygon(dx,dy,0))

    return 0
if __name__ == '__main__':
    main()

Please help me to improve my code without giving full solution. 请帮助我改进我的代码而不提供完整的解决方案。

EDIT Two 编辑二

After making discussion with senderle, I understood where is the problem and senderle's solution is better than mine so I suggest that you should use it. 在与senderle讨论之后,我明白了问题在哪里,发送者的解决方案比我的更好,所以我建议你应该使用它。 Anyway, He helped me to make my code correct.And I had to change my formula again. 无论如何,他帮助我使我的代码正确。我不得不再次更改我的公式。

area += x[i]*y[(i+1) % 3] - x[(i+1) % 3]*y[i]

He also added for longer polygons 3 must be len(vertices). 他还添加了更长的多边形3必须是len(顶点)。 Thanks everyone for their time. 谢谢大家的时间。

The implementation of your formula is flawed. 你的公式的实施是有缺陷的。 It looks ahead to values in your x, y lists that haven't been set yet with (x[i]*y[i+1] - x[i+1]*y[i]) 它预测了x,y列表中尚未设置的值(x[i]*y[i+1] - x[i+1]*y[i])

If you put a print statement inside your try-except block you will see that you are simply multiplying by zero and getting zero area: 如果你在try-except块中放置一个print语句,你会看到你只是乘以零并得到零区域:

try:
    x[i], y[i] = polygon[i]
    area += (x[i]*y[i+1] - x[i+1]*y[i])
    print x[i], y[i+1], x[i+1], y[i]
except IndexError, e:
    return area/2

#1 0 0 2
#2 0 0 5

Also, you are not returning the results of your recursive call to areaofpolygon, so you will never get that area/2 . 此外,您没有将递归调用的结果返回到areaofpolygon,因此您永远不会获得该area/2 You want: return areaofpolygon(polygon, i+1) . 你想要: return areaofpolygon(polygon, i+1) And make sure you actually divide by 2.0 so that you get float precision since your points are ints. 并确保你实际上除以2.0,以便你得到浮点精度,因为你的积分是整数。

Try just using the formula you found or that was suggested in another question. 尝试使用您找到的公式或另一个问题中建议的公式。

Update 更新

Here is a fixed version of your code: 以下是您的代码的固定版本:

#!/usr/bin/env python

from random import randint
from shapely.geometry import Polygon

area = 0

def areaofpolygon(polygon, i):
    global area
    if i == 0: 
        area = 0

    try:
        x1, y1 = polygon[i]
        x2, y2 = polygon[i+1]
        area += (x1*y2) - (x2*y1)

    except IndexError, e:
        x1, y1 = polygon[0]
        x2, y2 = polygon[-1]
        area += (x2*y1) - (x1*y2)
        return abs(area/2.0)

    return areaofpolygon(polygon, i+1)   

def main():
    mypolygon = [(randint(0, 100), randint(0, 100)) for _ in xrange(10)]
    print mypolygon

    area = areaofpolygon(mypolygon, 0)
    assert area == Polygon(mypolygon).area

    print "Test passed."
    return 0

if __name__ == '__main__':
    main()

### Output ###
$ ./test.py 
[(29, 76), (85, 49), (27, 80), (94, 98), (19, 1), (75, 6), (55, 38), (74, 62), (0, 25), (93, 94)]
Test passed.
$ ./test.py 
[(13, 37), (98, 74), (42, 58), (32, 64), (95, 97), (34, 62), (34, 59), (21, 76), (55, 32), (76, 31)]
Test passed.
$ ./test.py 
[(38, 67), (66, 59), (16, 71), (53, 100), (64, 52), (69, 31), (45, 23), (52, 37), (27, 21), (42, 74)]
Test passed.

Notice that you didn't need global x,y lists. 请注意,您不需要全局x,y列表。 And you also missed the last part of the equation where you use the last point and the first point. 你也错过了使用最后一点和第一点的等式的最后一部分。

The essence of recursion is as follows: 递归的本质如下:

  1. Identify a simple base case and solve for that. 找出一个简单的基本案例并解决这个问题。
  2. Conceive of a process that, when repeated, reduces a more complex case to that base case. 设想一个过程,当重复时,将一个更复杂的案例减少到该基本案例。
  3. Apply the process in #2 to the problem until you reach the base case. 将#2中的过程应用于问题,直到到达基本案例。

In your case, the first step is easy. 在您的情况下,第一步很容易。 The smallest polygon is a triangle. 最小的多边形是三角形。 The area of a triangle is (x1y2 + x2y3 + x3y1 – y1x2 –y2x3 – y3x1) / 2 . 三角形的面积是(x1y2 + x2y3 + x3y1 – y1x2 –y2x3 – y3x1) / 2 (It looks like they misstated it in the problem though...) (虽然看起来他们在问题中错了...)

The second step is also easy, because the problem statement gives it to you: given an n-vertex polygon, lop off a triangle, determine its area, and add it to the area of the resulting (n-1)-vertex polygon. 第二步也很简单,因为问题陈述给你:给定一个n顶点多边形,砍掉一个三角形,确定它的面积,然后将它添加到结果(n-1) - 多边形的多边形区域。

We'll break it down into parts. 我们将其细分为部分。 First, a function to solve #1: 首先,解决#1的功能:

def area_of_triangle(points):
    (x1, y1), (x2, y2), (x3, y3) = points
    return abs(x1 * y2 + x2 * y3 + x3 * y1 - y1 * x2 - y2 * x3 - y3 * x1) / 2

Easy. 简单。 Now a function to solve #2. 现在解决#2的功能。 All we need is a function that lops off a triangle and returns both it and the resulting smaller polygon: 我们需要的只是一个函数,它会丢弃一个三角形并返回它和生成的较小的多边形:

def lop_triangle(points):
    triangle = [points[0], points[-1], points[-2]]
    polygon = points[:-1]
    return triangle, polygon

If it's not obvious, this simply creates a triangle using the first and the last two points of the polygon. 如果不明显,这只是使用多边形的第一个和最后两个点创建一个三角形。 Then it removes the last point of the polygon, which is now equivalent to chopping off the triangle. 然后它删除多边形的最后一个点,现在相当于切掉三角形。 (Draw a n-polygon and label its vertices from 0 to n to see how it works.) So now we have a triangle and a simpler polygon. (绘制一个n多边形并将其顶点从0标记为n以查看它是如何工作的。)所以现在我们有了一个三角形和一个更简单的多边形。

Now, let's put it all together. 现在,让我们把它们放在一起。 This third step is in some ways the hardest, but because we solved the first two problems already, the third is easier to understand. 第三步在某些方面是最困难的,但因为我们已经解决了前两个问题,第三步更容易理解。

def area_of_polygon(points):
    if len(points) == 3:
        return area_of_triangle(points)
    else:
        triangle, polygon = lop_triangle(points)
        return area_of_triangle(triangle) + area_of_polygon(polygon)

All the magic happens in that last line. 所有的魔力都发生在最后一行。 Every time area_of_polygon gets a triangle, it just returns the area of a triangle. 每当area_of_polygon获得一个三角形时,它就会返回三角形的区域。 But when it gets a larger polygon, it lops off a triangle, takes the area of that triangle, and adds it to... the area of a smaller polygon. 但是当它获得一个更大的多边形时,它会跳过一个三角形,取出该三角形的区域,然后将其添加到...更小的多边形区域。 So say the polygon has 5 vertices. 所以说多边形有5个顶点。 The first time area_of_polygon is called (c1), it lops off a triangle, takes its area, and then calls area_of_polygon (c2) again , but this time with a 4-vertex polygon. 第一次area_of_polygon (c1)时,它会area_of_polygon一个三角形,取其面积,然后再次调用area_of_polygon (c2),但这次使用的是4顶点多边形。 Then area_of_polygon lops of a triangle, and calls area_of_polygon (c3) again , but this time with a 3-vertex polygon. 然后area_of_polygon三角形,并再次调用area_of_polygon (c3),但这次使用3顶点多边形。 And then it doesn't have to call area_of_polygon again. 然后它不必再次调用area_of_polygon It just returns the area of a triangle to the previous call (c2). 它只是将三角形区域返回到前一个调用(c2)。 That sums the result with the triangle in (c2) and returns that value to (c1). 将结果与(c2)中的三角形相加,并将该值返回到(c1)。 And then you have your answer. 然后你有答案。

Also, for what it's worth, the wolfram formula can be written with great clarity in three lines: 此外,对于它的价值, wolfram公式可以非常清晰地写成三行:

def area_of_polygon(vertices):
    pairs = zip(vertices, vertices[1:] + vertices[0:1])
    return sum(x1 * y2 - y1 * x2 for (x1, y1), (x2, y2) in pairs) / 2

Use this formula. 使用此公式。

https://upload.wikimedia.org/wikipedia/en/math/c/b/b/cbb6a25439b51061adb913c2a6706484.png https://upload.wikimedia.org/wikipedia/en/math/c/b/b/cbb6a25439b51061adb913c2a6706484.png

You accomplish your task in one for loop. 您可以在一个for循环中完成任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM