Данная программа рисует интересные геометрические кривые внутри некоторой
окружности. Эффект достигается простым приемом: по внутренней поверхности
окружности радиуса R катится диск радиуса r1. На поверхности этого диска
на расстоянии r2 от центра прикреплен карандаш, который рисует узоры. Форма
и размер узоров зависят от радиусов, единичного угла поворота, и временной
длиной пауз, на которые карандаш отрывается от листа бумаги. К программе я
наваял небольшой интерфейс для удобства использования и возможность
сохранять результат в файл.
Если говорить строго, то представленные кривые являются Эпитрохоидами.
Эпитрохоида - плоская кривая, образуемая точкой, жёстко связанной с
окружностью, катящейся по внешней стороне другой окружности.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#############################################################
#
# Polar, Python, 2011-01-20
#
# Artix, master@7masterov.ru, icq:53666599, skype:artixmaster
#
# * Error in code? Nothing is perfect!
# * Free source for free Linux, use it fo free!
# * Please, do not remove this comment!nts!
#
# x=R*cos(a)
# y=R*sin(a)
# L = 2*pi*R, 10<=R<=600
# l = 2*pi*r, 5<=r<=R
# n = L/l = R/r
# b = a*n
# a - единичный поворот
# N - количество оборотов
#
#############################################################
from Tkinter import *
from tkMessageBox import *
from tkFileDialog import *
from random import *
from math import *
class HelpDialog(Toplevel):
def __init__(self, parent):
Toplevel.__init__(self, parent)
self.title("Help")
Label(self,text="Artix, igor@7masterov.ru, (C) 2011").grid(
row=0,padx=5,pady=5, sticky=W+E)
Button(self,text="Close",command=self.destroy).grid(
row=1,padx=5, pady=5, sticky=W+E)
class Application(Frame):
button = None
label = None
menu = None
menuFile = None
menuHelp = None
status = None
canvas = None
def __init__(self, master=None):
Frame.__init__(self, master)
self.master.title("Application")
self.master.minsize(width=500,height=400)
w = 500; h = 400
ws = self.master.winfo_screenwidth()
hs = self.master.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
self.master.geometry('%dx%d+%d+%d' % (w, h, x, y))
self.master.resizable(width=NO, height=NO)
self.pack()
self.menu = Menu(self)
self.menuFile = Menu(self.menu, tearoff=0)
self.menuFile.add_command(label="New <space>",command=self.onClick)
self.menuFile.add_command(label="Save as ...",command=self.onSave)
self.menuFile.add_separator()
self.menuFile.add_command(label="Exit",command=self.onQuit)
self.menu.add_cascade(label="File",menu=self.menuFile)
self.menuHelp = Menu(self.menu, tearoff=0)
self.menuHelp.add_command(label="Help",command=self.onHelp)
self.menuHelp.add_command(label="About",command=self.onAbout)
self.menu.add_cascade(label="Help",menu=self.menuHelp)
self.master.config(menu=self.menu)
self.canvas = Canvas(self,width=500,height=400,bg="black")
self.canvas.pack()
self.canvas.bind('<space>',self.onSpace)
self.canvas.focus_set()
self.canvas.create_line(10,10,200,200)
self.drawPolar()
def center(self,obj):
ws = self.master.winfo_screenwidth()
hs = self.master.winfo_screenheight()
w = obj.winfo_reqwidth()
h = obj.winfo_reqheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
obj.geometry('+%d+%d' % (x, y))
def drawPolar(self):
self.canvas.delete(ALL)
self.canvas.create_rectangle(0,0,self.canvas.winfo_reqwidth(),
self.canvas.winfo_reqheight(),fill="black")
rnd = Random()
R = rnd.random()*self.canvas.winfo_reqheight()/5+50
r1 = rnd.random()*(R+1)+10
r2 = rnd.random()*(r1-1)+10
step = rnd.random()*45
pause = int(rnd.random()*3)+1
self.rotate(R,r1,r2,step,pause,30)
def rotate(self, R, r1, r2, a, p, N):
color_list = ['blue', 'red', 'black']
angle1 = 0.0
angle2 = 0.0
b = a*(R/r1)
cx = self.canvas.winfo_reqwidth()/2.0
cy = self.canvas.winfo_reqheight()/2.0
x1 = 0
y1 = 0
loop = 0
loop1 = 0
loop2 = 0
while True:
if loop1>N or loop2>2*N: break
x = R*cos(pi/180.0*angle1)
y = R*sin(pi/180.0*angle1)
sx = r2*cos(pi/180.0*angle2)
sy = r2*sin(pi/180.0*angle2)
x2 = int(cx + (x+sx))
y2 = int(cy - (y+sy))
if x1==0 and y1==0:
x1 = x2; y1 = y2
if x1!=x2 and y1!=y2 and loop % p == 0:
color = "#%02X%02X%02X" % (0, loop % 200+55, 0)
self.canvas.create_line(x1,y1,x2,y2,fill=color)
angle1+=a
angle2-=b
x1 = x2
y1 = y2
if angle1>=360:
angle1-=360
loop1+=1
if angle2<=-360:
angle2+=360
loop2+=1
loop+=1
def onSave(self):
f = asksaveasfilename(
filetypes=[('PostScript', '*.ps')],defaultextension='.ps')
if f!='':
self.canvas.postscript(file=f)
def onClick(self):
self.drawPolar()
def onSpace(self,event):
self.drawPolar()
def onQuit(self):
if askokcancel("Quit", "Do you really wish to quit?"):
self.quit()
def onHelp(self):
dialog = HelpDialog(self)
self.center(dialog)
self.master.wait_window(dialog)
def onAbout(self):
showinfo("Header", "Message")
if __name__ == "__main__":
root = Tk()
app = Application(root)
root.mainloop()
Справочник алгоритмов v0.05 © 2007-2025 Igor Salnikov aka SunDoctor