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:
@@ -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),
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -20,5 +20,7 @@ INSTALL(
|
||||
Templates
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_DATADIR}/Mod/Drawing
|
||||
FILES_MATCHING PATTERN "*.svg*"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.svg*"
|
||||
PATTERN "*.dxf*"
|
||||
)
|
||||
|
||||
15822
src/Mod/Drawing/Templates/A3_Landscape.dxf
Normal file
15822
src/Mod/Drawing/Templates/A3_Landscape.dxf
Normal file
File diff suppressed because it is too large
Load Diff
18982
src/Mod/Drawing/Templates/A4_Landscape.dxf
Normal file
18982
src/Mod/Drawing/Templates/A4_Landscape.dxf
Normal file
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 |
Reference in New Issue
Block a user