2011-04-26 14 views
8

मैं एक निजी परियोजना के रूप में प्रसिद्ध हेनलेन उपन्यास The Moon is a Harsh Mistress से लुना फ्री स्टेट ध्वज उत्पन्न करने के लिए एक पायथन कार्यक्रम लिख रहा हूं। मैं हेराल्ड्री नियमों को क्रोधित कर रहा हूं और वेब से गणितीय सूत्रों से मेल खाता हूं, लेकिन मेरे bendsinister दिनचर्या में कुछ स्पष्ट रूप से गलत है, क्योंकि असम्बद्ध होने पर दावा विफल रहता है। मोड़ भयावह क्षेत्रफल ध्वज के कुल क्षेत्र 1/3 होना चाहिए, और यह नहीं है। मैंने जो किया है केवल एकमात्र वास्तव में डोजी चीज ट्राइपोज़ाइड की ऊंचाई के लिए सूत्र पर अनुमान लगाना है, लेकिन मुझे लगता है कि त्रुटियां कहीं भी हो सकती हैं। मैंने अधिकांश कोड को छीन लिया है, जिससे समस्या को दिखाने के लिए केवल जरूरी है। उम्मीद है कि कोई भी गणितीय रूप से चुनौतीपूर्ण त्रुटि को खोज सकता है!खराब गणित या खराब प्रोग्रामिंग, शायद दोनों?

#!/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 

यहाँ, उत्पादन की एक छवि है कुछ अतिरिक्त लाइनों के साथ: bend sinister लाल रेखा दो त्रिभुजों को विभाजित करती है, या तो ट्रैपेज़ॉयड की गणना के लिए उपयोग किया जा सकता है। मैं ऊपर बाईं ओर से शुरू एक का उपयोग कर रहा हूँ। हरे रंग की रेखा उस त्रिभुज की ऊंचाई है, कार्यक्रम में चर एच।


समाप्त लिपि और ध्वज (माइकल एंडरसन द्वारा प्रदान किए गए सुधार का उपयोग करके) के लिए http://unternet.net/tanstaafl/ देखें। आप सब का सहायता के लिए धन्यवाद!

+0

शायद यह [कोड समीक्षा] (http://codereview.stackexchange.com/) के लिए बेहतर है? –

+0

@ टिम, आप ऐसा क्यों सोचते हैं? यह एक प्रोग्रामिंग समस्या है जिसे मैं हल करने की कोशिश कर रहा हूं, ऐसा कुछ नहीं जो काम करता है और मैं सुधार करने की कोशिश कर रहा हूं। –

+0

अभी तक उत्तर की कमी और नज़दीकी वोट (मेरे द्वारा नहीं) के आधार पर बस एक झटका है। –

उत्तर

8

आयत को दो त्रिकोणों में तोड़ दें। वे समान होंगे।

काले त्रिकोण + ब्लू चतुर्भुज त्रिभुज ए काले त्रिभुज है अपने आप ही त्रिभुज बी

त्रिभुज ए और बी त्रिभुज है समान त्रिकोण ताकि उनके क्षेत्र के लिए उन्हें संबंधित पैमाने कारक के वर्ग से संबंधित है कर रहे हैं ।

हम ब्लू ट्रैपेज़ॉयड त्रिभुज ए के क्षेत्र का एक तिहाई होना चाहते हैं (इस तरह मोड़ कुल आयत का एक तिहाई ले जाएगा)। इसका मतलब है कि त्रिभुज बी त्रिभुज ए के 2/3 क्षेत्र होना चाहिए। इस प्रकार स्केलफैक्टर को वर्ग (2/3) होना चाहिए।

तब आपको इसे आसानी से मोड़ ज्यामिति के निर्देशांक देने के लिए इसे परिवर्तित करने में सक्षम होना चाहिए।

+0

+1, यह मुख्य बिंदु है: '2/3' से क्षेत्र को स्केल करने के लिए, आपको' sqrt (2/3) 'लंबाई को स्केल करना होगा। यह एकमात्र 'वर्गिक' ऑपरेशन है जिसे आपको चाहिए। – AakashM

+0

धन्यवाद, मुझे कुछ नींद आने के बाद शायद अधिक समझदारी होगी! किसी भी मामले में अब के लिए +1 –

+0

सो नहीं सका, इसे आजमा देना था। धन्यवाद * बहुत * बहुत, यह हल किया। मैं अभी भी जानना चाहता हूं कि मैं अपने दृष्टिकोण के साथ कहां गलत हुआ, लेकिन मैं उम्मीद कर सकता हूं कि मैं मर चुका हूं: ^) –

2

मैं एक निष्क्रिय सत्र में निम्न कोड निष्पादित

from PIL import Image, ImageDraw 
from math import sqrt 

'generate bend sinister according to rules of heraldry' 
import sys, os, random, math 
FLAG = Image.new('RGB', (900, 600), 'black') 
CANVAS = ImageDraw.Draw(FLAG) 
DEBUGGING = True 

def debug(message): 
    if DEBUGGING: 
     print >>sys.stderr, message 


def show_bendsinister(x, y, width, image = FLAG, draw = CANVAS): 
'for debugging formula' 
dexter_base, sinister_chief = (0, y), (x, 0) 
print 'dexter_base==',dexter_base,'sinister_chief==',sinister_chief 
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 trapezoid_height(x, y, P): 
'''Given a rectangle whose width and length are (x) and (y) 

The half of this rectangle is a large triangle A 
whose base (b) is the diagonal of the rectangle 
and its height (H) goes from its base (b) to 
the right angle of the large triangle. 
(x) and (y) are the side-lengths of the triangle. 
The area of this large triangle is (x*y)/2 = (H*b)/2 

Given a trapezoid whose base is the diagonal (b) of the rectangle 
and base (b) of the large triangle, its height is (h) 
and its top is (t). 
Given (S) as the area of the trapezoid. 
In general, the trapezoid is disymtric because the triangle have x != y. 
So the area is S = h*(b + t)/2 

This function trapezoid_height() calculates the height (h) of the trapezoid 
in order that the trapezoid have an area (S) which must be 
the percentage (P) of the area of the large triangle A. So: 
h*(b + t)/2 = S = P*[H*b /2] ==> h*(b + t) = P*H*b 
==> h*t = P*H*b - h*b ==> h*t*(H-h) = [P*H - h]*b*(H-h) 

The large triangle is the sum of the trapezoid and of a little triangle B 
having an height equal to (H-h) and a base which is the top (t) 
of the trapezoid. 
The area of this little triangle B is t*(H-h)/2 and must be equal to (1-P)*[H*b/2] 
==> t*(H-h) = (1-P)*H*b ==> h*t*(H-h) = h*(1-P)*H*b 

From h*t*(H-h) = [P*H - h]*b*(H-h) and h*t*(H-h) = h*(1-P)*H*b 
we obtain [P*H - h]*b*(H-h) = h*(1-P)*H*b 
==> b*h**2 - (b*H + xy)*h + P*x*y*H = 0 
==> h**2 - 2*H*h + P*(H**2) = 0 
That leads to the solution H*(1 - sqrt(1-P)), the other H*(1 + sqrt(1-P)) 
being bigger than H 
''' 

H = math.sqrt((x*x*y*y)/(x*x + y*y)) 
return H*(1 - sqrt(1-P)) 



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 
print 'x ==',x,'y ==',y 
percentage = float(1)/3 
width = 2 * trapezoid_height(x, y , percentage) 
print 'height ==',width/2 
print 'width==',width 


if command == 'bendsinister': 
    show_bendsinister(x, y, width, image, draw) 
return width 

command = 'bendsinister' 
print bendsinister() 

परिणाम

x == 900 y == 600 
height == 91.6103029364 
width== 183.220605873 
dexter_base== (0, 600) sinister_chief== (900, 0) 
[(180340, (0, 0, 255)), (359660, (0, 0, 0))] 
183.220605873 

नीले पट्टी प्रदर्शित किया छाप क्षेत्र के क्षेत्र के 1/3 होने के लिए नहीं देता है, लेकिन संख्याएं बोलती हैं:

359660/180340 = 1.994344 
+0

सभी समस्याओं का विश्लेषण करने के लिए बीजगणित और कम्प्यूटेशनल तरीके की दुनिया में तर्क के ज्यामितीय तरीके को जीवित रखते हुए हम दोनों त्रिकोण और ट्राइपोज़ाइड के क्षेत्र के लिए एक ही सूत्र का उपयोग करते थे, लेकिन आपका व्युत्पन्न सही हो गया और मेरा नहीं था। कल आपको माइकल एंडरसन से जरूरी जवाब मिलने के बावजूद आपको +1 दे रहा है। धन्यवाद! –

+0

@jcomeau_ictx आप बिल्कुल सही हैं: आपने अच्छे सूत्र का उपयोग किया था। मैंने आपकी समस्या के लिए अपनी रूचि की शुरुआत में बहुत सतही रूप से जांच की जब मैंने इसके बारे में सोचने के लिए आसानता हासिल नहीं की थी, और मैंने भ्रम किया होगा। मुझे आश्चर्य है कि मुझे अपने दिमाग में कुछ आराम नहीं देना चाहिए। – eyquem

संबंधित मुद्दे