Skip to content

Commit 99794b9

Browse files
committed
relative angle added
arc started move added
1 parent f3c8791 commit 99794b9

File tree

3 files changed

+88
-21
lines changed

3 files changed

+88
-21
lines changed

bezier-console.py

+47-8
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
# all values are relative if the case is lover to use absolute coordinates use upper case.
2323
################################################################################
2424

25-
from csp import CSP
25+
from csp import CSP, CSPsubpath
2626
from points import P
2727
from math import *
2828
import inkex
2929
import re
3030
import sys
3131
import traceback
32-
32+
from biarc import Arc, Line
3333

3434
def warn(s) :
3535
if bezier_console.options.silent : return
@@ -102,6 +102,42 @@ def draw_line(self,x,y,a,l) :
102102
p1 = self.get_line_xy(x,y,a,l)
103103
self.path.join( CSP([[[self.p,self.p,self.p],[p1,p1,p1]]]) )
104104

105+
106+
def move_to(self,x,y,a,l) :
107+
p1 = self.get_line_xy(x,y,a,l)
108+
self.path.items.append(CSPSubpath([[p1,p1,p1]]))
109+
110+
def arc_on_two_points_and_slope(self,st,end,slope) :
111+
# find the center
112+
m = (end - st)/2
113+
n = slope.ccw()
114+
# get the intersection of lines throught st and m normal to slope and st-end line
115+
l1 = Line(st,st+n)
116+
l2 = Line(st+m,st+m+m.ccw())
117+
p = l1.intersect(l2,True)
118+
if len(p)!=1 :
119+
warn((p,l1,l2,slope))
120+
error("Bad parameters for arc on two points. Command: %s"%self.command)
121+
c = p[0]
122+
a = (st-c).cross(slope)
123+
return Arc(st,end,c,a)
124+
125+
126+
def get_arc_param(self,x,y,a,r,i,j,l) :
127+
st = self.p
128+
129+
if a==None and r==None and i==None and j==None and l==None :
130+
# using two points and slope.
131+
if x==None and y==None : error("To few parametersfor arc. Command: %s"%self.command)
132+
end = P(x if x!=None else self.p.x, y if y!=None else self.p.y)
133+
return self.arc_on_two_points_and_slope(self.p,end,self.slope)
134+
135+
136+
def draw_arc(self,x,y,a,r,i,j,l) :
137+
st = self.p
138+
arc = self.get_arc_param(x,y,a,r,i,j,l)
139+
warn(arc)
140+
self.path.join(arc.to_csp())
105141

106142
def parse_command(self, a) :
107143
if a.strip() == "" : return
@@ -115,10 +151,15 @@ def parse_command(self, a) :
115151
t = self.last_command
116152
# parse the parameters
117153
x,y,a,l,r,i,j = None, None, None, None, None, None, None
154+
try:
155+
self.slope = self.path.slope(-1,-1,1)
156+
except:
157+
self.slope = P(1.,0.)
118158
for p in re.findall("([alxyrijALXYRIJ])\s*(\-?\d*\.?\d*)",params) :
119159
#warn(p)
120160
p = list(p)
121-
if p[0] in ("a","A") : a = -float(p[1])/180*pi
161+
if p[0] == "A" : a = -float(p[1])/180*pi
162+
elif p[0] == "a" : a = self.slope.angle() -float(p[1])/180*pi
122163
else : p[1] = float(p[1])*self.options.units
123164
if p[0] == "x" : x = self.p.x + p[1]
124165
elif p[0] == "X" : x = p[1]
@@ -128,15 +169,13 @@ def parse_command(self, a) :
128169
elif p[0] == "I" : I = p[1]
129170
elif p[0] == "j" : j = self.p.y - p[1]
130171
elif p[0] == "J" : J = -p[1]
131-
132-
# TODO add relative angles
172+
elif p[0] in ("r","R") : r = -p[1]
133173
elif p[0] in ("l","L") : l = p[1]
134174

135175
# exec command
136176
if t in ("l","L") : self.draw_line(x,y,a,l)
137-
if t in ("h","H") : self.draw_line(x,self.p.y,None,l)
138-
if t in ("v","V") : self.draw_line(self.p.x,y,None,l)
139-
if t in ("a","A") : self.draw_line(self.p.x,y,None,l)
177+
if t in ("a","A") : self.draw_arc(x,y,a,r,i,j,l)
178+
if t in ("m","M") : self.move_to(x,y,a,l)
140179
self.last_command = t
141180

142181
def effect(self) :

biarc.py

+37-10
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import points
1+
from points import P
22
from math import *
33
import inkex
4+
from csp import CSP, CSPsubpath
5+
pi2 = pi*2
46

57
################################################################################
68
### Biarc classes - Arc, Line and Biarc
79
################################################################################
810
class Arc():
911
def __init__(self,st,end,c,a,r=None) :
10-
debugger.add_debugger_to_class(self.__class__)
12+
#debugger.add_debugger_to_class(self.__class__)
1113
# a - arc's angle, it's not defining actual angle before now, but defines direction so it's value does not mather matters only the sign.
1214
if st.__class__ == P : st = st.to_list()
1315
if end.__class__ == P : end = end.to_list()
@@ -28,6 +30,27 @@ def __repr__(self) :
2830
def copy(self) :
2931
return Arc(self.st,self.end,self.c,self.a,self.r)
3032

33+
def to_csp(self) :
34+
# Taken from cubicsuperpath's ArcToCsp
35+
O = self.c
36+
sectors = int(abs(self.a)*2/pi)+1
37+
da = self.a/sectors
38+
v = 4*tan(da/4)/3
39+
angle = (self.st-self.c).angle()
40+
cspsubpath = CSPsubpath()
41+
for i in range(sectors+1) :
42+
c,s = cos(angle)*self.r, sin(angle)*self.r
43+
v1=P([O.x+c - (-v)*s, O.y+s + (-v)*c])
44+
pt=P([O.x+c, O.y+s])
45+
v2=P([O.x+c - v*s, O.y+s + v*c])
46+
cspsubpath.points.append([v1,pt,v2])
47+
angle += da
48+
cspsubpath.points[0][0] = cspsubpath.points[0][1].copy()
49+
cspsubpath.points[-1][2] = cspsubpath.points[-1][1].copy()
50+
csp = CSP()
51+
csp.items.append(cspsubpath)
52+
return csp
53+
3154
def rebuild(self,st=None,end=None,c=None,a=None,r=None) :
3255
if st==None: st=self.st
3356
if end==None: end=self.end
@@ -59,7 +82,7 @@ def bounds(self) :
5982
x1,y1, x2,y2 = ( min(self.st.x,self.end.x),min(self.st.y,self.end.y),
6083
max(self.st.x,self.end.x),max(self.st.y,self.end.y) )
6184
# Then check 0,pi/2,pi and 2pi angles.
62-
if self.point_inside_angle(self.c+P(0,self.r)) :
85+
if self.point_Gde_angle(self.c+P(0,self.r)) :
6386
y2 = max(y2, self.c.y+self.r)
6487
if self.point_inside_angle(self.c+P(0,-self.r)) :
6588
y1 = min(y1, self.c.y-self.r)
@@ -174,7 +197,7 @@ def point_d2(self, p):
174197
class Line():
175198

176199
def __init__(self,st,end):
177-
debugger.add_debugger_to_class(self.__class__)
200+
#debugger.add_debugger_to_class(self.__class__)
178201
if st.__class__ == P : st = st.to_list()
179202
if end.__class__ == P : end = end.to_list()
180203
self.st = P(st)
@@ -233,7 +256,7 @@ def draw(self, group=None, style=None, layer=None, transform=None, num = 0, reve
233256
attr["transform"] = transform
234257
inkex.etree.SubElement( group, inkex.addNS('path','svg'), attr )
235258

236-
def intersect(self,b) :
259+
def intersect(self,b, false_intersection = False) :
237260
if b.__class__ == Line :
238261
if self.l < 10e-8 or b.l < 10e-8 : return []
239262
v1 = self.end - self.st
@@ -260,7 +283,7 @@ def intersect(self,b) :
260283
t1 = ( v2.x*(self.st.y-b.st.y) - v2.y*(self.st.x-b.st.x) ) / x
261284
t2 = ( v1.x*(self.st.y-b.st.y) - v1.y*(self.st.x-b.st.x) ) / x
262285

263-
if 0<=t1<=1 and 0<=t2<=1 : return [ self.st+v1*t1 ]
286+
if 0<=t1<=1 and 0<=t2<=1 or false_intersection : return [ self.st+v1*t1 ]
264287
else : return []
265288
else:
266289
# taken from http://mathworld.wolfram.com/Circle-LineIntersection.html
@@ -277,10 +300,14 @@ def intersect(self,b) :
277300
if descr==0 : return self.check_intersection(b.check_intersection([ P([D*dy/dr+b.c.x,-D*dx/dr+b.c.y]) ]))
278301
sign = -1. if dy<0 else 1.
279302
descr = sqrt(descr)
280-
return self.check_intersection(b.check_intersection([
281-
P( [ (D*dy+sign*dx*descr)/dr+b.c.x, (-D*dx+abs(dy)*descr)/dr+b.c.y ] ),
303+
points = [
304+
P( [ (D*dy+sign*dx*descr)/dr+b.c.x, (-D*dx+abs(dy)*descr)/dr+b.c.y ] ),
282305
P( [ (D*dy-sign*dx*descr)/dr+b.c.x, (-D*dx-abs(dy)*descr)/dr+b.c.y ] )
283-
]))
306+
]
307+
if false_intersection :
308+
return points
309+
else:
310+
return self.check_intersection(b.check_intersection( points ))
284311

285312

286313
def check_intersection(self, points):
@@ -349,7 +376,7 @@ def point_d2(self, p) :
349376

350377
class Biarc:
351378
def __init__(self, items=None):
352-
debugger.add_debugger_to_class(self.__class__)
379+
#debugger.add_debugger_to_class(self.__class__)
353380
if items == None :
354381
self.items = []
355382
else:

csp.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ def from_list(self, csp) :
9292
for subpath in csp :
9393
self.items.append(CSPsubpath(subpath))
9494

95-
96-
9795
def to_list(self) :
9896
res = []
9997
for subpath in self.items :
@@ -113,10 +111,13 @@ def from_el(self, el) :
113111
def to_string(self) :
114112
return cubicsuperpath.formatPath(self.to_list())
115113

116-
117114
def length(self) :
118115
return sum([subpath.length() for subpath in self.items()])
119116

117+
def slope(self,i,j,t) :
118+
# slope - normalized slope, i.e. l(n)=1
119+
return self.items[i].slope(j,t)
120+
120121
def normal(self,i,j,t) :
121122
# normal - normalized normal, i.e. l(n)=1
122123
return self.items[i].normal(j,t)

0 commit comments

Comments
 (0)