Я хотел бы добавить некоторые математические соображения к обсуждению...
(Просто потому, что грустно, что функция JES addLine рисует только черные линии и весьма ограничена...)
Примечание. В следующем коде используется алгоритм линии Брезенхэма, на который указал MartinStettner
(спасибо ему).
Алгоритм линии Брезенхэма — это алгоритм, который определяет, в каком порядке формировать близкое приближение к прямой линии между двумя заданными точками. Поскольку пиксель является атомарным объектом, линию можно нарисовать на экране компьютера только с использованием некоторого приближения.
Примечание. Чтобы понять следующий код, вам нужно немного вспомнить базовые школьные курсы математики (уравнение прямой и тригонометрия).
Код:
# The following is fast implementation and contains side effects...
import random
# Draw point, with check if the point is in the image area
def drawPoint(pic, col, x, y):
if (x >= 0) and (x < getWidth(pic)) and (y >= 0) and (y < getHeight(pic)):
px = getPixel(pic, x, y)
setColor(px, col)
# Draw line segment, given two points
# From Bresenham's line algorithm
# http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
def drawLine(pic, col, x0, y0, x1, y1):
dx = abs(x1-x0)
dy = abs(y1-y0)
sx = sy = 0
#sx = 1 if x0 < x1 else -1
#sy = 1 if y0 < y1 else -1
if (x0 < x1):
sx = 1
else:
sx = -1
if (y0 < y1):
sy = 1
else:
sy = -1
err = dx - dy
while (True):
drawPoint(pic, col, x0, y0)
if (x0 == x1) and (y0 == y1):
break
e2 = 2 * err
if (e2 > -dy):
err = err - dy
x0 = x0 + sx
if (x0 == x1) and (y0 == y1):
drawPoint(pic, col, x0, y0)
break
if (e2 < dx):
err = err + dx
y0 = y0 + sy
# Draw infinite line from segment
def drawInfiniteLine(pic, col, x0, y0, x1, y1):
# y = m * x + b
m = (y0-y1) / (x0-x1)
# y0 = m * x0 + b => b = y0 - m * x0
b = y0 - m * x0
x0 = 0
y0 = int(m*x0 + b)
# get a 2nd point far away from the 1st one
x1 = getWidth(pic)
y1 = int(m*x1 + b)
drawLine(pic, col, x0, y0, x1, y1)
# Draw infinite line from origin point and angle
# Angle 'theta' expressed in degres
def drawInfiniteLineA(pic, col, x, y, theta):
# y = m * x + b
dx = y * tan(theta * pi / 180.0) # (need radians)
dy = y
if (dx == 0):
dx += 0.000000001 # Avoid to divide by zero
m = dy / dx
# y = m * x + b => b = y - m * x
b = y - m * x
# get a 2nd point far away from the 1st one
x1 = 2 * getWidth(pic)
y1 = m*x1 + b
drawInfiniteLine(pic, col, x, y, x1, y1)
# Draw multiple parallele lines, given offset and angle
def multiLines(pic, col, offset, theta, randOffset = 0):
# Range is [-2*width, 2*width] to cover the whole surface
for i in xrange(-2*getWidth(pic), 2*getWidth(pic), offset):
drawInfiniteLineA(pic, col, i + random.randint(0, randOffset), 1, theta)
# Draw multiple lines, given offset, angle and angle offset
def multiLinesA(pic, col, offsetX, offsetY, theta, offsetA):
j = 0
# Range is [-2*width, 2*width] to cover the whole surface
for i in xrange(-2*getWidth(pic), 2*getWidth(pic), offsetX):
drawInfiniteLineA(pic, col, i, j, theta)
j += offsetY
theta += offsetA
file = pickAFile()
picture = makePicture(file)
color = makeColor(0, 65, 65) #pickAColor()
#drawline(picture, color, 10, 10, 100, 100)
#drawInfiniteLine(picture, color, 10, 10, 100, 100)
#drawInfiniteLineA(picture, color, 50, 50, 135.0)
#multiLines(picture, color, 20, 56.0)
#multiLines(picture, color, 10, 56.0, 15)
multiLinesA(picture, color, 10, 2, 1.0, 1.7)
show(picture)
Результат (картина Пьера Сулажа):
Надеюсь, это повеселило и дало новые идеи студентам JES... И другим тоже...
person
Gauthier Boaglio
schedule
27.06.2013