00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
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
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
00524
00525 if point[4] == 1:
00526
00527 perp = fcvec.rotate2D(chord,-math.pi/2)
00528 else:
00529
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
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
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
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
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
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
00737
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
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
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
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
00843 svg.write('</svg>')
00844 svg.close()
00845 FreeCAD.Console.PrintMessage("successfully exported "+filename)