I was looking for a way to put a four petal flower shape on my Python-POV-ray generated egg. As it turns out, this shape is a common geometric one called
Pascal's Rose.
For expediency rather than efficiency's sake, I opted to generate the shape using individual x, y points (actually x, z in POV-ray):
def getcoords(theta, factorr, factortheta, trigfunc):
"""
Returns two tuple of x and y values for
the equation in the form
factorr * r * r = trigfunc(factortheta * theta)
"""
r = math.sqrt((trigfunc(factortheta * theta)) ** 2 / factorr)
x = r * math.cos(theta)
y = r * math.sin(theta)
if abs(x) < ZEROLIMIT:
x = 0.0
if abs(y) < ZEROLIMIT:
y = 0.0
print x, y, theta
return x, y
def cycleequation(step, start, stop, trigfunc, factorr, factortheta):
"""
Returns list of x, y coordinates that correspond
to the equation of the form
factorr * r * r = trigfunc(factortheta * theta)
theta will be incremented by step.
start is the first value of theta.
stop is the last value of theta.
"""
coords = []
theta = start
while theta < stop:
coords.append(getcoords(theta, factorr, factortheta, trigfunc))
theta += step
coords.append(getcoords(stop, factorr, factortheta, trigfunc))
return coords
math.cos creates Pascal's Rose for this equation. I had to add a Prism object to the
POV-ray recipe I am using.
class Prism(Item):
def __init__(self, base, top, numpts, *opts, **kwargs):
Item.__init__(self,"prism",(base, top, numpts),opts,**kwargs)
For me it was easiest to just translate the points of the prism into POV-ray SDL language prior to feeding them to Python:
def translatetopovray(pts):
"""
Returns string in povray format of list
of points pts.
"""
stringpoints = []
for pt in pts:
stringpoints.append('<%.8f, %.8f>' % pt)
return string.join(stringpoints, ',')
This allowed for generation of a prism:
This is just a rough representation of what I wanted. The scene I was creating required a two colored flower, the outside as gold and the inside as orange. Further, the outside edge needed to appear to be of constant width, as one would achieve by applying wax to an egg with the pysanky drawing tool, the kistka.
To get this effect I used a rough offset algorithm - get the centerpoint of the line segment on the outside edge of the "flower", offset a set distance along the normal to the outside line segment, then connect all the inner points.
def gettan(pt1, pt2):
"""
Returns the tangent of the directional
angle formed by line segment pt1-pt2.
"""
return (pt2[1] - pt1[1])/(pt2[0] - pt1[0])
def getmidpoint(pt1, pt2):
"""
Get the midpoint of the line segment
pt1-pt2.
"""
x = pt1[0] + (pt2[0] - pt1[0])/2.0
y = pt1[1] + (pt2[1] - pt1[1])/2.0
return x, y
def calcoffsetpoint(pt1, pt2, offset):
"""
Get point offset distance offset
from the midpoint of line segment
pt1-pt2 to the left.
"""
midpoint = getmidpoint(pt1, pt2)
# get normal
# quadrant I
if pt2[0] >= pt1[0] and pt2[1] >= pt1[1]:
theta = math.atan(gettan(pt1, pt2)) + math.pi/2.0
x = midpoint[0] + math.cos(theta) * offset
y = midpoint[1] + math.sin(theta) * offset
# quadrant II
elif pt2[0] <= pt1[0] and pt2[1] >= pt1[1]:
theta = math.atan(gettan(pt1, pt2)) + math.pi/2.0
x = midpoint[0] - math.cos(theta) * offset
y = midpoint[1] - math.sin(theta) * offset
# quadrant III
elif pt2[0] <= pt1[0] and pt2[1] <= pt1[1]:
theta = 3.0 * math.pi/2.0 + math.atan(gettan(pt1, pt2))
x = midpoint[0] + math.cos(theta) * offset
y = midpoint[1] + math.sin(theta) * offset
# quadrant IV
elif pt2[0] >= pt1[0] and pt2[1] <= pt1[1]:
theta = 3.0 * math.pi/2.0 + math.atan(gettan(pt1, pt2))
x = midpoint[0] - math.cos(theta) * offset
y = midpoint[1] - math.sin(theta) * offset
else:
print pt1, pt2
print 'error - theta undefined'
theta = 0.0
return x, y
def getmiddle(step, start, stop, trigfunc, factorr, factortheta, offset):
"""
Return list of points for middle of 'petal'.
"""
startend = (0.0, 0.0)
pts = [startend]
# need to offset by fixed distance along
# normal to each line segment
# need to get pts along original flower
# but not near 0.0, 0.0 where they will
# overlap
outsidepts = cycleequation(step, start, stop,
trigfunc, factorr, factortheta)
counter = 0
maxcounter = len(outsidepts)
while (counter + 1) < (maxcounter - 1):
pts.append(calcoffsetpoint(outsidepts[counter],
outsidepts[counter + 1], offset))
counter += 1
pts.append(startend)
return pts
My analytical geometry is a bit rough, but this works well enough for what I was trying to accomplish.
Through some intersecting and positioning, I was able to get the effect I wanted. This egg design, according to the Sixty Score of Easter Eggs book by Elyjiw, is from the Odessa region of the Ukraine.
Thanks for having a look.