So I was playing with animating some Bezier curves - just part of learning how to use ipycanvas (0,10,2) -- The animation I produced is really hurting my head. What I expected to see was a set of straight lines between 4 Bezier control points "bouncing" around the canvas with the Bezier curve moving along with them.
I did get the moving Bezier curve -- BUT the control points stayed static. Even stranger they were static in the final position and the curve came to meet them.
Now sometimes Python's structures and references can get a little tricky and so you can sometimes get confusing results if you are not really thinking it through -- and this totally could be what's going on - but I am at a loss.
So to make sure I was not confused I printed the control points (pts) at the beginning and then displayed them to the canvas. This confirmed my suspicion. Through quantum tunneling or some other magic time travel the line canvas.stroke_lines(pts)
reaches into the future and grabs the pts
array as it will exist in the future and keeps the control points in their final state.
Every other use of pts
uses the current temporal state.
So what I need to know is A) The laws of physics are safe and I am just too dumb to understand my own code. B) There is some odd bug in ipycanvas that I should report. C) How to monetize this time-traveling code -- like, could we use it to somehow factor large numbers?
from ipycanvas import Canvas, hold_canvas
import numpy as np
def rgb_to_hex(rgb):
if len(rgb) == 3:
return '#%02x%02x%02x' % rgb
elif len(rgb) == 4:
return '#%02x%02x%02x%02x' % rgb
def Bezier4(t, pts):
p = t**np.arange(0, 4,1)
M=np.matrix([[0,0,0,1],[0,0,3,-3],[0,3,-6,3],[1,-3,3,-1]])
return np.asarray((p*M*pts))
canvas = Canvas(width=800, height=800)
display(canvas) # display the canvas in the output cell..
pts = np.random.randint(50, 750, size=[4, 2]) #choose random starting point
print(pts) #print so we can compare with ending state
d = np.random.uniform(-4,4,size=[4,2]) #some random velocity vectors
c = rgb_to_hex(tuple(np.random.randint(75, 255,size=3))) #some random color
canvas.font = '16px serif' #font for displaying the changing pts array
with hold_canvas(canvas):
for ani in range(300):
#logic to bounce the points about...
for n in range(0,len(pts)):
pts[n]=pts[n] + d[n]
if pts[n][0] >= 800 or pts[n][0] <= 0 :
d[n][0] = - d[n][0]
if pts[n][1] >= 800 or pts[n][1] <= 0 :
d[n][1] = - d[n][1]
#calculate the points needed to display a bezier curve
B = [(Bezier4(i, pts)).ravel() for i in np.linspace(0,1,15)]
#begin display output....
canvas.clear()
#first draw bezier curve...
canvas.stroke_style = c
canvas.stroke_lines(B)
#Now draw control points
canvas.stroke_style = rgb_to_hex((255,255,128, 50))
canvas.stroke_lines(pts)
#print the control points to the canvas so we can see them move
canvas.stroke_style = rgb_to_hex((255,255,128, 150))
canvas.stroke_text(str(pts), 10, 32)
canvas.sleep(20)
In all seriousness, I have tried to think through what can be happening and I am coming up blank. Since ipycanvas is talking to the browser/javascript maybe all of the data for the frames are rendered first and the array used to hold the pts
data for the stroke_lines
ends up with the final values... Whereas the B array is recreated in each loop... It's a guess.