Help with creating macro for export to DXF and SVG.

Post here for help on using FreeCAD's graphical user interface (GUI).
Forum rules
and Helpful information
IMPORTANT: Please click here and read this first, before asking for help

Also, be nice to others! Read the FreeCAD code of conduct!
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Help with creating macro for export to DXF and SVG.

Post by triplus »

I could be wrong but it looks like importDXF.py is not getting what it wants. If you copy/paste this in Python console when at least one document is opened:

Code: Select all

FreeCADGui.ActiveDocument.ActiveView.getViewDirection()
What does it return? I tested macro on FreeCAD stable and dev PPA on Ubuntu and it works and your version is just a bit newer than what Ubuntu has on PPA stable and maybe there was a change/commit to FreeCAD that is responsible for this and was later on reverted/fixed (probably Yorik will know more about this).
User avatar
ralvejd
Posts: 58
Joined: Wed Feb 20, 2013 10:31 pm
Location: Sweden

Re: Help with creating macro for export to DXF and SVG.

Post by ralvejd »

If you select object in tree view and run standalone macro or just copy/paste in Python console does it work:

import os
homepath = os.path.expanduser("~")
selection = FreeCADGui.Selection.getSelection()
obj = selection[0]
filename = homepath + os.sep + obj.Name + ".dxf"
import importDXF
importDXF.export(selection,filename)
This output a dxf file
I could be wrong but it looks like importDXF.py is not getting what it wants. If you copy/paste this in Python console when at least one document is opened:
It return:
>>> FreeCADGui.ActiveDocument.ActiveView.getViewDirection()
Vector (0.0, 0.0, -1.0)
>>>
sorry for my outrageous English, but I have a bad excuse
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Help with creating macro for export to DXF and SVG.

Post by triplus »

Does this work too:

Code: Select all

import os
homepath = os.path.expanduser("~")
selection = FreeCADGui.Selection.getSelection()
obj = selection[0]
filename = homepath + os.sep + obj.Label.encode("utf-8") + ".dxf"
import importDXF
importDXF.export(selection,filename)
P.S. What about selecting object in tree view and copy/paste the macro in the Python console.
User avatar
ralvejd
Posts: 58
Joined: Wed Feb 20, 2013 10:31 pm
Location: Sweden

Re: Help with creating macro for export to DXF and SVG.

Post by ralvejd »

Does this work too:
Yes
P.S. What about selecting object in tree view and copy/paste the macro in the Python console.
No, the macro never completes, seem to stop on the last line.
sorry for my outrageous English, but I have a bad excuse
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Help with creating macro for export to DXF and SVG.

Post by triplus »

Yes
Interesting then i guess the whole macro should work too. Do you have the macro saved in a macro folder set in FreeCAD preferences?
No, the macro never completes, seem to stop on the last line.
Yes just press enter at the last line and it will complete.
User avatar
ralvejd
Posts: 58
Joined: Wed Feb 20, 2013 10:31 pm
Location: Sweden

Re: Help with creating macro for export to DXF and SVG.

Post by ralvejd »

Interesting then i guess the whole macro should work too. Do you have the macro saved in a macro folder set in FreeCAD preferences?
Macro path is set like this
Edit
..Prefrerences
....General
......Macro
........Macro path
/home/isak/Dokument/9_Projekt/cad/FeeCAD/Macro
And the macro filename
/home/isak/Dokument/9_Projekt/cad/FeeCAD/Macro/ExoprtDxfSvg.FCMacro
Yes just press enter at the last line and it will complete.
No, nothing happens, but if I type a character and then press [ENTER] then it will throw me out with an error. I guess there are proper ways to quit, but I have not been searching.

I guess the error is to be found in the "Traceback"
Traceback (most recent call last):
File "/home/isak/Dokument/9_Projekt/cad/FeeCAD/Macro/ExoprtDxfSvg.FCMacro", line 303, in <module>
importDXF.export(selection,filename)
File "/usr/Mod/Draft/importDXF.py", line 1449, in export
direction = FreeCADGui.ActiveDocument.ActiveView.getViewDirection()
<type 'exceptions.AttributeError'>: 'NoneType' object has no attribute 'getViewDirection'
A small part of the code File "/usr/Mod/Draft/importDXF.py", line 1449 (The line markt "LINE1449)

Code: Select all

def export(objectslist,filename,nospline=False):
    "called when freecad exports a file. If nospline=True, bsplines are exported as straight segs"
    global exportList
    exportList = objectslist

    if (len(exportList) == 1) and (Draft.getType(exportList[0]) == "ArchSectionView"):
        # arch view: export it "as is"
        dxf = exportList[0].Proxy.getDXF()
        if dxf:
            f = open(filename,"w")
            f.write(dxf)
            f.close()

    elif (len(exportList) == 1) and (exportList[0].isDerivedFrom("Drawing::FeaturePage")):
        # page: special hack-export! (see below)
        exportPage(exportList[0],filename)

    else:
        # other cases, treat edges
        dxf = dxfLibrary.Drawing()
        for ob in exportList:
            print "processing ",ob.Name
            if ob.isDerivedFrom("Part::Feature"):
                if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"):
                    sh = None
                    if not ob.Shape.isNull():
                        writeMesh(ob,dxf)
                elif FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfproject"):
LINE1449                    direction = FreeCADGui.ActiveDocument.ActiveView.getViewDirection()                    LINE1449 
                    sh = projectShape(ob.Shape,direction)
                else:
                    if ob.Shape.Volume > 0:
                        sh = projectShape(ob.Shape,Vector(0,0,1))
                    else:
                        sh = ob.Shape
                if sh:
                    if not sh.isNull():
                        if sh.ShapeType == 'Compound':
                            if (len(sh.Wires) == 1):
                                # only one wire in this compound, no lone edge -> polyline
                                if (len(sh.Wires[0].Edges) == len(sh.Edges)):
                                    writeShape(sh,ob,dxf,nospline)
                                else:
                                    # 1 wire + lone edges -> block
                                    block = getBlock(sh,ob)
                                    dxf.blocks.append(block)
                                    dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
                            else:
                                # all other cases: block
                                block = getBlock(sh,ob)
                                dxf.blocks.append(block)
                                dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
                        else:
                            writeShape(sh,ob,dxf,nospline)
                    
            elif Draft.getType(ob) == "Annotation":
                # texts
    
                # temporary - as dxfLibrary doesn't support mtexts well, we use several single-line texts
                # well, anyway, at the moment, Draft only writes single-line texts, so...
                for text in ob.LabelText:
                    point = DraftVecUtils.tup(FreeCAD.Vector(ob.Position.x,
                                                     ob.Position.y-ob.LabelText.index(text),
                                                     ob.Position.z))
                    if gui: height = float(ob.ViewObject.FontSize)
                    else: height = 1
                    dxf.append(dxfLibrary.Text(text,point,height=height,
                                               color=getACI(ob,text=True),
                                               style='STANDARD',
                                               layer=getGroup(ob,exportList)))
    
            elif Draft.getType(ob) == "Dimension":
                p1 = DraftVecUtils.tup(ob.Start)
                p2 = DraftVecUtils.tup(ob.End)
                base = Part.Line(ob.Start,ob.End).toShape()
                proj = DraftGeomUtils.findDistance(ob.Dimline,base)
                if not proj:
                    pbase = DraftVecUtils.tup(ob.End)
                else:
                    pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj)))
                dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob),
                                                layer=getGroup(ob,exportList)))
                        
        dxf.saveas(filename)
    FreeCAD.Console.PrintMessage("successfully exported "+filename+"\r\n")
sorry for my outrageous English, but I have a bad excuse
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Help with creating macro for export to DXF and SVG.

Post by triplus »

I don't know it seems strange to me and whatever i try i don't get that error. Facts are:

-Macro is inside macro folder from preferences.
-Drawing is created and exported as SVG.
-Only DXF export fails.
-Standalone DXF export works.

If you delete this last part from macro or disable DXF export altogether:

Code: Select all

exportsDXF = 0
Or delete:

Code: Select all

# Export DXF.
if exportsDXF == 1:
    homepath = os.path.expanduser("~")
    filename = homepath + os.sep + obj.Label.encode("utf-8") + ".dxf"
    importDXF.export(selection,filename)
Everything works just like it should? Copy/past in Python console works? Try this slightly modified version:

Code: Select all

import FreeCAD
import Part
import Drawing
import math
import os

#-------------------------------- User Settings -------------------------------

# Centerpoint (centerpoint of combined views).
centerX = 420 / 2
centerY = 235 / 2

# Additional horizontal/vertical space between views.
viewsSpace = 40

# Maximum width/height of combined views.
# Used for auto-scale mode 0 and 1.
viewsSize = 170

# Scale.
# 0 - Maximum scale
# 1 - Maximum standard scale (1000:1 to 1:1000)
# 2 - Manual scale
scaleType = 0
manualScale = 1    # scaleType must be set to value 2.
scaleIso = 1         # Isometric view (Scale*scaleIso).

# Projection type.
# 0 - First angle
# 1 - Third angle
projectionType = 0

# Show hidden lines.
# 0 - False
# 1 - True
linesViews = 1
linesIso = 1

# Annotation (drawing info) shown under views.
# 0 = False
# 1 = True
annotationEnable = 1
textSize = 4

# Template location.
templateSet = App.getResourceDir() + 'Mod/Drawing/Templates/A3_Landscape.svg'

# Export to home folder.
# 0 - False
# 1 - True
exportsSVG = 1
exportsDXF = 1

#---------------------------- End Of User Settings ----------------------------

# Select part.
Piece = Gui.Selection.getSelectionEx()[0]
selection = FreeCADGui.Selection.getSelection()
obj = selection[0]

autoDrawing = App.activeDocument().addObject('Drawing::FeaturePage', 'Drawing')
autoDrawing.Template = templateSet

# Part centerpoints.
XM = Piece.Object.Shape.BoundBox.XMax
Xm = Piece.Object.Shape.BoundBox.XMin
XC = Xm + ((XM - Xm) / 2)
YM = Piece.Object.Shape.BoundBox.YMax
Ym = Piece.Object.Shape.BoundBox.YMin
YC = Ym + ((YM - Ym) / 2)
ZM = Piece.Object.Shape.BoundBox.ZMax
Zm = Piece.Object.Shape.BoundBox.ZMin
ZC = Zm + ((ZM - Zm) / 2)

# Scale.
SX = XM - Xm
SY = YM - Ym
SZ = ZM - Zm
scaleMax = ((viewsSize - viewsSpace) / 2) / max(SZ, SY, SX)

if scaleType == 0:
    scale = scaleMax
    ratio = scaleMax
elif scaleType == 1:
    if scaleMax > 2000 or scaleMax < 0.001:
        scale = scaleMax
        ratio = scaleMax
    elif scaleMax > 1000 and scaleMax <= 2000:
        scale = 1000
        ratio = '1000:1'
    elif scaleMax > 500 and scaleMax <= 1000:
        scale = 500
        ratio = '500:1'
    elif scaleMax > 200 and scaleMax <= 500:
        scale = 200
        ratio = '200:1'
    elif scaleMax > 100 and scaleMax <= 200:
        scale = 100
        ratio = '100:1'
    elif scaleMax > 50 and scaleMax <= 100:
        scale = 50
        ratio = '50:1'
    elif scaleMax > 20 and scaleMax <= 50:
        scale = 20
        ratio = '20:1'
    elif scaleMax > 10 and scaleMax <= 20:
        scale = 10
        ratio = '10:1'
    elif scaleMax > 5 and scaleMax <= 10:
        scale = 5
        ratio = '5:1'
    elif scaleMax > 2 and scaleMax <= 5:
        scale = 2
        ratio = '2:1'
    elif scaleMax > 1 and scaleMax <= 2:
        scale = 1
        ratio = '1:1'
    elif scaleMax > 0.5 and scaleMax <= 1:
        scale = 0.5
        ratio = '1:2'
    elif scaleMax > 0.2 and scaleMax <= 0.5:
        scale = 0.2
        ratio = '1:5'
    elif scaleMax > 0.1 and scaleMax <= 0.2:
        scale = 0.1
        ratio = '1:10'
    elif scaleMax > 0.05 and scaleMax <= 0.1:
        scale = 0.05
        ratio = '1:20'
    elif scaleMax > 0.02 and scaleMax <= 0.05:
        scale = 0.02
        ratio = '1:50'
    elif scaleMax > 0.01 and scaleMax <= 0.02:
        scale = 0.01
        ratio = '1:100'
    elif scaleMax > 0.005 and scaleMax <= 0.01:
        scale = 0.005
        ratio = '1:200'
    elif scaleMax > 0.002 and scaleMax <= 0.005:
        scale = 0.002
        ratio = '1:500'
    elif scaleMax > 0.001 and scaleMax <= 0.002:
        scale = 0.001
        ratio = '1:1000'
elif scaleType == 2:
    scale = manualScale
    ratio = manualScale

# Views centerpoints.
X1 = centerX - viewsSpace / 2 - max(SZ, SY, SX) * scale / 2
Y1 = centerY - viewsSpace / 2 - max(SZ, SY, SX) * scale / 2
X2 = centerX + viewsSpace / 2 + max(SZ, SY, SX) * scale / 2
Y2 = centerY - viewsSpace / 2 - max(SZ, SY, SX) * scale / 2
X3 = centerX - viewsSpace / 2 - max(SZ, SY, SX) * scale / 2
Y3 = centerY + viewsSpace / 2 + max(SZ, SY, SX) * scale / 2
X4 = centerX + viewsSpace / 2 + max(SZ, SY, SX) * scale / 2
Y4 = centerY + viewsSpace / 2 + max(SZ, SY, SX) * scale / 2

# Front view.
viewFront = App.activeDocument().addObject('Drawing::FeatureViewPart', 'Front')
viewFront.Source = Piece.Object

if projectionType == 0:
    angleFront = 270
    viewFront.Direction = (0, 1, 0)
    viewFront.Rotation = angleFront
    viewFront.X = X1 - XC * scale
    viewFront.Y = Y1 + ZC * scale
elif projectionType == 1:
    angleFront = 270
    viewFront.Direction = (0, 1, 0)
    viewFront.Rotation = angleFront
    viewFront.X = X3 - XC * scale
    viewFront.Y = Y3 + ZC * scale

if linesViews == 0:
    viewFront.ShowHiddenLines = False
elif linesViews == 1:
    viewFront.ShowHiddenLines = True

viewFront.Scale = scale
autoDrawing.addObject(viewFront)

# Side view.
viewSide = App.activeDocument().addObject('Drawing::FeatureViewPart', 'Side')
viewSide.Source = Piece.Object

if projectionType == 0:
    angleSide = 90
    viewSide.Direction = (-1, 0, 0)
    viewSide.Rotation = angleSide
    viewSide.X = X2 - YC * scale
    viewSide.Y = Y2 + ZC * scale
elif projectionType == 1:
    angleSide = 270
    viewSide.Direction = (1, 0, 0)
    viewSide.Rotation = angleSide
    viewSide.X = X4 + YC * scale
    viewSide.Y = Y4 + ZC * scale

if linesViews == 0:
    viewSide.ShowHiddenLines = False
elif linesViews == 1:
    viewSide.ShowHiddenLines = True

viewSide.Scale = scale
autoDrawing.addObject(viewSide)

# Top view.
viewTop = App.activeDocument().addObject('Drawing::FeatureViewPart', 'Top')
viewTop.Source = Piece.Object

if projectionType == 0:
    angleTop = 0
    viewTop.Direction = (0, 0, 1)
    viewTop.Rotation = angleTop
    viewTop.X = X3 - XC * scale
    viewTop.Y = Y3 - YC * scale
elif projectionType == 1:
    angleTop = 0
    viewTop.Direction = (0, 0, 1)
    viewTop.Rotation = angleTop
    viewTop.X = X1 - XC * scale
    viewTop.Y = Y1 - YC * scale

if linesViews == 0:
    viewTop.ShowHiddenLines = False
elif linesViews == 1:
    viewTop.ShowHiddenLines = True

viewTop.Scale = scale
autoDrawing.addObject(viewTop)

# Iso view.
viewIso = App.activeDocument().addObject('Drawing::FeatureViewPart', 'Isometric')
viewIso.Source = Piece.Object
angleIso = 60
viewIso.Direction = (1, 1, 1)
viewIso.Rotation = angleIso
k = math.sin(math.radians(45)) / math.sin(math.radians(60))
if projectionType == 0:
    if XC >= YC:
        viewIso.X = X4 - math.sqrt(2 * (YC - XC) ** 2) / 2 * scale * scaleIso
    elif XC < YC:
        viewIso.X = X4 + math.sqrt(2 * (YC - XC) ** 2) / 2 * scale * scaleIso
    viewIso.Y = Y4 + ((max(XC, YC, ZC) - XC) * k / 2) * scale * scaleIso + ((max(XC, YC, ZC) - YC) * k / 2) * scale * scaleIso - ((max(XC, YC, ZC) - ZC) * k) * scale * scaleIso
elif projectionType == 1:
    if XC >= YC:
        viewIso.X = X2 - math.sqrt(2 * (YC - XC) ** 2) / 2 * scale * scaleIso
    elif XC < YC:
        viewIso.X = X2 + math.sqrt(2 * (YC - XC) ** 2) / 2 * scale * scaleIso
    viewIso.Y = Y2 + ((max(XC, YC, ZC) - XC) * k / 2) * scale * scaleIso + ((max(XC, YC, ZC) - YC) * k / 2) * scale * scaleIso - ((max(XC, YC, ZC) - ZC) * k) * scale * scaleIso

if linesIso == 0:
    viewIso.ShowHiddenLines = False
elif linesIso == 1:
    viewIso.ShowHiddenLines = True

viewIso.Scale = scale * scaleIso
autoDrawing.addObject(viewIso)

# Annotation projection.
if projectionType == 0:
    projection = 'first-angle'
elif projectionType == 1:
    projection = 'third-angle'

# Annotation.
if annotationEnable == 1:
    annotation = App.activeDocument().addObject('Drawing::FeatureViewAnnotation', 'Annotation')
    annotation.X = centerX - viewsSize / 2
    annotation.Y = centerY + viewsSize / 2 + textSize
    annotation.Scale = textSize
    if scaleType != 1:
        if scaleIso != 1:
            annotation.Text = [unicode('Scale: ' + "%.3f" % ratio + ' (Iso: Scale*' + str(scaleIso) + ') Projection: ' + str(projection), 'utf-8'), ]
        elif scaleIso == 1:
            annotation.Text = [unicode('Scale: ' + "%.3f" % ratio + ' Projection: ' + str(projection), 'utf-8'), ]
    elif scaleType == 1:
        if scaleIso != 1:
            annotation.Text = [unicode('Scale: ' + str(ratio) + ' (Iso: Scale*' + str(scaleIso) + ') ' + ' Projection: ' + str(projection), 'utf-8'), ]
        elif scaleIso == 1:
            annotation.Text = [unicode('Scale: ' + str(ratio) + ' Projection: ' + str(projection), 'utf-8'), ]

autoDrawing.addObject(annotation)

# Refresh.
App.activeDocument().recompute()

# Export SVG.
if exportsSVG == 1:
    homepath = os.path.expanduser("~")
    filename = homepath + os.sep + obj.Label.encode("utf-8") + ".svg"
    PageFile = open(App.activeDocument().Drawing.PageResult,'r')
    OutFile = open(filename,'w')
    OutFile.write(PageFile.read())
    del OutFile,PageFile

# Export DXF.
if exportsDXF == 1:
    homepath = os.path.expanduser("~")
    filename = homepath + os.sep + obj.Label.encode("utf-8") + ".dxf"
    import importDXF
    importDXF.export(selection,filename)
If it won't work i honestly don't see what could be wrong with the code (the last DXF export part code). And don't use SELECT ALL on forum when copy/paste code but manually select the code and do copy/paste because SELECT ALL tempers slightly with indentation.
User avatar
ralvejd
Posts: 58
Joined: Wed Feb 20, 2013 10:31 pm
Location: Sweden

Re: Help with creating macro for export to DXF and SVG.

Post by ralvejd »

I have tried all of your suggestions.
Turn off dxf export, then the macro functions without error.
Delete the last paragraph of code, then the macro functions without error.
Copy/past in Python console works? Yes, if I press [ENTER] twice. (With above mentioned code removed.)

Some desperate tests:
Turn off svg export, I get the same error message as before.
Tried a new Macro folder, no effect. "/home/isak/.FreeCAD/ExportDxfSvg.FCMacro"

Tested your new code:
Traceback (most recent call last):
File "/home/isak/.FreeCAD/ExportDxfSvg.FCMacro", line 304, in <module>
importDXF.export(selection,filename)
File "/usr/Mod/Draft/importDXF.py", line 1449, in export
direction = FreeCADGui.ActiveDocument.ActiveView.getViewDirection()
<type 'exceptions.AttributeError'>: 'NoneType' object has no attribute 'getViewDirection'
Guessing that something must be wrong in my installation, either Debian or FreeCAD.
If there are users out there who are running Debian Wheezy 64Bit please test if it works for you :?:
The deb file I installed: https://www.dropbox.com/sh/0poyknpnlys5xc7/3CPwGf1NIY (freecad_0.13-git2207_amd64.deb)

Triplus, thank you for all the time you have sacrificed for me. :)
sorry for my outrageous English, but I have a bad excuse
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Help with creating macro for export to DXF and SVG.

Post by triplus »

On the "bright side" this really isn't that much of an issue. Just set exportsDXF = 0 and use DXF standalone macro as one click solution to export to DXF. It does the same it exports DXF in your home folder with the name of the selected object in tree view. The only "downside" is you will have 2 buttons in custom toolbar. ;)
User avatar
ralvejd
Posts: 58
Joined: Wed Feb 20, 2013 10:31 pm
Location: Sweden

Re: Help with creating macro for export to DXF and SVG.

Post by ralvejd »

When I run the standalone dxf macro, then I get only one view. Is that right or should it be like the svg file?
Links to the output, svg and dxf.
http://www.ralvejd.se/post/FreeCAD/Box.dxf
http://www.ralvejd.se/post/FreeCAD/Box.svg
sorry for my outrageous English, but I have a bad excuse
Post Reply