Add new extension qcad_svg_to_modern_dxf

This commit is contained in:
Mario Voigt 2024-01-14 19:43:34 +01:00
parent 40b802def8
commit bc87968598
3 changed files with 207 additions and 0 deletions

View File

@ -0,0 +1,32 @@
include("scripts/ImportExport/SvgImporter/SvgImporter.js")
include("scripts/ImportExport/SvgImporter/SvgImporterInit.js");
include("scripts/Pro/Draw/Polyline/PolylineFromSelection/PolylineFromSelection.js");
include("scripts/Pro/Modify/Detection/Duplicates/Duplicates.js");
RFileImporterRegistry.registerFileImporter(new SvgImporterFactory());
qApp.applicationName = "SVG-DXF";
var storage = new RMemoryStorage();
var spatialIndex = new RSpatialIndexSimple();
var doc = new RDocument(storage, spatialIndex);
var di = new RDocumentInterface(doc);
var tolerance = $QCAD_TOLERANCE$;
const importer = new SvgImporter(doc);
di.importFile("$SVG_PATH$");
var purge_duplicates = $QCAD_PURGE_DUPLICATES$;
if (purge_duplicates === true) {
Duplicates.findDuplicates(di, true, tolerance, 0.0, true);
var counter = doc.countSelectedEntities();
var op = new RDeleteSelectionOperation();
di.applyOperation(op);
print("Purged duplicates: " + counter);
}
di.selectAll();
PolylineFromSelection.autoJoinSegments(di, tolerance);
di.exportFile("$EXPORT_PATH$", "$QCAD_DXF_FORMAT$");
di.destroy();

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>QCAD SVG to modern DXF</name>
<id>fablabchemnitz.de.qcad_svg_to_modern_dxf</id>
<param name="tab" type="notebook">
<page name="tab_settings" gui-text="Settings">
<param name="qcad_dxf_format" type="optiongroup" appearance="combo" gui-text="DXF export type">
<option value="R32 DXF">R32/2018 (OpenDesign)</option>
<option value="R27 DXF">R27/2013 (OpenDesign)</option>
<option value="R24 DXF">R24/2010 (OpenDesign)</option>
<option value="R21 DXF">R21/2007 (OpenDesign)</option>
<option value="R18 DXF">R18/2004 (OpenDesign)</option>
<option value="R15 DXF">R15/2000 (OpenDesign)</option>
<option value="dxflib">R15/2000 (dxflib)</option>
<option value="R14 DXF">R14 (OpenDesign)</option>
<option value="R13 DXF">R13 (OpenDesign)</option>
<option value="R12 DXF">R12 (OpenDesign)</option>
<option value="R11 DXF">R11 (OpenDesign)</option>
<option value="R10 DXF">R10 (OpenDesign)</option>
<option value="R9 DXF">R9 (OpenDesign)</option>
</param>
<param name="qcad_tolerance" type="float" min="0.0000001" max="999999" precision="3" gui-text="Polyline tolerance" gui-description="">0.001</param>
<param name="qcad_purge_duplicates" type="bool" gui-text="Purge duplicate lines">false</param>
<param name="qcad_pro_path" type="path" mode="file" gui-text="QCAD Pro executable path" gui-description="Do not use Community Edition, as it will not work.">~/opt/qcad-3.28.2-pro-linux-x86_64/qcad</param>
<param name="debug" type="bool" gui-text="Show debug info">false</param>
<param name="open_in_qcad" type="bool" gui-text="Open export file in QCAD">false</param>
</page>
<page name="tab_about" gui-text="About">
<label appearance="header">QCAD SVG to modern DXF</label>
<label>This extension uses QCAD Pro 3.28 to convert an Inkscape SVG file to a nice DXF file, which has continuous polylines.</label>
<label>2024 / written by Mario Voigt (Stadtfabrikanten e.V. / FabLab Chemnitz)</label>
<spacer/>
<label appearance="header">Online Documentation</label>
<label appearance="url">https://y.stadtfabrikanten.org/qcad_svg_to_modern_dxf</label>
<spacer/>
<label appearance="header">Contributing</label>
<label appearance="url">https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.2</label>
<label appearance="url">mailto:mario.voigt@stadtfabrikanten.org</label>
<spacer/>
<label appearance="header">MightyScape Extension Collection</label>
<label>This piece of software is part of the MightyScape for Inkscape Extension Collection and is licensed under GNU GPL v3</label>
<label appearance="url">https://y.stadtfabrikanten.org/mightyscape-overview</label>
</page>
<page name="tab_donate" gui-text="Donate">
<label appearance="header">Coffee + Pizza</label>
<label>We are the Stadtfabrikanten, running the FabLab Chemnitz since 2016. A FabLab is an open workshop that gives people access to machines and digital tools like 3D printers, laser cutters and CNC milling machines.</label>
<spacer/>
<label>You like our work and want to support us? You can donate to our non-profit organization by different ways:</label>
<label appearance="url">https://y.stadtfabrikanten.org/donate</label>
<spacer/>
<label>Thanks for using our extension and helping us!</label>
<image>../000_about_fablabchemnitz.svg</image>
</page>
</param>
<output>
<extension>.dxf</extension>
<mimetype>image/dxf</mimetype>
<filetypename>QCAD DXF (*.dxf)</filetypename>
<filetypetooltip>AutoDesk DXF - OpenDesign/dxflibs</filetypetooltip>
<dataloss>true</dataloss>
</output>
<script>
<command location="inx" interpreter="python">qcad_svg_to_modern_dxf.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,109 @@
#!/usr/bin/env python3
import inkex
import os
import shutil
import sys
import subprocess
from subprocess import Popen, PIPE
'''
Simple extension to utilize QCAD Pro for some neat DXF operations. Based on:
- https://ribbonsoft.com/rsforum/viewtopic.php?t=6801
- https://qcad.org/rsforum/viewtopic.php?t=8471
written 14.01.2024 by Mario Voigt / Stadtfabrikanten e.V.
ToDos
- black colored paths are getting blue or brown when using DXF Export of QCAD. Why? How to change this?
- keep canvas format
- keep original SVG Unit
'''
class QCAD_SVG(inkex.OutputExtension):
def __init__(self):
inkex.Effect.__init__(self)
def add_arguments(self, pars):
pars.add_argument("--tab")
pars.add_argument("--qcad_dxf_format", default="dxflib", help="DXF Export Type")
pars.add_argument("--qcad_tolerance", type=float, default=0.001, help="Polyline Tolerance")
pars.add_argument("--qcad_purge_duplicates", type=inkex.Boolean, default=False, help="Purge duplicate lines")
pars.add_argument("--qcad_pro_path", default="~/opt/qcad-3.28.2-pro-linux-x86_64/qcad", help="Location of qcad pro executable")
pars.add_argument("--debug", type=inkex.Boolean, default=False, help="Show debug info")
pars.add_argument("--open_in_qcad", type=inkex.Boolean, default=False, help="Open export file in QCAD")
def inplace_change(self, filename, old_string, new_string):
with open(filename) as f:
s = f.read()
with open(filename, 'w') as f:
s = s.replace(old_string, new_string)
f.write(s)
def effect(self):
so = self.options
qcad_pro_path = os.path.relpath(so.qcad_pro_path)
tmpdir_path = os.path.dirname(so.input_file)
export_path = self.document_path()
qcad_script = "qcad-dxf-script.js"
if so.qcad_purge_duplicates is True:
qcad_purge_duplicates = "true"
else:
qcad_purge_duplicates = "false"
qcad_tolerance = "{:6.6f}".format(so.qcad_tolerance)
qcad_dxf_format = so.qcad_dxf_format
if so.debug is True:
inkex.utils.debug("/tmp dir Path:{}".format(tmpdir_path))
inkex.utils.debug("Export Path{}".format(export_path))
inkex.utils.debug("QCAD Pro Path: {}".format(qcad_pro_path))
inkex.utils.debug("QCAD Polyline Tolerance: {}".format(qcad_tolerance))
inkex.utils.debug("QCAD DXF Format: {}".format(qcad_dxf_format))
#we must copy the input file to a new file with ending *.svg. Otherwise QCAD does not recognise the file type
target_file = self.options.input_file + ".svg"
shutil.copy2(self.options.input_file, target_file)
#copy the qcad-dxf-script.js file to temporary location and modify its content
shutil.copy2(qcad_script, tmpdir_path)
qcad_script_tmp = os.path.join(tmpdir_path, qcad_script)
self.inplace_change(qcad_script_tmp, "$SVG_PATH$", target_file)
self.inplace_change(qcad_script_tmp, "$QCAD_TOLERANCE$", qcad_tolerance)
self.inplace_change(qcad_script_tmp, "$EXPORT_PATH$", export_path)
self.inplace_change(qcad_script_tmp, "$QCAD_DXF_FORMAT$", qcad_dxf_format)
self.inplace_change(qcad_script_tmp, "$QCAD_PURGE_DUPLICATES$", qcad_purge_duplicates)
#build the command and execute the script
command = [qcad_pro_path + " -autostart \"" + qcad_script_tmp + "\""]
proc = subprocess.Popen(command, shell=True, stdout=PIPE, stderr=PIPE)
stdout, stderr = proc.communicate()
if proc.returncode != 0: #in this case we exit
inkex.utils.debug("QCAD Console Output: %d %s %s" % (proc.returncode, stdout, stderr))
if "Application already running" in stderr.decode('UTF-8'):
inkex.utils.debug("Warning. QCAD already running. Please close it and run this extension again!")
if so.debug is True:
inkex.utils.debug(stdout.decode('UTF-8'))
inkex.utils.debug(stderr.decode('UTF-8'))
proc.wait()
if so.open_in_qcad is True:
command = [qcad_pro_path + " " + export_path]
proc = subprocess.Popen(command, shell=True, stdout=PIPE, stderr=PIPE)
stdout, stderr = proc.communicate()
if proc.returncode != 0: #in this case we exit
inkex.utils.debug("QCAD Console Output: %d %s %s" % (proc.returncode, stdout, stderr))
if so.debug is True:
inkex.utils.debug(stdout.decode('UTF-8'))
inkex.utils.debug(stderr.decode('UTF-8'))
proc.wait()
#this is just implemented to avoid a warning. The file gets written twice, because its already generated by QCAD, then it gets written again by save() method
def save(self, stream):
with open(self.document_path(), 'rb') as finalfile:
stream.write(finalfile.read())
if __name__ == '__main__':
QCAD_SVG().run()