Draft - Allow to export Drawing pages to DXF - fixes #1686

* Uses DXF algos of the Drawing module instead of the Draft dxf library
* Uses a DXF template with the same name as the SVG template, if existing
* Only Draft, Arch, Part and Annotation views are currently supported
* Drawing module's projectToDXF() now returns only a fragment instead of a full DXF file
This commit is contained in:
Yorik van Havre
2014-08-15 18:14:17 -03:00
parent 4dc12740e8
commit b33d8f6244
10 changed files with 35073 additions and 263 deletions

View File

@@ -348,14 +348,14 @@ def getCutVolume(cutplane,shapes):
else:
p = cutplane.copy().Faces[0]
except:
FreeCAD.Console.PrintMessage(translate("Arch","Invalid cutplane"))
FreeCAD.Console.PrintMessage(translate("Arch","Invalid cutplane\n"))
return None,None,None
ce = p.CenterOfMass
ax = p.normalAt(0,0)
u = p.Vertexes[1].Point.sub(p.Vertexes[0].Point).normalize()
v = u.cross(ax)
if not bb.isCutPlane(ce,ax):
FreeCAD.Console.PrintMessage(translate("Arch","No objects are cut by the plane"))
FreeCAD.Console.PrintMessage(translate("Arch","No objects are cut by the plane\n"))
return None,None,None
else:
corners = [FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin),

View File

@@ -377,6 +377,7 @@ class _ArchDrawingView:
self.svg += svgf
if hshapes:
hshapes = Part.makeCompound(hshapes)
self.hiddenshape = hshapes
svgh = Drawing.projectToSVG(hshapes,self.direction)
if svgh:
svgh = svgh.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"')
@@ -386,6 +387,7 @@ class _ArchDrawingView:
self.svg += svgh
if sshapes:
sshapes = Part.makeCompound(sshapes)
self.sectionshape = sshapes
svgs = Drawing.projectToSVG(sshapes,self.direction)
if svgs:
svgs = svgs.replace('stroke-width="0.35"','stroke-width="SWPlaceholder"')
@@ -407,26 +409,26 @@ class _ArchDrawingView:
def setDisplayMode(self,mode):
return mode
def getFlatShape(self):
"returns a flat shape representation of the view"
def getDXF(self,obj):
"returns a DXF representation of the view"
if obj.RenderingMode == "Solid":
print "Unable to get DXF from Solid mode: ",obj.Label
return ""
result = []
import Drawing
if not hasattr(self,"baseshape"):
self.onChanged(obj,"Source")
if hasattr(self,"baseshape"):
import Drawing
[V0,V1,H0,H1] = Drawing.project(self.baseshape,self.direction)
return V0.Edges+V1.Edges
else:
FreeCAD.Console.PrintMessage(translate("Arch","No shape has been computed yet, select wireframe rendering and render again"))
return None
if self.baseshape:
result.append(Drawing.projectToDXF(self.baseshape,self.direction))
if hasattr(self,"sectionshape"):
if self.sectionshape:
result.append(Drawing.projectToDXF(self.sectionshape,self.direction))
if hasattr(self,"hiddenshape"):
if self.hiddenshape:
result.append(Drawing.projectToDXF(self.hiddenshape,self.direction))
return result
def getDXF(self):
"returns a flat shape representation of the view"
if hasattr(self,"baseshape"):
import Drawing
[V0,V1,H0,H1] = Drawing.project(self.baseshape,self.direction)
DxfOutput = Drawing.projectToDXF(self.baseshape,self.direction)
return DxfOutput
else:
FreeCAD.Console.PrintMessage(translate("Arch","No shape has been computed yet, select wireframe rendering and render again"))
return None
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Arch_SectionPlane',_CommandSectionPlane())

View File

@@ -1594,6 +1594,55 @@ def draftify(objectslist,makeblock=False,delete=True):
if len(newobjlist) == 1:
return newobjlist[0]
return newobjlist
def getDXF(obj,direction=None):
'''getDXF(object,[direction]): returns a DXF entity from the given
object. If direction is given, the object is projected in 2D.'''
plane = None
result = ""
if direction:
if isinstance(direction,FreeCAD.Vector):
if direction != Vector(0,0,0):
plane = WorkingPlane.plane()
plane.alignToPointAndAxis(Vector(0,0,0),direction)
def getProj(vec):
if not plane: return vec
nx = DraftVecUtils.project(vec,plane.u)
ny = DraftVecUtils.project(vec,plane.v)
return Vector(nx.Length,ny.Length,0)
if getType(obj) == "Dimension":
p1 = getProj(obj.Start)
p2 = getProj(obj.End)
p3 = getProj(obj.Dimline)
result += "0\nDIMENSION\n8\n0\n62\n0\n3\nStandard\n70\n1\n"
result += "10\n"+str(p3.x)+"\n20\n"+str(p3.y)+"\n30\n"+str(p3.z)+"\n"
result += "13\n"+str(p1.x)+"\n23\n"+str(p1.y)+"\n33\n"+str(p1.z)+"\n"
result += "14\n"+str(p2.x)+"\n24\n"+str(p2.y)+"\n34\n"+str(p2.z)+"\n"
elif getType(obj) == "Annotation":
p = getProj(obj.Position)
count = 0
for t in obj.LabeLtext:
result += "0\nTEXT\n8\n0\n62\n0\n"
result += "10\n"+str(p.x)+"\n20\n"+str(p.y+count)+"\n30\n"+str(p.z)+"\n"
result += "40\n1\n"
result += "1\n"+str(t)+"\n"
result += "7\nSTANDARD\n"
count += 1
elif obj.isDerivedFrom("Part::Feature"):
# TODO do this the Draft way, for ex. using polylines and rectangles
import Drawing
if not direction: direction = FreeCAD.Vector(0,0,-1)
result += Drawing.projectToDXF(obj.Shape,direction)
else:
print "Draft.getDXF: Unsupported object: ",obj.Label
return result
def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direction=None,linestyle=None,color=None):
'''getSVG(object,[scale], [linewidth],[fontsize],[fillstyle],[direction],[linestyle],[color]):
@@ -4133,6 +4182,17 @@ class _DrawingView(_DraftObject):
result += svg
result += '</g>'
obj.ViewResult = result
def getDXF(self,obj):
"returns a DXF fragment"
result = ""
if obj.Source.isDerivedFrom("App::DocumentObjectGroup"):
for o in obj.Source.Group:
if o.ViewObject.isVisible():
result += getDXF(o,obj.Direction)
else:
result += getDXF(o,obj.Direction)
return result
class _BSpline(_DraftObject):
"The BSpline object"

View File

@@ -112,7 +112,7 @@ class plane:
t.multiply(self.offsetToPoint(p, direction))
return p.add(t)
def alignToPointAndAxis(self, point, axis, offset, upvec=None):
def alignToPointAndAxis(self, point, axis, offset=0, upvec=None):
self.doc = FreeCAD.ActiveDocument
self.axis = axis;
self.axis.normalize()

View File

@@ -1666,8 +1666,112 @@ def export(objectslist,filename,nospline=False,lwPoly=False):
dxf.saveas(filename)
FreeCAD.Console.PrintMessage("successfully exported "+filename+"\r\n")
def exportPage(page,filename):
"special export for pages"
template = os.path.splitext(page.Template)[0]+".dxf"
global dxfhandle
dxfhandle = 1
if os.path.exists(template):
f = pythonopen(template,"rb")
template = f.read()
f.close()
# find & replace editable texts
import re
f = pythonopen(page.Template,"rb")
svgtemplate = f.read()
f.close()
editables = re.findall("freecad:editable=\"(.*?)\"",svgtemplate)
values = page.EditableTexts
for i in range(len(editables)):
if len(values) > i:
template = template.replace(editables[i],values[i])
else:
# dummy default template
print "DXF version of the template not found. Creating a default empty template."
template = "999\nFreeCAD DXF exporter v"+FreeCAD.Version()[0]+"."+FreeCAD.Version()[1]+"-"+FreeCAD.Version()[2]+"\n"
template += "0\nSECTION\n2\nHEADER\n9\n$ACADVER\n1\nAC1009\n0\nENDSEC\n"
template += "0\nSECTION\n2\nBLOCKS\n$blocks\n0\nENDSEC\n"
template += "0\nSECTION\n2\nENTITIES\n$entities\n0\nENDSEC\n"
template += "0\nEOF"
blocks = ""
entities = ""
for view in page.Group:
b,e = getViewDXF(view)
blocks += b
entities += e
result = template.replace("$blocks",blocks[:-1])
result = result.replace("$entities",entities[:-1])
f = pythonopen(filename,"wb")
f.write(result)
f.close()
def getViewDXF(view):
"returns a DXF fragment from a Drawing View"
global dxfhandle
block = ""
insert = ""
if view.isDerivedFrom("App::DocumentObjectGroup"):
for child in view.Group:
b,e = getViewDXF(child)
block += b
insert += e
elif view.isDerivedFrom("Drawing::FeatureViewPython"):
if hasattr(view.Proxy,"getDXF"):
r = view.Rotation
if r != 0: r = -r # fix rotation direction
count = 0
block = ""
insert = ""
geom = view.Proxy.getDXF(view)
if not isinstance(geom,list): geom = [geom]
for g in geom: # getDXF returns a list of entities
g = g.replace("sheet_layer\n","0\n6\nBYBLOCK\n62\n0\n") # change layer and set color and ltype to BYBLOCK (0)
block += "0\nBLOCK\n8\n0\n2\n"+view.Name+str(count)+"\n70\n0\n10\n0\n20\n0\n3\n"+view.Name+str(count)+"\n1\n\n"
block += g
block += "0\nENDBLK\n8\n0\n"
insert += "0\nINSERT\n5\naaaa"+hex(dxfhandle)[2:]+"\n8\n0\n6\nBYLAYER\n62\n256\n2\n"+view.Name+str(count)
insert += "\n10\n"+str(view.X)+"\n20\n"+str(-view.Y)
insert += "\n30\n0\n41\n"+str(view.Scale)+"\n42\n"+str(view.Scale)+"\n43\n"+str(view.Scale)
insert += "\n50\n"+str(r)+"\n"
dxfhandle += 1
count += 1
elif view.isDerivedFrom("Drawing::FeatureViewPart"):
r = view.Rotation
if r != 0: r = -r # fix rotation direction
import Drawing
proj = Drawing.projectToDXF(view.Source.Shape,view.Direction)
proj = proj.replace("sheet_layer\n","0\n6\nBYBLOCK\n62\n0\n") # change layer and set color and ltype to BYBLOCK (0)
block = "0\nBLOCK\n8\n0\n2\n"+view.Name+"\n70\n0\n10\n0\n20\n0\n3\n"+view.Name+"\n1\n\n"
block += proj
block += "0\nENDBLK\n8\n0\n"
insert = "0\nINSERT\n5\naaaa"+hex(dxfhandle)[2:]+"\n8\n0\n6\nBYLAYER\n62\n256\n2\n"+view.Name
insert += "\n10\n"+str(view.X)+"\n20\n"+str(-view.Y)
insert += "\n30\n0\n41\n"+str(view.Scale)+"\n42\n"+str(view.Scale)+"\n43\n"+str(view.Scale)
insert += "\n50\n"+str(r)+"\n"
dxfhandle += 1
elif view.isDerivedFrom("Drawing::FeatureViewAnnotation"):
r = view.Rotation
if r != 0: r = -r # fix rotation direction
insert ="0\nTEXT\n5\n"+hex(dxfhandle)[2:]+"\n8\n0"
insert += "\n10\n"+str(view.X)+"\n20\n"+str(-view.Y)
insert += "\n30\n0\n40\n"+str(view.Scale/2)
insert += "\n50\n"+str(r)
insert += "\n1\n"+view.Text[0]+"\n"
dxfhandle += 1
else:
print "Unable to get DXF representation from view: ",view.Label
return block,insert
def exportPageLegacy(page,filename):
"exports the given page the old way, by converting its SVG code to DXF with the Draft module"
import importSVG
tempdoc = importSVG.open(page.PageResult)
tempobj = tempdoc.Objects

View File

@@ -273,113 +273,36 @@ std::string ProjectionAlgos::getDXF(ExtractionType type, double scale, double to
std::stringstream result;
DXFOutput output;
result << "0" << endl
<< "SECTION" << endl
<< "2" << endl
<< "ENTITIES" << endl;
if (!H.IsNull() && (type & WithHidden)) {
//float width = 0.15f/scale;
BRepMesh_IncrementalMesh(H,tolerance);
result //<< "<g"
//<< " id=\"" << ViewName << "\"" << endl
/*<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " stroke-dasharray=\"5 3\"" << endl
<< " fill=\"none\"" << endl
<< " >" << endl*/
<< output.exportEdges(H);
//<< "</g>" << endl;
result << output.exportEdges(H);
}
if (!HO.IsNull() && (type & WithHidden)) {
//float width = 0.15f/scale;
BRepMesh_IncrementalMesh(HO,tolerance);
result //<< "<g"
//<< " id=\"" << ViewName << "\"" << endl
/*<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " stroke-dasharray=\"5 3\"" << endl
<< " fill=\"none\"" << endl
<< " >" << endl*/
<< output.exportEdges(HO);
//<< "</g>" << endl;
result << output.exportEdges(HO);
}
if (!VO.IsNull()) {
//float width = 0.35f/scale;
BRepMesh_IncrementalMesh(VO,tolerance);
result //<< "<g"
//<< " id=\"" << ViewName << "\"" << endl
/*<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " fill=\"none\"" << endl
<< " >" << endl*/
<< output.exportEdges(VO);
//<< "</g>" << endl;
result << output.exportEdges(VO);
}
if (!V.IsNull()) {
//float width = 0.35f/scale;
BRepMesh_IncrementalMesh(V,tolerance);
result //<< "<g"
//<< " id=\"" << ViewName << "\"" << endl
/*<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " fill=\"none\"" << endl
<< " >" << endl*/
<< output.exportEdges(V);
//<< "</g>" << endl;
result << output.exportEdges(V);
}
if (!V1.IsNull() && (type & WithSmooth)) {
//float width = 0.35f/scale;
BRepMesh_IncrementalMesh(V1,tolerance);
result //<< "<g"
//<< " id=\"" << ViewName << "\"" << endl
/* << " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " fill=\"none\"" << endl
<< " >" << endl*/
<< output.exportEdges(V1);
//<< "</g>" << endl;
result << output.exportEdges(V1);
}
if (!H1.IsNull() && (type & WithSmooth) && (type & WithHidden)) {
//float width = 0.15f/scale;
BRepMesh_IncrementalMesh(H1,tolerance);
result //<< "<g"
//<< " id=\"" << ViewName << "\"" << endl
/*<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " stroke-dasharray=\"5 3\"" << endl
<< " fill=\"none\"" << endl
<< " >" << endl*/
<< output.exportEdges(H1);
//<< "</g>" << endl;
result << output.exportEdges(H1);
}
result << 0 << endl
<< "ENDSEC" << endl
<< 0 << endl
<< "EOF";
return result.str();
}

View File

@@ -20,5 +20,7 @@ INSTALL(
Templates
DESTINATION
${CMAKE_INSTALL_DATADIR}/Mod/Drawing
FILES_MATCHING PATTERN "*.svg*"
FILES_MATCHING
PATTERN "*.svg*"
PATTERN "*.dxf*"
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 75 KiB