#! /usr/bin/python # # graph_cycloid.py # # Joseph Mack (C) 2008, jmack (at) wm7d (dot) net. Released under GPL v3 # generates graph of angles at edge of pyramid, against angle of face. # uses PIL library. from math import * #import math import os, sys import random from PIL import Image, ImageDraw, ImageFont, ImageOps #fix coordinate system # #origin of diagram is at top left #there appears to be no translate function ;-\ #strings are right (not center) justified #axes origin is at 50,450 (bottom left) #x_origin=50 #y_origin=450 x_origin=75 y_origin=450 #unit=400 #400 pixels = 1 in cartesian coords, suitable for box dimension 1x1 unit=4 #4 pixels = 1 in cartesian coords, suitable for box dimension 100x100 #x_unit=4 #y_unit=400 x_unit=4 #100*100 grid y_unit=4 x14=0 #needs to be global y14=0 #change coordinate system. #cartesian to pil coords def x2pil(x): result=x_origin +x*x_unit return result def y2pil(y): result=y_origin -y*y_unit return result def draw_axes(): #axes axes_origin=(x2pil(xmin), y2pil(ymin)) x_axes=(axes_origin,x2pil(xmax),y2pil(ymin)) draw.line(x_axes,fill="black") y_axes=(axes_origin,x2pil(xmin),y2pil(ymax)) draw.line(y_axes,fill="black") #complete box x_axes=(x2pil(xmax),y2pil(ymin),x2pil(xmax),y2pil(ymax)) draw.line(x_axes,fill="black") y_axes=(x2pil(xmin),y2pil(ymax),x2pil(xmax),y2pil(ymax)) draw.line(y_axes,fill="black") #axes: numerical label #x_axes color="#000000" x_axes_label_position_0=(x2pil(xmin-2), y2pil(ymin-0.05)) draw.text(x_axes_label_position_0, str(xmin), font=label_font, fill=color) x_axes_label_position_1=(x2pil(xmax-5), y2pil(ymin-0.05)) draw.text(x_axes_label_position_1, str(xmax), font=label_font, fill=color) #y_axes y_ayes_label_position_0=(x2pil(xmin-1), y2pil(ymin+0.025)) draw.text(y_ayes_label_position_0, str(ymin), font=label_font, fill=color) y_ayes_label_position_1=(x2pil(xmin-1), y2pil(ymax+0.025)) draw.text(y_ayes_label_position_1, str(ymax), font=label_font, fill=color) def draw_cycloid(): # have 100 grid intervals to draw on # since are drawing 8 minutes, draw 10..90 # top graph start at y=9 in user space # are using 100 units, as loop parameter must be integers #these are feed as globals #offsety = 90 #cycloid_radius = 5 cycloid_color="#00FF00" line_color="#000000" square_color="#D0D0D0" ellipse_color="#FF0000" diag_bbox=1 offsetx = 10 startx = 0 endx = 80 #circle is 80 steps #start cycloid with arrow pointing left (270deg) #angle then is radians(360.0*x/80) stepx = 1 #offsety = 90 #cycloid_radius = 5 offset_angle = 90 cycloid_period = 40 #the following are being drawn #at 1 min intervals #the real shadow spot (grey) #the actual shadow #the line joining the two spots #continuously #the line of the real shadow #since sometimes the read shadow follows and sometimes leads #if you draw all the spots and lines for any 1 min interval #they can be occluded by later drawn points #so draw all dots in separate loops # for x in xrange(startx,endx + 1,stepx): # #point 1 # angle1 = radians(360.0*x/cycloid_period - offset_angle) # xpos1 = offsetx + x + cycloid_radius * cos (angle1) # ypos1 = offsety + cycloid_radius * sin(angle1) # angle2 = radians(360.0*(x+stepx)/cycloid_period - offset_angle) # xpos2 = offsetx + (x+stepx) + cycloid_radius * cos (angle2) # ypos2 = offsety + cycloid_radius * sin(angle2) # line=(x2pil(xpos1),y2pil(ypos1),x2pil(xpos2),y2pil(ypos2)) # draw.line(line,fill=cycloid_color) # if (x%5 == 0): #every 5th point # line=(x2pil(x + offsetx),y2pil(offsety),x2pil(xpos1), y2pil(ypos1)) # draw.line(line,fill=ellipse_color) # #ellipse bbox has to be bottom left corner and top right corner # #this doesn't work # #ellipse_bbox=((x2pil(xpos1 - diag_bbox), y2pil(ypos1 - diag_bbox)), (x2pil(xpos1 + diag_bbox), y2pil(ypos1 + diag_bbox))) # #this works # ellipse_bbox=((x2pil(xpos1 - diag_bbox), y2pil(ypos1 + diag_bbox)), (x2pil(xpos1 + diag_bbox), y2pil(ypos1 - diag_bbox))) # #print ellipse_bbox # #draw.line(ellipse_bbox, fill="#0000FF") # draw.ellipse(ellipse_bbox, fill=ellipse_color, outline=ellipse_color) # # #draws a square # #polygon_points=( # # (x2pil(xpos1 - diag_bbox), y2pil(ypos1 - diag_bbox)), # # (x2pil(xpos1 - diag_bbox), y2pil(ypos1 + diag_bbox)), # # (x2pil(xpos1 + diag_bbox), y2pil(ypos1 + diag_bbox)), # # (x2pil(xpos1 + diag_bbox), y2pil(ypos1 - diag_bbox)) # # ) # #print polygon_points # #draw.polygon(polygon_points, fill=ellipse_color, outline=ellipse_color) # polygon_points=( # (x2pil(x + offsetx - diag_bbox), y2pil(offsety - diag_bbox)), # (x2pil(x + offsetx - diag_bbox), y2pil(offsety + diag_bbox)), # (x2pil(x + offsetx + diag_bbox), y2pil(offsety + diag_bbox)), # (x2pil(x + offsetx + diag_bbox), y2pil(offsety - diag_bbox)) # ) # print polygon_points # draw.polygon(polygon_points, fill=square_color, outline=square_color) if (random_flag==0): for x in xrange(startx,endx + 1,stepx): angle1 = radians(360.0*x/cycloid_period - offset_angle) xpos1 = offsetx + x + cycloid_radius * cos (angle1) ypos1 = offsety + cycloid_radius * sin(angle1) angle2 = radians(360.0*(x+stepx)/cycloid_period - offset_angle) xpos2 = offsetx + (x+stepx) + cycloid_radius * cos (angle2) ypos2 = offsety + cycloid_radius * sin(angle2) if (x%5 == 0): #every 5th point line=(x2pil(x + offsetx),y2pil(offsety),x2pil(xpos1), y2pil(ypos1)) draw.line(line,fill=ellipse_color) if (random_flag==0): for x in xrange(startx,endx + 1,stepx): angle1 = radians(360.0*x/cycloid_period - offset_angle) xpos1 = offsetx + x + cycloid_radius * cos (angle1) ypos1 = offsety + cycloid_radius * sin(angle1) angle2 = radians(360.0*(x+stepx)/cycloid_period - offset_angle) xpos2 = offsetx + (x+stepx) + cycloid_radius * cos (angle2) ypos2 = offsety + cycloid_radius * sin(angle2) if (x%5 == 0): #every 5th point #draws a square polygon_points=( (x2pil(x + offsetx - diag_bbox), y2pil(offsety - diag_bbox)), (x2pil(x + offsetx - diag_bbox), y2pil(offsety + diag_bbox)), (x2pil(x + offsetx + diag_bbox), y2pil(offsety + diag_bbox)), (x2pil(x + offsetx + diag_bbox), y2pil(offsety - diag_bbox)) ) #print polygon_points draw.polygon(polygon_points, fill=square_color, outline=square_color) for x in xrange(startx,endx + 1,stepx): angle1 = radians(360.0*x/cycloid_period - offset_angle) xpos1 = offsetx + x + cycloid_radius * cos (angle1) ypos1 = offsety + cycloid_radius * sin(angle1) if (random_flag == 1): xpos1 += random.gauss(0,cycloid_radius) ypos1 += random.gauss(0,cycloid_radius) #save 14th point if ((x%(14*5) == 0) and (x != 0)): #damn. python doesn't see the global var of the same name global x14 x14 = xpos1 global y14 y14 = ypos1 print x, offsety, x14, y14 #angle2 = radians(360.0*(x+stepx)/cycloid_period - offset_angle) #xpos2 = offsetx + (x+stepx) + cycloid_radius * cos (angle2) #ypos2 = offsety + cycloid_radius * sin(angle2) if (x%5 == 0): #every 5th point if (parity_flag==0): ellipse_color = "#FF0000" if (x%8 == 0): ellipse_color = "#0000FF" if (parity_flag==1): ellipse_color = "#0000FF" if (x%8 == 0): ellipse_color = "#FF0000" #ellipse bbox has to be bottom left corner and top right corner #this doesn't work #ellipse_bbox=((x2pil(xpos1 - diag_bbox), y2pil(ypos1 - diag_bbox)), (x2pil(xpos1 + diag_bbox), y2pil(ypos1 + diag_bbox))) #this works ellipse_bbox=((x2pil(xpos1 - diag_bbox), y2pil(ypos1 + diag_bbox)), (x2pil(xpos1 + diag_bbox), y2pil(ypos1 - diag_bbox))) #print ellipse_bbox #draw.line(ellipse_bbox, fill="#0000FF") draw.ellipse(ellipse_bbox, fill=ellipse_color, outline=ellipse_color) if (random_flag==0): for x in xrange(startx,endx + 1,stepx): #point 1 angle1 = radians(360.0*x/cycloid_period - offset_angle) xpos1 = offsetx + x + cycloid_radius * cos (angle1) ypos1 = offsety + cycloid_radius * sin(angle1) angle2 = radians(360.0*(x+stepx)/cycloid_period - offset_angle) xpos2 = offsetx + (x+stepx) + cycloid_radius * cos (angle2) ypos2 = offsety + cycloid_radius * sin(angle2) line=(x2pil(xpos1),y2pil(ypos1),x2pil(xpos2),y2pil(ypos2)) draw.line(line,fill=cycloid_color) def label_graph(): color="#000000" #graph label label_position=(x2pil(xmin+30), y2pil(ymax+0.1)) label="One Engine" draw.text(label_position, label, font=label_font, fill=color) #x_axes label label_position=(x2pil(xmin+22), y2pil(ymin-0.025)) label="flying time, hr" draw.text(label_position, label, font=label_font, fill=color) #rotated text #from http://mail.python.org/pipermail/image-sig/2008-August/005145.html #x=-10 #y=ymax+5 x=-7 y=ymax-0.05 for c in "probability flying": draw.text ((x2pil(x),y2pil(y)), c, font=label_font, fill=color) y -= 0.05 def draw_fine_grid(): #draw fine grid, start=xmin end=xmax step=1 #in user units color="#00ff00" for x in xrange(start,end+1,step): #vertical line line=(x2pil(x),y2pil(ymin),x2pil(x),y2pil(ymax)) draw.line(line,fill=color) magnification=100 #loop parameters must be integers start=ymin*magnification end=ymax*magnification step=1 for y in xrange(start,end,step): #horizontal line line=(x2pil(1.0*xmin),y2pil(1.0*y/magnification),x2pil(1.0*xmax),y2pil(1.0*y/magnification)) draw.line(line,fill=color) #horizontal line line=(x2pil(xmin),y2pil(x),x2pil(xmax),y2pil(x)) draw.line(line,fill=color) def draw_coarse_grid(): #draw coarse grid start=xmin end=xmax step=10 #user units color="#000000" for x in xrange(start,end+1,step): #vertical line line=(x2pil(x),y2pil(ymin),x2pil(x),y2pil(ymax)) draw.line(line,fill=color) start=ymin end=ymax step=10 for y in xrange(start,end,step): #horizontal line line=(x2pil(1.0*xmin),y2pil(1.0*y),x2pil(1.0*xmax),y2pil(1.0*y)) draw.line(line,fill=color) def draw_line(): import math step=1 #in x_axis user units #color="#0000FF" color="#FF0000" y0=0.9 for x in xrange(xmin,xmax,step): y1 = y0*(1.0-1.0/MTBF) line=(x2pil(x),y2pil(y0),x2pil(x+step),y2pil(y1)) draw.line(line,fill=color) y0 = y1 #draw reference line #line=(x2pil(xmin),y2pil(ymin),x2pil(xmax),y2pil(ymax)) #draw.line(line,fill="#777777") def draw_marker(): #time of Lindbergh's flight flight_time=33.5 line=(x2pil(flight_time),y2pil(ymin),x2pil(flight_time),y2pil(ymax)) draw.line(line,fill="#FF7700") #--------------------- size=(500,500) mode="RGBA" xmin=0 ymin=0 xmax=100 ymax=100 MTBF=200 #fonts #print sys.path label_font = ImageFont.load("/usr/lib/python2.4/site-packages/PIL/courR18.pil") #label_font = ImageFont.load("PIL/courR18.pil") im=Image.new (mode,size,"white") draw=ImageDraw.Draw(im) #draw_axes() #label_graph() #draw_fine_grid() #draw_coarse_grid() #draw_marker() #draw_line() text_color="#000000" #title x_axes_label_position_0=(x2pil(-15), y2pil(105)) draw.text(x_axes_label_position_0, str("Cycloid pattern = fn(time error)"), font=label_font, fill=text_color) parity_flag = -1 random_flag=0 offsety = 70 cycloid_radius = 10 draw_cycloid() time_error=int(60/5*cycloid_radius) x_axes_label_position_0=(x2pil(-10), y2pil(offsety+4)) draw.text(x_axes_label_position_0, str(time_error), font=label_font, fill=text_color) offsety = 50 cycloid_radius = 5 draw_cycloid() time_error=int(60/5*cycloid_radius) x_axes_label_position_0=(x2pil(-10), y2pil(offsety+4)) draw.text(x_axes_label_position_0, str(time_error), font=label_font, fill=text_color) offsety = 30 cycloid_radius = 2.5 draw_cycloid() time_error=int(60/5*cycloid_radius) x_axes_label_position_0=(x2pil(-10), y2pil(offsety+4)) draw.text(x_axes_label_position_0, str(time_error), font=label_font, fill=text_color) offsety = 10 cycloid_radius = 1.25 draw_cycloid() time_error=int(60/5*cycloid_radius) x_axes_label_position_0=(x2pil(-10), y2pil(offsety+4)) draw.text(x_axes_label_position_0, str(time_error), font=label_font, fill=text_color) im.show() im.save("graph_cycloid.png") im=Image.new (mode,size,"white") draw=ImageDraw.Draw(im) data_color = "#00FF00" #title x_axes_label_position_0=(x2pil(0), y2pil(105)) draw.text(x_axes_label_position_0, str("Simulated data"), font=label_font, fill=text_color) x_axes_label_position_0=(x2pil(0), y2pil(95)) draw.text(x_axes_label_position_0, str("error=15sec, noise=15sec"), font=label_font, fill=text_color) cycloid_radius = 1.25 parity_flag = 0 offsety = 80 random_flag=1 draw_cycloid() #print x14, y14 x14_old = x14 y14_old = y14 parity_flag += 1 parity_flag %= 2 offsety = 70 random_flag=1 draw_cycloid() #print x14_old,y14_old,x14,y14 line=(x2pil(x14_old),y2pil(y14_old),x2pil(x14),y2pil(y14)) #print line draw.line(line,fill=data_color) x14_old = x14 y14_old = y14 parity_flag += 1 parity_flag %= 2 offsety = 60 random_flag=1 draw_cycloid() line=(x2pil(x14_old),y2pil(y14_old),x2pil(x14),y2pil(y14)) #print line draw.line(line,fill=data_color) x14_old = x14 y14_old = y14 parity_flag += 1 parity_flag %= 2 offsety = 50 random_flag=1 draw_cycloid() line=(x2pil(x14_old),y2pil(y14_old),x2pil(x14),y2pil(y14)) draw.line(line,fill=data_color) x14_old = x14 y14_old = y14 parity_flag += 1 parity_flag %= 2 offsety = 40 random_flag=1 draw_cycloid() line=(x2pil(x14_old),y2pil(y14_old),x2pil(x14),y2pil(y14)) draw.line(line,fill=data_color) x14_old = x14 y14_old = y14 parity_flag += 1 parity_flag %= 2 offsety = 30 random_flag=1 draw_cycloid() line=(x2pil(x14_old),y2pil(y14_old),x2pil(x14),y2pil(y14)) draw.line(line,fill=data_color) x14_old = x14 y14_old = y14 parity_flag += 1 parity_flag %= 2 offsety = 20 random_flag=1 draw_cycloid() line=(x2pil(x14_old),y2pil(y14_old),x2pil(x14),y2pil(y14)) draw.line(line,fill=data_color) x14_old = x14 y14_old = y14 parity_flag += 1 parity_flag %= 2 offsety = 10 random_flag=1 draw_cycloid() line=(x2pil(x14_old),y2pil(y14_old),x2pil(x14),y2pil(y14)) draw.line(line,fill=data_color) x14_old = x14 y14_old = y14 parity_flag += 1 parity_flag %= 2 offsety = 0 random_flag=1 draw_cycloid() line=(x2pil(x14_old),y2pil(y14_old),x2pil(x14),y2pil(y14)) draw.line(line,fill=data_color) im.show() im.save("graph_cycloid_random.png") # graph_cycloid.py---------------------------