我正在編寫一個Python程序,以從着名的Heinlein小說The Moon is a Harsh Mistress中生成Luna Free State標誌,作爲個人項目。我一直在破壞紋章規則和匹配網絡上的數學公式,但是在我的例程中顯然是錯誤的,因爲在取消註釋時斷言失敗。彎曲區域的面積應該是標誌總面積的三分之一,而不是。我做的唯一真正狡猾的事情是猜測梯形高度的公式,但我猜錯誤可能在任何地方。我已經刪除了大部分代碼,只留下了顯示問題的必要條件。希望沒有數學挑戰的人可以發現錯誤!數學不好或編程不好,也許都是?
#!/usr/bin/python
'generate bend sinister according to rules of heraldry'
import sys, os, random, math, Image, ImageDraw
FLAG = Image.new('RGB', (900, 600), 'black')
CANVAS = ImageDraw.Draw(FLAG)
DEBUGGING = True
def bendsinister(image = FLAG, draw = CANVAS):
'''a bend sinister covers 1/3 of the field, sinister chief to dexter base
(some sources on the web say 1/5 of the field, but we'll use 1/3)
the "field" in this case being the area of the flag, so we need to
find a trapezoid which is 1/6 the total area (width * height).
we need to return only the width of the diagonal, which is double
the height of the calculated trapezoid
'''
x, y = image.size
b = math.sqrt((x ** 2) + (y ** 2))
A = float(x * y)
debug('%d * %d = %d' % (x, y, A))
H = triangle_height(A/2, b) # height of triangular half of flag
width = trapezoid_height(b, H, A/6) * 2
if command == 'bendsinister':
show_bendsinister(x, y, width, image, draw)
return width
def show_bendsinister(x, y, width, image = FLAG, draw = CANVAS):
'for debugging formula'
dexter_base, sinister_chief = (0, y), (x, 0)
draw.line((dexter_base, sinister_chief), 'blue', int(width))
image.show()
debug(image.getcolors(2)) # should be twice as many black pixels as blue
def triangle_height(a, b):
'a=bh/2'
h = float(a)/(float(b)/2)
debug('triangle height: %.2f' % h)
return h
def trapezoid_height(b, H, a):
'''calculate trapezoid height (h) given the area (a) of the trapezoid and
base b, the longer base, when it is known that the trapezoid is a section
of a triangle of height H, such that the top, t, equals b when h=0 and
t=0 when h=H. h is therefore inversely proportional to t with the formula
t=(1-(h/H))*b, found simply by looking for what fit the two extremes.
the area of a trapezoid is simply the height times the average length of
the two bases, b and t, i.e.: a=h*((b+t)/2). the formula reduces
then to (2*a)/b=(2*h)+(h**2)/H, which is the quadratic equation
(1/H)*(h**2)+(2*h)-((2*a)/b)=0; solve for h using the quadratic formula
'''
try:
h = (-2 + math.sqrt(4 - 4 * (1.0/H) * -((2 * a)/b)))/(2 * (1.0/H))
debug('trapezoid height with plus: %.2f' % h)
except: # must be imaginary, so try minus instead
h = (-2 - math.sqrt(4 - 4 * (1.0/H) * -((2 * a)/b)))/(2 * (1.0/H))
debug('trapezoid height with minus: %.2f' % h)
t = (1 - (float(h)/H)) * b
debug('t=%d, a=%d, check=%d' % (t, round(a), round(h * ((b + t)/2))))
#assert round(a) == round(h * ((b + t)/2))
return h
def debug(message):
if DEBUGGING:
print >>sys.stderr, message
if __name__ == '__main__':
command = os.path.splitext(os.path.basename(sys.argv[0]))[0]
print eval(command)(*sys.argv[1:]) or ''
這裏是調試的輸出,顯示我遠從1/3面積:
[email protected]:~/rentacoder/jcomeau/tanstaafl$ ./bendsinister.py 900 * 600 = 540000 triangle height: 499.23 trapezoid height with plus: 77.23 t=914, a=90000, check=77077 [(154427, (0, 0, 255)), (385573, (0, 0, 0))] 154.462354191
這裏是輸出的圖像,與一些添加的行: 的紅線將兩個三角形分開,或者可以用於計算梯形。我使用從左上角開始的那個。綠線是該三角形的高度,即程序中的變量H.
對於完成的腳本和標誌(使用Michael Anderson提供的更正),請參閱 http://unternet.net/tanstaafl/。感謝所有的幫助!
也許這更適合[代碼評論](http://codereview.stackexchange.com/)? – 2011-04-26 06:47:18
@Tim,你爲什麼這麼認爲?這是一個編程問題,我試圖解決,而不是有效的,我試圖改善。 – 2011-04-26 06:50:54
只是一個預感,基於迄今爲止缺乏答案和近距離投票(而不是我)。 – 2011-04-26 07:04:02