00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 __title__="FreeCAD Draft Workbench - DXF importer/exporter"
00027 __author__ = "Yorik van Havre <yorik@gmx.fr>"
00028 __url__ = ["http://yorik.orgfree.com","http://free-cad.sourceforge.net"]
00029
00030 '''
00031 This script uses a DXF-parsing library created by Stani,
00032 Kitsu and Migius for Blender
00033
00034 imports:
00035 line, polylines, lwpolylines, arcs, circles, texts,
00036 mtexts, layers (as groups), colors
00037
00038 exports:
00039 lines, polylines, lwpolylines, circles, arcs,
00040 texts, colors,layers (from groups)
00041 '''
00042
00043 import FreeCAD, os, Part, math, re, string, Mesh, Draft
00044 from draftlibs import fcvec, dxfColorMap, dxfLibrary, fcgeo
00045 from draftlibs.dxfReader import readDXF
00046 from Draft import Dimension, ViewProviderDimension
00047 from FreeCAD import Vector
00048
00049 try: import FreeCADGui
00050 except: gui = False
00051 else: gui = True
00052 try: draftui = FreeCADGui.draftToolBar
00053 except: draftui = None
00054
00055 pythonopen = open
00056
00057 def prec():
00058 "returns the current Draft precision level"
00059 return Draft.getParam("precision")
00060
00061 def decodeName(name):
00062 "decodes encoded strings"
00063 try:
00064 decodedName = (name.decode("utf8"))
00065 except UnicodeDecodeError:
00066 try:
00067 decodedName = (name.decode("latin1"))
00068 except UnicodeDecodeError:
00069 print "dxf: error: couldn't determine character encoding"
00070 decodedName = name
00071 return decodedName
00072
00073 def locateLayer(wantedLayer):
00074 "returns layer group and creates it if needed"
00075 wantedLayerName = decodeName(wantedLayer)
00076 for l in layers:
00077 if wantedLayerName==l.Label:
00078 return l
00079 newLayer = doc.addObject("App::DocumentObjectGroup",wantedLayer)
00080 newLayer.Label = wantedLayerName
00081 layers.append(newLayer)
00082 return newLayer
00083
00084 def calcBulge(v1,bulge,v2):
00085 '''
00086 calculates intermediary vertex for curved segments.
00087 algorithm from http://www.afralisp.net/lisp/Bulges1.htm
00088 '''
00089 chord = v2.sub(v1)
00090 sagitta = (bulge * chord.Length)/2
00091 startpoint = v1.add(fcvec.scale(chord,0.5))
00092 perp = chord.cross(Vector(0,0,1))
00093 if not fcvec.isNull(perp): perp.normalize()
00094 endpoint = fcvec.scale(perp,sagitta)
00095 return startpoint.add(endpoint)
00096
00097 def getGroup(ob,exportList):
00098 "checks if the object is part of a group"
00099 for i in exportList:
00100 if (i.Type == "App::DocumentObjectGroup"):
00101 for j in i.Group:
00102 if (j == ob):
00103 return i.Label
00104 return "0"
00105
00106 def getACI(ob,text=False):
00107 "gets the ACI color closest to the objects color"
00108 if not gui: return 0
00109 else:
00110 if text:
00111 col=ob.ViewObject.TextColor
00112 else:
00113 col=ob.ViewObject.LineColor
00114 aci=[0,442]
00115 for i in range (255,-1,-1):
00116 ref=dxfColorMap.color_map[i]
00117 dist=((ref[0]-col[0])**2 + (ref[1]-col[1])**2 + (ref[2]-col[2])**2)
00118 if (dist <= aci[1]): aci=[i,dist]
00119 return aci[0]
00120
00121 def rawValue(entity,code):
00122 "returns the value of a DXF code in an entity section"
00123 value = None
00124 for pair in entity.data:
00125 if pair[0] == code:
00126 value = pair[1]
00127 return value
00128
00129 class fcformat:
00130 "this contains everything related to color/lineweight formatting"
00131 def __init__(self,drawing):
00132 self.dxf = drawing
00133 params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
00134 self.paramtext = params.GetBool("dxftext")
00135 self.paramstarblocks = params.GetBool("dxfstarblocks")
00136 self.dxflayout = params.GetBool("dxflayouts")
00137 self.paramstyle = params.GetInt("dxfstyle")
00138 self.join = params.GetBool("joingeometry")
00139 self.makeBlocks = params.GetBool("groupLayers")
00140 bparams = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View")
00141
00142 if self.paramstyle > 1:
00143
00144 if bparams.GetBool("Gradient"):
00145 c1 = bparams.GetUnsigned("BackgroundColor2")
00146 c2 = bparams.GetUnsigned("BackgroundColor3")
00147 r1 = float((c1>>24)&0xFF)
00148 g1 = float((c1>>16)&0xFF)
00149 b1 = float((c1>>8)&0xFF)
00150 r2 = float((c2>>24)&0xFF)
00151 g2 = float((c2>>16)&0xFF)
00152 b2 = float((c2>>8)&0xFF)
00153 v1 = FreeCAD.Vector(r1,g1,b1)
00154 v2 = FreeCAD.Vector(r2,g2,b2)
00155 v = v2.sub(v1)
00156 v = fcvec.scale(v,0.5)
00157 cv = v1.add(v)
00158 else:
00159 c1 = bparams.GetUnsigned("BackgroundColor")
00160 r1 = float((c1>>24)&0xFF)
00161 g1 = float((c1>>16)&0xFF)
00162 b1 = float((c1>>8)&0xFF)
00163 cv = FreeCAD.Vector(r1,g1,b1)
00164 value = cv.x*.3 + cv.y*.59 + cv.z*.11
00165 if value < 128: self.brightbg = False
00166 else:
00167 self.brightbg = True
00168
00169 if gui and draftui:
00170 r = float(draftui.color.red()/255.0)
00171 g = float(draftui.color.green()/255.0)
00172 b = float(draftui.color.blue()/255.0)
00173 self.lw = float(draftui.linewidth)
00174 else:
00175 self.lw = float(params.GetInt("linewidth"))
00176 c = params.GetUnsigned("color")
00177 r = float(((c>>24)&0xFF)/255)
00178 g = float(((c>>16)&0xFF)/255)
00179 b = float(((c>>8)&0xFF)/255)
00180 self.col = (r,g,b,0.0)
00181
00182 if self.paramstyle == 3:
00183 parammappingfile = params.GetString("dxfmappingfile")
00184 self.table = self.buildTable(parammappingfile)
00185
00186 def buildTable(self,tablefile):
00187 "builds a table for converting colors into linewidths"
00188 try: f = pythonopen(tablefile)
00189 except ValueError:
00190 print "error: ",tablefile, " not found"
00191 return None
00192 table = {}
00193 header = len(f.readline().split("\t"))
00194 if header == 15:
00195 for l in f:
00196 s = l.split("\t")
00197 if "Color_" in s[0]:
00198 index = int(s[0].split("_")[1])
00199 if s[1] == "(Object)": color = "object"
00200 else:
00201 c = s[2].split(",")
00202 color = [float(c[0])/255,float(c[1])/255,float(c[2])/255]
00203 if (color == [0.0,0.0,0.0]) and (not self.brightbg):
00204 color = [1.0,1.0,1.0]
00205 if s[2] == "(Object)": width = "object"
00206 else: width = float(s[10])*10
00207 table[index]=[color,width]
00208 elif header == 3:
00209 for l in f:
00210 s = l.split("\t")
00211 index = int(s[0])
00212 c = string.replace(s[1],'"','')
00213 c = c.split(",")
00214 color = [float(c[0])/255,float(c[1])/255,float(c[2])/255]
00215 width = float(s[2])
00216 table[index]=[color,width]
00217 for i in range(256):
00218 if not i in table.keys():
00219 table[i]=["object","object"]
00220 else:
00221 print "error building mapping table: file format not recognized"
00222 table = None
00223 print table
00224 return table
00225
00226 def formatObject(self,obj,dxfobj,textmode=False):
00227 "applies color and linetype to objects"
00228 if self.paramstyle == 1:
00229 if textmode:
00230 obj.ViewObject.TextColor = (0.0,0.0,0.0)
00231 else:
00232 obj.ViewObject.LineColor = self.col
00233 obj.ViewObject.LineWidth = self.lw
00234 elif self.paramstyle == 2:
00235 if textmode:
00236 if dxfobj.color_index == 256: cm = self.getGroupColor(dxfobj)[:3]
00237 else: cm = dxfColorMap.color_map[dxfobj.color_index]
00238 obj.ViewObject.TextColor = (cm[0],cm[1],cm[2])
00239 else:
00240 if dxfobj.color_index == 256: cm = self.getGroupColor(dxfobj)
00241 elif (dxfobj.color_index == 7) and self.brightbg: cm = [0.0,0.0,0.0]
00242 else: cm = dxfColorMap.color_map[dxfobj.color_index]
00243 obj.ViewObject.LineColor = (cm[0],cm[1],cm[2],0.0)
00244 obj.ViewObject.LineWidth = self.lw
00245 elif self.paramstyle == 3:
00246 if textmode:
00247 cm = table[dxfobj.color_index][0]
00248 wm = table[dxfobj.color_index][1]
00249 obj.ViewObject.TextColor = (cm[0],cm[1],cm[2])
00250 else:
00251 if dxfobj.color_index == 256:
00252 cm = self.table[self.getGroupColor(dxfobj,index=True)][0]
00253 wm = self.table[self.getGroupColor(dxfobj,index=True)][1]
00254 else:
00255 cm = self.table[dxfobj.color_index][0]
00256 wm = self.table[dxfobj.color_index][1]
00257 if cm == "object": cm = self.getGroupColor(dxfobj)
00258 else: obj.ViewObject.LineColor = (cm[0],cm[1],cm[2],0.0)
00259 if wm == "object": wm = self.lw
00260 else: obj.ViewObject.LineWidth = wm
00261
00262 def getGroupColor(self,dxfobj,index=False):
00263 "get color of bylayer stuff"
00264 name = dxfobj.layer
00265 for table in self.dxf.tables.get_type("table"):
00266 if table.name == "layer":
00267 for l in table.get_type("layer"):
00268 if l.name == name:
00269 if index: return l.color
00270 else:
00271 if (l.color == 7) and self.brightbg: return [0.0,0.0,0.0]
00272 else: return dxfColorMap.color_map[l.color]
00273
00274 def vec(pt):
00275 "returns a rounded Vector from a dxf point"
00276 return FreeCAD.Vector(round(pt[0],prec()),round(pt[1],prec()),round(pt[2],prec()))
00277
00278 def drawLine(line,shapemode=False):
00279 "returns a Part shape from a dxf line"
00280 if (len(line.points) > 1):
00281 v1=vec(line.points[0])
00282 v2=vec(line.points[1])
00283 if not fcvec.equals(v1,v2):
00284 try:
00285 if (fmt.paramstyle == 4) and (not fmt.makeBlocks) and (not shapemode):
00286 return Draft.makeWire([v1,v2])
00287 else:
00288 return Part.Line(v1,v2).toShape()
00289 except:
00290 warn(line)
00291 return None
00292
00293 def drawPolyline(polyline,shapemode=False):
00294 "returns a Part shape from a dxf polyline"
00295 if (len(polyline.points) > 1):
00296 edges = []
00297 curves = False
00298 verts = []
00299 for p in range(len(polyline.points)-1):
00300 p1 = polyline.points[p]
00301 p2 = polyline.points[p+1]
00302 v1 = vec(p1)
00303 v2 = vec(p2)
00304 verts.append(v1)
00305 if not fcvec.equals(v1,v2):
00306 if polyline.points[p].bulge:
00307 curves = True
00308 cv = calcBulge(v1,polyline.points[p].bulge,v2)
00309 if fcvec.isColinear([v1,cv,v2]):
00310 try: edges.append(Part.Line(v1,v2).toShape())
00311 except: warn(polyline)
00312 else:
00313 try: edges.append(Part.Arc(v1,cv,v2).toShape())
00314 except: warn(polyline)
00315 else:
00316 try: edges.append(Part.Line(v1,v2).toShape())
00317 except: warn(polyline)
00318 verts.append(v2)
00319 if polyline.closed:
00320 p1 = polyline.points[len(polyline.points)-1]
00321 p2 = polyline.points[0]
00322 v1 = vec(p1)
00323 v2 = vec(p2)
00324 cv = calcBulge(v1,polyline.points[-1].bulge,v2)
00325 if not fcvec.equals(v1,v2):
00326 if fcvec.isColinear([v1,cv,v2]):
00327 try: edges.append(Part.Line(v1,v2).toShape())
00328 except: warn(polyline)
00329 else:
00330 try: edges.append(Part.Arc(v1,cv,v2).toShape())
00331 except: warn(polyline)
00332 if edges:
00333 try:
00334 if (fmt.paramstyle == 4) and (not curves) and (not fmt.makeBlocks) and (not shapemode):
00335 ob = Draft.makeWire(verts)
00336 ob.Closed = polyline.closed
00337 return ob
00338 else:
00339 if polyline.closed:
00340 w = Part.Wire(edges)
00341 return(Part.Face(w))
00342 else:
00343 return Part.Wire(edges)
00344 except:
00345 warn(polyline)
00346 return None
00347
00348 def drawArc(arc,shapemode=False):
00349 "returns a Part shape from a dxf arc"
00350 v=vec(arc.loc)
00351 firstangle=round(arc.start_angle,prec())
00352 lastangle=round(arc.end_angle,prec())
00353 circle=Part.Circle()
00354 circle.Center=v
00355 circle.Radius=round(arc.radius,prec())
00356 try:
00357 if (fmt.paramstyle == 4) and (not fmt.makeBlocks) and (not shapemode):
00358 pl = FreeCAD.Placement()
00359 pl.move(v)
00360 return Draft.makeCircle(arc.radius,pl,False,firstangle,lastangle)
00361 else:
00362 return circle.toShape(math.radians(firstangle),math.radians(lastangle))
00363 except:
00364 warn(arc)
00365 return None
00366
00367 def drawCircle(circle,shapemode=False):
00368 "returns a Part shape from a dxf circle"
00369 v = vec(circle.loc)
00370 curve = Part.Circle()
00371 curve.Radius = round(circle.radius,prec())
00372 curve.Center = v
00373 try:
00374 if (fmt.paramstyle == 4) and (not fmt.makeBlocks) and (not shapemode):
00375 pl = FreeCAD.Placement()
00376 pl.move(v)
00377 return Draft.makeCircle(circle.radius,pl)
00378 else:
00379 return curve.toShape()
00380 except:
00381 warn(circle)
00382 return None
00383
00384 def drawFace(face):
00385 "returns a Part face from a list of points"
00386 pl = []
00387 for p in face.points:
00388 pl.append(vec(p))
00389 p1 = face.points[0]
00390 pl.append(vec(p1))
00391 try:
00392 pol = Part.makePolygon(pl)
00393 return Part.Face(pol)
00394 except:
00395 warn(face)
00396 return None
00397
00398 def drawMesh(mesh):
00399 "returns a Mesh from a dxf mesh"
00400 md = []
00401 if mesh.flags == 16:
00402 pts = mesh.points
00403 udim = rawValue(mesh,71)
00404 vdim = rawValue(mesh,72)
00405 for u in range(udim-1):
00406 for v in range(vdim-1):
00407 b = u+v*udim
00408 p1 = pts[b]
00409 p2 = pts[b+1]
00410 p3 = pts[b+udim]
00411 p4 = pts[b+udim+1]
00412 md.append([p1,p2,p4])
00413 md.append([p1,p4,p3])
00414 elif mesh.flags == 64:
00415 pts = []
00416 fcs = []
00417 for p in mesh.points:
00418 if p.flags == 192:
00419 pts.append(p)
00420 elif p.flags == 128:
00421 fcs.append(p)
00422 for f in fcs:
00423 p1 = pts[rawValue(f,71)-1]
00424 p2 = pts[rawValue(f,72)-1]
00425 p3 = pts[rawValue(f,73)-1]
00426 md.append([p1,p2,p3])
00427 if rawValue(f,74) != None:
00428 p4 = pts[rawValue(f,74)-1]
00429 md.append([p1,p3,p4])
00430 try:
00431 return Mesh.Mesh(md)
00432 except:
00433 warn(mesh)
00434 return None
00435
00436 def drawSolid(solid):
00437 "returns a Part shape from a dxf solid"
00438 p4 = None
00439 p1x = rawValue(solid,10)
00440 p1y = rawValue(solid,20)
00441 p1z = rawValue(solid,30) or 0
00442 p2x = rawValue(solid,11)
00443 p2y = rawValue(solid,21)
00444 p2z = rawValue(solid,31) or p1z
00445 p3x = rawValue(solid,12)
00446 p3y = rawValue(solid,22)
00447 p3z = rawValue(solid,32) or p1z
00448 p4x = rawValue(solid,13)
00449 p4y = rawValue(solid,23)
00450 p4z = rawValue(solid,33) or p1z
00451 p1 = FreeCAD.Vector(p1x,p1y,p1z)
00452 p2 = FreeCAD.Vector(p2x,p2y,p2z)
00453 p3 = FreeCAD.Vector(p3x,p3y,p3z)
00454 if p4x != None: p4 = FreeCAD.Vector(p4x,p4y,p4z)
00455 if p4 and (p4 != p3) and (p4 != p2) and (p4 != p1):
00456 try:
00457 return Part.Face(Part.makePolygon([p1,p2,p3,p4,p1]))
00458 except:
00459 warn(solid)
00460 else:
00461 try:
00462 return Part.Face(Part.makePolygon([p1,p2,p3,p1]))
00463 except:
00464 warn(solid)
00465 return None
00466
00467 def drawSpline(spline,shapemode=False):
00468 "returns a Part Shape from a dxf spline"
00469 flag = rawValue(spline,70)
00470 if flag == 1:
00471 closed = True
00472 else:
00473 closed = False
00474 verts = []
00475 knots = []
00476 for dline in spline.data:
00477 if dline[0] == 10:
00478 cp = [dline[1]]
00479 elif dline[0] == 20:
00480 cp.append(dline[1])
00481 elif dline[0] == 30:
00482 cp.append(dline[1])
00483 pt = Vector(cp[0],cp[1],cp[2])
00484 if verts:
00485 if pt != verts[-1]:
00486 verts.append(pt)
00487 else:
00488 verts.append(pt)
00489 elif dline[0] == 40:
00490 knots.append(dline[1])
00491 try:
00492 if (fmt.paramstyle == 4) and (not fmt.makeBlocks) and (not shapemode):
00493 ob = Draft.makeSpline(verts)
00494 ob.Closed = closed
00495 return ob
00496 else:
00497 sp = Part.BSplineCurve()
00498 print knots
00499 sp.interpolate(verts)
00500 sh = Part.Wire(sp.toShape())
00501 if closed:
00502 return Part.Face(sh)
00503 else:
00504 return sh
00505 except:
00506 warn(spline)
00507 return None
00508
00509 def drawBlock(blockref):
00510 "returns a shape from a dxf block reference"
00511 shapes = []
00512 for line in blockref.entities.get_type('line'):
00513 s = drawLine(line,shapemode=True)
00514 if s: shapes.append(s)
00515 for polyline in blockref.entities.get_type('polyline'):
00516 s = drawPolyline(polyline,shapemode=True)
00517 if s: shapes.append(s)
00518 for polyline in blockref.entities.get_type('lwpolyline'):
00519 s = drawPolyline(polyline,shapemode=True)
00520 if s: shapes.append(s)
00521 for arc in blockref.entities.get_type('arc'):
00522 s = drawArc(arc,shapemode=True)
00523 if s: shapes.append(s)
00524 for circle in blockref.entities.get_type('circle'):
00525 s = drawCircle(circle,shapemode=True)
00526 if s: shapes.append(s)
00527 for insert in blockref.entities.get_type('insert'):
00528 s = drawInsert(insert)
00529 if s: shapes.append(s)
00530 for solid in blockref.entities.get_type('solid'):
00531 s = drawSolid(solid)
00532 if s: shapes.append(s)
00533 for spline in blockref.entities.get_type('spline'):
00534 s = drawSpline(spline,shapemode=True)
00535 if s: shapes.append(s)
00536 for text in blockref.entities.get_type('text'):
00537 if fmt.dxflayout or (not rawValue(text,67)):
00538 addText(text)
00539 for text in blockref.entities.get_type('mtext'):
00540 if fmt.dxflayout or (not rawValue(text,67)):
00541 addText(text)
00542 try: shape = Part.makeCompound(shapes)
00543 except: warn(blockref)
00544 if shape:
00545 blockshapes[blockref.name]=shape
00546 return shape
00547 return None
00548
00549 def drawInsert(insert):
00550 if blockshapes.has_key(insert):
00551 shape = blockshapes[insert.block]
00552 else:
00553 shape = None
00554 for b in drawing.blocks.data:
00555 if b.name == insert.block:
00556 shape = drawBlock(b)
00557 if fmt.paramtext:
00558 attrs = attribs(insert)
00559 for a in attrs:
00560 addText(a,attrib=True)
00561 if shape:
00562 pos = vec(insert.loc)
00563 rot = math.radians(insert.rotation)
00564 scale = insert.scale
00565 tsf = FreeCAD.Matrix()
00566 tsf.scale(vec(scale))
00567 tsf.rotateZ(rot)
00568 shape = shape.transformGeometry(tsf)
00569 shape.translate(pos)
00570 return shape
00571 return None
00572
00573 def drawLayerBlock(shapeslist):
00574 "draws a compound with the given shapes"
00575 shape = None
00576 try:
00577 shape = Part.makeCompound(shapeslist)
00578 except:
00579 pass
00580 return shape
00581
00582 def attribs(insert):
00583 "checks if an insert has attributes, and returns the values if yes"
00584 atts = []
00585 if rawValue(insert,66) != 1: return []
00586 index = None
00587 for i in range(len(drawing.entities.data)):
00588 if drawing.entities.data[i] == insert:
00589 index = i
00590 break
00591 if index == None: return []
00592 j = index+1
00593 while True:
00594 ent = drawing.entities.data[j]
00595 print str(ent)
00596 if str(ent) == 'seqend':
00597 return atts
00598 elif str(ent) == 'attrib':
00599 atts.append(ent)
00600 j += 1
00601
00602 def addObject(shape,name="Shape",layer=None):
00603 "adds a new object to the document with passed arguments"
00604 if isinstance(shape,Part.Shape):
00605 newob=doc.addObject("Part::Feature",name)
00606 newob.Shape = shape
00607 else:
00608 newob = shape
00609 if layer:
00610 lay=locateLayer(layer)
00611 lay.addObject(newob)
00612 return newob
00613
00614 def addText(text,attrib=False):
00615 "adds a new text to the document"
00616 if attrib:
00617 lay = locateLayer(rawValue(text,8))
00618 val = rawValue(text,1)
00619 pos = FreeCAD.Vector(rawValue(text,10),rawValue(text,20),rawValue(text,30))
00620 hgt = rawValue(text,40)
00621 else:
00622 lay = locateLayer(text.layer)
00623 val = text.value
00624 pos = FreeCAD.Vector(text.loc[0],text.loc[1],text.loc[2])
00625 hgt = text.height
00626 if val:
00627 newob=doc.addObject("App::Annotation","Text")
00628 lay.addObject(newob)
00629 val = re.sub('{([^!}]([^}]|\n)*)}', '', val)
00630 val = re.sub('%%d','°',val)
00631 val = re.sub('%%c','Ø',val)
00632 val = val.decode("Latin1").encode("Latin1")
00633 newob.LabelText = val
00634 newob.Position = pos
00635 if gui:
00636 newob.ViewObject.FontSize=float(hgt)
00637 newob.ViewObject.DisplayMode = "World"
00638 fmt.formatObject(newob,text,textmode=True)
00639
00640 def addToBlock(shape,layer):
00641 "adds given shape to the layer dict"
00642 if layer in layerBlocks:
00643 layerBlocks[layer].append(shape)
00644 else:
00645 layerBlocks[layer] = [shape]
00646
00647 def processdxf(document,filename):
00648 "this does the translation of the dxf contents into FreeCAD Part objects"
00649 global drawing
00650 FreeCAD.Console.PrintMessage("opening "+filename+"...\n")
00651 drawing = readDXF(filename)
00652 global layers
00653 layers = []
00654 global doc
00655 doc = document
00656 global blockshapes
00657 blockshapes = {}
00658 global badobjects
00659 badobjects = []
00660 global layerBlocks
00661 layerBlocks = {}
00662
00663
00664
00665 global fmt
00666 fmt = fcformat(drawing)
00667 shapes = []
00668
00669
00670
00671 lines = drawing.entities.get_type("line")
00672 if lines: FreeCAD.Console.PrintMessage("drawing "+str(len(lines))+" lines...\n")
00673 for line in lines:
00674 if fmt.dxflayout or (not rawValue(line,67)):
00675 shape = drawLine(line)
00676 if shape:
00677 if fmt.join:
00678 if isinstance(shape,Part.Shape):
00679 shapes.append(shape)
00680 else:
00681 shapes.append(shape.Shape)
00682 elif fmt.makeBlocks:
00683 if isinstance(shape,Part.Shape):
00684 addToBlock(shape,line.layer)
00685 else:
00686 addToBlock(shape.Shape,line.layer)
00687 else:
00688 newob = addObject(shape,"Line",line.layer)
00689 if gui: fmt.formatObject(newob,line)
00690
00691
00692
00693 pls = drawing.entities.get_type("lwpolyline")
00694 pls.extend(drawing.entities.get_type("polyline"))
00695 polylines = []
00696 meshes = []
00697 for p in pls:
00698 if hasattr(p,"flags"):
00699 if p.flags in [16,64]:
00700 meshes.append(p)
00701 else:
00702 polylines.append(p)
00703 else:
00704 polylines.append(p)
00705 if polylines: FreeCAD.Console.PrintMessage("drawing "+str(len(polylines))+" polylines...\n")
00706 for polyline in polylines:
00707 if fmt.dxflayout or (not rawValue(polyline,67)):
00708 shape = drawPolyline(polyline)
00709 if shape:
00710 if fmt.join:
00711 if isinstance(shape,Part.Shape):
00712 shapes.append(shape)
00713 else:
00714 shapes.append(shape.Shape)
00715 elif fmt.makeBlocks:
00716 if isinstance(shape,Part.Shape):
00717 addToBlock(shape,polyline.layer)
00718 else:
00719 addToBlock(shape.Shape,polyline.layer)
00720 else:
00721 newob = addObject(shape,"Polyline",polyline.layer)
00722 if gui: fmt.formatObject(newob,polyline)
00723
00724
00725
00726 arcs = drawing.entities.get_type("arc")
00727 if arcs: FreeCAD.Console.PrintMessage("drawing "+str(len(arcs))+" arcs...\n")
00728 for arc in arcs:
00729 if fmt.dxflayout or (not rawValue(arc,67)):
00730 shape = drawArc(arc)
00731 if shape:
00732 if fmt.join:
00733 if isinstance(shape,Part.Shape):
00734 shapes.append(shape)
00735 else:
00736 shapes.append(shape.Shape)
00737 elif fmt.makeBlocks:
00738 if isinstance(shape,Part.Shape):
00739 addToBlock(shape,arc.layer)
00740 else:
00741 addToBlock(shape.Shape,arc.layer)
00742 else:
00743 newob = addObject(shape,"Arc",arc.layer)
00744 if gui: fmt.formatObject(newob,arc)
00745
00746
00747
00748 if fmt.join and shapes:
00749 FreeCAD.Console.PrintMessage("Joining geometry...\n")
00750 edges = []
00751 for s in shapes:
00752 edges.extend(s.Edges)
00753 shapes = fcgeo.findWires(edges)
00754 for s in shapes:
00755 newob = addObject(s)
00756
00757
00758
00759 circles = drawing.entities.get_type("circle")
00760 if circles: FreeCAD.Console.PrintMessage("drawing "+str(len(circles))+" circles...\n")
00761 for circle in circles:
00762 if fmt.dxflayout or (not rawValue(circle,67)):
00763 shape = drawCircle(circle)
00764 if shape:
00765 if fmt.makeBlocks:
00766 if isinstance(shape,Part.Shape):
00767 addToBlock(shape,circle.layer)
00768 else:
00769 addToBlock(shape.Shape,circle.layer)
00770 else:
00771 newob = addObject(shape,"Circle",circle.layer)
00772 if gui: fmt.formatObject(newob,circle)
00773
00774
00775
00776 solids = drawing.entities.get_type("solid")
00777 if solids: FreeCAD.Console.PrintMessage("drawing "+str(len(circles))+" solids...\n")
00778 for solid in solids:
00779 lay = rawValue(solid,8)
00780 if fmt.dxflayout or (not rawValue(solid,67)):
00781 shape = drawSolid(solid)
00782 if shape:
00783 if fmt.makeBlocks:
00784 if isinstance(shape,Part.Shape):
00785 addToBlock(shape,lay)
00786 else:
00787 addToBlock(shape.Shape,lay)
00788 else:
00789 newob = addObject(shape,"Solid",lay)
00790 if gui: fmt.formatObject(newob,solid)
00791
00792
00793
00794 splines = drawing.entities.get_type("spline")
00795 if splines: FreeCAD.Console.PrintMessage("drawing "+str(len(splines))+" splines...\n")
00796 for spline in splines:
00797 lay = rawValue(spline,8)
00798 if fmt.dxflayout or (not rawValue(spline,67)):
00799 shape = drawSpline(spline)
00800 if shape:
00801 if fmt.makeBlocks:
00802 if isinstance(shape,Part.Shape):
00803 addToBlock(shape,lay)
00804 else:
00805 addToBlock(shape.Shape,lay)
00806 else:
00807 newob = addObject(shape,"Spline",lay)
00808 if gui: fmt.formatObject(newob,spline)
00809
00810
00811
00812 if fmt.paramtext:
00813 texts = drawing.entities.get_type("mtext")
00814 texts.extend(drawing.entities.get_type("text"))
00815 if texts: FreeCAD.Console.PrintMessage("drawing "+str(len(texts))+" texts...\n")
00816 for text in texts:
00817 if fmt.dxflayout or (not rawValue(text,67)):
00818 addText(text)
00819
00820 else: FreeCAD.Console.PrintMessage("skipping texts...\n")
00821
00822
00823
00824 faces3d = drawing.entities.get_type("3dface")
00825 if faces3d: FreeCAD.Console.PrintMessage("drawing "+str(len(faces3d))+" 3dfaces...\n")
00826 for face3d in faces3d:
00827 shape = drawFace(face3d)
00828 if shape:
00829 newob = addObject(shape,"Face",face3d.layer)
00830 if gui: fmt.formatObject(newob,face3d)
00831 if meshes: FreeCAD.Console.PrintMessage("drawing "+str(len(meshes))+" 3dmeshes...\n")
00832 for mesh in meshes:
00833 me = drawMesh(mesh)
00834 if me:
00835 newob = doc.addObject("Mesh::Feature","Mesh")
00836 lay = locateLayer(rawValue(mesh,8))
00837 lay.addObject(newob)
00838 newob.Mesh = me
00839 if gui: fmt.formatObject(newob,mesh)
00840
00841
00842
00843 if fmt.paramtext:
00844 dims = drawing.entities.get_type("dimension")
00845 FreeCAD.Console.PrintMessage("drawing "+str(len(dims))+" dimensions...\n")
00846 for dim in dims:
00847 if fmt.dxflayout or (not rawValue(dim,67)):
00848 try:
00849 layer = rawValue(dim,8)
00850 x1 = float(rawValue(dim,10))
00851 y1 = float(rawValue(dim,20))
00852 z1 = float(rawValue(dim,30))
00853 x2 = float(rawValue(dim,13))
00854 y2 = float(rawValue(dim,23))
00855 z2 = float(rawValue(dim,33))
00856 x3 = float(rawValue(dim,14))
00857 y3 = float(rawValue(dim,24))
00858 z3 = float(rawValue(dim,34))
00859 d = rawValue(dim,70)
00860 if d: align = int(d)
00861 else: align = 0
00862 d = rawValue(dim,50)
00863 if d: angle = float(d)
00864 else: angle = 0
00865 except:
00866 warn(dim)
00867 else:
00868 lay=locateLayer(layer)
00869 pt = FreeCAD.Vector(x1,y1,z1)
00870 p1 = FreeCAD.Vector(x2,y2,z2)
00871 p2 = FreeCAD.Vector(x3,y3,z3)
00872 if align == 0:
00873 if angle == 0:
00874 p2 = FreeCAD.Vector(x3,y2,z2)
00875 else:
00876 p2 = FreeCAD.Vector(x2,y3,z2)
00877 newob = doc.addObject("App::FeaturePython","Dimension")
00878 lay.addObject(newob)
00879 Dimension(newob)
00880 ViewProviderDimension(newob.ViewObject)
00881 newob.Start = p1
00882 newob.End = p2
00883 newob.Dimline = pt
00884 if gui:
00885 dim.layer = layer
00886 dim.color_index = 256
00887 fmt.formatObject (newob,dim)
00888
00889 else: FreeCAD.Console.PrintMessage("skipping dimensions...\n")
00890
00891
00892
00893 inserts = drawing.entities.get_type("insert")
00894 if not fmt.paramstarblocks:
00895 FreeCAD.Console.PrintMessage("skipping *blocks...\n")
00896 newinserts = []
00897 for i in inserts:
00898 if fmt.dxflayout or (not rawValue(i,67)):
00899 if i.block[0] != '*':
00900 newinserts.append(i)
00901 inserts = newinserts
00902 if inserts:
00903 FreeCAD.Console.PrintMessage("drawing "+str(len(inserts))+" blocks...\n")
00904 blockrefs = drawing.blocks.data
00905 for ref in blockrefs:
00906 drawBlock(ref)
00907 for insert in inserts:
00908 shape = drawInsert(insert)
00909 if shape:
00910 if fmt.makeBlocks:
00911 if isinstance(shape,Part.Shape):
00912 addToBlock(shape,block.layer)
00913 else:
00914 addToBlock(shape.Shape,block.layer)
00915 else:
00916 newob = addObject(shape,"Block."+insert.block,insert.layer)
00917 if gui: fmt.formatObject(newob,insert)
00918
00919
00920
00921 if fmt.makeBlocks:
00922 for k,l in layerBlocks.iteritems():
00923 shape = drawLayerBlock(l)
00924 if shape:
00925 newob = addObject(shape,k)
00926 del layerBlocks
00927
00928
00929
00930 doc.recompute()
00931 FreeCAD.Console.PrintMessage("successfully imported "+filename+"\n")
00932 if badobjects: print "dxf: ",len(badobjects)," objects were not imported"
00933 del fmt
00934 del doc
00935 del blockshapes
00936
00937 def warn(dxfobject):
00938 "outputs a warning if a dxf object couldn't be imported"
00939 print "dxf: couldn't import ", dxfobject
00940 badobjects.append(dxfobject)
00941
00942 def open(filename):
00943 "called when freecad opens a file."
00944 docname = os.path.splitext(os.path.basename(filename))[0]
00945 doc = FreeCAD.newDocument(docname)
00946 doc.Label = decodeName(docname)
00947 processdxf(doc,filename)
00948 return doc
00949
00950 def insert(filename,docname):
00951 "called when freecad imports a file"
00952 groupname = os.path.splitext(os.path.basename(filename))[0]
00953 try:
00954 doc=FreeCAD.getDocument(docname)
00955 except:
00956 doc=FreeCAD.newDocument(docname)
00957 importgroup = doc.addObject("App::DocumentObjectGroup",groupname)
00958 importgroup.Label = decodeName(groupname)
00959 processdxf(doc,filename)
00960 for l in layers:
00961 importgroup.addObject(l)
00962
00963
00964
00965
00966 def getArcData(edge):
00967 "returns center, radius, start and end angles of a circle-based edge"
00968 ce = edge.Curve.Center
00969 radius = edge.Curve.Radius
00970 if len(edge.Vertexes) == 1:
00971
00972 return ce, radius, 0, 0
00973 else:
00974
00975 tang1 = edge.Curve.tangent(edge.ParameterRange[0])
00976 tang2 = edge.Curve.tangent(edge.ParameterRange[1])
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988 ve1 = edge.Vertexes[0].Point
00989 ve2 = edge.Vertexes[-1].Point
00990 ang1 = -math.degrees(fcvec.angle(ve1.sub(ce)))
00991 ang2 = -math.degrees(fcvec.angle(ve2.sub(ce)))
00992 ve3 = fcgeo.findMidpoint(edge)
00993 ang3 = -math.degrees(fcvec.angle(ve3.sub(ce)))
00994 if (ang3 < ang1) and (ang2 < ang3):
00995 ang1, ang2 = ang2, ang1
00996 return fcvec.tup(ce), radius, ang1, ang2
00997
00998 def getSplineSegs(edge):
00999 "returns an array of vectors from a bSpline edge"
01000 params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
01001 seglength = params.GetInt("maxsplinesegment")
01002 points = []
01003 if seglength == 0:
01004 points.append(edge.Vertexes[0].Point)
01005 points.append(edge.Vertexes[-1].Point)
01006 else:
01007 l = edge.Length
01008 points.append(edge.valueAt(0))
01009 if l > seglength:
01010 nbsegs = int(math.ceil(l/seglength))
01011 step = l/nbsegs
01012 for nv in range(1,nbsegs):
01013 v = edge.valueAt(nv*step)
01014 points.append(v)
01015 points.append(edge.valueAt(edge.Length))
01016 return points
01017
01018 def getWire(wire,nospline=False):
01019 "returns an array of dxf-ready points and bulges from a wire"
01020 edges = fcgeo.sortEdges(wire.Edges)
01021 points = []
01022 for edge in edges:
01023 v1 = edge.Vertexes[0].Point
01024 if (isinstance(edge.Curve,Part.Circle)):
01025 mp = fcgeo.findMidpoint(edge)
01026 v2 = edge.Vertexes[-1].Point
01027 c = edge.Curve.Center
01028 angle = abs(fcvec.angle(v1.sub(c),v2.sub(c)))
01029
01030
01031
01032 bul = math.tan(angle/4)
01033
01034
01035 tang1 = edge.Curve.tangent(edge.ParameterRange[0])
01036 tang2 = edge.Curve.tangent(edge.ParameterRange[1])
01037 cross1 = Vector.cross(Vector(tang1[0][0],tang1[0][1],tang1[0][2]),Vector(tang2[0][0],tang2[0][1],tang2[0][2]))
01038 if cross1[2] < 0:
01039
01040 bul = -bul
01041 points.append((v1.x,v1.y,v1.z,None,None,bul))
01042 elif (isinstance(edge.Curve,Part.BSplineCurve)) and (not nospline):
01043 bul = 0.0
01044 spline = getSplineSegs(edge)
01045 spline.pop()
01046 for p in spline:
01047 points.append((p.x,p.y,p.z,None,None,bul))
01048 else:
01049 bul = 0.0
01050 points.append((v1.x,v1.y,v1.z,None,None,bul))
01051 if not fcgeo.isReallyClosed(wire):
01052 v = edges[-1].Vertexes[-1].Point
01053 points.append(fcvec.tup(v))
01054
01055 return points
01056
01057 def getBlock(obj):
01058 "returns a dxf block with the contents of the object"
01059 block = dxfLibrary.Block(name=obj.Name,layer=getGroup(obj,exportList))
01060 writeShape(obj,block)
01061 return block
01062
01063 def writeShape(ob,dxfobject,nospline=False):
01064 "writes the object's shape contents in the given dxf object"
01065 processededges = []
01066 for wire in ob.Shape.Wires:
01067 for e in wire.Edges:
01068 processededges.append(e.hashCode())
01069 if (len(wire.Edges) == 1) and isinstance(wire.Edges[0].Curve,Part.Circle):
01070 center, radius, ang1, ang2 = getArcData(wire.Edges[0])
01071 if len(wire.Edges[0].Vertexes) == 1:
01072 dxfobject.append(dxfLibrary.Circle(center, radius,
01073 color=getACI(ob),
01074 layer=getGroup(ob,exportList)))
01075 else:
01076 dxfobject.append(dxfLibrary.Arc(center, radius,
01077 ang1, ang2, color=getACI(ob),
01078 layer=getGroup(ob,exportList)))
01079 else:
01080 dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline), [0.0,0.0,0.0],
01081 int(fcgeo.isReallyClosed(wire)), color=getACI(ob),
01082 layer=getGroup(ob,exportList)))
01083 if len(processededges) < len(ob.Shape.Edges):
01084 loneedges = []
01085 for e in ob.Shape.Edges:
01086 if not(e.hashCode() in processededges): loneedges.append(e)
01087
01088 for edge in loneedges:
01089 if (isinstance(edge.Curve,Part.BSplineCurve)) and ((not nospline) or (len(edge.Vertexes) == 1)):
01090 points = []
01091 spline = getSplineSegs(edge)
01092 for p in spline:
01093 points.append((p.x,p.y,p.z,None,None,0.0))
01094 dxfobject.append(dxfLibrary.PolyLine(points, [0.0,0.0,0.0],
01095 0, color=getACI(ob),
01096 layer=getGroup(ob,exportList)))
01097 elif isinstance(edge.Curve,Part.Circle):
01098 center, radius, ang1, ang2 = getArcData(edge)
01099 if len(edge.Vertexes) == 1:
01100 dxfobject.append(dxfLibrary.Circle(center, radius,
01101 color=getACI(ob),
01102 layer=getGroup(ob,exportList)))
01103 else :
01104 dxfobject.append(dxfLibrary.Arc(center, radius,
01105 ang1, ang2, color=getACI(ob),
01106 layer=getGroup(ob,exportList)))
01107 else:
01108 ve1=edge.Vertexes[0].Point
01109 ve2=edge.Vertexes[1].Point
01110 dxfobject.append(dxfLibrary.Line([fcvec.tup(ve1), fcvec.tup(ve2)],
01111 color=getACI(ob),
01112 layer=getGroup(ob,exportList)))
01113
01114 def writeMesh(ob,dxfobject):
01115 "export a shape as a polyface mesh"
01116 meshdata = ob.Shape.tessellate(0.5)
01117
01118 points = []
01119 faces = []
01120 for p in meshdata[0]:
01121 points.append([p.x,p.y,p.z])
01122 for f in meshdata[1]:
01123 faces.append([f[0]+1,f[1]+1,f[2]+1])
01124
01125 dxfobject.append(dxfLibrary.PolyLine([points,faces], [0.0,0.0,0.0],
01126 64, color=getACI(ob),
01127 layer=getGroup(ob,exportList)))
01128
01129 def export(objectslist,filename,nospline=False):
01130 "called when freecad exports a file. If nospline=True, bsplines are exported as straight segs"
01131 global exportList
01132 exportList = objectslist
01133 dxf = dxfLibrary.Drawing()
01134 if (len(exportList) == 1) and (exportList[0].isDerivedFrom("Drawing::FeaturePage")):
01135 exportPage(exportList[0],filename)
01136 return
01137 for ob in exportList:
01138 print "processing ",ob.Name
01139 if ob.isDerivedFrom("Part::Feature"):
01140 if not ob.Shape.isNull():
01141 if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"):
01142 writeMesh(ob,dxf)
01143 else:
01144 if ob.Shape.ShapeType == 'Compound':
01145 if (len(ob.Shape.Wires) == 1):
01146
01147 if (len(ob.Shape.Wires[0].Edges) == len(ob.Shape.Edges)):
01148 writeShape(ob,dxf,nospline)
01149 else:
01150
01151 block = getBlock(ob)
01152 dxf.blocks.append(block)
01153 dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
01154 else:
01155
01156 block = getBlock(ob)
01157 dxf.blocks.append(block)
01158 dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
01159 else:
01160 writeShape(ob,dxf,nospline)
01161
01162 elif (ob.Type == "App::Annotation"):
01163
01164
01165
01166
01167
01168 for text in ob.LabelText:
01169 point = fcvec.tup(FreeCAD.Vector(ob.Position.x,
01170 ob.Position.y-ob.LabelText.index(text),
01171 ob.Position.z))
01172 if gui: height = float(ob.ViewObject.FontSize)
01173 else: height = 1
01174 dxf.append(dxfLibrary.Text(text,point,height=height,
01175 color=getACI(ob,text=True),
01176 style='STANDARD',
01177 layer=getGroup(ob,exportList)))
01178
01179 elif 'Dimline' in ob.PropertiesList:
01180 p1 = fcvec.tup(ob.Start)
01181 p2 = fcvec.tup(ob.End)
01182 base = Part.Line(ob.Start,ob.End).toShape()
01183 proj = fcgeo.findDistance(ob.Dimline,base)
01184 if not proj:
01185 pbase = fcvec.tup(ob.End)
01186 else:
01187 pbase = fcvec.tup(ob.End.add(fcvec.neg(proj)))
01188 dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob),
01189 layer=getGroup(ob,exportList)))
01190
01191 dxf.saveas(filename)
01192 FreeCAD.Console.PrintMessage("successfully exported "+filename+"\r\n")
01193
01194 def exportPage(page,filename):
01195 "special export for pages"
01196 import importSVG
01197 tempdoc = importSVG.open(page.PageResult)
01198 tempobj = tempdoc.Objects
01199 export(tempobj,filename,nospline=True)
01200 FreeCAD.closeDocument(tempdoc.Name)
01201
01202
01203
01204
01205
01206
01207