Merge branch 'master' of https://github.com/skykooler/Lightningbeam
This commit is contained in:
commit
f0e2de1c2f
1
control
1
control
|
|
@ -7,3 +7,4 @@ Installed-size: 27000
|
||||||
Depends: bash, python, python-imaging, imagemagick, libzzip-0-13, sox, python-numpy, mplayer
|
Depends: bash, python, python-imaging, imagemagick, libzzip-0-13, sox, python-numpy, mplayer
|
||||||
Maintainer: skycooler@gmail.com
|
Maintainer: skycooler@gmail.com
|
||||||
Description: Lightningbeam is an open-source animated content creation tool.
|
Description: Lightningbeam is an open-source animated content creation tool.
|
||||||
|
|
||||||
|
|
|
||||||
12
kt.py
12
kt.py
|
|
@ -9,16 +9,18 @@ from kivy.graphics import Color, Ellipse, Line
|
||||||
|
|
||||||
Builder.load_file("lightningbeam.kv")
|
Builder.load_file("lightningbeam.kv")
|
||||||
|
|
||||||
class Lightningbeam(TabbedPanel):
|
class LightningbeamPanel(TabbedPanel):
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class KivyCanvas(Widget):
|
||||||
|
def on_touch_down(self, touch):
|
||||||
|
print touch.button
|
||||||
|
|
||||||
class MyPaintApp(App):
|
class LightningbeamApp(App):
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
return Lightningbeam()
|
return LightningbeamPanel()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
MyPaintApp().run()
|
LightningbeamApp().run()
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
#:kivy 1.0
|
#:kivy 1.0
|
||||||
#:import ActionScriptLexer pygments.lexers.ActionScriptLexer
|
#:import ActionScriptLexer pygments.lexers.ActionScriptLexer
|
||||||
|
|
||||||
<Lightningbeam>:
|
<KivyCanvas>:
|
||||||
|
|
||||||
|
|
||||||
|
<LightningbeamPanel>:
|
||||||
do_default_tab: False
|
do_default_tab: False
|
||||||
TabbedPanelItem:
|
TabbedPanelItem:
|
||||||
text: 'Drawing'
|
text: 'Drawing'
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
orientation: "vertical"
|
orientation: "vertical"
|
||||||
|
KivyCanvas:
|
||||||
|
|
||||||
TabbedPanelItem:
|
TabbedPanelItem:
|
||||||
text: 'Tools'
|
text: 'Tools'
|
||||||
|
|
@ -25,7 +29,7 @@
|
||||||
Button:
|
Button:
|
||||||
text: "Ellipse"
|
text: "Ellipse"
|
||||||
Button:
|
Button:
|
||||||
text: "Painbrush"
|
text: "Paintbrush"
|
||||||
TabbedPanelItem:
|
TabbedPanelItem:
|
||||||
text: 'ActionScript'
|
text: 'ActionScript'
|
||||||
CodeInput:
|
CodeInput:
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ def onMouseDownGroup(self, x, y,button=1,clicks=1):
|
||||||
if svlgui.MODE in [" ", "s"]:
|
if svlgui.MODE in [" ", "s"]:
|
||||||
if self.hitTest(x, y):
|
if self.hitTest(x, y):
|
||||||
self.clicked = True
|
self.clicked = True
|
||||||
|
|
||||||
elif svlgui.MODE in ["r", "e", "p"]:
|
elif svlgui.MODE in ["r", "e", "p"]:
|
||||||
if svlgui.MODE=="r":
|
if svlgui.MODE=="r":
|
||||||
# 'c' stands for 'current'
|
# 'c' stands for 'current'
|
||||||
|
|
@ -118,7 +119,26 @@ def onMouseDownGroup(self, x, y,button=1,clicks=1):
|
||||||
elif svlgui.MODE=="e":
|
elif svlgui.MODE=="e":
|
||||||
self.cshape = ellipse(x, y, 0, 0)
|
self.cshape = ellipse(x, y, 0, 0)
|
||||||
elif svlgui.MODE=="p":
|
elif svlgui.MODE=="p":
|
||||||
|
for i in self.lines:
|
||||||
|
if abs(x-i.endpoint1.x)<10 and abs(y-i.endpoint1.y)<10:
|
||||||
|
x, y = i.endpoint1.x, i.endpoint1.y
|
||||||
|
break
|
||||||
|
elif abs(x-i.endpoint2.x)<10 and abs(i.endpoint2.y)<10:
|
||||||
|
x, y = i.endpoint2.x, i.endpoint2.y
|
||||||
|
break
|
||||||
self.cshape = shape(x, y)
|
self.cshape = shape(x, y)
|
||||||
|
'''self.cshape = svlgui.Line(svlgui.Point(x, y),svlgui.Point(x,y))
|
||||||
|
for i in self.lines:
|
||||||
|
if abs(self.cshape.endpoint1.x-i.endpoint1.x)<10 and abs(self.cshape.endpoint1.y-i.endpoint1.y)<10:
|
||||||
|
self.cshape.connection1 = i.endpoint1
|
||||||
|
self.cshape.connection1.lines.add(self.cshape)
|
||||||
|
break
|
||||||
|
elif abs(self.cshape.endpoint1.x-i.endpoint2.x)<10 and abs(self.cshape.endpoint1.y-i.endpoint2.y)<10:
|
||||||
|
self.cshape.connection1 = i.endpoint2
|
||||||
|
self.cshape.connection1.lines.add(self.cshape)
|
||||||
|
break
|
||||||
|
self.lines.append(self.cshape)
|
||||||
|
return'''
|
||||||
#self.cshape.rotation = 5
|
#self.cshape.rotation = 5
|
||||||
self.cshape.initx,self.cshape.inity = x, y
|
self.cshape.initx,self.cshape.inity = x, y
|
||||||
self.add(self.cshape)
|
self.add(self.cshape)
|
||||||
|
|
@ -185,9 +205,50 @@ def onMouseUpGroup(self, x, y,button=1,clicks=1):
|
||||||
undo_stack[-1] = undo_stack[-1].complete({"obj":cobj, "frame":self.activelayer.currentframe, "layer":self.activelayer})
|
undo_stack[-1] = undo_stack[-1].complete({"obj":cobj, "frame":self.activelayer.currentframe, "layer":self.activelayer})
|
||||||
clear(redo_stack)
|
clear(redo_stack)
|
||||||
elif svlgui.MODE=="p":
|
elif svlgui.MODE=="p":
|
||||||
print len(self.cshape.shapedata)
|
prelen = len(self.cshape.shapedata)
|
||||||
self.cshape.shapedata = misc_funcs.simplify_shape(self.cshape.shapedata, svlgui.PMODE.split()[-1],1)
|
self.cshape.shapedata = misc_funcs.simplify_shape(self.cshape.shapedata, svlgui.PMODE.split()[-1],1)
|
||||||
print len(self.cshape.shapedata)
|
postlen = len(self.cshape.shapedata)
|
||||||
|
print str((prelen-postlen)*100/prelen)+"% reduction: started at "+str(prelen)+" vertices, ended at "+str(postlen)+" vertices"
|
||||||
|
if svlgui.PMODE.split()[-1]=="straight":
|
||||||
|
lastline = None
|
||||||
|
x, y = self.cshape.x, self.cshape.y
|
||||||
|
for a, b in misc_funcs.pairwise(self.cshape.shapedata):
|
||||||
|
l = svlgui.Line(svlgui.Point(a[1]+x,a[2]+y),svlgui.Point(b[1]+x,b[2]+y))
|
||||||
|
if lastline:
|
||||||
|
l.connection1 = lastline.endpoint2
|
||||||
|
l.connection1.lines.add(l)
|
||||||
|
lastline = l
|
||||||
|
self.lines.append(l)
|
||||||
|
self.delete(self.activelayer.frames[self.currentframe].objs[-1])
|
||||||
|
for line in self.lines:
|
||||||
|
for otherline in self.lines:
|
||||||
|
if not otherline is line:
|
||||||
|
if line.connection1 and otherline in line.connection1.lines: continue
|
||||||
|
if line.connection2 and otherline in line.connection2.lines: continue
|
||||||
|
inter = line.intersects(otherline)
|
||||||
|
if inter:
|
||||||
|
print "INTERSECTION"
|
||||||
|
inter = svlgui.Point(*inter)
|
||||||
|
l1 = svlgui.Line(line.endpoint1,inter,line.connection1,inter)
|
||||||
|
l2 = svlgui.Line(line.endpoint2,inter,line.connection2,inter)
|
||||||
|
l3 = svlgui.Line(otherline.endpoint1,inter,otherline.connection1,inter)
|
||||||
|
l4 = svlgui.Line(otherline.endpoint2,inter,otherline.connection2,inter)
|
||||||
|
inter.lines.add(l1)
|
||||||
|
inter.lines.add(l2)
|
||||||
|
inter.lines.add(l3)
|
||||||
|
inter.lines.add(l4)
|
||||||
|
self.lines[self.lines.index(line):self.lines.index(line)+1]=[l1,l2]
|
||||||
|
self.lines[self.lines.index(otherline):self.lines.index(otherline)+1]=[l3,l4]
|
||||||
|
break
|
||||||
|
'''for i in self.lines:
|
||||||
|
if abs(self.cshape.endpoint2.x-i.endpoint1.x)<10 and abs(self.cshape.endpoint2.y-i.endpoint1.y)<10:
|
||||||
|
self.cshape.connection2 = i.endpoint1
|
||||||
|
self.cshape.connection2.lines.add(self.cshape)
|
||||||
|
break
|
||||||
|
elif abs(self.cshape.endpoint2.x-i.endpoint2.x)<10 and abs(self.cshape.endpoint2.y-i.endpoint2.y)<10:
|
||||||
|
self.cshape.connection2 = i.endpoint2
|
||||||
|
self.cshape.connection2.lines.add(self.cshape)
|
||||||
|
break'''
|
||||||
self.cshape = None
|
self.cshape = None
|
||||||
MainWindow.stage.draw()
|
MainWindow.stage.draw()
|
||||||
def onMouseUpObj(self, x, y,button=1,clicks=1):
|
def onMouseUpObj(self, x, y,button=1,clicks=1):
|
||||||
|
|
@ -247,6 +308,8 @@ def onMouseDragGroup(self, x, y,button=1,clicks=1):
|
||||||
self.cshape.shapedata = [["M",x/2,0],["C",4*x/5,0,x,y/5,x,y/2],["C",x,4*y/5,4*x/5,y,x/2,y],["C",x/5,y,0,4*y/5,0,y/2],["C",0,y/5,x/5,0,x/2,0]]
|
self.cshape.shapedata = [["M",x/2,0],["C",4*x/5,0,x,y/5,x,y/2],["C",x,4*y/5,4*x/5,y,x/2,y],["C",x/5,y,0,4*y/5,0,y/2],["C",0,y/5,x/5,0,x/2,0]]
|
||||||
elif svlgui.MODE == "p":
|
elif svlgui.MODE == "p":
|
||||||
self.cshape.shapedata.append(["L",x-self.cshape.initx,y-self.cshape.inity])
|
self.cshape.shapedata.append(["L",x-self.cshape.initx,y-self.cshape.inity])
|
||||||
|
# self.cshape.endpoint2.x = x
|
||||||
|
# self.cshape.endpoint2.y = y
|
||||||
def onMouseDragObj(self, x, y,button=1,clicks=1):
|
def onMouseDragObj(self, x, y,button=1,clicks=1):
|
||||||
if svlgui.MODE==" ":
|
if svlgui.MODE==" ":
|
||||||
self.x = x-self.initx
|
self.x = x-self.initx
|
||||||
|
|
@ -546,6 +609,8 @@ if svlgui.SYSTEM == "gtk":
|
||||||
MainWindow = lightningbeam_windows.MainWindow()
|
MainWindow = lightningbeam_windows.MainWindow()
|
||||||
elif svlgui.SYSTEM=="osx":
|
elif svlgui.SYSTEM=="osx":
|
||||||
MainWindow = lightningbeam_windows.MainWindowOSX()
|
MainWindow = lightningbeam_windows.MainWindowOSX()
|
||||||
|
elif svlgui.SYSTEM=="kivy":
|
||||||
|
MainWindow = lightningbeam_windows.MainWindowKivy()
|
||||||
elif svlgui.SYSTEM=="html":
|
elif svlgui.SYSTEM=="html":
|
||||||
MainWindow = lightningbeam_windows.MainWindowHTML()
|
MainWindow = lightningbeam_windows.MainWindowHTML()
|
||||||
elif svlgui.SYSTEM=="pyglet":
|
elif svlgui.SYSTEM=="pyglet":
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import misc_funcs
|
||||||
from misc_funcs import *
|
from misc_funcs import *
|
||||||
|
|
||||||
class MainWindow:
|
class MainWindow:
|
||||||
|
''' GTK UI. Not currently used. '''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.window = svlgui.Window("Lightningbeam")
|
self.window = svlgui.Window("Lightningbeam")
|
||||||
self.window.maximize()
|
self.window.maximize()
|
||||||
|
|
@ -134,6 +135,7 @@ class MainWindow:
|
||||||
|
|
||||||
|
|
||||||
class MainWindowAndroid:
|
class MainWindowAndroid:
|
||||||
|
''' Android UI. Not currently used. Will be replaced with Kivy. '''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
class stagewrapper:
|
class stagewrapper:
|
||||||
def add(self, obj, x, y):
|
def add(self, obj, x, y):
|
||||||
|
|
@ -231,7 +233,8 @@ class MainWindowOSX:
|
||||||
# self.toolbox.buttons[1][0]._int().enabled = False
|
# self.toolbox.buttons[1][0]._int().enabled = False
|
||||||
self.toolbox.buttons[3][0]._int().enabled = False
|
self.toolbox.buttons[3][0]._int().enabled = False
|
||||||
self.toolbox.buttons[4][0]._int().enabled = False
|
self.toolbox.buttons[4][0]._int().enabled = False
|
||||||
self.scriptwindow = svlgui.TextView(code=True)
|
# self.scriptwindow = svlgui.TextView(code=True)
|
||||||
|
self.scriptwindow = svlgui.TextView(code=False)
|
||||||
self.paintgroup = svlgui.RadioGroup("Draw straight", "Draw smooth", "Draw as inked")
|
self.paintgroup = svlgui.RadioGroup("Draw straight", "Draw smooth", "Draw as inked")
|
||||||
def setmode(self):
|
def setmode(self):
|
||||||
svlgui.PMODE = self.value
|
svlgui.PMODE = self.value
|
||||||
|
|
@ -435,7 +438,10 @@ class MainWindowHTML:
|
||||||
[self.stage,self.toolbox._int(),self.scriptwindow._int(),self.timelinebox._int()+2,0,"nsew", "hv"] )
|
[self.stage,self.toolbox._int(),self.scriptwindow._int(),self.timelinebox._int()+2,0,"nsew", "hv"] )
|
||||||
self.window.add(self.frame)
|
self.window.add(self.frame)
|
||||||
|
|
||||||
|
class MainWindowKivy:
|
||||||
|
def __init__(self):
|
||||||
|
from kivy.lang import Builder
|
||||||
|
Builder.load_file("lightningbeam.kv")
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
a = MainWindow()
|
a = MainWindow()
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@
|
||||||
|
|
||||||
import svlgui
|
import svlgui
|
||||||
from threading import Event, Thread
|
from threading import Event, Thread
|
||||||
|
from itertools import tee, izip
|
||||||
import math
|
import math
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
def select_any(self):
|
def select_any(self):
|
||||||
svlgui.MODE = " "
|
svlgui.MODE = " "
|
||||||
|
|
@ -96,8 +98,30 @@ def lastval(arr,index):
|
||||||
return i
|
return i
|
||||||
|
|
||||||
|
|
||||||
|
def angle_to_point(point1, point2):
|
||||||
|
deltaX = point2.x-point1.x
|
||||||
|
deltaY = point2.y-point1.y
|
||||||
|
angleInDegrees = math.atan2(-deltaY, deltaX) * 180 / math.pi
|
||||||
|
if angleInDegrees<0: angleInDegrees = 360+angleInDegrees
|
||||||
|
return angleInDegrees
|
||||||
|
|
||||||
|
def sqr(x) :
|
||||||
|
return x * x
|
||||||
|
def dist2(v, w):
|
||||||
|
return sqr(v.x - w.x) + sqr(v.y - w.y)
|
||||||
|
def distToSegmentSquared(p, v, w):
|
||||||
|
l2 = dist2(v, w)
|
||||||
|
if l2 == 0:
|
||||||
|
return dist2(p, v)
|
||||||
|
t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2
|
||||||
|
if t < 0:
|
||||||
|
return dist2(p, v)
|
||||||
|
if t > 1:
|
||||||
|
return dist2(p, w)
|
||||||
|
return dist2(p, svlgui.Point(x=(v.x+t*(w.x-v.x)), y=(v.y+t*(w.y-v.y))))
|
||||||
|
|
||||||
|
def distToSegment(p, v, w):
|
||||||
|
return math.sqrt(distToSegmentSquared(p, v, w))
|
||||||
|
|
||||||
def catmullRom2bezier( points ) :
|
def catmullRom2bezier( points ) :
|
||||||
#crp = points.split(/[,\s]/);
|
#crp = points.split(/[,\s]/);
|
||||||
|
|
@ -184,7 +208,6 @@ def simplify_shape(shape,mode,iterations):
|
||||||
del shape[j]
|
del shape[j]
|
||||||
if mode=="smooth":
|
if mode=="smooth":
|
||||||
shape = catmullRom2bezier([shape[0]]*2+shape+[shape[-1]])
|
shape = catmullRom2bezier([shape[0]]*2+shape+[shape[-1]])
|
||||||
print shape
|
|
||||||
|
|
||||||
return shape#+nshape
|
return shape#+nshape
|
||||||
|
|
||||||
|
|
@ -237,3 +260,34 @@ class RepeatTimer(Thread):
|
||||||
|
|
||||||
def cancel(self):
|
def cancel(self):
|
||||||
self.finished.set()
|
self.finished.set()
|
||||||
|
|
||||||
|
|
||||||
|
def pairwise(iterable):
|
||||||
|
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
|
||||||
|
a, b = tee(iterable)
|
||||||
|
next(b, None)
|
||||||
|
return izip(a, b)
|
||||||
|
|
||||||
|
def hittest(linelist,x,y):
|
||||||
|
hits = False
|
||||||
|
def IsOnLeft(a, b, c):
|
||||||
|
return Area2(a, b, c) > 0
|
||||||
|
def IsOnRight(a, b, c):
|
||||||
|
return Area2(a, b, c) < 0
|
||||||
|
def IsCollinear(a, b, c):
|
||||||
|
return Area2(a, b, c) == 0
|
||||||
|
# calculates the triangle's size (formed by the "anchor" segment and additional point)
|
||||||
|
def Area2(a, b, c):
|
||||||
|
return (b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1])
|
||||||
|
def intersects(a,b,c,d):
|
||||||
|
return not (IsOnLeft(a,b,c) != IsOnRight(a,b,d))
|
||||||
|
def ccw(a,b,c):
|
||||||
|
return (c[1]-a[1])*(b[0]-a[0]) > (b[1]-a[1])*(c[0]-a[0])
|
||||||
|
def intersect(a,b,c,d):
|
||||||
|
return ccw(a,c,d) != ccw(b,c,d) and ccw(a,b,c) != ccw(a,b,d)
|
||||||
|
for i in xrange(len(linelist)):
|
||||||
|
hits = hits != intersect([linelist[i-1].endpoint1.x,linelist[i-1].endpoint1.y],
|
||||||
|
[linelist[i].endpoint1.x,linelist[i].endpoint1.y],[x,y],[x,sys.maxint])
|
||||||
|
print hits, x, y
|
||||||
|
return hits
|
||||||
|
|
||||||
|
|
|
||||||
442
svlgui.py
442
svlgui.py
|
|
@ -136,6 +136,8 @@ class Color (object):
|
||||||
retval = "var "+self.val.split('/')[-1].replace(' ','_').replace('.','_')+" = new Image();\n"
|
retval = "var "+self.val.split('/')[-1].replace(' ','_').replace('.','_')+" = new Image();\n"
|
||||||
retval = retval+self.val.split('/')[-1].replace(' ','_').replace('.','_')+".src = \""+self.val.split("/")[-1]+"\";\n"
|
retval = retval+self.val.split('/')[-1].replace(' ','_').replace('.','_')+".src = \""+self.val.split("/")[-1]+"\";\n"
|
||||||
return retval
|
return retval
|
||||||
|
def print_json(self):
|
||||||
|
return {'type':'Color','arguments':{'val':self.val}}
|
||||||
def rgb2hex(r, g, b, a=1):
|
def rgb2hex(r, g, b, a=1):
|
||||||
r=hex(int(r*255)).split("x")[1].zfill(2)
|
r=hex(int(r*255)).split("x")[1].zfill(2)
|
||||||
g=hex(int(g*255)).split("x")[1].zfill(2)
|
g=hex(int(g*255)).split("x")[1].zfill(2)
|
||||||
|
|
@ -176,6 +178,8 @@ LINECOLOR = Color("#990099")
|
||||||
FILLCOLOR = Color("#00FF00")
|
FILLCOLOR = Color("#00FF00")
|
||||||
TEXTCOLOR = Color("#000000")
|
TEXTCOLOR = Color("#000000")
|
||||||
|
|
||||||
|
LINEWIDTH = 2
|
||||||
|
|
||||||
#Magic. Detect platform and select appropriate toolkit. To be used throughout code.
|
#Magic. Detect platform and select appropriate toolkit. To be used throughout code.
|
||||||
if sys.platform=="linux2":
|
if sys.platform=="linux2":
|
||||||
id = platform.machine()
|
id = platform.machine()
|
||||||
|
|
@ -201,6 +205,7 @@ if sys.platform=="linux2":
|
||||||
import pickle
|
import pickle
|
||||||
import tarfile
|
import tarfile
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import GUI # Using PyGUI. Experimental.
|
import GUI # Using PyGUI. Experimental.
|
||||||
from GUI import Window as OSXWindow, Button as OSXButton, Image as OSXImage
|
from GUI import Window as OSXWindow, Button as OSXButton, Image as OSXImage
|
||||||
from GUI import Frame as OSXFrame, Color as OSXColor, Grid as OSXGrid, CheckBox as OSXCheckBox
|
from GUI import Frame as OSXFrame, Color as OSXColor, Grid as OSXGrid, CheckBox as OSXCheckBox
|
||||||
|
|
@ -218,7 +223,17 @@ if sys.platform=="linux2":
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import Image as PILImage
|
import Image as PILImage
|
||||||
|
SYSTEM="osx"
|
||||||
from GUI.Geometry import offset_rect, rect_sized
|
from GUI.Geometry import offset_rect, rect_sized
|
||||||
|
'''
|
||||||
|
|
||||||
|
from kivy.app import App # Using Kivy. Very experimental.
|
||||||
|
from kivy.uix.widget import Widget
|
||||||
|
from kivy.uix.codeinput import CodeInput
|
||||||
|
from kivy.uix.tabbedpanel import TabbedPanel
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.graphics import Color, Ellipse, Line
|
||||||
|
SYSTEM="kivy"'''
|
||||||
|
|
||||||
#If we can import this, we are in the install directory. Mangle media paths accordingly.
|
#If we can import this, we are in the install directory. Mangle media paths accordingly.
|
||||||
try:
|
try:
|
||||||
|
|
@ -226,7 +241,6 @@ if sys.platform=="linux2":
|
||||||
except:
|
except:
|
||||||
media_path = ""
|
media_path = ""
|
||||||
#app = GUI.application()
|
#app = GUI.application()
|
||||||
SYSTEM="osx"
|
|
||||||
TEMPDIR = "/tmp"
|
TEMPDIR = "/tmp"
|
||||||
FONT = u'Times New Roman'
|
FONT = u'Times New Roman'
|
||||||
'''
|
'''
|
||||||
|
|
@ -377,6 +391,31 @@ if SYSTEM=="osx":
|
||||||
|
|
||||||
|
|
||||||
app = Lightningbeam()
|
app = Lightningbeam()
|
||||||
|
elif SYSTEM=="kivy":
|
||||||
|
class Lightningbeam(App):
|
||||||
|
def build(self):
|
||||||
|
return LightningbeamPanel()
|
||||||
|
class LightningbeamPanel(TabbedPanel):
|
||||||
|
pass
|
||||||
|
class KivyCanvas(Widget):
|
||||||
|
def draw(self):
|
||||||
|
with self.canvas:
|
||||||
|
for i in self.objs:
|
||||||
|
try:
|
||||||
|
i.draw(None)
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
def on_touch_down(self, touch):
|
||||||
|
x, y = touch.x, touch.y
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
for i in self.objs:
|
||||||
|
i._onMouseDown(x,y,button=touch.button, clicks=(3 if touch.is_triple_click else (2 if touch.is_double_click else 1)))
|
||||||
|
except ObjectDeletedError:
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
self.draw()
|
||||||
elif SYSTEM=="html":
|
elif SYSTEM=="html":
|
||||||
app = ""
|
app = ""
|
||||||
|
|
||||||
|
|
@ -1151,6 +1190,9 @@ class Canvas(Widget):
|
||||||
pass
|
pass
|
||||||
self.canvas = OSXCanvas(extent = (width, height), scrolling = 'hv')
|
self.canvas = OSXCanvas(extent = (width, height), scrolling = 'hv')
|
||||||
self.canvas.objs = self.objs
|
self.canvas.objs = self.objs
|
||||||
|
elif SYSTEM=="kivy":
|
||||||
|
|
||||||
|
self.canvas = KivyCanvas()
|
||||||
elif SYSTEM=="html":
|
elif SYSTEM=="html":
|
||||||
global ids
|
global ids
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -1183,6 +1225,8 @@ class Canvas(Widget):
|
||||||
def draw(self):
|
def draw(self):
|
||||||
if SYSTEM=="gtk":
|
if SYSTEM=="gtk":
|
||||||
self.expose_event(self.canvas, "draw_event", self.objs)
|
self.expose_event(self.canvas, "draw_event", self.objs)
|
||||||
|
elif SYSTEM=="kivy":
|
||||||
|
self.canvas.draw()
|
||||||
elif SYSTEM in ["osx", "android"]:
|
elif SYSTEM in ["osx", "android"]:
|
||||||
self.canvas.invalidate_rect((0,0,self.canvas.extent[0],self.canvas.extent[1]))
|
self.canvas.invalidate_rect((0,0,self.canvas.extent[0],self.canvas.extent[1]))
|
||||||
elif SYSTEM=="html":
|
elif SYSTEM=="html":
|
||||||
|
|
@ -1190,6 +1234,8 @@ class Canvas(Widget):
|
||||||
def is_focused(self):
|
def is_focused(self):
|
||||||
if SYSTEM=="osx":
|
if SYSTEM=="osx":
|
||||||
return self.canvas.is_target()
|
return self.canvas.is_target()
|
||||||
|
else:
|
||||||
|
return false
|
||||||
def add(self, obj, x, y):
|
def add(self, obj, x, y):
|
||||||
obj.x = x
|
obj.x = x
|
||||||
obj.y = y
|
obj.y = y
|
||||||
|
|
@ -1491,6 +1537,8 @@ class Image(object):
|
||||||
pass
|
pass
|
||||||
def print_sc(self):
|
def print_sc(self):
|
||||||
return ".png "+self.name+" \""+self.path+"\"\n"
|
return ".png "+self.name+" \""+self.path+"\"\n"
|
||||||
|
def print_json(self):
|
||||||
|
return {'type':'Image','arguments':{'image':self.image,'x':self.x,'y':self.y,'animated':self.animated,'canvas':None,'htiles':self.htiles,'vtiles':self.vtiles,'skipl':false}}
|
||||||
|
|
||||||
class Shape (object):
|
class Shape (object):
|
||||||
def __init__(self,x=0,y=0,rotation=0,fillcolor=None,linecolor=None):
|
def __init__(self,x=0,y=0,rotation=0,fillcolor=None,linecolor=None):
|
||||||
|
|
@ -1636,6 +1684,10 @@ class Shape (object):
|
||||||
else:
|
else:
|
||||||
cr.stroke()
|
cr.stroke()
|
||||||
cr.grestore()
|
cr.grestore()
|
||||||
|
elif SYSTEM=="kivy":
|
||||||
|
Color(1, 1, 0)
|
||||||
|
d = 30.
|
||||||
|
Ellipse(pos=(self.x - d / 2, self.y - d / 2), size=(d, d))
|
||||||
elif SYSTEM=="html":
|
elif SYSTEM=="html":
|
||||||
tb = ""
|
tb = ""
|
||||||
tb+="cr.save()\n"
|
tb+="cr.save()\n"
|
||||||
|
|
@ -1766,6 +1818,13 @@ class Shape (object):
|
||||||
retval += self.name+".fill = \""+self.fillcolor.rgb+"\";\n"+self.name+".line = \""+self.linecolor.rgb+"\";\n"
|
retval += self.name+".fill = \""+self.fillcolor.rgb+"\";\n"+self.name+".line = \""+self.linecolor.rgb+"\";\n"
|
||||||
retval += self.name+".filled = "+str(self.filled).lower()+";\n"
|
retval += self.name+".filled = "+str(self.filled).lower()+";\n"
|
||||||
return retval
|
return retval
|
||||||
|
def print_json(self):
|
||||||
|
return {'type':'Shape','arguments':{'x':self.x,
|
||||||
|
'y':self.y,
|
||||||
|
'rotation':self.rotation,
|
||||||
|
'linecolor':self.linecolor.print_json(),
|
||||||
|
'fillcolor':self.fillcolor.print_json()},
|
||||||
|
'properties':{'shapedata':self.shapedata}}
|
||||||
|
|
||||||
class Text (object):
|
class Text (object):
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
|
|
@ -2359,6 +2418,7 @@ class Layer:
|
||||||
print "#>>",i
|
print "#>>",i
|
||||||
for j in self.frames[self.currentframe].objs:
|
for j in self.frames[self.currentframe].objs:
|
||||||
if j == i:
|
if j == i:
|
||||||
|
print "Deleting",j
|
||||||
del self.currentFrame()[self.currentFrame().index(j)]
|
del self.currentFrame()[self.currentFrame().index(j)]
|
||||||
def add_frame(self,populate):
|
def add_frame(self,populate):
|
||||||
if self.activeframe>len(self.frames):
|
if self.activeframe>len(self.frames):
|
||||||
|
|
@ -2553,6 +2613,9 @@ class Group (object):
|
||||||
self.tempgroup = None
|
self.tempgroup = None
|
||||||
self.is_mc = False
|
self.is_mc = False
|
||||||
self.name = "g"+str(int(random.random()*10000))+str(SITER)
|
self.name = "g"+str(int(random.random()*10000))+str(SITER)
|
||||||
|
self.lines = []
|
||||||
|
self.fills = []
|
||||||
|
self.activepoint = None
|
||||||
if "onload" in kwargs:
|
if "onload" in kwargs:
|
||||||
kwargs["onload"](self)
|
kwargs["onload"](self)
|
||||||
def draw(self,cr=None,transform=None,rect=None):
|
def draw(self,cr=None,transform=None,rect=None):
|
||||||
|
|
@ -2573,8 +2636,14 @@ class Group (object):
|
||||||
cr.pencolor = Color([0,0,1]).pygui
|
cr.pencolor = Color([0,0,1]).pygui
|
||||||
cr.stroke_rect([sorted([self.startx,self.cx])[0], sorted([self.starty,self.cy])[0], \
|
cr.stroke_rect([sorted([self.startx,self.cx])[0], sorted([self.starty,self.cy])[0], \
|
||||||
sorted([self.startx,self.cx])[1], sorted([self.starty,self.cy])[1]])
|
sorted([self.startx,self.cx])[1], sorted([self.starty,self.cy])[1]])
|
||||||
|
for i in self.fills:
|
||||||
|
i.draw(cr, rect=rect)
|
||||||
|
for i in self.lines:
|
||||||
|
i.draw(cr, rect=rect)
|
||||||
def add(self, *args):
|
def add(self, *args):
|
||||||
self.activelayer.add(*args)
|
self.activelayer.add(*args)
|
||||||
|
def delete(self, *args):
|
||||||
|
self.activelayer.delete(*args)
|
||||||
def add_frame(self, populate):
|
def add_frame(self, populate):
|
||||||
self.activelayer.add_frame(populate)
|
self.activelayer.add_frame(populate)
|
||||||
def add_layer(self, index):
|
def add_layer(self, index):
|
||||||
|
|
@ -2644,6 +2713,147 @@ class Group (object):
|
||||||
self.tempgroup = None
|
self.tempgroup = None
|
||||||
self.activelayer.currentselect = None
|
self.activelayer.currentselect = None
|
||||||
self.startx, self.starty = x, y
|
self.startx, self.starty = x, y
|
||||||
|
if MODE in " s":
|
||||||
|
for i in self.lines:
|
||||||
|
if abs(x-i.endpoint1.x)<10 and abs(y-i.endpoint1.y)<10:
|
||||||
|
i.endpoint1.x = x
|
||||||
|
i.endpoint1.y = y
|
||||||
|
self.activepoint = i.endpoint1
|
||||||
|
return
|
||||||
|
elif abs(x-i.endpoint2.x)<10 and abs(y-i.endpoint2.y)<10:
|
||||||
|
i.endpoint2.x = x
|
||||||
|
i.endpoint2.y = y
|
||||||
|
self.activepoint = i.endpoint2
|
||||||
|
return
|
||||||
|
elif MODE=="b":
|
||||||
|
nlines = [i for i in self.lines]
|
||||||
|
# First, remove all line segments that have at least one free endpoit, not coincident with any other segment.
|
||||||
|
# Do that repeatedly until no such segment remains.
|
||||||
|
for i in reversed(nlines):
|
||||||
|
if not (i.endpoint1 in [j.endpoint1 for j in nlines if not j==i]+[j.endpoint2 for j in nlines if not j==i]):
|
||||||
|
nlines.remove(i)
|
||||||
|
elif not (i.endpoint2 in [j.endpoint1 for j in nlines if not j==i]+[j.endpoint2 for j in nlines if not j==i]):
|
||||||
|
nlines.remove(i)
|
||||||
|
|
||||||
|
# Find the closest segment to the point.
|
||||||
|
if nlines:
|
||||||
|
mindist = sys.maxint
|
||||||
|
point = Point(x, y)
|
||||||
|
closestsegment = None
|
||||||
|
for i in nlines:
|
||||||
|
d = misc_funcs.distToSegment(point,i.endpoint1,i.endpoint2)
|
||||||
|
if d<mindist:
|
||||||
|
mindist = d
|
||||||
|
closestsegment = i
|
||||||
|
|
||||||
|
print closestsegment
|
||||||
|
|
||||||
|
# Go to the endpoint and turn right. Repeat until you hit the closest segment again.
|
||||||
|
if closestsegment:
|
||||||
|
# Grab angles to closest segments endpoints, go to the counterclockwise-most one
|
||||||
|
angle1 = misc_funcs.angle_to_point(point, closestsegment.endpoint1)
|
||||||
|
angle2 = misc_funcs.angle_to_point(point, closestsegment.endpoint2)
|
||||||
|
if (angle1<angle2 and angle2-angle1<180):
|
||||||
|
startpoint = closestsegment.endpoint2
|
||||||
|
sp = 2
|
||||||
|
else:
|
||||||
|
startpoint = closestsegment.endpoint1
|
||||||
|
sp = 1
|
||||||
|
linelist = [closestsegment]
|
||||||
|
while True:
|
||||||
|
# try:
|
||||||
|
nextline = max([[closestsegment.angle(i),i] for i in startpoint.lines if not i==closestsegment])[1]
|
||||||
|
# except:
|
||||||
|
# break
|
||||||
|
closestsegment = nextline
|
||||||
|
startpoint = [None,closestsegment.endpoint1,closestsegment.endpoint2][sp]
|
||||||
|
if not nextline in linelist:
|
||||||
|
linelist.append(nextline)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Check if the polygon encloses the given point. If it is not, then we've found an "island"
|
||||||
|
if misc_funcs.hittest(linelist,x,y):
|
||||||
|
f = Fill()
|
||||||
|
dic = {}
|
||||||
|
for i in linelist:
|
||||||
|
dic[i.endpoint1]=i
|
||||||
|
|
||||||
|
def walk(list_of_lines, starting_point):
|
||||||
|
lookup_map = {}
|
||||||
|
for i in list_of_lines:
|
||||||
|
lookup_map[i.endpoint1]=i
|
||||||
|
cur_point = starting_point
|
||||||
|
visited_points = []
|
||||||
|
print lookup_map
|
||||||
|
while cur_point.endpoint2 in lookup_map and not cur_point in visited_points:
|
||||||
|
visited_points.append(cur_point)
|
||||||
|
cur_point = lookup_map[cur_point.endpoint2]
|
||||||
|
yield cur_point
|
||||||
|
|
||||||
|
|
||||||
|
# f.lines = linelist
|
||||||
|
f.lines = [x for x in walk(linelist,linelist[0])]
|
||||||
|
print f.lines
|
||||||
|
self.fills.append(f)
|
||||||
|
else:
|
||||||
|
print "No hit"
|
||||||
|
|
||||||
|
|
||||||
|
'''nlines = [i for i in self.lines]
|
||||||
|
endsleft = True
|
||||||
|
while endsleft:
|
||||||
|
endsleft = False
|
||||||
|
for i in reversed(nlines):
|
||||||
|
if not (i.endpoint1 in [j.endpoint1 for j in nlines if not j==i]+[j.endpoint2 for j in nlines if not j==i]):
|
||||||
|
nlines.remove(i)
|
||||||
|
endsleft = True
|
||||||
|
elif not (i.endpoint2 in [j.endpoint1 for j in nlines if not j==i]+[j.endpoint2 for j in nlines if not j==i]):
|
||||||
|
nlines.remove(i)
|
||||||
|
endsleft = True
|
||||||
|
print "2728",nlines
|
||||||
|
|
||||||
|
if nlines:
|
||||||
|
mindist = sys.maxint
|
||||||
|
point = Point(x, y)
|
||||||
|
closestsegment = None
|
||||||
|
|
||||||
|
for i in nlines:
|
||||||
|
d = misc_funcs.distToSegment(point,i.endpoint1,i.endpoint2)
|
||||||
|
if d<mindist:
|
||||||
|
mindist = d
|
||||||
|
closestsegment = i
|
||||||
|
|
||||||
|
f = Fill()
|
||||||
|
f.lines = nlines
|
||||||
|
self.fills.append(f)
|
||||||
|
|
||||||
|
if closestsegment:
|
||||||
|
# Then go to endpoint of closestsegment counterclockwise from point
|
||||||
|
angle1 = misc_funcs.angle_to_point(point, closestsegment.endpoint1)
|
||||||
|
angle2 = misc_funcs.angle_to_point(point, closestsegment.endpoint2)
|
||||||
|
if (angle1<angle2 and angle2-angle1<180):
|
||||||
|
startpoint = closestsegment.endpoint2
|
||||||
|
else:
|
||||||
|
startpoint = closestsegment.endpoint1
|
||||||
|
print startpoint.lines
|
||||||
|
linelist = [closestsegment]
|
||||||
|
# nextline = max([[closestsegment.angle(i),i] for i in startpoint.lines if not i in linelist])
|
||||||
|
# print nextline
|
||||||
|
# Then, follow clockwise-most segment leading off from said point
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
nextline = max([[closestsegment.angle(i),i] for i in startpoint.lines if not i==closestsegment])[1]
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
closestsegment = nextline
|
||||||
|
if not nextline in linelist:
|
||||||
|
linelist.append(nextline)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
print "*****",linelist
|
||||||
|
# Continue until closestsegment is reached. I _think_ this is inevitable.'''
|
||||||
|
|
||||||
self.selecting = True
|
self.selecting = True
|
||||||
else:
|
else:
|
||||||
self.onMouseDown(self, x, y, button=button, clicks=clicks)
|
self.onMouseDown(self, x, y, button=button, clicks=clicks)
|
||||||
|
|
@ -2658,10 +2868,35 @@ class Group (object):
|
||||||
self.dragging = False
|
self.dragging = False
|
||||||
self.selecting = False
|
self.selecting = False
|
||||||
x, y = self.localtransform(x, y)
|
x, y = self.localtransform(x, y)
|
||||||
|
# If we are in selection mode and the current level (i.e. what we're inside of) is this layer
|
||||||
if self.activelayer.level and MODE in [" ", "s"]:
|
if self.activelayer.level and MODE in [" ", "s"]:
|
||||||
|
# If we have a selection
|
||||||
if self.activelayer.currentselect:
|
if self.activelayer.currentselect:
|
||||||
self.activelayer.currentselect._onMouseUp(x, y, button=button, clicks=clicks)
|
self.activelayer.currentselect._onMouseUp(x, y, button=button, clicks=clicks)
|
||||||
|
# If we have a point that we're dragging around (vector editing)
|
||||||
|
elif self.activepoint:
|
||||||
|
for i in self.lines:
|
||||||
|
if abs(self.activepoint.x-i.endpoint1.x)<10 and abs(self.activepoint.y-i.endpoint1.y)<10:
|
||||||
|
try:
|
||||||
|
[j for j in self.lines if self.activepoint==j.endpoint1][0].assign(i.endpoint1, 1)
|
||||||
|
except IndexError:
|
||||||
|
try:
|
||||||
|
[j for j in self.lines if self.activepoint==j.endpoint2][0].assign(i.endpoint1, 2)
|
||||||
|
break
|
||||||
|
except IndexError: pass
|
||||||
|
if abs(self.activepoint.x-i.endpoint2.x)<10 and abs(self.activepoint.y-i.endpoint2.y)<10:
|
||||||
|
try:
|
||||||
|
[j for j in self.lines if self.activepoint==j.endpoint1][0].assign(i.endpoint2, 1)
|
||||||
|
except IndexError:
|
||||||
|
try:
|
||||||
|
[j for j in self.lines if self.activepoint==j.endpoint2][0].assign(i.endpoint2, 2)
|
||||||
|
break
|
||||||
|
except IndexError: pass
|
||||||
|
break
|
||||||
|
self.activepoint = None
|
||||||
|
# if neither of those, but we've dragged the mouse at least 4 pixels in either axis
|
||||||
elif abs(self.startx-x)>4 or abs(self.starty-y)>4:
|
elif abs(self.startx-x)>4 or abs(self.starty-y)>4:
|
||||||
|
# this should make a temporary group containing all the objects within the area we dragged
|
||||||
objs = []
|
objs = []
|
||||||
for i in reversed(self.currentFrame()):
|
for i in reversed(self.currentFrame()):
|
||||||
if self.startx<i.x+i.minx<x or self.startx<i.x+i.maxx<x:
|
if self.startx<i.x+i.minx<x or self.startx<i.x+i.maxx<x:
|
||||||
|
|
@ -2695,6 +2930,9 @@ class Group (object):
|
||||||
if self.activelayer.level and MODE in [" ", "s"]:
|
if self.activelayer.level and MODE in [" ", "s"]:
|
||||||
if self.activelayer.currentselect:
|
if self.activelayer.currentselect:
|
||||||
self.activelayer.currentselect._onMouseDrag(x, y, button=button)
|
self.activelayer.currentselect._onMouseDrag(x, y, button=button)
|
||||||
|
elif self.activepoint:
|
||||||
|
self.activepoint.x = x
|
||||||
|
self.activepoint.y = y
|
||||||
else:
|
else:
|
||||||
self.onMouseDrag(self, x, y, button=button)
|
self.onMouseDrag(self, x, y, button=button)
|
||||||
def onMouseDrag(self, self1, x, y, button=1, clicks=1):
|
def onMouseDrag(self, self1, x, y, button=1, clicks=1):
|
||||||
|
|
@ -2732,6 +2970,17 @@ class Group (object):
|
||||||
# retval+=i.print_sc(True, False)
|
# retval+=i.print_sc(True, False)
|
||||||
if not self.name=="_root":
|
if not self.name=="_root":
|
||||||
retval+=".sprite "+self.name+"\n"
|
retval+=".sprite "+self.name+"\n"
|
||||||
|
if self.fills:
|
||||||
|
for i in self.fills:
|
||||||
|
retval+=i.print_sc()
|
||||||
|
retval+=".put fill_"+str(i.__hash__())+"\n"
|
||||||
|
if self.lines:
|
||||||
|
for i in self.lines:
|
||||||
|
retval+=".outline "+self.name+"_line_"+str(i.__hash__())+"_outline:\n"
|
||||||
|
retval+=" "+i.print_sc()
|
||||||
|
retval+="\n.end\n"
|
||||||
|
retval+=".filled "+self.name+"_line_"+str(i.__hash__())+" outline="+self.name+"_line_"+str(i.__hash__())+"_outline color="+i.linecolor.rgb+"\n"
|
||||||
|
retval+=".put "+self.name+"_line_"+str(i.__hash__())+"\n"
|
||||||
for i in xrange(self.maxframe()):
|
for i in xrange(self.maxframe()):
|
||||||
for j in self.layers:
|
for j in self.layers:
|
||||||
if j.frames[i]:
|
if j.frames[i]:
|
||||||
|
|
@ -2776,7 +3025,7 @@ class Group (object):
|
||||||
class TemporaryGroup(Group):
|
class TemporaryGroup(Group):
|
||||||
"""Created when selecting multiple items, for ease of use."""
|
"""Created when selecting multiple items, for ease of use."""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
(TemporaryGroup, self).__init__(*args, **kwargs)
|
super(TemporaryGroup, self).__init__(*args, **kwargs)
|
||||||
# def draw(self, cr=None, transform=None, rect=None):
|
# def draw(self, cr=None, transform=None, rect=None):
|
||||||
# super(TemporaryGroup, self).draw(cr, transform, rect)
|
# super(TemporaryGroup, self).draw(cr, transform, rect)
|
||||||
# print self.x, self.activelayer.x
|
# print self.x, self.activelayer.x
|
||||||
|
|
@ -2834,6 +3083,195 @@ class TemporaryGroup(Group):
|
||||||
elif key=="down_arrow":
|
elif key=="down_arrow":
|
||||||
self1.y+=1
|
self1.y+=1
|
||||||
|
|
||||||
|
class Point(object):
|
||||||
|
"""represents an x,y point, might store other data in the future"""
|
||||||
|
def __init__(self, x, y):
|
||||||
|
super(Point, self).__init__()
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.lines = set()
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Point x="+str(self.x)+" y="+str(self.y)+">"
|
||||||
|
|
||||||
|
|
||||||
|
class Line(object):
|
||||||
|
"""Use Lines to build Shapes while allowing paintbucketing."""
|
||||||
|
def __init__(self, endpoint1, endpoint2, connection1 = None, connection2 = None):
|
||||||
|
super(Line, self).__init__()
|
||||||
|
self.endpoint1 = endpoint1
|
||||||
|
self.endpoint2 = endpoint2
|
||||||
|
self.endpoint1.lines.add(self)
|
||||||
|
self.endpoint2.lines.add(self)
|
||||||
|
self.connection1 = connection1
|
||||||
|
self.connection2 = connection2
|
||||||
|
if self.connection1: self.connection1.lines.add(self)
|
||||||
|
if self.connection2: self.connection2.lines.add(self)
|
||||||
|
self.linecolor = LINECOLOR
|
||||||
|
self.linewidth = LINEWIDTH
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Line (endpoint1=("+str(self.endpoint1.x)+","+str(self.endpoint1.y)+"),endpoint2=("+str(self.endpoint2.x)+","+str(self.endpoint2.y)+"))>"
|
||||||
|
def assign(self, point, which):
|
||||||
|
if which==1:
|
||||||
|
self.connection1 = point
|
||||||
|
self.connection1.lines.add(self)
|
||||||
|
elif which==2:
|
||||||
|
self.connection2 = point
|
||||||
|
self.connection2.lines.add(self)
|
||||||
|
def angle(self, other):
|
||||||
|
if self.endpoint1==other.endpoint1:
|
||||||
|
x1 = self.endpoint2.x-self.endpoint1.x
|
||||||
|
y1 = self.endpoint2.y-self.endpoint1.y
|
||||||
|
x2 = other.endpoint2.x-other.endpoint1.x
|
||||||
|
y2 = other.endpoint2.y-other.endpoint1.y
|
||||||
|
elif self.endpoint2==other.endpoint1:
|
||||||
|
x1 = self.endpoint1.x-self.endpoint2.x
|
||||||
|
y1 = self.endpoint1.y-self.endpoint2.y
|
||||||
|
x2 = other.endpoint2.x-other.endpoint1.x
|
||||||
|
y2 = other.endpoint2.y-other.endpoint1.y
|
||||||
|
elif self.endpoint1==other.endpoint2:
|
||||||
|
x1 = self.endpoint2.x-self.endpoint1.x
|
||||||
|
y1 = self.endpoint2.y-self.endpoint1.y
|
||||||
|
x2 = other.endpoint1.x-other.endpoint2.x
|
||||||
|
y2 = other.endpoint1.y-other.endpoint2.y
|
||||||
|
elif self.endpoint2==other.endpoint2:
|
||||||
|
x1 = self.endpoint1.x-self.endpoint2.x
|
||||||
|
y1 = self.endpoint1.y-self.endpoint2.y
|
||||||
|
x2 = other.endpoint1.x-other.endpoint2.x
|
||||||
|
y2 = other.endpoint1.y-other.endpoint2.y
|
||||||
|
dot = x1*x2+y1*y2
|
||||||
|
mag1 = math.sqrt(x1**2+y1**2)
|
||||||
|
mag2 = math.sqrt(x2**2+y2**2)
|
||||||
|
angle = math.acos(dot/(mag1*mag2))/math.pi*180
|
||||||
|
cz = x1*y2-y1*x2
|
||||||
|
if cz>0: angle=360-angle
|
||||||
|
return angle
|
||||||
|
def intersects(self,other):
|
||||||
|
'''def IsOnLeft(a,b,c):
|
||||||
|
return Area2(a,b,c) > 0
|
||||||
|
def IsOnRight(a,b,c):
|
||||||
|
return Area2(a,b,c) < 0
|
||||||
|
def IsCollinear(a,b,c):
|
||||||
|
return Area2(a,b,c) == 0
|
||||||
|
def Area2 (a,b,c):
|
||||||
|
return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y)
|
||||||
|
if (IsOnLeft(self.endpoint1,self.endpoint2,other.endpoint1) and IsOnRight(self.endpoint1,self.endpoint2,other.endpoint2))
|
||||||
|
or (IsOnLeft(self.endpoint1,self.endpoint2,other.endpoint2) and IsOnRight(self.endpoint1,self.endpoint2,other.endpoint1):
|
||||||
|
if (IsOnLeft(other.endpoint1,other.endpoint2,self.endpoint1) and IsOnRight(other.endpoint1,other.endpoint2,self.endpoint2))
|
||||||
|
or (IsOnLeft(other.endpoint1,other.endpoint2,self.endpoint2) and IsOnRight(other.endpoint1,other.endpoint2,self.endpoint1):
|
||||||
|
return True'''
|
||||||
|
# Formula for line is y = mx + b
|
||||||
|
try:
|
||||||
|
sm = (self.endpoint1.y-self.endpoint2.y)/(self.endpoint1.x-self.endpoint1.y)
|
||||||
|
om = (other.endpoint1.y-other.endpoint2.y)/(other.endpoint1.x-other.endpoint1.y)
|
||||||
|
sb = self.endpoint1.y-sm*self.endpoint1.x
|
||||||
|
ob = other.endpoint1.y-sm*other.endpoint1.x
|
||||||
|
if sm == om: return False
|
||||||
|
x = (ob-sb)/(sm-om)
|
||||||
|
y = sm*x + sb
|
||||||
|
if min(self.endpoint1.x,self.endpoint2.x)<x<max(self.endpoint1.x,self.endpoint2.x):
|
||||||
|
return [x,y]
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except ZeroDivisionError:
|
||||||
|
# One of the lines is vertical.
|
||||||
|
# Formula for line in terms of y is x = my + b
|
||||||
|
try:
|
||||||
|
sm = (self.endpoint1.x-self.endpoint2.x)/(self.endpoint1.y-self.endpoint1.x)
|
||||||
|
om = (other.endpoint1.x-other.endpoint2.x)/(other.endpoint1.y-other.endpoint1.x)
|
||||||
|
sb = self.endpoint1.x-sm*self.endpoint1.y
|
||||||
|
ob = other.endpoint1.x-sm*other.endpoint1.y
|
||||||
|
if sm == om: return False
|
||||||
|
y = (ob-sb)/(sm-om)
|
||||||
|
x = sm*y + sb
|
||||||
|
if min(self.endpoint1.y,self.endpoint2.y)<y<max(self.endpoint1.y,self.endpoint2.y):
|
||||||
|
return [x,y]
|
||||||
|
except ZeroDivisionError:
|
||||||
|
# One of the lines is horizontal, too. Or one has zero length.
|
||||||
|
# Logic this.
|
||||||
|
return False
|
||||||
|
|
||||||
|
return False
|
||||||
|
def draw(self, cr=None, transform=None, rect=None):
|
||||||
|
if self.connection1:
|
||||||
|
self.endpoint1 = self.connection1
|
||||||
|
if self.connection2:
|
||||||
|
self.endpoint2 = self.connection2
|
||||||
|
if SYSTEM=="gtk":
|
||||||
|
cr.save()
|
||||||
|
cr.set_source(self.linecolor.cairo)
|
||||||
|
cr.set_line_width(max(self.linewidth,1))
|
||||||
|
cr.move_to(self.endpoint1.x,self.endpoint2.y)
|
||||||
|
cr.line_to(self.endpoint2.x,self.endpoint2.y)
|
||||||
|
cr.stroke()
|
||||||
|
cr.restore()
|
||||||
|
elif SYSTEM=="android":
|
||||||
|
global tb
|
||||||
|
tb+="cr.save()\n"
|
||||||
|
tb+="cr.lineWidth = "+str(max(self.linewidth,1))+"\n"
|
||||||
|
tb+="cr.moveTo("+str(self.endpoint1.x)+","+str(self.endpoint1.y)+")\n"
|
||||||
|
tb+="cr.lineTo("+str(self.endpoint2.x)+","+str(self.endpoint2.y)+")\n"
|
||||||
|
tb+="cr.stroke()\n"
|
||||||
|
tb+="cr.restore()\n"
|
||||||
|
elif SYSTEM=="osx":
|
||||||
|
if USING_GL:
|
||||||
|
cr.save()
|
||||||
|
glColor3f(1.0,0.0,0.0)
|
||||||
|
glBegin(GL_LINES)
|
||||||
|
cr.x, cr.y = (self.endpoint1.x, self.endpoint1.y)
|
||||||
|
glVertex2f(cr.x, -cr.y)
|
||||||
|
point = (self.endpoint2.x, self.endpoint2.y)
|
||||||
|
glVertex2f(point[0], -point[1]) # because OpenGL swaps y coords
|
||||||
|
cr.x, cr.y = point
|
||||||
|
glEnd()
|
||||||
|
cr.restore()
|
||||||
|
else:
|
||||||
|
cr.gsave()
|
||||||
|
cr.newpath()
|
||||||
|
cr.pencolor = self.linecolor.pygui
|
||||||
|
cr.pensize = max(self.linewidth,1)
|
||||||
|
cr.moveto(self.endpoint1.x, self.endpoint1.y)
|
||||||
|
cr.lineto(self.endpoint2.x,self.endpoint2.y)
|
||||||
|
cr.stroke()
|
||||||
|
cr.grestore()
|
||||||
|
elif SYSTEM=="html":
|
||||||
|
tb = ""
|
||||||
|
tb+="cr.save()\n"
|
||||||
|
tb+="cr.lineWidth = "+str(max(self.linewidth,1))+"\n"
|
||||||
|
tb+="cr.moveTo("+str(self.endpoint1.x)+","+str(self.endpoint1.y)+")\n"
|
||||||
|
tb+="cr.lineTo("+str(self.endpoint2.x)+","+str(self.endpoint2.y)+")\n"
|
||||||
|
tb+="cr.stroke()\n"
|
||||||
|
tb+="cr.restore()\n"
|
||||||
|
jscommunicate(tb)
|
||||||
|
def print_sc(self):
|
||||||
|
return "M "+str(self.endpoint1.x)+" "+str(self.endpoint1.y)+" L "+str(self.endpoint2.x)+" "+str(self.endpoint2.y)
|
||||||
|
|
||||||
|
class Fill(object):
|
||||||
|
"""Fills are Shapes without edges, built from Lines"""
|
||||||
|
def __init__(self):
|
||||||
|
super(Fill,self).__init__()
|
||||||
|
self.lines = []
|
||||||
|
self.fillcolor = FILLCOLOR
|
||||||
|
def draw(self, cr=None, transform=None, rect=None):
|
||||||
|
if SYSTEM=="osx":
|
||||||
|
if USING_GL:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
cr.gsave()
|
||||||
|
cr.newpath()
|
||||||
|
cr.fillcolor = self.fillcolor.pygui
|
||||||
|
cr.moveto(self.lines[0].endpoint1.x,self.lines[0].endpoint1.y)
|
||||||
|
for i in self.lines:
|
||||||
|
cr.lineto(i.endpoint2.x,i.endpoint2.y)
|
||||||
|
cr.fill()
|
||||||
|
cr.grestore()
|
||||||
|
def print_sc(self):
|
||||||
|
retval = ".outline fill_"+str(self.__hash__())+"_outline:\n"
|
||||||
|
retval += "M "+str(self.lines[0].endpoint1.x)+" "+str(self.lines[0].endpoint1.y)
|
||||||
|
for i in self.lines:
|
||||||
|
retval += " L "+str(i.endpoint2.x)+" "+str(i.endpoint2.y)
|
||||||
|
retval += "\n.end\n"
|
||||||
|
retval += ".filled fill_"+str(self.__hash__())+" outline=fill_"+str(self.__hash__())+"_outline fill="+self.fillcolor.rgb+"\n"
|
||||||
|
return retval
|
||||||
|
|
||||||
def set_cursor(curs, widget=None):
|
def set_cursor(curs, widget=None):
|
||||||
if SYSTEM == "osx":
|
if SYSTEM == "osx":
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue