# Is it possible do this processing.gif in drawbot?

• A simple example of how to move the wave through a grid of dots. The position of the dots does not matter.

@frederik probably has a better and more robust solution for this also

• ``````frames = 24
page_size = 1000
grid_size = 20
grid_spacing = page_size / grid_size
min_dot_size = 10
max_dot_size = 50

def draw_dot(center, diameter):
x = center[0] - diameter / 2
y = center[1] - diameter / 2
oval(x, y, diameter, diameter)

for f in range(frames):
percentage_animated = f / frames
newPage()

fill(0)
rect(0, 0, page_size, page_size)

for row in range(grid_size):
for column in range(grid_size):
x = row * grid_spacing + grid_spacing / 2
y = column * grid_spacing + grid_spacing / 2
# Calculate distance from (x,y) of the dot to the center of the page
distance = pow( (pow(x - page_size / 2, 2 ) + pow(y - page_size / 2, 2)), 0.5)
# The wave must seem to move, so for every frame in the
# animation, add a precentage of the length of the wave.
# Add or substract to change direction.
distance = distance - percentage_animated * radius * 2
# Use modulo to get a distance between 0 and double the radius
distance = distance % (radius * 2)
# The wave has a lenghth of double the radius. In the
# first halve of the lenght, the dots get larger, in the
# second halve the dots get smaller.
# So, we calculate a percentage between 0 and 2, and when
# the percentage is larger than 1, we count backwards.
if percentage > 1:
percentage = 2 - percentage
dot_size = min_dot_size + percentage * (max_dot_size - min_dot_size)
fill(1)
draw_dot((x,y), dot_size)

saveImage("animated.gif")
``````

• Almost the same code, but instead of drawing a grid we draw 1000 circles randomly. As they have to stay in the same place, we save their locations in an array.

(Also in this script some nice code to have if you want to publish animated gifs; a way to reduce the colours in the gif.)

``````
import random
import struct

frames = 24
page_size = 1000
number_of_circles = 1000
min_dot_size = 10
max_dot_size = 70

# create color table for gif
# https://stackoverflow.com/questions/6269765/what-does-the-b-character-do-in-front-of-a-string-literal
table = b""
greys = [0,85,170,255]
for i in greys:
r = struct.pack(">B", i)
g = struct.pack(">B", i)
b = struct.pack(">B", i)
table += r + g + b # + a

def draw_dot(center, diameter):
x = center[0] - diameter / 2
y = center[1] - diameter / 2
oval(x, y, diameter, diameter)

# Generate circles, randomly distributed
circles = []
for i in range(number_of_circles):
x = random.randint(0,page_size)
y = random.randint(0,page_size)
circles.append((x,y))

for f in range(frames):
percentage_animated = f / frames
newPage()

fill(0)
rect(0, 0, page_size, page_size)

for c in circles:
x = c[0]
y = c[1]
distance = pow( (pow(x - page_size / 2, 2 ) + pow(y - page_size / 2, 2)), 0.5)
distance = distance - percentage_animated * radius * 2
distance = distance % (radius * 2)
if percentage > 1:
percentage = 2 - percentage
dot_size = min_dot_size + percentage * (max_dot_size - min_dot_size)
fill(None)
stroke(1)
draw_dot((x,y), dot_size)

saveImage("animated.gif", imageGIFRGBColorTable = table)
``````

• @monomonnik
How could you figure out the control-points and the second point for the segment (your first code snippet)?
(My "solution" would be, draw it in illustrator at the right coordinates, and copy/paste the numbers to drawbot.)

• It's fantastic, what is possible in drawbot!
Thank you @monomonnik for your great help!
Also @frederik for other interesting solutions! Thank you both

Some really new topics to me, and I need some time to understand step by (small) step.

• @pi That is exactly my solution. Itβs not elegant, but itβs quick and it works.

Below is the Applescript I used. If you name your paths in Illustrator and put the names in pathNames it will copy the coordinates of the points and corresponding control points to an array you can paste in DrawBot.

``````on run
set pathNames to {"segment_concave"}
set pathsArray to "segment = ["

activate
set docRef to current document

repeat with pathName in pathNames
set pointsArray to "["
set itemRef to path item pathName of docRef

set pointsRef to every path point of itemRef
repeat with pointRef in pointsRef
-- anchor point
set pointAsString to "["
set x to my string_float(item 1 of anchor of pointRef)
set y to my string_float(item 2 of anchor of pointRef)
set pointAsString to pointAsString & "(" & x & "," & y & "), "

-- left bcp
set x to my string_float(item 1 of left direction of pointRef)
set y to my string_float(item 2 of left direction of pointRef)
set pointAsString to pointAsString & "(" & x & "," & y & "), "

-- right bcp
set x to my string_float(item 1 of right direction of pointRef)
set y to my string_float(item 2 of right direction of pointRef)
set pointAsString to pointAsString & "(" & x & "," & y & ")"

set pointAsString to pointAsString & "]"
set pointsArray to pointsArray & pointAsString & ", "
end repeat
set pointsArrayLength to length of pointsArray
set pointsArray to (characters 1 through (pointsArrayLength - 2) of pointsArray) as string
set pointsArray to pointsArray & "]"

set pathsArray to pathsArray & pointsArray & ", "
end repeat
set pathsArrayLength to length of pathsArray
set pathsArray to (characters 1 through (pathsArrayLength - 2) of pathsArray) as string
set pathsArray to pathsArray & "]"

end tell

activate
set the clipboard to pathsArray
log pathsArray
end run

on string_float(s)
set s to s as string
set new_s to ""
repeat with c in s
if c as string is equal to "," then set c to "."
set new_s to new_s & c as string
end repeat
return new_s
end string_float
``````

• @frederik: Why is it 0.38?

``````# calculate the offcurve handle length
offCurveLength = distance * 0.38
``````

Still a few things I don't understand so far.
And I didn't find out, how to have one color for the circle, and a second color for the star.

BUT IT WORKS, thanks to all your inputs!
And it's fun to figure things out (if there's no deadline ).
This is my result (probably not with a very clean code...):

``````frames = 36

## circleHex
corners = 6
angleStep = pi * 2 / corners             # = 1.0471975511965976
offCurveLength = distance_hex * 0.38
minFactor = .6
maxFactor = 1

grid_spacingX = radius_hex/3 * 4          # 32
grid_spacingY = 28                        # radius_hex/3 * 4 - 4  --> doesn's work
stepsX = 27
stepsY = 15
pageW = 24*grid_spacingX + 2*radius_hex    # 816
pageH = 14*grid_spacingY + 2*radius_hex    # 440

for f in range(frames):
newPage(pageW, pageH)
fill(0)
rect(0, 0, pageW, pageH)

##  circleHex
factor = f / frames * 2
if factor > 1:
factor = 2 - factor

percentage_animated = f / frames

for row in range(stepsX):
for column in range(stepsY):
x = row * grid_spacingX
y = column * grid_spacingY

# Calculate distance from (x,y) of each circleHex to the center of the page
distance = pow( (pow(x - pageW/2, 2 ) + pow(y - pageH/2 + grid_spacingY, 2)), 0.5)
# The wave must seem to move, so for every frame in the
# animation, add a precentage of the length of the wave.
# Add or substract to change direction.
distance = distance - percentage_animated * radius_wave * 2
# Use modulo to get a distance between 0 and double the radius
distance = distance % (radius_wave * 2)
# The wave has a lenghth of double the radius. In the
# first halve of the lenght, the dots get larger, in the
# second halve the dots get smaller.
# So, we calculate a percentage between 0 and 2, and when
# the percentage is larger than 1, we count backwards.
if percentage > 1:
percentage = 2 - percentage

# interpolate the factor with our min max settings
factor = minFactor + percentage * (maxFactor - minFactor)

blendMode("hardLight")
fill(0.8,0,0.8, .3)
strokeWidth(None)
with savedState():
if y in range(0, pageH, grid_spacingY*2):
print(y)
pen = BezierPath()
pen.beginPath()
for i in range(corners):
angle = angleStep * i
offx1 = (x + cos(angle + pi / 2) * offCurveLength) * factor
offy1 = (y + sin(angle + pi / 2) * offCurveLength) * factor
offx2 = (x - cos(angle + pi / 2) * offCurveLength) * factor
offy2 = (y - sin(angle + pi / 2) * offCurveLength) * factor
pen.endPath()
drawPath(pen)
else:
pen = BezierPath()
pen.beginPath()
for i in range(corners):
angle = angleStep * i
offx1 = (x + cos(angle + pi / 2) * offCurveLength) * factor
offy1 = (y + sin(angle + pi / 2) * offCurveLength) * factor
offx2 = (x - cos(angle + pi / 2) * offCurveLength) * factor
offy2 = (y - sin(angle + pi / 2) * offCurveLength) * factor
pen.endPath()
drawPath(pen)
``````

• @frederik: Why is it 0.38?

the handle of the off curve is 38% of the distance between the oncurve points, that seems to be generating nice curves

• @frederik
Cool, thanks - less math, more trying out