analytics

Thursday, October 2, 2014

"wiggling" a polygon keeping constant area

Ok suppose you have a polygon:
I noticed you can "wiggle" any of the points to 4 possible new points so that the distance to the new point from the original point is a certain number delta and the overall area of the polygon remains unchanged. Below the point (5.11) and the 4 points it can wiggle to with delta = .1




A way to figure the polygon's area is the shoelace formula:
I define the wiggle of a polygon as solving an equation like this:
where xp,yp then x,y then xn,yn are 3 consecutive points on the polygon listed clockwise with wrap around and delta is how far the wiggled point will end up being from the original point. The structure of the formula for the overall area, interestingly, is such that we can just consider the part of the sum where the variables x or y occur, which is only 4 terms depending only on the point before or after x,y as you go around clockwise no matter the polygon, and keep that the same, and the rest stays the same so the total is the same.
For example, the polygon above "wiggling" the point (5,11) with delta of .1
The interpretation is that the point (5,11) can have it's x coordinate moved + or - .288 and the y coordinate moved + or - .128 and the polygon as a whole will still have the same area.
So I thought it would be interesting to make an animation of random points on this starting polygon being wiggled 2700 wiggles altogether...
I think with many more points than 5 making a sort of blob it might look a lot like a drop of water sizzling on a frying pan, as it moves all around but maintaining area.
** Python source code (Warning! Creates 2700 .png images for making a movie with)
import random
import Image, ImageDraw

def wigglepoly(points, delta):
    i = random.randint(0, len(points)-1)
    x,y = points[i]
    if i > 0:
        xp, yp = points[i-1]
    else:
        xp, yp = points[len(points)-1]
    if i < len(points)-1:
        xn, yn = points[i+1]
    else:
        xn, yn = points[0]
    
    rad = (xp**2.0-2*xp*xn+xn**2+yn**2-2*yn*yp+yp**2)*delta
    b = ((rad)**.5*(yn-yp))/(xp**2.0-2*xp*xn+xn**2+yn**2-2*yn*yp+yp**2)
    a = (delta-b**2.0)**.5
    sign = random.randint(0, 1)
    if sign == 0:
        signa = -1
    else:
        signa = 1
    sign = random.randint(0, 1)
    if sign == 0:
        signb = -1
    else:
        signb = 1
    points2 = []
    for j in range(0, len(points)):
        if j == i:
            points2.append((x+signa*a, y+signb*b))
        else:
            points2.append(points[j])
    return points2
def main():
    
    points = [(500,1100),(1200,800),(900,500),(500,600),(300,400)]
    delta = 100
    for i in range(0, 2700):
        points = wigglepoly(points, delta)
        plot = Image.new("RGB", (1400,1400))
        draw = ImageDraw.Draw(plot)
        draw.polygon(points, fill=(255,255,255))
        plot.save("wigglepoly"+str(i)+".png")
main()

 
 

No comments:

Post a Comment