mathandy / svgpathtools

A collection of tools for manipulating and analyzing SVG Path objects and Bezier curves.
MIT License
557 stars 142 forks source link

Iterate split on 4 continuous Arc fails #26

Closed sensor56 closed 6 years ago

sensor56 commented 7 years ago

Hi,

when I split iteratly a circle (if it is 4 Arcs for example - no problem if it's Bezier Curve), I obtain this error : math domain error The problem is caused by acos() in parameterize function in Path.py circle_arcsx4.svg.txt

. Value for u1.real can be -1.000000002 and it's the problem...

My solution : add this function in misctools (it should be useful everywhere...) :

-- constrain(x,a,b)

def constrain(x,valMin,valMax): if x < valMin : return valMin

elif valMax < x :
    return valMax

else :
    return x

Import it in path.py : from .misctools import BugException, constrain # added XH

And in def _parameterize, change :

    if u1.imag > 0:
        self.theta = degrees(acos(constrain(u1. real,-1.0, 1.0))) # acos need -1<=value<=1 - added XH
    elif u1.imag < 0:
        self.theta = -degrees(acos(constrain(u1. real,-1.0, 1.0))) # acos need -1<=value<=1 - added XH

And it's work well to iterate split on circle !

Test file joined. (remove .txt to obtain .svg - github seems not support svg file joined...)

Xavier HINAULT France

mathandy commented 7 years ago

Hi @sensor56, how did you produce this error? I tried (both in python2 and python3):

In [1]: from svgpathtools import *

In [2]: ps, _ = svg2paths('circle_arcsx4.svg')

In [3]: ps[0]
Out[3]: 
Path(Arc(start=(200.022502354+106.636683873j), radius=(88.5826797485+88.5826797485j), rotation=0.0, large_arc=False, sweep=True, end=(111.439822606+195.219363621j)),
     Arc(start=(111.439822606+195.219363621j), radius=(88.5826797485+88.5826797485j), rotation=0.0, large_arc=False, sweep=True, end=(22.8571428571+106.636683873j)),
     Arc(start=(22.8571428571+106.636683873j), radius=(88.5826797485+88.5826797485j), rotation=0.0, large_arc=False, sweep=True, end=(111.439822606+18.0540041241j)),
     Arc(start=(111.439822606+18.0540041241j), radius=(88.5826797485+88.5826797485j), rotation=0.0, large_arc=False, sweep=True, end=(200.022502354+106.636683873j)))

No errors encountered. Am I missing a step?

sensor56 commented 7 years ago

Hi @mathandy ,

the file have no problem... but when you split the Path() iteratly, you have the problem, look like : newPath=spt.Path()#Crée un nouvel objet Path vide

for elem in paths[0]: # défile les éléments de l'objet Path

print (elem) # debug

newElems=elem.split(0.5) # calcule les 2 nouveaux sous éléments = renvoie un list de 2 objets éléments
newPath.append(newElems[0]) # ajoute séparément chaque élément
newPath.append(newElems[1])

paths[0]=newPath # le nouveau Path remplace le Path source

print (paths[0])

and again :

newPath=spt.Path()#Crée un nouvel objet Path vide

for elem in paths[0]: # défile les éléments de l'objet Path

print (elem) # debug

newElems=elem.split(0.5) # calcule les 2 nouveaux sous éléments = renvoie un list de 2 objets éléments
newPath.append(newElems[0]) # ajoute séparément chaque élément
newPath.append(newElems[1])

paths[0]=newPath # le nouveau Path remplace le Path source

print (paths[0])

and again :

newPath=spt.Path()#Crée un nouvel objet Path vide

for elem in paths[0]: # défile les éléments de l'objet Path

print (elem) # debug

newElems=elem.split(0.5) # calcule les 2 nouveaux sous éléments = renvoie un list de 2 objets éléments
newPath.append(newElems[0]) # ajoute séparément chaque élément
newPath.append(newElems[1])

paths[0]=newPath # le nouveau Path remplace le Path source

print (paths[0])

You can place of course this code in a loop, but it's for test here, in Jupyter for example. The problem appear in 2nd or third repeat.

Xavier

123Spork commented 6 years ago

Started having this exact issue today. In __parameterize, the following line of code is causing some grief on circle arcs. acos(u1.real)

Forcing to -1 or 1 if u1.real exceeds the bounds would solve the issue, as Arcs larger than those bounds are impossible.

For ref, my u1.real evaluates to 1.0000000000000002 from these Arc instance vals.

radius: (57.45+57.45j) rot_matrix: (1_0j) start: (233.65+174.45j) end: (176.2+117j) large_arc: True sweep: True rotation: 0.0 autoscale_radius: True phi: 0.0 rot_matrix (1+0j)

mathandy commented 6 years ago

Hi @123Spork and @sensor56 , this should be fixed now. Please let me know if it is not.