408 lines
14 KiB
Python
408 lines
14 KiB
Python
# -*- coding: utf8 -*-
|
|
## @package importDWG
|
|
# \ingroup DRAFT
|
|
# \brief DWG file importer & exporter
|
|
'''
|
|
@package importDWG
|
|
ingroup DRAFT
|
|
\brief DWG file importer & exporter
|
|
|
|
This module provides support for importing and exporting Autodesk DWG files.
|
|
This module is only a thin layer that uses the ODA (formerly Teigha) File
|
|
Converter application to convert to/from DXF. Then the real work is done by
|
|
importDXF
|
|
|
|
Test files
|
|
https://knowledge.autodesk.com/support/autocad/downloads/
|
|
caas/downloads/content/autocad-sample-files.html
|
|
'''
|
|
# Check code quality with
|
|
# flake8 --ignore=E226,E266,E401,W503
|
|
|
|
# ***************************************************************************
|
|
# * Copyright (c) 2009 Yorik van Havre <yorik@uncreated.net> *
|
|
# * *
|
|
# * This program is free software; you can redistribute it and/or modify *
|
|
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
|
# * as published by the Free Software Foundation; either version 2 of *
|
|
# * the License, or (at your option) any later version. *
|
|
# * for detail see the LICENCE text file. *
|
|
# * *
|
|
# * This program is distributed in the hope that it will be useful, *
|
|
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
# * GNU Library General Public License for more details. *
|
|
# * *
|
|
# * You should have received a copy of the GNU Library General Public *
|
|
# * License along with this program; if not, write to the Free Software *
|
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
|
# * USA *
|
|
# * *
|
|
# ***************************************************************************
|
|
|
|
import FreeCAD
|
|
from FreeCAD import Console as FCC
|
|
from draftutils import params
|
|
|
|
if FreeCAD.GuiUp:
|
|
from draftutils.translate import translate
|
|
else:
|
|
def translate(context, txt):
|
|
return txt
|
|
|
|
|
|
|
|
|
|
def open(filename):
|
|
"""Open filename and parse using importDXF.open().
|
|
|
|
Parameters
|
|
----------
|
|
filename : str
|
|
The path to the filename to be opened.
|
|
|
|
Returns
|
|
-------
|
|
App::Document
|
|
The new FreeCAD document object created, with the parsed information.
|
|
"""
|
|
dxf = convertToDxf(filename)
|
|
if dxf:
|
|
import importDXF
|
|
doc = importDXF.open(dxf)
|
|
return doc
|
|
return
|
|
|
|
|
|
def insert(filename, docname):
|
|
"""Imports a file using importDXF.insert().
|
|
|
|
If no document exist, it is created.
|
|
|
|
Parameters
|
|
----------
|
|
filename : str
|
|
The path to the filename to be opened.
|
|
docname : str
|
|
The name of the active App::Document if one exists, or
|
|
of the new one created.
|
|
|
|
Returns
|
|
-------
|
|
App::Document
|
|
The active FreeCAD document, or the document created if none exists,
|
|
with the parsed information.
|
|
"""
|
|
dxf = convertToDxf(filename)
|
|
if dxf:
|
|
import importDXF
|
|
# Warning: function doesn't return?
|
|
doc = importDXF.insert(dxf, docname)
|
|
return doc
|
|
return
|
|
|
|
|
|
def export(objectslist, filename):
|
|
"""Export the DWG file with a given list of objects.
|
|
|
|
The objects are exported with importDXF.export().
|
|
Then the result is converted to DWG.
|
|
|
|
Parameters
|
|
----------
|
|
exportList : list
|
|
List of document objects to export.
|
|
filename : str
|
|
Path to the new file.
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
The same `filename` input.
|
|
"""
|
|
import importDXF
|
|
import os
|
|
import tempfile
|
|
outdir = tempfile.mkdtemp()
|
|
_basename = os.path.splitext(os.path.basename(filename))[0]
|
|
dxf = outdir + os.sep + _basename + ".dxf"
|
|
importDXF.export(objectslist, dxf)
|
|
convertToDwg(dxf, filename)
|
|
return filename
|
|
|
|
|
|
def get_libredwg_converter(typ):
|
|
"""Find the LibreDWG converter.
|
|
|
|
It searches the FreeCAD parameters database, then searches the OS search path.
|
|
There are no standard installation paths.
|
|
|
|
`typ` is required because LibreDWG uses two converters and we store only one.
|
|
|
|
Parameters
|
|
----------
|
|
typ : str
|
|
"dwg2dxf" or "dxf2dwg".
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
The full path of the converter.
|
|
"""
|
|
import os
|
|
import platform
|
|
|
|
path = params.get_param("TeighaFileConverter")
|
|
|
|
if "dwg2dxf" in path or "dxf2dwg" in path: # path set manually
|
|
if typ not in path:
|
|
path = os.path.dirname(path) + "/" + typ + os.path.splitext(path)[1]
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
return path
|
|
elif platform.system() == "Windows":
|
|
for sub in os.getenv("PATH").split(os.pathsep):
|
|
path = sub.replace("\\", "/") + "/" + typ + ".exe"
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
return path
|
|
else: # for Linux and macOS
|
|
for sub in os.getenv("PATH").split(os.pathsep):
|
|
path = sub + "/" + typ
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
return path
|
|
|
|
return None
|
|
|
|
|
|
def get_oda_converter():
|
|
"""Find the ODA converter.
|
|
|
|
It searches the FreeCAD parameters database, then searches for common paths.
|
|
|
|
Parameters
|
|
----------
|
|
None
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
The full path of the converter.
|
|
"""
|
|
import os
|
|
import platform
|
|
|
|
path = params.get_param("TeighaFileConverter")
|
|
|
|
if "ODAFileConverter" in path: # path set manually
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
return path
|
|
elif platform.system() == "Windows":
|
|
odadir = os.path.expandvars("%ProgramFiles%\\ODA").replace("\\", "/")
|
|
if os.path.exists(odadir):
|
|
for sub in os.listdir(odadir):
|
|
path = odadir + "/" + sub + "/" + "ODAFileConverter.exe"
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
return path
|
|
elif platform.system() == "Linux":
|
|
path = "/usr/bin/ODAFileConverter"
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
return path
|
|
else: # for macOS
|
|
path = "/Applications/ODAFileConverter.app/Contents/MacOS/ODAFileConverter"
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
return path
|
|
|
|
return None
|
|
|
|
|
|
def get_qcad_converter():
|
|
"""Find the QCAD converter.
|
|
|
|
It searches the FreeCAD parameters database, then searches for common paths.
|
|
|
|
Parameters
|
|
----------
|
|
None
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
The full path of the converter.
|
|
"""
|
|
import os
|
|
import platform
|
|
|
|
path = params.get_param("TeighaFileConverter")
|
|
|
|
if "dwg2dwg" in path: # path set manually
|
|
pass
|
|
elif platform.system() == "Windows":
|
|
path = os.path.expandvars("%ProgramFiles%\\QCAD\\dwg2dwg.bat").replace("\\", "/")
|
|
elif platform.system() == "Linux":
|
|
# /home/$USER/opt/qcad-3.28.1-trial-linux-qt5.14-x86_64/dwg2dwg
|
|
path = os.path.expandvars("/home/$USER/opt")
|
|
if os.path.exists(path) and os.path.isdir(path):
|
|
for sub in os.listdir(path):
|
|
if "qcad" in sub:
|
|
path = path + "/" + sub + "/" + "dwg2dwg"
|
|
break
|
|
else: # for macOS
|
|
path = "/Applications/QCAD.app/Contents/Resources/dwg2dwg"
|
|
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
return path
|
|
return None
|
|
|
|
|
|
def convertToDxf(dwgfilename):
|
|
"""Convert a DWG file to a DXF file.
|
|
|
|
If the converter is found it is used, otherwise the conversion fails.
|
|
|
|
Parameters
|
|
----------
|
|
dwgfilename : str
|
|
The input filename.
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
The new file produced.
|
|
"""
|
|
import os
|
|
import subprocess
|
|
import tempfile
|
|
|
|
dwgfilename = dwgfilename.replace("\\", "/")
|
|
conv = params.get_param("DWGConversion")
|
|
error_msg = translate("draft", """Error during DWG conversion.
|
|
Try moving the DWG file to a directory path without spaces and non-english characters,
|
|
or try saving to a lower DWG version.""") + "\n"
|
|
|
|
if conv in [0, 1]: # LibreDWG
|
|
libredwg = get_libredwg_converter("dwg2dxf")
|
|
if libredwg is not None:
|
|
outdir = tempfile.mkdtemp().replace("\\", "/")
|
|
basename = os.path.basename(dwgfilename)
|
|
result = outdir + "/" + os.path.splitext(basename)[0] + ".dxf"
|
|
cmdline = [libredwg, dwgfilename, "-o", result]
|
|
FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n")
|
|
proc = subprocess.Popen(cmdline)
|
|
proc.communicate()
|
|
if os.path.exists(result):
|
|
FCC.PrintMessage(translate("draft", "Conversion successful") + "\n")
|
|
return result
|
|
else:
|
|
FCC.PrintError(error_msg)
|
|
elif conv != 0:
|
|
FCC.PrintError(translate("draft", "LibreDWG converter not found") + "\n")
|
|
|
|
if conv in [0, 2]: # ODA
|
|
oda = get_oda_converter()
|
|
if oda is not None:
|
|
indir = os.path.dirname(dwgfilename)
|
|
outdir = tempfile.mkdtemp().replace("\\", "/")
|
|
basename = os.path.basename(dwgfilename)
|
|
cmdline = [oda, indir, outdir, "ACAD2000", "DXF", "0", "1", basename]
|
|
FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n")
|
|
proc = subprocess.Popen(cmdline)
|
|
proc.communicate()
|
|
result = outdir + "/" + os.path.splitext(basename)[0] + ".dxf"
|
|
if os.path.exists(result):
|
|
FCC.PrintMessage(translate("draft", "Conversion successful") + "\n")
|
|
return result
|
|
else:
|
|
FCC.PrintError(error_msg)
|
|
elif conv != 0:
|
|
FCC.PrintError(translate("draft", "ODA converter not found") + "\n")
|
|
|
|
if conv in [0, 3]: # QCAD
|
|
qcad = get_qcad_converter()
|
|
if qcad is not None:
|
|
outdir = tempfile.mkdtemp().replace("\\", "/")
|
|
basename = os.path.basename(dwgfilename)
|
|
result = outdir + "/" + os.path.splitext(basename)[0] + ".dxf"
|
|
cmdline = [qcad, "-f", "-o", result, dwgfilename]
|
|
FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n")
|
|
proc = subprocess.Popen(cmdline, cwd=os.path.dirname(qcad)) # cwd required for Windows
|
|
proc.communicate()
|
|
if os.path.exists(result):
|
|
FCC.PrintMessage(translate("draft", "Conversion successful") + "\n")
|
|
return result
|
|
else:
|
|
FCC.PrintError(error_msg)
|
|
elif conv != 0:
|
|
FCC.PrintError(translate("draft", "QCAD converter not found") + "\n")
|
|
|
|
FCC.PrintError(translate("draft", """No suitable external DWG converter has been found.
|
|
Please set one manually under menu Edit -> Preferences -> Import/Export -> DWG
|
|
For more information see:
|
|
https://wiki.freecad.org/Import_Export_Preferences""") + "\n")
|
|
return None
|
|
|
|
|
|
def convertToDwg(dxffilename, dwgfilename):
|
|
"""Convert a DXF file to a DWG file.
|
|
|
|
If the converter is found it is used, otherwise the conversion fails.
|
|
|
|
Parameters
|
|
----------
|
|
dxffilename : str
|
|
The input DXF file
|
|
dwgfilename : str
|
|
The output DWG file
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
The same `dwgfilename` file path.
|
|
"""
|
|
import os
|
|
import subprocess
|
|
|
|
dxffilename = dxffilename.replace("\\", "/")
|
|
dwgfilename = dwgfilename.replace("\\", "/")
|
|
conv = params.get_param("DWGConversion")
|
|
|
|
if conv in [0, 1]: # LibreDWG
|
|
libredwg = get_libredwg_converter("dxf2dwg")
|
|
if libredwg is not None:
|
|
cmdline = [libredwg, dxffilename, "-y", "-o", dwgfilename]
|
|
FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n")
|
|
proc = subprocess.Popen(cmdline)
|
|
proc.communicate()
|
|
return dwgfilename
|
|
elif conv != 0:
|
|
FCC.PrintError(translate("draft", "LibreDWG converter not found") + "\n")
|
|
|
|
if conv in [0, 2]: # ODA
|
|
oda = get_oda_converter()
|
|
if oda is not None:
|
|
indir = os.path.dirname(dxffilename)
|
|
outdir = os.path.dirname(dwgfilename)
|
|
basename = os.path.basename(dxffilename)
|
|
cmdline = [oda, indir, outdir, "ACAD2000", "DWG", "0", "1", basename]
|
|
FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n")
|
|
proc = subprocess.Popen(cmdline)
|
|
proc.communicate()
|
|
return dwgfilename
|
|
elif conv != 0:
|
|
FCC.PrintError(translate("draft", "ODA converter not found") + "\n")
|
|
|
|
if conv in [0, 3]: # QCAD
|
|
qcad = get_qcad_converter()
|
|
if qcad is not None:
|
|
cmdline = [qcad, "-f", "-o", dwgfilename, dxffilename]
|
|
FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n")
|
|
proc = subprocess.Popen(cmdline, cwd=os.path.dirname(qcad)) # cwd required for Windows
|
|
proc.communicate()
|
|
return dwgfilename
|
|
elif conv != 0:
|
|
FCC.PrintError(translate("draft", "QCAD converter not found") + "\n")
|
|
|
|
FCC.PrintError(translate("draft", """No suitable external DWG converter has been found.
|
|
Please set one manually under menu Edit -> Preferences -> Import/Export -> DWG
|
|
For more information see:
|
|
https://wiki.freecad.org/Import_Export_Preferences""") + "\n")
|
|
return None
|