124 lines
6.0 KiB
Python
124 lines
6.0 KiB
Python
|
#!/usr/bin/env python3
|
||
|
import sys
|
||
|
import os
|
||
|
import inkex
|
||
|
import tempfile
|
||
|
import subprocess
|
||
|
from subprocess import Popen, PIPE
|
||
|
from lxml import etree
|
||
|
from inkex import Transform
|
||
|
|
||
|
class PlyCutter(inkex.EffectExtension):
|
||
|
|
||
|
def add_arguments(self, pars):
|
||
|
pars.add_argument("--tab")
|
||
|
pars.add_argument("--infile")
|
||
|
pars.add_argument("--resizetoimport", type=inkex.Boolean, default=True, help="Resize the canvas to the imported drawing's bounding box")
|
||
|
pars.add_argument("--extraborder", type=float, default=0.0)
|
||
|
pars.add_argument("--extraborder_units", default="mm")
|
||
|
|
||
|
pars.add_argument("--thickness", type=float, default=6.000, help="Set the thickness of sheets to find.")
|
||
|
pars.add_argument("--debug", type=inkex.Boolean, default=False, help="Turn on debugging")
|
||
|
pars.add_argument("--min_finger_width", type=float, default=3.000, help="Set minimum width for generated fingers.")
|
||
|
pars.add_argument("--max_finger_width", type=float, default=5.000, help="Set maximum width for generated fingers.")
|
||
|
pars.add_argument("--support_radius", type=float, default=12.000, help="Set maximum range for generating material on a sheet where neither surface is visible")
|
||
|
pars.add_argument("--final_dilation", default=0.05, type=float, help="Final dilation (laser cutter kerf compensation)")
|
||
|
pars.add_argument("--random_seed", type=int, default=42, help="Random seed for pseudo-random heuristics")
|
||
|
|
||
|
#-o OUTPUT_FILE, --output_file OUTPUT_FILE
|
||
|
# File to write the DXF output in (default: None)
|
||
|
|
||
|
|
||
|
def effect(self):
|
||
|
stl_input = self.options.infile
|
||
|
if not os.path.exists(stl_input):
|
||
|
inkex.utils.debug("The input file does not exist. Please select a proper file and try again.")
|
||
|
exit(1)
|
||
|
|
||
|
# Prepare output
|
||
|
dxf_output = os.path.join(tempfile.gettempdir(), os.path.splitext(os.path.basename(stl_input))[0] + ".dxf")
|
||
|
svg_output = os.path.join(tempfile.gettempdir(), os.path.splitext(os.path.basename(stl_input))[0] + ".svg")
|
||
|
|
||
|
# Clean up possibly previously generated output file from plycutter
|
||
|
if os.path.exists(dxf_output):
|
||
|
try:
|
||
|
os.remove(dxf_output)
|
||
|
except OSError as e:
|
||
|
inkex.utils.debug("Error while deleting previously generated output file " + stl_input)
|
||
|
|
||
|
# Run PlyCutter
|
||
|
plycutter_cmd = "plycutter "
|
||
|
plycutter_cmd += "--thickness " + str(self.options.thickness) + " "
|
||
|
if self.options.debug == True: plycutter_cmd += "--debug "
|
||
|
plycutter_cmd += "--min_finger_width " + str(self.options.min_finger_width) + " "
|
||
|
plycutter_cmd += "--max_finger_width " + str(self.options.max_finger_width) + " "
|
||
|
plycutter_cmd += "--support_radius " + str(self.options.support_radius) + " "
|
||
|
plycutter_cmd += "--final_dilation " + str(self.options.final_dilation) + " "
|
||
|
plycutter_cmd += "--random_seed " + str(self.options.random_seed) + " "
|
||
|
plycutter_cmd += "-o \"" + dxf_output + "\" "
|
||
|
plycutter_cmd += "\"" + stl_input + "\""
|
||
|
|
||
|
#print command
|
||
|
inkex.utils.debug(plycutter_cmd)
|
||
|
|
||
|
#os.system(plycutter_cmd) #does not work
|
||
|
|
||
|
#pid=os.fork()
|
||
|
#if pid==0: # new process
|
||
|
# os.system("nohup " + plycutter_cmd + " &") #does not work too
|
||
|
# exit()
|
||
|
# parent process continues
|
||
|
|
||
|
p = Popen(plycutter_cmd, shell=True, stdout=PIPE, stderr=PIPE)
|
||
|
stdout, stderr = p.communicate()
|
||
|
p.wait()
|
||
|
if p.returncode != 0:
|
||
|
inkex.utils.debug("PlyCutter failed: %d %s %s" % (p.returncode,
|
||
|
str(stdout).replace('\\n', '\n').replace('\\t', '\t'),
|
||
|
str(stderr).replace('\\n', '\n').replace('\\t', '\t'))
|
||
|
)
|
||
|
exit(1)
|
||
|
if not os.path.exists(dxf_output):
|
||
|
inkex.utils.debug("There was no DXF output generated by PlyCutter. Please check your model file.")
|
||
|
exit(1)
|
||
|
|
||
|
# Convert the DXF output to SVG
|
||
|
wd = os.path.join(os.getcwd(), "kabeja")
|
||
|
proc = subprocess.Popen("java -jar launcher.jar -nogui -pipeline svg " + dxf_output + " " + svg_output, cwd=wd, shell=True, stdout=PIPE, stderr=PIPE)
|
||
|
stdout, stderr = proc.communicate()
|
||
|
if proc.returncode != 0:
|
||
|
inkex.errormsg("kabeja failed: %d %s %s" % (proc.returncode, stdout, stderr))
|
||
|
|
||
|
# Write the generated SVG into InkScape's canvas
|
||
|
try:
|
||
|
stream = open(svg_output, 'r')
|
||
|
except FileNotFoundError as e:
|
||
|
inkex.utils.debug("There was no SVG output generated by kabeja. Cannot continue")
|
||
|
exit(1)
|
||
|
p = etree.XMLParser(huge_tree=True)
|
||
|
doc = etree.parse(stream, parser=etree.XMLParser(huge_tree=True)).getroot()
|
||
|
stream.close()
|
||
|
|
||
|
dxfGroup = inkex.Group(id=self.svg.get_unique_id("plycutter-"))
|
||
|
for element in doc.iter("{http://www.w3.org/2000/svg}g"):
|
||
|
dxfGroup.append(element)
|
||
|
self.document.getroot().add(dxfGroup)
|
||
|
|
||
|
#apply scale factor
|
||
|
translation_matrix = [[self.options.scalefactor, 0.0, 0.0], [0.0, self.options.scalefactor, 0.0]]
|
||
|
dxfGroup.transform = Transform(translation_matrix) * dxfGroup.transform
|
||
|
|
||
|
#Adjust viewport and width/height to have the import at the center of the canvas
|
||
|
if self.options.resizetoimport:
|
||
|
bbox = dxfGroup.bounding_box() #does not work. why?
|
||
|
if bbox is not None:
|
||
|
root = self.svg.getElement('//svg:svg');
|
||
|
offset = self.svg.unittouu(str(self.options.extraborder) + self.options.extraborder_units)
|
||
|
root.set('viewBox', '%f %f %f %f' % (bbox.left - offset, bbox.top - offset, bbox.width + 2 * offset, bbox.height + 2 * offset))
|
||
|
root.set('width', bbox.width + 2 * offset)
|
||
|
root.set('height', bbox.height + 2 * offset)
|
||
|
else:
|
||
|
self.msg("Error resizing to bounding box.")
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
PlyCutter().run()
|