Прикреплённый файл «grap_7.py»

Загрузка

   1 #!/usr/bin/env python
   2 # -*- coding: UTF-8 -*-
   3 # vim: expandtab shiftwidth=4
   4 '''
   5 Проект "Построение графика"
   6 Графический редактор в возможностью рисовать графики
   7 см. диаграммы PyGameState_*.dia
   8 '''
   9 
  10 from math import *
  11 import sys
  12 
  13 import pygame
  14 pygame.init()
  15 pygame.font.init()
  16 # Векторы, указывающие на соседнюю точку
  17 dxy=[(-1,-1),(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1)]
  18 dxyW=len(dxy)
  19 
  20 def distance(M1,M2):
  21     'Расстояние от точки до точки'
  22     return sqrt(float(M1[0]-M2[0])**2+float(M1[1]-M2[1])**2)
  23 
  24 def dxydist(M1, M2, M, R, ind):
  25     '''Вспомогательная функция. Вычисляет координаты точек, соседних с M,
  26     соответствующих векторам, индексы которых в dxy перечислены в ind;
  27     вычисляет, насколько отличается заданное значение R 
  28     от суммы расстояний от каждой из этих точек до центров эллипса.
  29     Возвращает список вида [ (отличие, точка, индекс в dxy), ...]'''
  30     return [(abs((R-distance(m,M1)-distance(m,M2))),m,i) for m,i in [((M[0]+dxy[i][0],M[1]+dxy[i][1]),i) for i in ind]]
  31 
  32 def Ellipse(screen, M1, M2, M0, pen, width):
  33     'Рисование эллипса по двум центрам и точке M0'
  34     L=distance(M1,M2)
  35     R=distance(M0,M1)+distance(M0,M2)
  36     if int(R)<=int(L):
  37         D=[M1,M2]
  38     elif L<3:
  39         pygame.draw.circle(screen, pen, M1, max(R/2, width), width)
  40         return
  41     else:
  42         D=[M0]
  43         r,M,v=min(dxydist(M1, M2, M0, R, range(dxyW)))
  44         # здесь иногда вечный цикл: какая-то неточность в расчётах
  45         c=0
  46         while M!=M0 and c <10020:
  47             c+=1
  48             if c > 10000: print r,M,v, R, M1, M2
  49             D.append(M)
  50             r,M,v=min(dxydist(M1, M2, M, R, ((dxyW+v-1)%dxyW,v,(dxyW+v+1)%dxyW)))
  51     pygame.draw.polygon(screen, pen, D, width)
  52 
  53 def scale(x, X0, X1, Z0, Z1):
  54     'Преобразует координату x в диапазоне [X0, X1] в координату z в диапазоне [Z0, Z1]'
  55     return Z0 + (x!=X0 and (Z1-Z0)*(x-X0)/float(X1-X0)) or 0
  56 
  57 def Function(screen, M1, M2, pen, width):
  58     'Рисование графика функции fml в диапазоне fml(X0)..fml(X1)'
  59     global X0, X1, fml
  60     mw,mh=min(M1[0],M2[0]),min(M1[1],M2[1])
  61     Mw,Mh=max(M1[0],M2[0]),max(M1[1],M2[1])
  62     count=max(Mw-mw,2)
  63     dots=[(x,eval(fml)) for x in [scale(i,0,count-1,X0,X1) for i in range(count)]]
  64     Y0,Y1=min([e[1] for e in dots]), max([e[1] for e in dots])
  65     gr=[(round(scale(x,X0,X1,mw,Mw)),round(scale(y,Y0,Y1,mh,Mh))) for x,y in dots]
  66     pygame.draw.lines(screen, pen, False, gr, width)
  67 
  68 def Draw(screen, pen, width, center, pos, figure, center2=None):
  69     if figure == "Line":
  70         pygame.draw.line(screen, pen, center, pos, width)
  71     elif figure == "Rect":
  72         pygame.draw.rect(screen, pen, (center, (pos[0]-center[0],pos[1]-center[1])), width)
  73     elif figure == "Function":
  74         Function(screen, center, pos, pen, width)
  75     elif figure == "Circle":
  76         r=int(round(distance(center, pos)))
  77         pygame.draw.circle(screen, pen, center, max(r, width), width)
  78     elif figure == "Ellipse":
  79         if center2:     # финальная фигура
  80             Ellipse(screen, center, center2, pos, pen, width)
  81         else:           # фигура второй стадии
  82             Ellipse(screen, center, (center[0]*.2+pos[0]*.8, center[1]*.2+pos[1]*.8), pos, pen, width)
  83 
  84 def DrawState(screen, event, stages):
  85     'Рисование фигуры по точкам'
  86     global State, Stage, Center, Copy, pen, width, Action, Center2
  87     if event.type == pygame.MOUSEMOTION:
  88         if Stage == 2:
  89             screen.blit(Copy, (0,0))    # восстанавливаем 
  90             Draw(screen, pen, width, Center, event.pos, Action)
  91         if Stage == 3:
  92             screen.blit(Copy, (0,0))    # восстанавливаем 
  93             Draw(screen, pen, width, Center, event.pos, Action, Center2)
  94     elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
  95         if Stage == 1:                  # первое нажатие
  96             Stage += 1
  97             Center = event.pos
  98             Copy = screen.copy()        # состояние экрана без нарисованной линии
  99         elif Stage == stages:           # Последнее нажатие
 100             Stage = 1
 101         elif Stage == 2:                # второе нажатие из более чем двух
 102             Stage += 1
 103             Center2 = event.pos
 104     elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 3:
 105         if Stage > 1:                   # Нарисовано что-то резиновое
 106             screen.blit(Copy, (0,0))    # восстанавливаем 
 107             Stage = 1
 108     elif event.type == pygame.KEYDOWN and event.key == 27:
 109         screen.blit(Copy, (0,0))
 110         State = "Base"
 111 
 112 def ScrInput(screen, prompt, pos):
 113     '''Ввести строку с клавиатуры, отображая её.
 114     Backspace -- удалить один символ, ESC -- вернуть None'''
 115     global Copy
 116     res = ""
 117     Copy = screen.copy()
 118     while True:
 119         text = font.render(prompt+": "+res, 1, (255,255,255))
 120         screen.blit(Copy, (0,0))
 121         screen.blit(text, pos)
 122         pygame.display.flip()
 123         event = pygame.event.wait()
 124         if event.type == pygame.KEYDOWN:
 125             if event.unicode:                     # real characters
 126                 if event.unicode == u"\033":      # ESC
 127                     res = None
 128                     break
 129                 elif event.unicode == "\010":     # Backspace
 130                     res=res[:-1]
 131                 elif event.unicode in u"\r\n":    # Enter
 132                     break
 133                 elif event.unicode > u" ":        # printable characters
 134                     res += event.unicode
 135                 #print event.unicode.__repr__()
 136     screen.blit(Copy, (0,0))
 137     pygame.display.flip()
 138     return res
 139 
 140 def Ask_n_Do(screen, what, prompt):
 141     '''Ввести строку, проверить, и сделать с ней что полагается.
 142     Вернуть True или False в зависимости от успешности'''
 143     global width, pen, fml, X0, X1
 144     str_res=ScrInput(screen,u"Введите "+prompt, (10,10))
 145     if str_res is None: return False    # ввод был прерван
 146     try:
 147         res = eval(str_res)
 148     except:     # неизвестно что, пусть это остаётся строкой
 149         res = str_res
 150     if what == "Width":
 151         if type(res) != int:
 152             print what, "must be integer"
 153             return False
 154         width = res
 155     elif what == "Color":
 156         if type(res) not in (list, tuple) or len(res) != 3:
 157             print what, "must be 3-element list"
 158             return False
 159         pen = [r%256 for r in res]      # лень проверять ещё и < 256
 160     elif what == "Absc":
 161         try:
 162             X0,X1=float(res[0]),float(res[1])
 163         except:
 164             print sys.exc_value
 165             return False
 166     elif what == "Funct":
 167         try:
 168             x=X0
 169             y=eval(str(res))
 170             fml=str(res)
 171             print "FML:",fml
 172         except:
 173             print sys.exc_value
 174             return False
 175     elif what == "Save":
 176         try:
 177             pygame.image.save(screen,res)
 178         except:
 179             print sys.exc_value
 180             return False
 181     elif what == "Edit":
 182         try:
 183             newscr = pygame.image.load(res)
 184             screen.blit(newscr,(0,0))
 185         except:
 186             print sys.exc_value
 187             return False
 188     else:
 189         print "Unknown", what
 190     return True
 191 
 192 # Основной экран
 193 W,H=640,480
 194 screen=pygame.display.set_mode((W,H))
 195 
 196 pen,width=(10,100,200),2
 197 X0,X1=1,8
 198 fml="sin(x)"
 199 font = pygame.font.Font(None, W/24)
 200 States=("Draw", "Input", "Base")
 201 Figures={"o":"Circle", "l":"Line", "r":"Rect", "y":"Function"}
 202 Figures3={"d":"Ellipse"}
 203 Inputs={"w":    ("Width", u"ширину линии"),
 204         "c":    ("Color", u"цвет линии"),
 205         "f":    ("Funct", u"функцию для рисования"),
 206         "x":    ("Absc", u"минимальное, максимальное значение X"),
 207         "s":    ("Save", u"имя файла для сохранения"),
 208         "e":    ("Edit", u"имя файла для чтения"),
 209 }
 210 Center=(0,0)
 211 Copy=None
 212 
 213 State, Stage, Action = "Base", 1, "Line"
 214 while True:
 215   pygame.display.flip()
 216   event = pygame.event.wait()
 217   # Выход по закрытию окна
 218   if event.type == pygame.QUIT: sys.exit()
 219   if State == "Base":   # основное состояние
 220     if event.type == pygame.KEYDOWN:
 221         key = event.unicode.lower()
 222         if key == "q":
 223             sys.exit()
 224         elif key in Figures.keys():     # Начать рисование фигуры
 225             State,Stage,Action = "Draw", 1, Figures[event.unicode.lower()]
 226             Copy = screen.copy()
 227         elif key in Figures3.keys():     # Начать рисование фигуры
 228             State,Stage,Action = "Draw3", 1, Figures3[event.unicode.lower()]
 229             Copy = screen.copy()
 230         elif key in Inputs.keys():      # Что-то ввести и обработать результат
 231             Ask_n_Do(screen, *Inputs[key])
 232   elif State == "Draw": # рисование фигуры
 233     DrawState(screen, event, 2)
 234   elif State == "Draw3": # рисование фигуры
 235     DrawState(screen, event, 3)

Прикреплённые файлы

Для ссылки на прикреплённый файл в тексте страницы напишите attachment:имяфайла, как показано ниже в списке файлов. Не используйте URL из ссылки «[получить]», так как он чисто внутренний и может измениться.

Вам нельзя прикреплять файлы к этой странице.