[feat] drawing_optimisation: in progess

the feature implement a paper: https://art-science.org/journal/v7n4/v7n4pp155/artsci-v7n4pp155.pdf

there is some generator to test the optimisation in: ./clitools/generators/drawingTests/
Now, all the optimisation will be in ./libs3/plotOptimizer.py
in ./libs3/tracer3.py the adding of point is avoid an will be replace by the optimisation from the paper
This commit is contained in:
Lapin 2020-12-17 20:21:04 +01:00
parent 8164320694
commit f3314441d3
6 changed files with 493 additions and 27 deletions

View File

@ -0,0 +1,98 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
This generator print different angle form 0 to 180 degres
v0.1.0
LICENCE : CC
by lapin (aka nipal)
'''
from __future__ import print_function
import time
import argparse
import sys
import math
name="generator::endingPoint"
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
argsparser = argparse.ArgumentParser(description="dummy generator")
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
argsparser.add_argument("-s","--speed",help="point per frame progress",default=3,type=int)
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
args = argsparser.parse_args()
fps=args.fps
verbose=args.verbose
optimal_looptime = 1 / fps
debug(name+" optimal looptime "+str(optimal_looptime))
width = 800
height = 800
white = 0xFFFFFF
blank = 0
radius = 100
offset_circles = 10
beg_angle = 0
end_angle = 90
offset_angle = 10
angles_lines = []
shape = []
def set_angles_lines():
margin = radius + offset_circles
spacing_betwen = 2 * radius + offset_circles
circles_per_line = math.floor((width - margin) / spacing_betwen)
for ang in range(beg_angle, end_angle + offset_angle, offset_angle):
nb = int(ang / offset_angle)
cx = margin + (nb % circles_per_line) * spacing_betwen
cy = margin + int(nb / circles_per_line) * spacing_betwen
px = radius * math.cos(math.radians(ang))
py = radius * math.sin(math.radians(ang))
# line up
angles_lines.append([-px + cx, py + cy, blank])
angles_lines.append([-px + cx, py + cy, white])
angles_lines.append([ cx, 2 + cy, white])
angles_lines.append([ px + cx, py + cy, white])
#angles_lines.append([ px + cx, py + cy, blank])
# line down
angles_lines.append([-px + cx, -py + cy, blank])
angles_lines.append([-px + cx, -py + cy, white])
angles_lines.append([ cx, -2 + cy, white])
angles_lines.append([ px + cx, -py + cy, white])
#angles_lines.append([ px + cx, -py + cy, blank])
set_angles_lines()
shape = angles_lines
# print(angles_lines)
while True:
start = time.time()
print(shape, flush=True);
looptime = time.time() - start
if( looptime < optimal_looptime ):
time.sleep( optimal_looptime - looptime)
debug(name+" micro sleep:"+str( optimal_looptime - looptime))

View File

@ -0,0 +1,117 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
This generator print a shape with 3 discinected component, 2 non eulerian and one eulerian.
v0.1.0
LICENCE : CC
by lapin (aka nipal)
'''
from __future__ import print_function
import time
import argparse
import sys
import math
name="generator::endingPoint"
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
def debug2(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
argsparser = argparse.ArgumentParser(description="dummy generator")
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
argsparser.add_argument("-s","--speed",help="point per frame progress",default=3,type=int)
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
args = argsparser.parse_args()
fps=args.fps
verbose=args.verbose
optimal_looptime = 1 / fps
debug(name+" optimal looptime "+str(optimal_looptime))
width = 800
height = 800
white = 0xFFFFFF
blank = 0
def shape_scale(shape, scale_factor):
new_shape = []
for p in shape:
new_shape.append([p[0] * scale_factor, p[1] * scale_factor, p[2]])
return new_shape
def shape_incr(shape, x, y):
new_shape = []
for p in shape:
new_shape.append([p[0] + x, p[1] + y, p[2]])
return new_shape
comp_a = []
comp_b = []
comp_c = []
comp_b.append([ 0, 3, blank])
comp_b.append([ 0, 4, white])
comp_b.append([ 0, 0, white])
comp_b.append([ 3, 0, white])
comp_b.append([ 3, 6, white])
comp_b.append([ 3, 6, white])
comp_b.append([ 3, 0, white])
comp_b.append([ 3, 0, blank])
comp_b.append([ 3, 0, white])
comp_b.append([ 5, 4, white])
comp_b.append([ 5, 4, blank])
comp_a.append([ 5, 17, blank])
comp_a.append([ 5, 17, white])
comp_a.append([ 0, 5, white])
comp_a.append([12, 0, white])
comp_a.append([17, 12, white])
comp_a.append([ 5, 17, white])
comp_a.append([ 5, 17, blank])
comp_c.append([-3, 5, blank])
comp_c.append([-3, 5, white])
comp_c.append([ 0, 4, white])
comp_c.append([ 0, 0, white])
comp_c.append([ 4, 0, white])
comp_c.append([ 4, 4, white])
comp_c.append([ 7, 5, white])
comp_c.append([ 7, 5, blank])
comp_a = shape_scale(comp_a, 11)
comp_a = shape_incr(comp_a, 300, 75)
comp_b = shape_scale(comp_b, 45)
comp_b = shape_incr(comp_b, 0, 300)
comp_c = shape_scale(comp_c, 30)
comp_c = shape_incr(comp_c, 600, 300)
shape = comp_a + comp_b + comp_c
while True:
start = time.time()
print(shape, flush=True);
looptime = time.time() - start
if( looptime < optimal_looptime ):
time.sleep( optimal_looptime - looptime)
debug(name+" micro sleep:"+str( optimal_looptime - looptime))

View File

@ -0,0 +1,77 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
This generator print 3 static vertical line.
The aim is to show The aim is to show the laser beam ignition time.
beam when ther is no optimisation
v0.1.0
LICENCE : CC
by lapin (aka nipal)
'''
from __future__ import print_function
import time
import argparse
import sys
name="generator::endingPoint"
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
argsparser = argparse.ArgumentParser(description="dummy generator")
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
argsparser.add_argument("-s","--speed",help="point per frame progress",default=3,type=int)
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
args = argsparser.parse_args()
fps=args.fps
verbose=args.verbose
optimal_looptime = 1 / fps
debug(name+" optimal looptime "+str(optimal_looptime))
white = 0xFFFFFF
blank = 0
offset_y = 100
offset_x = 50
begin_x = 200
begin_y = 200
shape_factor = [
[0, 0, white],
[0, 1, blank],
[1, 1, white],
[1, 0, blank],
[2, 0, white],
[2, 1, blank],
[2, 1, blank],
]
shape = []
for point in shape_factor:
shape.append([begin_x + offset_x * point[0],
begin_y + offset_y * point[1],
point[2]])
while True:
start = time.time()
print(shape, flush=True);
looptime = time.time() - start
if( looptime < optimal_looptime ):
time.sleep( optimal_looptime - looptime)
debug(name+" micro sleep:"+str( optimal_looptime - looptime))

View File

@ -0,0 +1,84 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
This generator print a shape with best angle representation when the path is redraw
v0.1.0
LICENCE : CC
by lapin (aka nipal)
'''
from __future__ import print_function
import time
import argparse
import sys
import math
name="generator::endingPoint"
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
def debug2(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
argsparser = argparse.ArgumentParser(description="dummy generator")
argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int)
argsparser.add_argument("-s","--speed",help="point per frame progress",default=3,type=int)
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
args = argsparser.parse_args()
fps=args.fps
verbose=args.verbose
optimal_looptime = 1 / fps
debug(name+" optimal looptime "+str(optimal_looptime))
width = 800
height = 800
white = 0xFFFFFF
blank = 0
point_offset = 250
point_width = 4
point_list = [
[8,7,6,10,7,3,6,2,7,11,6,9],
[5,6,1,],
[4,7,12,],
]
shape = []
# on ajoute des lilste de point
for l in point_list:
x = point_offset * ((l[0] - 1) % (point_width))
y = point_offset * int((l[0] - 1) / (point_width))
shape.append([x, y, blank])
debug2("=====")
debug2(f"id: {l[0]}\tx: {x}\ty: {y}\t\tpoint_width: {point_width}\t\n")
for p in l:
x = point_offset * ((p - 1) % (point_width))
y = point_offset * int((p - 1) / (point_width))
shape.append([x, y, white])
debug2(f"id: {p}\tx: {x}\ty: {y}\t\tpoint_width: {point_width}\t\n")
while True:
start = time.time()
print(shape, flush=True);
looptime = time.time() - start
if( looptime < optimal_looptime ):
time.sleep( optimal_looptime - looptime)
debug(name+" micro sleep:"+str( optimal_looptime - looptime))

93
libs3/plotOptimizer.py Normal file
View File

@ -0,0 +1,93 @@
class Node:
def __init__(self, sid, color):
self.sid = sid
self.connected = []
self.used = False
self.color = color
self.is_free = None # may be an other value to initialise
def add_nodes(self, neighbord):
not_the_same = neighbord != self.sid
not_allrady_inside = neighbord not in self.connected
if neighbord != self.sid and neighbord not in self.connected:
self.connected.append(neighbord)
# print the content of the objet to debug with print()
def __repr__(self):
is_free = " \t###" if self.is_free else " \t___"
return is_free + str(self.connected) + "\n"
#class Graph:
# nodes = {} # dict of all nodes
#
# def __init__(selt):
# pass
def list_to_nodes(pl):
all_nodes = {} # it will contain all nodes
sid_prev = None
for p in pl:
sid = str([int(p[0]), int(p[1])])
is_colored = p[2] != 0
if is_colored:
if sid not in all_nodes:
all_nodes[sid] = Node(sid, p[2])
if sid_prev != None:
all_nodes[sid].add_nodes(sid_prev)
all_nodes[sid_prev].add_nodes(sid)
sid_prev = sid if is_colored else None
return all_nodes
# recursiv function witch get all connected node for one component and tag them as used
def get_one_comp(id_elem, nodes):
comp = []
comp.append(id_elem)
nodes[id_elem].used = True
for id_near in nodes[id_elem].connected:
if nodes[id_near].used == False:
comp += get_one_comp(id_near, nodes)
return comp
def get_comps(nodes):
comps = [] #all component
iter_nodes = iter(nodes)
nb_elem = len(nodes)
for id_nodes in iter_nodes:
if nodes[id_nodes].used == False:
comps.append(get_one_comp(id_nodes, nodes))
return comps
# if ther is a class for the component it would be a good idea to set en atribute about eulerian graph or non eulerian graph
def set_free_vertices(components, nodes):
for comp in components:
all_even_neighbord = True
for id_node in comp:
if len(nodes[id_node].connected) % 2 == 0: # test if even neighbord
nodes[id_node].is_free = False
else:
nodes[id_node].is_free = True
all_even_neighbord = False
if all_even_neighbord:
for id_node in comp:
nodes[id_node].is_free = True
def optimizer(pl):
all_nodes = {} # it will contain all nodes
components = [] # list of connected node as a graph
# construct dict of connected all_nodes
all_nodes = list_to_nodes(pl)
components = get_comps(all_nodes)
set_free_vertices(components, all_nodes)
print("\n\nall_nodes:\n", all_nodes)
print("\n\nconnected_components:\n", components)
return pl
if __name__ == '__main__':
pl = [(355, 262, 0), (355, 262, 16777215), (300, 130, 16777215), (432, 75, 16777215), (487, 207, 16777215), (355, 262, 16777215), (355, 262, 0), (0, 435, 0), (0, 480, 16777215), (0, 300, 16777215), (135, 300, 16777215), (135, 570, 16777215), (135, 570, 16777215), (135, 300, 16777215), (135, 300, 0), (135, 300, 16777215), (225, 480, 16777215), (225, 480, 0), (510, 450, 0), (510, 450, 16777215), (600, 420, 16777215), (600, 300, 16777215), (720, 300, 16777215), (720, 420, 16777215), (810, 450, 16777215), (810, 450, 0)]
optimizer(pl)

View File

@ -81,7 +81,8 @@ import pdb
import ast import ast
import redis import redis
from libs3 import homographyp from libs3 import homographyp, plotOptimizer as po
import numpy as np import numpy as np
import binascii import binascii
@ -223,43 +224,39 @@ class DAC(object):
while True: while True:
#pdb.set_trace() self.pl = po.optimizer(self.pl)
for indexpoint,currentpoint in enumerate(self.pl): for indexpoint,currentpoint in enumerate(self.pl):
#print indexpoint, currentpoint
# transformations des point au format adapter au etherdream
xyc = [currentpoint[0],currentpoint[1],currentpoint[2]] xyc = [currentpoint[0],currentpoint[1],currentpoint[2]]
self.xyrgb = self.EtherPoint(xyc) self.xyrgb = self.EtherPoint(xyc)
#print(self.xyrgb[2:])
rgb = (round(self.xyrgb[2:][0] *self.intred/100), round(self.xyrgb[2:][1] *self.intgreen/100), round(self.xyrgb[2:][2] *self.intblue/100)) rgb = (round(self.xyrgb[2:][0] *self.intred/100), round(self.xyrgb[2:][1] *self.intgreen/100), round(self.xyrgb[2:][2] *self.intblue/100))
#print("rgb :", rgb)
#round(*self.intred/100) yield self.xyrgb
#round(*self.intgreen/100) ##**//# ajout de point pour un tracer adapter
#round(*self.intblue/100) ##**//delta_x, delta_y = self.xyrgb[0] - self.xyrgb_prev[0], self.xyrgb[1] - self.xyrgb_prev[1]
##**//#test adaptation selon longueur ligne
##**//if math.hypot(delta_x, delta_y) < 4000:
delta_x, delta_y = self.xyrgb[0] - self.xyrgb_prev[0], self.xyrgb[1] - self.xyrgb_prev[1] ##**// # For glitch art : decrease lsteps
##**// #l_steps = [ (1.0, 8)]
##**// l_steps = gstt.stepshortline
#test adaptation selon longueur ligne ##**//else:
if math.hypot(delta_x, delta_y) < 4000: ##**// # For glitch art : decrease lsteps
##**// #l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
##**// l_steps = gstt.stepslongline
# For glitch art : decrease lsteps ##**//for e in l_steps:
#l_steps = [ (1.0, 8)] ##**// step = e[0]
l_steps = gstt.stepshortline
else: ##**// for i in range(0,e[1]):
# For glitch art : decrease lsteps
#l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
l_steps = gstt.stepslongline
for e in l_steps: ##**// self.xyrgb_step = (self.xyrgb_prev[0] + step*delta_x, self.xyrgb_prev[1] + step*delta_y) + rgb # + self.xyrgb_prev[2:]# + rgb
step = e[0] ##**// #print(self.xyrgb_step)
##**// yield self.xyrgb_step
for i in range(0,e[1]): ##**//self.xyrgb_prev = self.xyrgb
self.xyrgb_step = (self.xyrgb_prev[0] + step*delta_x, self.xyrgb_prev[1] + step*delta_y) + rgb # + self.xyrgb_prev[2:]# + rgb
#print(self.xyrgb_step)
yield self.xyrgb_step
self.xyrgb_prev = self.xyrgb
def GetPoints(self, n): def GetPoints(self, n):