kopia lustrzana https://github.com/villares/sketch-a-day
rodzic
ac92dd3383
commit
6dd1905fcc
|
@ -1,5 +1,5 @@
|
|||
add_library('gifAnimation')
|
||||
from gif_animation_helper import gif_export
|
||||
# add_library('gifAnimation')
|
||||
# from gif_animation_helper import gif_export
|
||||
|
||||
from arcs import *
|
||||
|
||||
|
@ -51,9 +51,9 @@ def draw():
|
|||
else:
|
||||
t = 0
|
||||
i = (i + 1) % num_transitions
|
||||
if i == 0:
|
||||
gif_export(GifMaker, finish=True)
|
||||
gif_export(GifMaker, filename="sketch")
|
||||
# if i == 0:
|
||||
# gif_export(GifMaker, finish=True)
|
||||
# gif_export(GifMaker, filename="sketch")
|
||||
|
||||
def lerp_arrow(a, b, t):
|
||||
result = []
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division
|
||||
|
||||
ROTATION = {0: 0,
|
||||
BOTTOM: 0,
|
||||
DOWN: 0,
|
||||
1: HALF_PI,
|
||||
LEFT: HALF_PI,
|
||||
2: PI,
|
||||
TOP: PI,
|
||||
UP: PI,
|
||||
3: PI + HALF_PI,
|
||||
RIGHT: PI + HALF_PI,
|
||||
BOTTOM + RIGHT: 0,
|
||||
DOWN + RIGHT: 0,
|
||||
DOWN + LEFT: HALF_PI,
|
||||
BOTTOM + LEFT: HALF_PI,
|
||||
TOP + LEFT: PI,
|
||||
UP + LEFT: PI,
|
||||
TOP + RIGHT: PI + HALF_PI,
|
||||
UP + RIGHT: PI + HALF_PI,
|
||||
}
|
||||
|
||||
def quarter_circle(x, y, radius, quadrant):
|
||||
circle_arc(x, y, radius, ROTATION[quadrant], HALF_PI)
|
||||
|
||||
def half_circle(x, y, radius, quadrant):
|
||||
circle_arc(x, y, radius, ROTATION[quadrant], PI)
|
||||
|
||||
def circle_arc(x, y, radius, start_ang, sweep_ang):
|
||||
arc(x, y, radius * 2, radius * 2, start_ang, start_ang + sweep_ang)
|
||||
|
||||
def b_circle_arc(x, y, radius, start_ang, sweep_ang, mode=0):
|
||||
"""
|
||||
Alternative interface for b_arc
|
||||
"""
|
||||
b_arc(x, y, radius * 2, radius * 2, start_ang, start_ang + sweep_ang,
|
||||
mode=mode)
|
||||
|
||||
def b_arc(cx, cy, w, h, start_angle, end_angle, mode=0):
|
||||
"""
|
||||
A bezier approximation of an arc
|
||||
using the same signature as the original Processing arc()
|
||||
mode: 0 "normal" or stand-alone arc, using beginShape() and endShape()
|
||||
1 "middle" used in recursive call of smaller arcs
|
||||
2 "naked" like normal, but without beginShape() and endShape()
|
||||
for use inside a larger PShape
|
||||
"""
|
||||
theta = end_angle - start_angle
|
||||
# Compute raw Bezier coordinates.
|
||||
if mode != 1 or abs(theta) <= QUARTER_PI:
|
||||
x0 = cos(theta / 2.0)
|
||||
y0 = sin(theta / 2.0)
|
||||
x3 = x0
|
||||
y3 = 0 - y0
|
||||
x1 = (4.0 - x0) / 3.0
|
||||
if y0 != 0:
|
||||
y1 = ((1.0 - x0) * (3.0 - x0)) / (3.0 * y0) # y0 != 0...
|
||||
else:
|
||||
y1 = 0
|
||||
x2 = x1
|
||||
y2 = 0 - y1
|
||||
# Compute rotationally-offset Bezier coordinates, using:
|
||||
# x' = cos(angle) * x - sin(angle) * y
|
||||
# y' = sin(angle) * x + cos(angle) * y
|
||||
bezAng = start_angle + theta / 2.0
|
||||
cBezAng = cos(bezAng)
|
||||
sBezAng = sin(bezAng)
|
||||
rx0 = cBezAng * x0 - sBezAng * y0
|
||||
ry0 = sBezAng * x0 + cBezAng * y0
|
||||
rx1 = cBezAng * x1 - sBezAng * y1
|
||||
ry1 = sBezAng * x1 + cBezAng * y1
|
||||
rx2 = cBezAng * x2 - sBezAng * y2
|
||||
ry2 = sBezAng * x2 + cBezAng * y2
|
||||
rx3 = cBezAng * x3 - sBezAng * y3
|
||||
ry3 = sBezAng * x3 + cBezAng * y3
|
||||
# Compute scaled and translated Bezier coordinates.
|
||||
rx, ry = w / 2.0, h / 2.0
|
||||
px0 = cx + rx * rx0
|
||||
py0 = cy + ry * ry0
|
||||
px1 = cx + rx * rx1
|
||||
py1 = cy + ry * ry1
|
||||
px2 = cx + rx * rx2
|
||||
py2 = cy + ry * ry2
|
||||
px3 = cx + rx * rx3
|
||||
py3 = cy + ry * ry3
|
||||
# Debug points... comment this out!
|
||||
# stroke(0)
|
||||
# ellipse(px3, py3, 15, 15)
|
||||
# ellipse(px0, py0, 5, 5)
|
||||
# Drawing
|
||||
if mode == 0: # 'normal' arc (not 'middle' nor 'naked')
|
||||
beginShape()
|
||||
if mode != 1: # if not 'middle'
|
||||
vertex(px3, py3)
|
||||
if abs(theta) <= QUARTER_PI:
|
||||
bezierVertex(px2, py2, px1, py1, px0, py0)
|
||||
else:
|
||||
# to avoid distortion, break into 2 smaller arcs
|
||||
b_arc(cx, cy, w, h, start_angle, end_angle - theta / 2.0, mode=1)
|
||||
b_arc(cx, cy, w, h, start_angle + theta / 2.0, end_angle, mode=1)
|
||||
if mode == 0: # end of a 'normal' arc
|
||||
endShape()
|
||||
|
||||
def p_circle_arc(x, y, radius, start_ang, sweep_ang, mode=0, num_points=None):
|
||||
"""
|
||||
Alternative interface for b_arc
|
||||
"""
|
||||
p_arc(x, y, radius * 2, radius * 2, start_ang, start_ang + sweep_ang,
|
||||
mode=mode, num_points=num_points)
|
||||
|
||||
def p_arc(cx, cy, w, h, start_angle, end_angle, mode=0, num_points=None):
|
||||
"""
|
||||
A poly approximation of an arc
|
||||
using the same signature as the original Processing arc()
|
||||
mode: 0 "normal" arc, using beginShape() and endShape()
|
||||
2 "naked" like normal, but without beginShape() and endShape()
|
||||
for use inside a larger PShape
|
||||
"""
|
||||
if not num_points:
|
||||
num_points = 36
|
||||
# start_angle = start_angle if start_angle < end_angle else start_angle - TWO_PI
|
||||
sweep_angle = end_angle - start_angle
|
||||
if mode == 0:
|
||||
beginShape()
|
||||
if sweep_angle < 0:
|
||||
start_angle, end_angle = end_angle, start_angle
|
||||
sweep_angle = -sweep_angle
|
||||
angle = sweep_angle / int(num_points)
|
||||
a = end_angle
|
||||
while a >= start_angle:
|
||||
sx = cx + cos(a) * w / 2.
|
||||
sy = cy + sin(a) * h / 2.
|
||||
vertex(sx, sy)
|
||||
a -= angle
|
||||
elif sweep_angle > 0:
|
||||
angle = sweep_angle / int(num_points)
|
||||
a = start_angle
|
||||
while a <= end_angle:
|
||||
sx = cx + cos(a) * w / 2.
|
||||
sy = cy + sin(a) * h / 2.
|
||||
vertex(sx, sy)
|
||||
a += angle
|
||||
else:
|
||||
sx = cx + cos(start_angle) * w / 2.
|
||||
sy = cy + sin(start_angle) * h / 2.
|
||||
vertex(sx, sy)
|
||||
if mode == 0:
|
||||
endShape()
|
|
@ -0,0 +1,44 @@
|
|||
"""
|
||||
Alexandre B A Villares http://abav.lugaralgum.com - GPL v3
|
||||
|
||||
A helper for the Processing gifAnimation library https://github.com/extrapixel/gif-animation/tree/3.0
|
||||
Download from https://github.com/villares/processing-play/blob/master/export_GIF/unzip_and_move_to_libraries_GifAnimation.zip
|
||||
This helper was inspired by an example by Art Simon https://github.com/APCSPrinciples/AnimatedGIF/
|
||||
|
||||
v2019_09_23
|
||||
|
||||
# add at the start of your sketch:
|
||||
add_library('gifAnimation')
|
||||
from gif_animation_helper import gif_export
|
||||
# add at the end of draw():
|
||||
gif_export(GifMaker, "filename")
|
||||
"""
|
||||
|
||||
def gif_export(GifMaker, # gets a reference to the library
|
||||
filename="exported", # .gif will be added
|
||||
repeat=0, # 0 makes it an "endless" animation
|
||||
quality=200, # quality range 0 - 255
|
||||
delay=170, # this is quick
|
||||
frames=0, # 0 will stop on keyPressed or frameCount >= 100000
|
||||
finish=False): # force stop
|
||||
global gifExporter
|
||||
try:
|
||||
gifExporter
|
||||
except NameError:
|
||||
gifExporter = GifMaker(this, filename + ".gif")
|
||||
gifExporter.setRepeat(repeat)
|
||||
gifExporter.setQuality(quality)
|
||||
gifExporter.setDelay(delay)
|
||||
print("gif recording started")
|
||||
|
||||
|
||||
gifExporter.addFrame()
|
||||
|
||||
if (frames == 0 and keyPressed and key == "e" or
|
||||
frames != 0 and frameCount >= frames):
|
||||
finish = True
|
||||
|
||||
if finish:
|
||||
gifExporter.finish()
|
||||
print("gif saved, exit")
|
||||
exit()
|
|
@ -0,0 +1,156 @@
|
|||
add_library('gifAnimation')
|
||||
from gif_animation_helper import gif_export
|
||||
|
||||
from arcs import *
|
||||
|
||||
many_arrows = []
|
||||
num_arrows, num_transitions = 3, 4
|
||||
i, t = 0, 0
|
||||
|
||||
def setup():
|
||||
size(400, 400)
|
||||
colorMode(HSB)
|
||||
strokeJoin(ROUND)
|
||||
frameRate(30)
|
||||
smooth(8)
|
||||
for _ in range(num_transitions):
|
||||
many_arrows.append(create_arrows())
|
||||
global starting_arrows
|
||||
many_arrows.append(many_arrows[0][:])
|
||||
|
||||
|
||||
def create_arrows():
|
||||
arrows = []
|
||||
for _ in range(num_arrows):
|
||||
arrows.append(random_arrow())
|
||||
return arrows
|
||||
|
||||
def draw():
|
||||
global t, i
|
||||
background(200)
|
||||
if t <= width:
|
||||
tt = map(t, 0, width, 0, 1)
|
||||
else:
|
||||
tt = 1
|
||||
|
||||
ini_arrows, fin_arrows = many_arrows[i], many_arrows[i + 1]
|
||||
for a, b in zip(ini_arrows, fin_arrows):
|
||||
mid_arrow = lerp_arrow(a, b, tt)
|
||||
rad, start, sweep, thick, h = mid_arrow
|
||||
noFill()
|
||||
strokeWeight(4)
|
||||
if mouse_on_arrow(mid_arrow):
|
||||
stroke(255)
|
||||
else:
|
||||
stroke(h, 255, 200)
|
||||
if thick > 0:
|
||||
start = TWO_PI * tt
|
||||
else:
|
||||
start = TWO_PI * -tt
|
||||
arc_arrow(width / 2, height / 2, rad, start, sweep, thick)
|
||||
|
||||
if t < width:
|
||||
t = lerp(t, width + 1, .1)
|
||||
else:
|
||||
t = 0
|
||||
i = (i + 1) % num_transitions
|
||||
if i == 0:
|
||||
gif_export(GifMaker, finish=True)
|
||||
gif_export(GifMaker, filename="sketch")
|
||||
|
||||
def lerp_arrow(a, b, t):
|
||||
result = []
|
||||
for c_a, c_b in zip(a, b):
|
||||
result.append(lerp(c_a, c_b, t))
|
||||
return result
|
||||
|
||||
def random_arrow():
|
||||
d = -1 if random(100) >= 50 else 1
|
||||
return [int(random(10, height / 12)) * 5,
|
||||
0, # start
|
||||
int(6 * random(QUARTER_PI, TWO_PI - QUARTER_PI) / 6), # sweep
|
||||
int(random(2, height / 100)) * 10 * d, # thickness
|
||||
random(256) # hue
|
||||
]
|
||||
|
||||
def mouse_on_arrow(a, precision=10):
|
||||
mx, my = width / 2, height / 2
|
||||
rad, start, sweep, thick, _ = a
|
||||
start += thick * radians(frameCount % 361) / 10.
|
||||
same_rad = abs(abs(rad) - dist(mouseX, mouseY, mx, my)) < precision
|
||||
mouse_ang = atan2(mouseY - my, mouseX - mx)
|
||||
# in_sweep = start < mouse_ang < degrees(start + sweep) % 360
|
||||
return same_rad #and in_sweep
|
||||
|
||||
|
||||
def keyPressed():
|
||||
if key == ' ':
|
||||
many_arrows[:] = []
|
||||
for _ in range(3):
|
||||
many_arrows.append(create_arrows())
|
||||
if key == 's':
|
||||
saveFrame('#####.png')
|
||||
|
||||
# def mouseWheel(e):
|
||||
# w = e.getAmount()
|
||||
# player_arrow[3] += int(w) * 10
|
||||
# if player_arrow[3] < 10:
|
||||
# player_arrow[3] = 10
|
||||
|
||||
# def mouseDragged():
|
||||
# dx = mouseX - pmouseX
|
||||
# dy = mouseY - pmouseY
|
||||
# player_arrow[2] += radians(dx)
|
||||
# player_arrow[0] += dy
|
||||
|
||||
def arc_arrow(x, y, radius, start_ang, sweep_ang,
|
||||
thickness=None, correction=1):
|
||||
"""
|
||||
Draws an arrow in a circular arc shape
|
||||
"""
|
||||
if thickness is None:
|
||||
thickness = radius / 2
|
||||
if abs(radius) * .75 < abs(thickness / 2):
|
||||
thickness = radius * 1.5 if thickness > 0 else -radius * 1.5
|
||||
if radius < 0:
|
||||
thickness = -thickness
|
||||
|
||||
beginShape()
|
||||
b_circle_arc(x, y, radius + thickness / 2,
|
||||
start_ang, sweep_ang, mode=2)
|
||||
mid_ending(x, y, radius, start_ang + sweep_ang, thickness, correction)
|
||||
b_circle_arc(x, y, radius - thickness / 2,
|
||||
start_ang + sweep_ang, -sweep_ang, mode=2)
|
||||
mid_ending(x, y, radius, start_ang, thickness, correction)
|
||||
endShape(CLOSE)
|
||||
|
||||
def mid_ending(x, y, radius, angle, thickness, correction):
|
||||
if radius == 0:
|
||||
radius = 1
|
||||
half_thick = thickness / 2.
|
||||
pa = point_on_arc(x, y, radius + half_thick, angle)
|
||||
pb = point_on_arc(x, y, radius - half_thick, angle)
|
||||
mp = mid_point(pa, pb)
|
||||
tangent_ep = point_on_arc(mp[0], mp[1], half_thick, angle + HALF_PI)
|
||||
offset = half_thick / radius
|
||||
midline_ep = point_on_arc(x, y, radius, angle + offset)
|
||||
if correction == 0: # tangent
|
||||
vertex(*tangent_ep)
|
||||
elif correction == 2: # on mid-line
|
||||
vertex(*midline_ep)
|
||||
else: # half-way
|
||||
vertex(*mid_point(tangent_ep, midline_ep))
|
||||
|
||||
def mid_point(pa, pb):
|
||||
if len(pa) == 3 and len(pb) == 3:
|
||||
return ((pa[0] + pb[0]) / 2,
|
||||
(pa[1] + pb[1]) / 2,
|
||||
(pa[2] + pb[2]) / 2)
|
||||
else:
|
||||
return ((pa[0] + pb[0]) / 2,
|
||||
(pa[1] + pb[1]) / 2)
|
||||
|
||||
def point_on_arc(cx, cy, radius, angle):
|
||||
x = cx + radius * cos(angle)
|
||||
y = cy + radius * sin(angle)
|
||||
return (x, y)
|
Ładowanie…
Reference in New Issue