Update: ΤΖΩΤΖΙΟΥ was kind enough to introduce me to the math.atan2 function, which correctly identifies the quadrant the angle theta falls in, and rewrote my verbose function(s) concisely:

def calcoffsetpoint(pt1, pt2, offset):

theta = math.atan2(pt2[1] - pt1[1],

pt2[0] - pt1[0])

theta += math.pi/2.0

return (pt1[0] - math.cos(theta) * offset,

pt1[1] - math.sin(theta) * offset)

getoffsetintercept gets the b in y = mx + b needed to calculate the new point:

def getoffsetintercept(pt1, pt2, m, offset):

"""

From points pt1 and pt2 defining a line

in the Cartesian plane, the slope of the

line m, and an offset distance,

calculates the y intercept of

the new line offset from the original.

"""

x, y = calcoffsetpoint(pt1, pt2, offset)

return y - m * x

The function that gets a single point along the polygon:

"""

Gets intersection point of the two

lines defined by pt1, pt2, and pt3;

offset is the distance to offset

the point from the polygon.

"""

# get first offset intercept

m = (pt2[1] - pt1[1])/(pt2[0] - pt1[0])

boffset = getoffsetintercept(pt1, pt2, m, offset)

# get second offset intercept

mprime = (pt3[1] - pt2[1])/(pt3[0] - pt2[0])

boffsetprime = getoffsetintercept(pt2, pt3, mprime, offset)

# get intersection of two offset lines

newx = (boffsetprime - boffset)/(m - mprime)

newy = m * newx + boffset

return newx, newy

Lastly, the function that works the polygon offset:

"""

Offsets a clockwise list of coordinates

polyx distance offset to the inside of

the polygon.

Returns list of offset points.

"""

polyy = []

# need three points at a time

for counter in range(0, len(polyx) - 3):

# get first offset intercept

pt = getpt(polyx[counter],

polyx[counter + 1],

polyx[counter + 2],

offset)

# append new point to polyy

polyy.append(pt)

# last three points

pt = getpt(polyx[-3], polyx[-2], polyx[-1], offset)

polyy.append(pt)

pt = getpt(polyx[-2], polyx[-1], polyx[0], offset)

polyy.append(pt)

pt = getpt(polyx[-1], polyx[0], polyx[1], offset)

polyy.append(pt)

return polyy

Shown below is the shape I was trying to offset.

As the "Simple" in the entry's title suggests, this is a best case scenario:

1) no degenerate polygons inside or outside

2) no zero or infinite slopes

Actually, I should have some zero slopes, but I cheated and changed the coordinates. The differences won't be seen by the naked eye, but are big enough for the computer to handle them.

Here is the egg I was working on; it's a Hutsul design from the Sixty Score of Easter Eggs book:

Thanks for having a look.

## No comments:

## Post a Comment