importSVG.py

Go to the documentation of this file.
00001 
00002 #***************************************************************************
00003 #*                                                                         *
00004 #*   Copyright (c) 2009 Yorik van Havre <yorik@gmx.fr>                     * 
00005 #*                                                                         *
00006 #*   This program is free software; you can redistribute it and/or modify  *
00007 #*   it under the terms of the GNU General Public License (GPL)            *
00008 #*   as published by the Free Software Foundation; either version 2 of     *
00009 #*   the License, or (at your option) any later version.                   *
00010 #*   for detail see the LICENCE text file.                                 *
00011 #*                                                                         *
00012 #*   This program is distributed in the hope that it will be useful,       *
00013 #*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014 #*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015 #*   GNU Library General Public License for more details.                  *
00016 #*                                                                         *
00017 #*   You should have received a copy of the GNU Library General Public     *
00018 #*   License along with this program; if not, write to the Free Software   *
00019 #*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
00020 #*   USA                                                                   *
00021 #*                                                                         *
00022 #***************************************************************************
00023 
00024 __title__="FreeCAD Draft Workbench - SVG importer/exporter"
00025 __author__ = "Yorik van Havre <yorik@gmx.fr>"
00026 __url__ = ["http://yorik.orgfree.com","http://free-cad.sourceforge.net"]
00027 
00028 '''
00029 This script imports SVG files in FreeCAD. Currently only reads the following entities:
00030 paths, lines, arcs and rects.
00031 Bezier curves are skipped.
00032 '''
00033 
00034 import xml.sax, string, FreeCAD, os, Part, math, re, Draft
00035 from draftlibs import fcvec, fcgeo
00036 from FreeCAD import Vector
00037 
00038 try: import FreeCADGui
00039 except: gui = False
00040 else: gui = True
00041 try: draftui = FreeCADGui.draftToolBar
00042 except: draftui = None
00043 
00044 pythonopen = open
00045 
00046 svgcolors = {
00047           'Pink': [255, 192, 203], 
00048           'Blue': [0, 0, 255], 
00049           'Honeydew': [240, 255, 240],
00050           'Purple': [128, 0, 128],
00051           'Fuchsia': [255, 0, 255],
00052           'LawnGreen': [124, 252, 0],
00053           'Amethyst': [153, 102, 204],
00054           'Crimson': [220, 20, 60],
00055           'White': [255, 255, 255],
00056           'NavajoWhite': [255, 222, 173],
00057           'Cornsilk': [255, 248, 220],
00058           'Bisque': [255, 228, 196],
00059           'PaleGreen': [152, 251, 152],
00060           'Brown': [165, 42, 42],
00061           'DarkTurquoise': [0, 206, 209],
00062           'DarkGreen': [0, 100, 0],
00063           'MediumOrchid': [186, 85, 211],
00064           'Chocolate': [210, 105, 30],
00065           'PapayaWhip': [255, 239, 213],
00066           'Olive': [128, 128, 0],
00067           'Silver': [192, 192, 192],
00068           'PeachPuff': [255, 218, 185],
00069           'Plum': [221, 160, 221],
00070           'DarkGoldenrod': [184, 134, 11],
00071           'SlateGrey': [112, 128, 144],
00072           'MintCream': [245, 255, 250],
00073           'CornflowerBlue': [100, 149, 237],
00074           'Gold': [255, 215, 0],
00075           'HotPink': [255, 105, 180],
00076           'DarkBlue': [0, 0, 139],
00077           'LimeGreen': [50, 205, 50],
00078           'DeepSkyBlue': [0, 191, 255],
00079           'DarkKhaki': [189, 183, 107],
00080           'LightGrey': [211, 211, 211],
00081           'Yellow': [255, 255, 0],
00082           'Gainsboro': [220, 220, 220],
00083           'MistyRose': [255, 228, 225],
00084           'SandyBrown': [244, 164, 96],
00085           'DeepPink': [255, 20, 147],
00086           'Magenta': [255, 0, 255],
00087           'AliceBlue': [240, 248, 255],
00088           'DarkCyan': [0, 139, 139],
00089           'DarkSlateGrey': [47, 79, 79],
00090           'GreenYellow': [173, 255, 47],
00091           'DarkOrchid': [153, 50, 204],
00092           'OliveDrab': [107, 142, 35],
00093           'Chartreuse': [127, 255, 0],
00094           'Peru': [205, 133, 63],
00095           'Orange': [255, 165, 0],
00096           'Red': [255, 0, 0],
00097           'Wheat': [245, 222, 179],
00098           'LightCyan': [224, 255, 255],
00099           'LightSeaGreen': [32, 178, 170],
00100           'BlueViolet': [138, 43, 226],
00101           'LightSlateGrey': [119, 136, 153],
00102           'Cyan': [0, 255, 255],
00103           'MediumPurple': [147, 112, 219],
00104           'MidnightBlue': [25, 25, 112],
00105           'FireBrick': [178, 34, 34],
00106           'PaleTurquoise': [175, 238, 238],
00107           'PaleGoldenrod': [238, 232, 170],
00108           'Gray': [128, 128, 128],
00109           'MediumSeaGreen': [60, 179, 113],
00110           'Moccasin': [255, 228, 181],
00111           'Ivory': [255, 255, 240],
00112           'DarkSlateBlue': [72, 61, 139],
00113           'Beige': [245, 245, 220],
00114           'Green': [0, 128, 0],
00115           'SlateBlue': [106, 90, 205],
00116           'Teal': [0, 128, 128],
00117           'Azure': [240, 255, 255],
00118           'LightSteelBlue': [176, 196, 222],
00119           'DimGrey': [105, 105, 105],
00120           'Tan': [210, 180, 140],
00121           'AntiqueWhite': [250, 235, 215],
00122           'SkyBlue': [135, 206, 235],
00123           'GhostWhite': [248, 248, 255],
00124           'MediumTurquoise': [72, 209, 204],
00125           'FloralWhite': [255, 250, 240],
00126           'LavenderBlush': [255, 240, 245],
00127           'SeaGreen': [46, 139, 87],
00128           'Lavender': [230, 230, 250],
00129           'BlanchedAlmond': [255, 235, 205],
00130           'DarkOliveGreen': [85, 107, 47],
00131           'DarkSeaGreen': [143, 188, 143],
00132           'SpringGreen': [0, 255, 127],
00133           'Navy': [0, 0, 128],
00134           'Orchid': [218, 112, 214],
00135           'SaddleBrown': [139, 69, 19],
00136           'IndianRed': [205, 92, 92],
00137           'Snow': [255, 250, 250],
00138           'SteelBlue': [70, 130, 180],
00139           'MediumSlateBlue': [123, 104, 238],
00140           'Black': [0, 0, 0],
00141           'LightBlue': [173, 216, 230],
00142           'Turquoise': [64, 224, 208],
00143           'MediumVioletRed': [199, 21, 133],
00144           'DarkViolet': [148, 0, 211],
00145           'DarkGray': [169, 169, 169],
00146           'Salmon': [250, 128, 114],
00147           'DarkMagenta': [139, 0, 139],
00148           'Tomato': [255, 99, 71],
00149           'WhiteSmoke': [245, 245, 245],
00150           'Goldenrod': [218, 165, 32],
00151           'MediumSpringGreen': [0, 250, 154],
00152           'DodgerBlue': [30, 144, 255],
00153           'Aqua': [0, 255, 255],
00154           'ForestGreen': [34, 139, 34],
00155           'LemonChiffon': [255, 250, 205],
00156           'LightSlateGray': [119, 136, 153],
00157           'SlateGray': [112, 128, 144],
00158           'LightGray': [211, 211, 211],
00159           'Indigo': [75, 0, 130],
00160           'CadetBlue': [95, 158, 160],
00161           'LightYellow': [255, 255, 224],
00162           'DarkOrange': [255, 140, 0],
00163           'PowderBlue': [176, 224, 230],
00164           'RoyalBlue': [65, 105, 225],
00165           'Sienna': [160, 82, 45],
00166           'Thistle': [216, 191, 216],
00167           'Lime': [0, 255, 0],
00168           'Seashell': [255, 245, 238],
00169           'DarkRed': [139, 0, 0],
00170           'LightSkyBlue': [135, 206, 250],
00171           'YellowGreen': [154, 205, 50],
00172           'Aquamarine': [127, 255, 212],
00173           'LightCoral': [240, 128, 128],
00174           'DarkSlateGray': [47, 79, 79],
00175           'Khaki': [240, 230, 140],
00176           'DarkGrey': [169, 169, 169],
00177           'BurlyWood': [222, 184, 135],
00178           'LightGoldenrodYellow': [250, 250, 210],
00179           'MediumBlue': [0, 0, 205],
00180           'DarkSalmon': [233, 150, 122],
00181           'RosyBrown': [188, 143, 143],
00182           'LightSalmon': [255, 160, 122],
00183           'PaleVioletRed': [219, 112, 147],
00184           'Coral': [255, 127, 80],
00185           'Violet': [238, 130, 238],
00186           'Grey': [128, 128, 128],
00187           'LightGreen': [144, 238, 144],
00188           'Linen': [250, 240, 230],
00189           'OrangeRed': [255, 69, 0],
00190           'DimGray': [105, 105, 105],
00191           'Maroon': [128, 0, 0],
00192           'LightPink': [255, 182, 193],
00193           'MediumAquamarine': [102, 205, 170],
00194           'OldLace': [253, 245, 230]
00195           }
00196 
00197 def getcolor(color):
00198         "checks if the given string is a RGB value, or if it is a named color. returns 1-based RGBA tuple."
00199         if (color[:1] == "#"):
00200                 r = float(int(color[1:3],16)/255.0)
00201                 g = float(int(color[3:5],16)/255.0)
00202                 b = float(int(color[5:],16)/255.0)
00203                 return (r,g,b,0.0)
00204         else:
00205                 for k,v in svgcolors.iteritems():
00206                         if (k.lower() == color.lower()):
00207                                 r = float(v[0]/255.0)
00208                                 g = float(v[1]/255.0)
00209                                 b = float(v[2]/255.0)
00210                                 return (r,g,b,0.0)
00211 
00212 def getsize(width):
00213         "extracts a number from the given string (removes suffixes)"
00214         if width[-1] == "%":
00215                 return float(width[:-1])
00216         elif len(width) > 1:
00217                 for s in ['pt','pc','mm','cm','in','px']:
00218                         if width[-2:] == s:
00219                                 return float(width[:-2])
00220         try:
00221                 s = float(width)
00222                 return s
00223         except ValueError:
00224                 return width
00225 
00226 def getrgb(color):
00227         "returns a rgb value #000000 from a freecad color"
00228         r = str(hex(int(color[0]*255)))[2:].zfill(2)
00229         g = str(hex(int(color[1]*255)))[2:].zfill(2)
00230         b = str(hex(int(color[2]*255)))[2:].zfill(2)
00231         return "#"+r+g+b
00232 
00233 class svgHandler(xml.sax.ContentHandler):
00234         "this handler parses the svg files and creates freecad objects"
00235 
00236         def __init__(self):
00237                 "retrieving Draft parameters"
00238                 params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
00239                 self.style = params.GetInt("svgstyle")
00240                 self.count = 0
00241                 self.transform = None
00242                 self.grouptransform = []
00243                 self.lastdim = None
00244         
00245                 if gui and draftui:
00246                         r = float(draftui.color.red()/255.0)
00247                         g = float(draftui.color.green()/255.0)
00248                         b = float(draftui.color.blue()/255.0)
00249                         self.lw = float(draftui.widthButton.value())
00250                 else:
00251                         self.lw = float(params.GetInt("linewidth"))
00252                         c = params.GetUnsigned("color")
00253                         r = float(((c>>24)&0xFF)/255)
00254                         g = float(((c>>16)&0xFF)/255)
00255                         b = float(((c>>8)&0xFF)/255)
00256                 self.col = (r,g,b,0.0)
00257 
00258         def format(self,obj):
00259                 "applies styles to passed object"
00260                 if self.style and gui:
00261                         v = obj.ViewObject
00262                         if self.color: v.LineColor = self.color
00263                         if self.width: v.LineWidth = self.width
00264                         if self.fill: v.ShapeColor = self.fill
00265         
00266         def startElement(self, name, attrs):
00267 
00268                 # reorganizing data into a nice clean dictionary
00269 
00270                 self.count += 1
00271 
00272                 print "processing element ",self.count,": ",name
00273                 print "existing group transform: ", self.grouptransform
00274                 
00275                 data = {}
00276                 for (keyword,content) in attrs.items():
00277                         content = content.replace(',',' ')
00278                         content = content.split()
00279                         data[keyword]=content
00280 
00281                 if 'style' in data:
00282                         content = data['style'][0].replace(' ','')
00283                         content = content.split(';')
00284                         for i in content:
00285                                 pair = i.split(':')
00286                                 if len(pair)>1: data[pair[0]]=pair[1]
00287 
00288                 for k in ['x','y','x1','y1','x2','y2','width','height']:
00289                         if k in data:
00290                                 data[k] = getsize(data[k][0])
00291 
00292                 for k in ['fill','stroke','stroke-width','font-size']:
00293                         if k in data:
00294                                 if isinstance(data[k],list):
00295                                         data[k]=data[k][0]
00296 
00297                 # extracting style info
00298                         
00299                 self.fill = None
00300                 self.color = None
00301                 self.width = None
00302                 self.text = None
00303                 
00304                 if 'fill' in data:
00305                         if data['fill'][0] != 'none':
00306                                 self.fill = getcolor(data['fill'])
00307                 if 'stroke' in data:
00308                         if data['stroke'][0] != 'none':
00309                                 self.color = getcolor(data['stroke'])
00310                 if 'stroke-width' in data:
00311                         if data['stroke-width'] != 'none':
00312                                 self.width = getsize(data['stroke-width'])
00313                 if 'transform' in data:
00314                         m = self.getMatrix(data['transform'])
00315                         if name == "g":
00316                                 self.grouptransform.append(m)
00317                         else:
00318                                 self.transform = m
00319                 else:
00320                         if name == "g":
00321                                 self.grouptransform.append(FreeCAD.Matrix())
00322                                 
00323                         '''
00324                         print "existing grouptransform: ",self.grouptransform
00325                         print "existing transform: ",self.transform
00326                         if "translate" in tr:
00327                                 i0 = tr.index("translate")
00328                                 print "getting translate ",tr
00329                                 if "translate" in self.transform:
00330                                         self.transform['translate'] = self.transform['translate'].add(Vector(float(tr[i0+1]),-float(tr[i0+2]),0))
00331                                 else:
00332                                         self.transform['translate'] = Vector(float(tr[i0+1]),-float(tr[i0+2]),0)
00333                                 if "translate" in self.grouptransform:
00334                                         print "adding to group ",self.grouptransform['translate']
00335                                         self.transform['translate'] = self.grouptransform['translate'].add(self.transform['translate'])
00336                         else:
00337                                 if "translate" in self.grouptransform:
00338                                         print "adding to group ",self.grouptransform['translate']
00339                                         self.transform['translate'] = self.grouptransform['translate']
00340                         if "scale" in tr:
00341                                 i0 = tr.index("scale")
00342                                 if "scale" in self.transform:
00343                                         self.transform['scale'] = self.transform['scale'].add(Vector(float(tr[i0+1]),float(tr[i0+2]),0))
00344                                 else:
00345                                         print tr
00346                                         self.transform['scale'] = Vector(float(tr[i0+1]),float(tr[i0+2]),0)
00347                                 if "scale" in self.grouptransform:
00348                                         self.transform['scale'] = self.transform['scale'].add(self.grouptransform['scale'])
00349                         else:
00350                                 if "scale" in self.grouptransform:
00351                                         self.transform['scale'] = self.grouptransform['scale']
00352                         '''
00353  
00354                 if (self.style == 1):
00355                         self.color = self.col
00356                         self.width = self.lw
00357 
00358                 pathname = None
00359                 if 'id' in data:
00360                         pathname = data['id'][0]
00361                         print "name: ",pathname
00362                         
00363                 # processing paths
00364                         
00365                 if name == "path":
00366                         print data
00367                         
00368                         if not pathname: pathname = 'Path'
00369 
00370                         path = []
00371                         point = []
00372                         lastvec = Vector(0,0,0)
00373                         command = None
00374                         relative = False
00375                         firstvec = None
00376 
00377                         pathdata = []
00378                         for d in data['d']:
00379                                 if (len(d) == 1) and (d in ['m','M','l','L','h','H','v','V','a','A','c','C']):
00380                                         pathdata.append(d)
00381                                 else:
00382                                         try:
00383                                                 f = float(d)
00384                                                 pathdata.append(f)
00385                                         except ValueError:
00386                                                 if d[0].isdigit():
00387                                                         pathdata.append(d[:-1])
00388                                                         pathdata.append(d[-1])
00389                                                 else:
00390                                                         pathdata.append(d[0])
00391                                                         pathdata.append(d[1:])
00392 
00393                         # print "debug: pathdata:",pathdata
00394 
00395                         if "freecad:basepoint1" in data:
00396                                 p1 = data["freecad:basepoint1"]
00397                                 p1 = Vector(float(p1[0]),-float(p1[1]),0)
00398                                 p2 = data["freecad:basepoint2"]
00399                                 p2 = Vector(float(p2[0]),-float(p2[1]),0)
00400                                 p3 = data["freecad:dimpoint"]
00401                                 p3 = Vector(float(p3[0]),-float(p3[1]),0)
00402                                 obj = Draft.makeDimension(p1,p2,p3)
00403                                 self.applyTrans(obj)
00404                                 self.format(obj)
00405                                 pathdata = []
00406                                 self.lastdim = obj
00407 
00408                         for d in pathdata:
00409                                 if (d == "M"):
00410                                         command = "move"
00411                                         relative = False
00412                                         point = []
00413                                 elif (d == "m"):
00414                                         command = "move"
00415                                         relative = True
00416                                         point = []
00417                                 elif (d == "L"):
00418                                         command = "line"
00419                                         relative = False
00420                                         point = []
00421                                 elif (d == "l"):
00422                                         command = "line"
00423                                         relative = True
00424                                         point = []
00425                                 elif (d == "H"):
00426                                         command = "horizontal"
00427                                         relative = False
00428                                         point = []
00429                                 elif (d == "h"):
00430                                         command = "horizontal"
00431                                         relative = True
00432                                         point = []
00433                                 elif (d == "V"):
00434                                         command = "vertical"
00435                                         relative = False
00436                                         point = []
00437                                 elif (d == "v"):
00438                                         command = "vertical"
00439                                         relative = True
00440                                         point = []
00441                                 elif (d == "A"):
00442                                         command = "arc"
00443                                         relative = False
00444                                         point = []
00445                                 elif (d == "a"):
00446                                         command = "arc"
00447                                         relative = True
00448                                         point = []
00449                                 elif (d == "Z") or (d == "z"):
00450                                         command = "close"
00451                                         point = []
00452                                 elif (d == "C"):
00453                                         command = "curve"
00454                                         relative = False
00455                                         point = []
00456                                 elif (d == "c"):
00457                                         command = "curve"
00458                                         relative = True
00459                                         point = []
00460                                 else:
00461                                         try:
00462                                                 point.append(float(d))
00463                                         except ValueError:
00464                                                 pass
00465 
00466                                 print "command: ",command, ' point: ',point
00467 
00468                                 if (len(point)==2) and (command=="move"):
00469                                         if path:
00470                                                 sh = Part.Wire(path)
00471                                                 if self.fill: sh = Part.Face(sh)
00472                                                 sh = self.applyTrans(sh)
00473                                                 obj = self.doc.addObject("Part::Feature",pathname)
00474                                                 obj.Shape = sh
00475                                                 self.format(obj)
00476                                                 path = []
00477                                         if relative:
00478                                                 lastvec = lastvec.add(Vector(point[0],-point[1],0))
00479                                                 command="line"
00480                                         else:
00481                                                 lastvec = Vector(point[0],-point[1],0)
00482                                         firstvec = lastvec
00483                                         print "move ",lastvec
00484                                         command = "line"
00485                                         point = []
00486                                 elif (len(point)==2) and (command=="line"):
00487                                         if relative:
00488                                                 currentvec = lastvec.add(Vector(point[0],-point[1],0))
00489                                         else:
00490                                                 currentvec = Vector(point[0],-point[1],0)
00491                                         if not fcvec.equals(lastvec,currentvec):
00492                                                 seg = Part.Line(lastvec,currentvec).toShape()
00493                                                 print "line ",lastvec,currentvec
00494                                                 lastvec = currentvec
00495                                                 path.append(seg)
00496                                         point = []
00497                                 elif (len(point)==1) and (command=="horizontal"):
00498                                         if relative:
00499                                                 currentvec = lastvec.add(Vector(point[0],0,0))
00500                                         else:
00501                                                 lasty = path[-1].y
00502                                                 currentvec = Vector(point[0],lasty,0)
00503                                         seg = Part.Line(lastvec,currentvec).toShape()
00504                                         lastvec = currentvec
00505                                         path.append(seg)
00506                                         point = []
00507                                 elif (len(point)==1) and (command=="vertical"):
00508                                         if relative:
00509                                                 currentvec = lastvec.add(Vector(0,-point[0],0))
00510                                         else:
00511                                                 lastx = path[-1].x
00512                                                 currentvec = Vector(lastx,-point[0],0)
00513                                         seg = Part.Line(lastvec,currentvec).toShape()
00514                                         lastvec = currentvec
00515                                         path.append(seg)
00516                                         point = []
00517                                 elif (len(point)==7) and (command=="arc"):
00518                                         if relative:
00519                                                 currentvec = lastvec.add(Vector(point[-2],-point[-1],0))
00520                                         else:
00521                                                 currentvec = Vector(point[-2],-point[-1],0)
00522                                         chord = currentvec.sub(lastvec)
00523                                         # perp = chord.cross(Vector(0,0,-1))
00524                                         # here is a better way to find the perpendicular
00525                                         if point[4] == 1:
00526                                                 # clockwise
00527                                                 perp = fcvec.rotate2D(chord,-math.pi/2)
00528                                         else:
00529                                                 # anticlockwise
00530                                                 perp = fcvec.rotate2D(chord,math.pi/2)
00531                                         chord = fcvec.scale(chord,.5)
00532                                         if chord.Length > point[0]: a = 0
00533                                         else: a = math.sqrt(point[0]**2-chord.Length**2)
00534                                         s = point[0] - a
00535                                         perp = fcvec.scale(perp,s/perp.Length)
00536                                         midpoint = lastvec.add(chord.add(perp))
00537                                         seg = Part.Arc(lastvec,midpoint,currentvec).toShape()
00538                                         lastvec = currentvec
00539                                         path.append(seg)
00540                                         point = []
00541                                 elif (command == "close"):
00542                                         if not fcvec.equals(lastvec,firstvec):
00543                                                 seg = Part.Line(lastvec,firstvec).toShape()
00544                                                 path.append(seg)
00545                                         if path:
00546                                                 sh = Part.Wire(path)
00547                                                 if self.fill: sh = Part.Face(sh)
00548                                                 sh = self.applyTrans(sh)
00549                                                 obj = self.doc.addObject("Part::Feature",pathname)
00550                                                 obj.Shape = sh
00551                                                 self.format(obj)
00552                                                 path = []
00553                                         point = []
00554                                         command = None
00555                                 elif (len(point)==6) and (command=="curve"):
00556                                         if relative:
00557                                                 currentvec = lastvec.add(Vector(point[4],-point[5],0))
00558                                                 pole1 = lastvec.add(Vector(point[0],-point[1],0))
00559                                                 pole2 = lastvec.add(Vector(point[2],-point[3],0))
00560                                         else:
00561                                                 currentvec = Vector(point[4],-point[5],0)
00562                                                 pole1 = Vector(point[0],point[1],0)
00563                                                 pole2 = Vector(point[2],point[3],0)
00564                                         if not fcvec.equals(currentvec,lastvec):
00565                                                 mainv = currentvec.sub(lastvec)
00566                                                 pole1v = lastvec.add(pole1)
00567                                                 pole2v = currentvec.add(pole2)
00568                                                 print "curve data:",mainv.normalize(),pole1v.normalize(),pole2v.normalize()
00569                                                 if (round(mainv.getAngle(pole1v),4) in [0,round(math.pi,4)]) \
00570                                                             and (round(mainv.getAngle(pole2v),4) in [0,round(math.pi,4)]):
00571                                                         print "straight segment"
00572                                                         seg = Part.Line(lastvec,currentvec).toShape()
00573                                                 else:
00574                                                         print "bezier segment"
00575                                                         b = Part.BezierCurve()
00576                                                         b.setPoles([lastvec,pole1,pole2,currentvec])
00577                                                         seg = b.toShape()
00578                                                 print "connect ",lastvec,currentvec
00579                                                 lastvec = currentvec
00580                                                 path.append(seg)
00581                                         point = []
00582 
00583                         if path:
00584                                 sh = Part.Wire(path)
00585                                 if self.fill: sh = Part.Face(sh)
00586                                 sh = self.applyTrans(sh)
00587                                 obj = self.doc.addObject("Part::Feature",pathname)
00588                                 obj.Shape = sh
00589                                 self.format(obj)
00590 
00591                 # processing rects
00592 
00593                 if name == "rect":
00594                         if not pathname: pathname = 'Rectangle'
00595                         p1 = Vector(data['x'],-data['y'],0)
00596                         p2 = Vector(data['x']+data['width'],-data['y'],0)
00597                         p3 = Vector(data['x']+data['width'],-data['y']-data['height'],0)
00598                         p4 = Vector(data['x'],-data['y']-data['height'],0)
00599                         edges = []
00600                         edges.append(Part.Line(p1,p2).toShape())
00601                         edges.append(Part.Line(p2,p3).toShape())
00602                         edges.append(Part.Line(p3,p4).toShape())
00603                         edges.append(Part.Line(p4,p1).toShape())
00604                         sh = Part.Wire(edges)
00605                         if self.fill: sh = Part.Face(sh)
00606                         sh = self.applyTrans(sh)
00607                         obj = self.doc.addObject("Part::Feature",pathname)
00608                         obj.Shape = sh
00609                         self.format(obj)
00610                                      
00611                 # processing lines
00612 
00613                 if name == "line":
00614                         if not pathname: pathname = 'Line'
00615                         p1 = Vector(float(data['x1'][0]),-float(data['y1'][0]),0)
00616                         p2 = Vector(float(data['x2'][0]),-float(data['y2'][0]),0)
00617                         sh = Part.Line(p1,p2).toShape()
00618                         sh = self.applyTrans(sh)
00619                         obj = self.doc.addObject("Part::Feature",pathname)
00620                         obj.Shape = sh
00621                         self.format(obj)
00622 
00623                 # processing circles
00624 
00625                 if (name == "circle") and (not ("freecad:skip" in data)) :
00626                         if not pathname: pathname = 'Circle'
00627                         c = Vector(float(data['cx'][0]),-float(data['cy'][0]),0)
00628                         r = float(data['r'][0])
00629                         sh = Part.makeCircle(r)
00630                         if self.fill:
00631                                 sh = Part.Wire([sh])
00632                                 sh = Part.Face(sh)
00633                         sh.translate(c)
00634                         sh = self.applyTrans(sh)
00635                         obj = self.doc.addObject("Part::Feature",pathname)
00636                         obj.Shape = sh
00637                         self.format(obj)
00638 
00639                 # processing texts
00640 
00641                 if name in ["text","tspan"]:
00642                         if not("freecad:skip" in data):
00643                                 print "processing a text"
00644                                 if 'x' in data:
00645                                         self.x = data['x']
00646                                 else:
00647                                         self.x = 0
00648                                 if 'y' in data:
00649                                         self.y = data['y']
00650                                 else:
00651                                         self.y = 0
00652                                 if 'font-size' in data:
00653                                         if data['font-size'] != 'none':
00654                                                 self.text = getsize(data['font-size'])
00655                                 else:
00656                                         self.text = 1
00657                         else:
00658                                 if self.lastdim:
00659                                         self.lastdim.ViewObject.FontSize = int(getsize(data['font-size']))
00660 
00661                 print "done processing element ",self.count
00662                 
00663         def characters(self,content):
00664                 if self.text:
00665                         print "reading characters", str(content)
00666                         obj=self.doc.addObject("App::Annotation",'Text')
00667                         obj.LabelText = content.encode('latin1')
00668                         vec = Vector(self.x,-self.y,0)
00669                         if self.transform:
00670                                 vec = self.translateVec(vec,self.transform)
00671                                 print "own transform: ",self.transform, vec
00672                         for i in range(len(self.grouptransform)):
00673                                 #vec = self.translateVec(vec,self.grouptransform[-i-1])
00674                                 vec = self.grouptransform[-i-1].multiply(vec)
00675                         print "applying vector: ",vec
00676                         obj.Position = vec
00677                         if gui:
00678                                 obj.ViewObject.FontSize = int(self.text)
00679                                 if self.fill: obj.ViewObject.TextColor = self.fill
00680                                 else: obj.ViewObject.TextColor = (0.0,0.0,0.0,0.0)
00681 
00682         def endElement(self, name):
00683                 if not name in ["tspan"]:
00684                         self.transform = None
00685                         self.text = None
00686                 if name == "g":
00687                         print "closing group"
00688                         self.grouptransform.pop()
00689 
00690         def applyTrans(self,sh):
00691                 if isinstance(sh,Part.Shape):
00692                         if self.transform:
00693                                 print "applying object transform: ",self.transform
00694                                 sh = sh.transformGeometry(self.transform)
00695                         for i in range(len(self.grouptransform)):
00696                                 print "applying group transform: ",self.grouptransform[-i-1]
00697                                 sh = sh.transformGeometry(self.grouptransform[-i-1])
00698                         return sh
00699                 elif Draft.getType(sh) == "Dimension":
00700                         pts = []
00701                         for p in [sh.Start,sh.End,sh.Dimline]:
00702                                 cp = Vector(p)
00703                                 if self.transform:
00704                                         print "applying object transform: ",self.transform
00705                                         cp = self.transform.multiply(cp)
00706                                 for i in range(len(self.grouptransform)):
00707                                         print "applying group transform: ",self.grouptransform[-i-1]
00708                                         cp = self.grouptransform[-i-1].multiply(cp)
00709                                 pts.append(cp)
00710                         sh.Start = pts[0]
00711                         sh.End = pts[1]
00712                         sh.Dimline = pts[2]
00713 
00714         def translateVec(self,vec,mat):
00715                 v = Vector(mat.A14,mat.A24,mat.A34)
00716                 return vec.add(v)
00717 
00718         def getMatrix(self,tr):
00719                 "returns a FreeCAD matrix from a svg transform attribute"
00720                 s = ""
00721                 for l in tr:
00722                         s += l
00723                         s += " "
00724                 s=s.replace("("," ")
00725                 s=s.replace(")"," ")
00726                 s = s.strip()
00727                 tr = s.split()
00728                 m = FreeCAD.Matrix()
00729                 for i in range(len(tr)):
00730                         if tr[i] == 'translate':
00731                                 vec = Vector(float(tr[i+1]),-float(tr[i+2]),0)
00732                                 m.move(vec)
00733                         elif tr[i] == 'scale':
00734                                 vec = Vector(float(tr[i+1]),float(tr[i+2]),0)
00735                                 m.scale(vec)
00736                         #elif tr[i] == 'rotate':
00737                         #        m.rotateZ(float(tr[i+1]))
00738                 print "generating transformation: ",m
00739                 return m
00740                         
00741 def decodeName(name):
00742         "decodes encoded strings"
00743         try:
00744                 decodedName = (name.decode("utf8"))
00745         except UnicodeDecodeError:
00746                 try:
00747                         decodedName = (name.decode("latin1"))
00748                 except UnicodeDecodeError:
00749                         print "dxf: error: couldn't determine character encoding"
00750                         decodedName = name
00751         return decodedName
00752 
00753 def getContents(filename,tag,stringmode=False):
00754         "gets the contents of all the occurences of the given tag in the given file"
00755         result = {}
00756         if stringmode:
00757                 contents = filename
00758         else:
00759                 f = pythonopen(filename)
00760                 contents = ''
00761                 for line in f: contents += line
00762                 f.close()
00763         contents = contents.replace('\n','_linebreak')
00764         searchpat = '<'+tag+'.*?</'+tag+'>'
00765         tags = re.findall(searchpat,contents)
00766         for t in tags:
00767                 tagid = re.findall('id="(.*?)"',t)
00768                 if tagid:
00769                         tagid = tagid[0]
00770                 else:
00771                         tagid = 'none'
00772                 res = t.replace('_linebreak','\n')
00773                 result[tagid] = res
00774         return result
00775 
00776 def open(filename):
00777         docname=os.path.split(filename)[1]
00778         doc=FreeCAD.newDocument(docname)
00779         doc.Label = decodeName(docname[:-4])
00780         parser = xml.sax.make_parser()
00781         parser.setContentHandler(svgHandler())
00782         parser._cont_handler.doc = doc
00783         f = pythonopen(filename)
00784         parser.parse(f)
00785         f.close()
00786         doc.recompute()
00787         return doc
00788 
00789 def insert(filename,docname):
00790         try:
00791                 doc=FreeCAD.getDocument(docname)
00792         except:
00793                 doc=FreeCAD.newDocument(docname)
00794         parser = xml.sax.make_parser()
00795         parser.setContentHandler(svgHandler())
00796         parser._cont_handler.doc = doc
00797         parser.parse(pythonopen(filename))
00798         doc.recompute()
00799 
00800 def export(exportList,filename):
00801         "called when freecad exports a file"
00802 
00803         # finding sheet size
00804         minx = 10000
00805         miny = 10000
00806         maxx = 0
00807         maxy = 0
00808         for ob in exportList:
00809                 if ob.isDerivedFrom("Part::Feature"):
00810                         for v in ob.Shape.Vertexes:
00811                                 if v.Point.x < minx: minx = v.Point.x
00812                                 if v.Point.x > maxx: maxx = v.Point.x
00813                                 if v.Point.y < miny: miny = v.Point.y
00814                                 if v.Point.y > maxy: maxy = v.Point.y
00815         margin = (maxx-minx)*.01
00816         minx -= margin 
00817         maxx += margin
00818         miny -= margin
00819         maxy += margin
00820         sizex = maxx-minx
00821         sizey = maxy-miny
00822         miny += margin
00823         boty = sizey+miny
00824 
00825         # writing header
00826         svg = pythonopen(filename,'wb') 
00827         svg.write('<?xml version="1.0"?>\n')
00828         svg.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"')
00829         svg.write(' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n')
00830         svg.write('<svg')
00831         svg.write(' width="' + str(sizex) + '" height="' + str(sizey) + '"')
00832         svg.write(' viewBox="0 0 ' + str(sizex) + ' ' + str(sizey) + '"')
00833         svg.write(' xmlns="http://www.w3.org/2000/svg" version="1.1"')
00834         svg.write('>\n')
00835 
00836         # writing paths
00837         for ob in exportList:
00838                 svg.write('<g transform="translate('+str(-minx)+','+str(-miny+(2*margin))+') scale(1,-1)">\n')
00839                 svg.write(Draft.getSVG(ob))
00840                 svg.write('</g>\n')
00841                 
00842         # closing
00843         svg.write('</svg>')
00844         svg.close()
00845         FreeCAD.Console.PrintMessage("successfully exported "+filename)

Generated on Wed Nov 23 19:00:18 2011 for FreeCAD by  doxygen 1.6.1