# plot_utils.py # Common geometric plotting utilities for EiBotBoard # https://github.com/evil-mad/plotink # # Intended to provide some common interfaces that can be used by # EggBot, WaterColorBot, AxiDraw, and similar machines. # # Version 0.1, Dated January 8, 2016. # # # The MIT License (MIT) # # Copyright (c) 2016 Evil Mad Scientist Laboratories # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from math import sqrt import cspsubdiv from bezmisc import * def version(): return "0.1" # Version number for this document def distance( x, y ): ''' Pythagorean theorem! ''' return sqrt( x * x + y * y ) def parseLengthWithUnits( str ): ''' Parse an SVG value which may or may not have units attached This version is greatly simplified in that it only allows: no units, units of px, and units of %. Everything else, it returns None for. There is a more general routine to consider in scour.py if more generality is ever needed. ''' u = 'px' s = str.strip() if s[-2:] == 'px': s = s[:-2] elif s[-1:] == '%': u = '%' s = s[:-1] try: v = float( s ) except: return None, None return v, u def getLength( altself, name, default ): ''' Get the <svg> attribute with name "name" and default value "default" Parse the attribute into a value and associated units. Then, accept no units (''), units of pixels ('px'), and units of percentage ('%'). ''' str = altself.svg.get( name ) if str: v, u = parseLengthWithUnits( str ) if not v: # Couldn't parse the value return None elif ( u == '' ) or ( u == 'px' ): return v elif u == '%': return float( default ) * v / 100.0 else: # Unsupported units return None else: # No width specified; assume the default value return float( default ) def subdivideCubicPath( sp, flat, i=1 ): """ Break up a bezier curve into smaller curves, each of which is approximately a straight line within a given tolerance (the "smoothness" defined by [flat]). This is a modified version of cspsubdiv.cspsubdiv(). I rewrote the recursive call because it caused recursion-depth errors on complicated line segments. """ while True: while True: if i >= len( sp ): return p0 = sp[i - 1][1] p1 = sp[i - 1][2] p2 = sp[i][0] p3 = sp[i][1] b = ( p0, p1, p2, p3 ) if cspsubdiv.maxdist( b ) > flat: break i += 1 one, two = beziersplitatt( b, 0.5 ) sp[i - 1][2] = one[1] sp[i][0] = two[2] p = [one[2], one[3], two[1]] sp[i:1] = [p]