Commit 0e561ace authored by sumpfralle's avatar sumpfralle

fixed eol-style for startup script


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@632 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent eaa7fa68
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
$Id$ $Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de> Copyright 2010 Lars Kruse <devel@sumpfralle.de>
Copyright 2008-2009 Lode Leroy Copyright 2008-2009 Lode Leroy
This file is part of PyCAM. This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
from optparse import OptionParser from optparse import OptionParser
import sys import sys
import os import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src")) sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
from pycam.Physics.ode_physics import override_ode_availability from pycam.Physics.ode_physics import override_ode_availability
import pycam.Gui.common as GuiCommon import pycam.Gui.common as GuiCommon
import pycam.Gui.Settings import pycam.Gui.Settings
import pycam.Gui.Console import pycam.Gui.Console
import pycam.Importers.TestModel import pycam.Importers.TestModel
import pycam.Importers import pycam.Importers
import pycam.Exporters.SimpleGCodeExporter import pycam.Exporters.SimpleGCodeExporter
import pycam.Toolpath.Generator import pycam.Toolpath.Generator
from pycam.Toolpath import Bounds, Toolpath from pycam.Toolpath import Bounds, Toolpath
from pycam import VERSION from pycam import VERSION
import pycam.Utils.log import pycam.Utils.log
import logging import logging
import time import time
log = pycam.Utils.log.get_logger() log = pycam.Utils.log.get_logger()
EXAMPLE_MODEL_LOCATIONS = [ EXAMPLE_MODEL_LOCATIONS = [
os.path.join(os.path.dirname(__file__), "samples"), os.path.join(os.path.dirname(__file__), "samples"),
os.path.join(sys.prefix, "share", "pycam", "samples"), os.path.join(sys.prefix, "share", "pycam", "samples"),
os.path.join("usr", "share", "pycam", "samples")] os.path.join("usr", "share", "pycam", "samples")]
# for pyinstaller (windows distribution) # for pyinstaller (windows distribution)
if "_MEIPASS2" in os.environ: if "_MEIPASS2" in os.environ:
EXAMPLE_MODEL_LOCATIONS.insert(0, os.path.join(os.environ["_MEIPASS2"], "samples")) EXAMPLE_MODEL_LOCATIONS.insert(0, os.path.join(os.environ["_MEIPASS2"], "samples"))
DEFAULT_MODEL_FILE = "pycam.stl" DEFAULT_MODEL_FILE = "pycam.stl"
EXIT_CODES = {"ok": 0, "requirements": 1, "load_model_failed": 2, EXIT_CODES = {"ok": 0, "requirements": 1, "load_model_failed": 2,
"write_output_failed": 3, "parsing_failed": 4} "write_output_failed": 3, "parsing_failed": 4}
def show_gui(inputfile=None, task_settings_file=None): def show_gui(inputfile=None, task_settings_file=None):
deps_gtk = GuiCommon.requirements_details_gtk() deps_gtk = GuiCommon.requirements_details_gtk()
report_gtk = GuiCommon.get_dependency_report(deps_gtk, prefix="\t") report_gtk = GuiCommon.get_dependency_report(deps_gtk, prefix="\t")
if GuiCommon.check_dependencies(deps_gtk): if GuiCommon.check_dependencies(deps_gtk):
from pycam.Gui.Project import ProjectGui from pycam.Gui.Project import ProjectGui
gui_class = ProjectGui gui_class = ProjectGui
else: else:
full_report = [] full_report = []
full_report.append("PyCAM dependency problem") full_report.append("PyCAM dependency problem")
full_report.append("Error: Failed to load the GTK interface.") full_report.append("Error: Failed to load the GTK interface.")
full_report.append("Details:") full_report.append("Details:")
full_report.append(report_gtk) full_report.append(report_gtk)
full_report.append("") full_report.append("")
full_report.append("Detailed list of requirements: %s" % GuiCommon.REQUIREMENTS_LINK) full_report.append("Detailed list of requirements: %s" % GuiCommon.REQUIREMENTS_LINK)
log.critical(os.linesep.join(full_report)) log.critical(os.linesep.join(full_report))
sys.exit(EXIT_CODES["requirements"]) sys.exit(EXIT_CODES["requirements"])
gui = gui_class() gui = gui_class()
# load the given model or the default # load the given model or the default
if inputfile is None: if inputfile is None:
default_model = get_default_model() default_model = get_default_model()
if isinstance(default_model, basestring): if isinstance(default_model, basestring):
gui.load_model_file(filename=default_model) gui.load_model_file(filename=default_model)
else: else:
gui.load_model(default_model) gui.load_model(default_model)
else: else:
gui.load_model_file(filename=inputfile) gui.load_model_file(filename=inputfile)
# load task settings file # load task settings file
if not task_settings_file is None: if not task_settings_file is None:
gui.open_task_settings_file(task_settings_file) gui.open_task_settings_file(task_settings_file)
# open the GUI # open the GUI
gui.mainloop() gui.mainloop()
def get_default_model(): def get_default_model():
""" return a filename or a Model instance """ """ return a filename or a Model instance """
# try to load the default model file ("pycam" logo) # try to load the default model file ("pycam" logo)
for inputdir in EXAMPLE_MODEL_LOCATIONS: for inputdir in EXAMPLE_MODEL_LOCATIONS:
inputfile = os.path.join(inputdir, DEFAULT_MODEL_FILE) inputfile = os.path.join(inputdir, DEFAULT_MODEL_FILE)
if os.path.isfile(inputfile): if os.path.isfile(inputfile):
return inputfile return inputfile
else: else:
# fall back to the simple test model # fall back to the simple test model
log.warn("Failed to find the default model (%s) in the " \ log.warn("Failed to find the default model (%s) in the " \
"following locations: %s" % (DEFAULT_MODEL_FILE, "following locations: %s" % (DEFAULT_MODEL_FILE,
", ".join(EXAMPLE_MODEL_LOCATIONS))) ", ".join(EXAMPLE_MODEL_LOCATIONS)))
return pycam.Importers.TestModel.get_test_model() return pycam.Importers.TestModel.get_test_model()
def load_model_file(filename, program_locations): def load_model_file(filename, program_locations):
filename = os.path.expanduser(filename) filename = os.path.expanduser(filename)
if not os.path.isfile(filename): if not os.path.isfile(filename):
log.warn("The input file ('%') was not found!" % filename) log.warn("The input file ('%') was not found!" % filename)
return None return None
filetype, importer = pycam.Importers.detect_file_type(filename) filetype, importer = pycam.Importers.detect_file_type(filename)
model = importer(filename, program_locations=program_locations) model = importer(filename, program_locations=program_locations)
if model is None: if model is None:
log.warn("Failed to load the model file (%s)." % filename) log.warn("Failed to load the model file (%s)." % filename)
return None return None
else: else:
return model return model
def get_output_handler(destination): def get_output_handler(destination):
if destination == "-": if destination == "-":
handler = sys.stdout handler = sys.stdout
closer = lambda: None closer = lambda: None
else: else:
try: try:
handler = open(destination, "w") handler = open(destination, "w")
except IOError, err_msg: except IOError, err_msg:
log.error("Failed to open output file (%s) for writing: %s" \ log.error("Failed to open output file (%s) for writing: %s" \
% (destination, err_msg)) % (destination, err_msg))
return None, None return None, None
closer = handler.close closer = handler.close
return (handler, closer) return (handler, closer)
# check if we were started as a separate program # check if we were started as a separate program
if __name__ == "__main__": if __name__ == "__main__":
parser = OptionParser(prog="PyCAM", parser = OptionParser(prog="PyCAM",
usage="usage: pycam [options] [inputfile]\n\n" \ usage="usage: pycam [options] [inputfile]\n\n" \
+ "Start the PyCAM toolpath generator. Supplying one of " \ + "Start the PyCAM toolpath generator. Supplying one of " \
+ "the '--export-?' parameters will cause PyCAM to start " \ + "the '--export-?' parameters will cause PyCAM to start " \
+ "in batch mode. Most parameters are useful only for " \ + "in batch mode. Most parameters are useful only for " \
+ "batch mode.", + "batch mode.",
epilog="Take a look at the wiki for more information: " \ epilog="Take a look at the wiki for more information: " \
+ "http://sourceforge.net/apps/mediawiki/pycam/.\n" \ + "http://sourceforge.net/apps/mediawiki/pycam/.\n" \
+ "Bug reports: http://sourceforge.net/tracker/?group_id=237831&atid=1104176") + "Bug reports: http://sourceforge.net/tracker/?group_id=237831&atid=1104176")
group_general = parser.add_option_group("General options") group_general = parser.add_option_group("General options")
group_export = parser.add_option_group("Export formats", group_export = parser.add_option_group("Export formats",
"Export the resulting toolpath or meta-data in various formats. " \ "Export the resulting toolpath or meta-data in various formats. " \
+ "These options trigger the non-interactive mode. Thus the GUI " \ + "These options trigger the non-interactive mode. Thus the GUI " \
+ "is disabled.") + "is disabled.")
group_tool = parser.add_option_group("Tool definition", group_tool = parser.add_option_group("Tool definition",
"Specify the tool paramters. The default tool is spherical and " \ "Specify the tool paramters. The default tool is spherical and " \
+ "has a diameter of 1 unit. The default speeds are 1000 " \ + "has a diameter of 1 unit. The default speeds are 1000 " \
+ "units/minute (feedrate) and 250 (spindle rotations per minute)") + "units/minute (feedrate) and 250 (spindle rotations per minute)")
group_process = parser.add_option_group("Process definition", group_process = parser.add_option_group("Process definition",
"Specify the process parameters: toolpath strategy, layer height," \ "Specify the process parameters: toolpath strategy, layer height," \
+ " and others. A typical roughing operation is configured by " \ + " and others. A typical roughing operation is configured by " \
+ "default.") + "default.")
group_bounds = parser.add_option_group("Boundary definition", group_bounds = parser.add_option_group("Boundary definition",
"Specify the outer limits of the processing area (x/y/z). " \ "Specify the outer limits of the processing area (x/y/z). " \
+ "You may choose between 'relative_margin' (margin is given as " \ + "You may choose between 'relative_margin' (margin is given as " \
+ "percentage of the respective model dimension), 'fixed_margin' " \ + "percentage of the respective model dimension), 'fixed_margin' " \
+ "(margin for each face given in absolute units of length) " \ + "(margin for each face given in absolute units of length) " \
+ "and 'custom' (absolute coordinates of the bounding box - " \ + "and 'custom' (absolute coordinates of the bounding box - " \
+ "regardless of the model size and position). Negative values " \ + "regardless of the model size and position). Negative values " \
+ "are allowed and can make sense (e.g. negative margin).") + "are allowed and can make sense (e.g. negative margin).")
group_support_grid = parser.add_option_group("Support grid", group_support_grid = parser.add_option_group("Support grid",
"An optional support grid can be used to keep the object in " \ "An optional support grid can be used to keep the object in " \
+ "place during the mill operation. The support grid can be " \ + "place during the mill operation. The support grid can be " \
+ "removed manually afterwards. The support grid can have a " \ + "removed manually afterwards. The support grid can have a " \
+ "rectangular profile. By default the support grid is disabled.") + "rectangular profile. By default the support grid is disabled.")
group_external_programs = parser.add_option_group("External programs", group_external_programs = parser.add_option_group("External programs",
"Some optional external programs are used for format conversions.") "Some optional external programs are used for format conversions.")
# general options # general options
group_general.add_option("-c", "--config", dest="config_file", group_general.add_option("-c", "--config", dest="config_file",
default=None, action="store", type="string", default=None, action="store", type="string",
help="load a task settings file") help="load a task settings file")
group_general.add_option("", "--unit", dest="unit_size", group_general.add_option("", "--unit", dest="unit_size",
default="mm", action="store", type="choice", default="mm", action="store", type="choice",
choices=["mm", "inch"], help="choose 'mm' or 'inch' for all " \ choices=["mm", "inch"], help="choose 'mm' or 'inch' for all " \
+ "numbers. By default 'mm' is assumed.") + "numbers. By default 'mm' is assumed.")
group_general.add_option("", "--collision-engine", dest="collision_engine", group_general.add_option("", "--collision-engine", dest="collision_engine",
default="triangles", action="store", type="choice", default="triangles", action="store", type="choice",
choices=["triangles", "ode"], choices=["triangles", "ode"],
help="choose a specific collision detection engine. The default " \ help="choose a specific collision detection engine. The default " \
+ "is 'triangles'. Use 'help' to get a list of possible " \ + "is 'triangles'. Use 'help' to get a list of possible " \
+ "engines.") + "engines.")
group_general.add_option("", "--boundary-mode", dest="boundary_mode", group_general.add_option("", "--boundary-mode", dest="boundary_mode",
default="along", action="store", type="choice", default="along", action="store", type="choice",
choices=["inside", "along", "outside"], choices=["inside", "along", "outside"],
help="specify if the mill tool (including its radius) should " \ help="specify if the mill tool (including its radius) should " \
+ "move completely 'inside', 'along' or 'outside' the " \ + "move completely 'inside', 'along' or 'outside' the " \
+ "defined processing boundary.") + "defined processing boundary.")
group_general.add_option("", "--disable-psyco", dest="disable_psyco", group_general.add_option("", "--disable-psyco", dest="disable_psyco",
default=False, action="store_true", help="disable the Psyco " \ default=False, action="store_true", help="disable the Psyco " \
+ "just-in-time-compiler even when it is available") + "just-in-time-compiler even when it is available")
group_general.add_option("-q", "--quiet", dest="quiet", group_general.add_option("-q", "--quiet", dest="quiet",
default=False, action="store_true", help="show only warnings and " \ default=False, action="store_true", help="show only warnings and " \
+ "errors.") + "errors.")
group_general.add_option("", "--progress", dest="progress", group_general.add_option("", "--progress", dest="progress",
default="text", action="store", type="choice", default="text", action="store", type="choice",
choices=["none", "text", "bar", "dot"], choices=["none", "text", "bar", "dot"],
help="specify the type of progress bar used in non-GUI mode. " \ help="specify the type of progress bar used in non-GUI mode. " \
+ "The following options are available: text, none, bar, dot.") + "The following options are available: text, none, bar, dot.")
group_general.add_option("-v", "--version", dest="show_version", group_general.add_option("-v", "--version", dest="show_version",
default=False, action="store_true", help="show the current " \ default=False, action="store_true", help="show the current " \
+ "version of PyCAM and exit") + "version of PyCAM and exit")
# export options # export options
group_export.add_option("", "--export-gcode", dest="export_gcode", group_export.add_option("", "--export-gcode", dest="export_gcode",
default=None, action="store", type="string", default=None, action="store", type="string",
help="export the generated toolpaths to a file") help="export the generated toolpaths to a file")
group_export.add_option("", "--export-task-config", group_export.add_option("", "--export-task-config",
dest="export_task_config", default=None, action="store", dest="export_task_config", default=None, action="store",
type="string", type="string",
help="export the current task configuration (mainly for debugging)") help="export the current task configuration (mainly for debugging)")
# tool options # tool options
group_tool.add_option("", "--tool-shape", dest="tool_shape", group_tool.add_option("", "--tool-shape", dest="tool_shape",
default="cylindrical", action="store", type="choice", default="cylindrical", action="store", type="choice",
choices=["cylindrical", "spherical", "toroidal"], choices=["cylindrical", "spherical", "toroidal"],
help="tool shape for the operation (cylindrical, spherical, " \ help="tool shape for the operation (cylindrical, spherical, " \
+ "toroidal)") + "toroidal)")
group_tool.add_option("", "--tool-size", dest="tool_diameter", group_tool.add_option("", "--tool-size", dest="tool_diameter",
default=1.0, action="store", type="float", default=1.0, action="store", type="float",
help="diameter of the tool") help="diameter of the tool")
group_tool.add_option("", "--tool-torus-size", dest="tool_torus_diameter", group_tool.add_option("", "--tool-torus-size", dest="tool_torus_diameter",
default=0.25, action="store", type="float", default=0.25, action="store", type="float",
help="torus diameter of the tool (only for toroidal tool shape)") help="torus diameter of the tool (only for toroidal tool shape)")
group_tool.add_option("", "--tool-feedrate", dest="tool_feedrate", group_tool.add_option("", "--tool-feedrate", dest="tool_feedrate",
default=1000, action="store", type="float", default=1000, action="store", type="float",
help="allowed movement velocity of the tool (units/minute)") help="allowed movement velocity of the tool (units/minute)")
group_tool.add_option("", "--tool-spindle-speed", dest="tool_spindle_speed", group_tool.add_option("", "--tool-spindle-speed", dest="tool_spindle_speed",
default=250, action="store", type="float", default=250, action="store", type="float",
help="rotation speed of the tool (per minute)") help="rotation speed of the tool (per minute)")
group_tool.add_option("", "--tool-id", dest="tool_id", group_tool.add_option("", "--tool-id", dest="tool_id",
default=1, action="store", type="int", default=1, action="store", type="int",
help="tool ID - to be used for tool selection via GCode " \ help="tool ID - to be used for tool selection via GCode " \
+ "(default: 1)") + "(default: 1)")
# process options # process options
group_process.add_option("", "--process-path-direction", group_process.add_option("", "--process-path-direction",
dest="process_path_direction", default="x", action="store", dest="process_path_direction", default="x", action="store",
type="choice", choices=["x", "y", "xy"], type="choice", choices=["x", "y", "xy"],
help="primary direction of the generated toolpath (x/y/xy)") help="primary direction of the generated toolpath (x/y/xy)")
group_process.add_option("", "--process-path-generator", group_process.add_option("", "--process-path-generator",
dest="process_path_generator", default="layer", action="store", dest="process_path_generator", default="layer", action="store",
type="choice", choices=["layer", "surface", "engrave"], type="choice", choices=["layer", "surface", "engrave"],
help="one of the available toolpath strategies (layer, surface, " \ help="one of the available toolpath strategies (layer, surface, " \
+ "engrave)") + "engrave)")
group_process.add_option("", "--process-path-postprocessor", group_process.add_option("", "--process-path-postprocessor",
dest="process_path_postprocessor", default="polygon", dest="process_path_postprocessor", default="polygon",
action="store", type="choice", action="store", type="choice",
choices=["polygon", "contour", "zigzag"], help="one of the " \ choices=["polygon", "contour", "zigzag"], help="one of the " \
+ "available toolpath postprocessors (polygon, zigzag, contour)") + "available toolpath postprocessors (polygon, zigzag, contour)")
group_process.add_option("", "--process-material-allowance", group_process.add_option("", "--process-material-allowance",
dest="process_material_allowance", default=0.0, action="store", dest="process_material_allowance", default=0.0, action="store",
type="float", help="minimum distance between the tool and the " \ type="float", help="minimum distance between the tool and the " \
+ "object (for rough processing)") + "object (for rough processing)")
group_process.add_option("", "--process-step-down", group_process.add_option("", "--process-step-down",
dest="process_step_down", default=3.0, action="store", type="float", dest="process_step_down", default=3.0, action="store", type="float",
help="the maximum thickness of each processed material layer " \ help="the maximum thickness of each processed material layer " \
+ "(only for 'layer' strategy)") + "(only for 'layer' strategy)")
group_process.add_option("", "--process-overlap-percent", group_process.add_option("", "--process-overlap-percent",
dest="process_overlap_percent", default=0, action="store", dest="process_overlap_percent", default=0, action="store",
type="int", help="how much should two adjacent parallel " \ type="int", help="how much should two adjacent parallel " \
+ "toolpaths overlap each other (0..99)") + "toolpaths overlap each other (0..99)")
group_process.add_option("", "--safety-height", dest="safety_height", group_process.add_option("", "--safety-height", dest="safety_height",
default=25.0, action="store", type="float", default=25.0, action="store", type="float",
help="height for safe re-positioning moves") help="height for safe re-positioning moves")
group_process.add_option("", "--process-engrave-offset", group_process.add_option("", "--process-engrave-offset",
dest="process_engrave_offset", default=0.0, action="store", dest="process_engrave_offset", default=0.0, action="store",
type="float", help="engrave along the contour of a model with a " \ type="float", help="engrave along the contour of a model with a " \
+ "given distance (only for 'engrave' strategy)") + "given distance (only for 'engrave' strategy)")
# bounds settings # bounds settings
group_bounds.add_option("", "--bounds-type", dest="bounds_type", group_bounds.add_option("", "--bounds-type", dest="bounds_type",
default="fixed-margin", action="store", type="choice", default="fixed-margin", action="store", type="choice",
choices=["relative-margin", "fixed-margin", "custom"], choices=["relative-margin", "fixed-margin", "custom"],
help="type of the boundary definition (relative-margin, " \ help="type of the boundary definition (relative-margin, " \
+ "fixed-margin, custom)") + "fixed-margin, custom)")
group_bounds.add_option("", "--bounds-lower", dest="bounds_lower", group_bounds.add_option("", "--bounds-lower", dest="bounds_lower",
default="", action="store", type="string", default="", action="store", type="string",
help="comma-separated x/y/z combination of the lower boundary " \ help="comma-separated x/y/z combination of the lower boundary " \
+ "(e.g. '4,4,-0.5')") + "(e.g. '4,4,-0.5')")
group_bounds.add_option("", "--bounds-upper", dest="bounds_upper", group_bounds.add_option("", "--bounds-upper", dest="bounds_upper",
default="", action="store", type="string", default="", action="store", type="string",
help="comma-separated x/y/z combination of the upper boundary " \ help="comma-separated x/y/z combination of the upper boundary " \
+ "(e.g. '12,5.5,0')") + "(e.g. '12,5.5,0')")
# support grid settings # support grid settings
group_support_grid.add_option("", "--enable-support-grid", group_support_grid.add_option("", "--enable-support-grid",
dest="support_grid_enabled", default=False, action="store_true", dest="support_grid_enabled", default=False, action="store_true",
help="enable the support grid") help="enable the support grid")
group_support_grid.add_option("", "--support-grid-distance-x", group_support_grid.add_option("", "--support-grid-distance-x",
dest="support_grid_distance_x", default=10.0, action="store", dest="support_grid_distance_x", default=10.0, action="store",
type="float", help="distance along the x-axis between two " \ type="float", help="distance along the x-axis between two " \
+ "adjacent parallel lines of the support grid pattern") + "adjacent parallel lines of the support grid pattern")
group_support_grid.add_option("", "--support-grid-distance-y", group_support_grid.add_option("", "--support-grid-distance-y",
dest="support_grid_distance_y", default=10.0, action="store", dest="support_grid_distance_y", default=10.0, action="store",
type="float", help="distance along the y-axis between two " \ type="float", help="distance along the y-axis between two " \
+ "adjacent parallel lines of the support grid pattern") + "adjacent parallel lines of the support grid pattern")
group_support_grid.add_option("", "--support-grid-height", group_support_grid.add_option("", "--support-grid-height",
dest="support_grid_height", default=2.0, action="store", dest="support_grid_height", default=2.0, action="store",
type="float", help="height of the support grid profile") type="float", help="height of the support grid profile")
group_support_grid.add_option("", "--support-grid-thickness", group_support_grid.add_option("", "--support-grid-thickness",
dest="support_grid_thickness", default=0.5, action="store", dest="support_grid_thickness", default=0.5, action="store",
type="float", help="width of the support grid profile") type="float", help="width of the support grid profile")
# external program settings # external program settings
group_external_programs.add_option("", "--location-inkscape", group_external_programs.add_option("", "--location-inkscape",
dest="external_program_inkscape", default="", action="store", dest="external_program_inkscape", default="", action="store",
type="string", help="location of the Inkscape executable. " \ type="string", help="location of the Inkscape executable. " \
+ "This program is required for importing SVG files.") + "This program is required for importing SVG files.")
group_external_programs.add_option("", "--location-pstoedit", group_external_programs.add_option("", "--location-pstoedit",
dest="external_program_pstoedit", default="", action="store", dest="external_program_pstoedit", default="", action="store",
type="string", help="location of the PStoEdit executable. " \ type="string", help="location of the PStoEdit executable. " \
+ "This program is required for importing SVG files.") + "This program is required for importing SVG files.")
(opts, args) = parser.parse_args() (opts, args) = parser.parse_args()
if len(args) > 0: if len(args) > 0:
inputfile = os.path.expanduser(args[0]) inputfile = os.path.expanduser(args[0])
else: else:
inputfile = None inputfile = None
if opts.quiet: if opts.quiet:
log.setLevel(logging.WARNING) log.setLevel(logging.WARNING)
# disable the progress bar # disable the progress bar
opts.progress = "none" opts.progress = "none"
# show version and exit # show version and exit
if opts.show_version: if opts.show_version:
if opts.quiet: if opts.quiet:
# print only the bare version number # print only the bare version number
print VERSION print VERSION
else: else:
print "PyCAM %s" % VERSION print "PyCAM %s" % VERSION
print "Copyright (C) 2008-2010 Lode Leroy" print "Copyright (C) 2008-2010 Lode Leroy"
print "Copyright (C) 2010 Lars Kruse" print "Copyright (C) 2010 Lars Kruse"
print print
print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>." print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>."
print "This is free software: you are free to change and redistribute it." print "This is free software: you are free to change and redistribute it."
print "There is NO WARRANTY, to the extent permitted by law." print "There is NO WARRANTY, to the extent permitted by law."
sys.exit(EXIT_CODES["ok"]) sys.exit(EXIT_CODES["ok"])
if not opts.disable_psyco: if not opts.disable_psyco:
try: try:
import psyco import psyco
psyco.full() psyco.full()
log.info("Psyco enabled") log.info("Psyco enabled")
except ImportError: except ImportError:
log.info("Psyco is not available (performance will probably " \ log.info("Psyco is not available (performance will probably " \
+ "suffer slightly)") + "suffer slightly)")
else: else:
log.info("Psyco was disabled via the commandline") log.info("Psyco was disabled via the commandline")
# initialize the progress bar # initialize the progress bar
progress_styles = {"none": pycam.Gui.Console.ConsoleProgressBar.STYLE_NONE, progress_styles = {"none": pycam.Gui.Console.ConsoleProgressBar.STYLE_NONE,
"text": pycam.Gui.Console.ConsoleProgressBar.STYLE_TEXT, "text": pycam.Gui.Console.ConsoleProgressBar.STYLE_TEXT,
"bar": pycam.Gui.Console.ConsoleProgressBar.STYLE_BAR, "bar": pycam.Gui.Console.ConsoleProgressBar.STYLE_BAR,
"dot": pycam.Gui.Console.ConsoleProgressBar.STYLE_DOT, "dot": pycam.Gui.Console.ConsoleProgressBar.STYLE_DOT,
} }
progress_bar = pycam.Gui.Console.ConsoleProgressBar(sys.stdout, progress_bar = pycam.Gui.Console.ConsoleProgressBar(sys.stdout,
progress_styles[opts.progress]) progress_styles[opts.progress])
if opts.config_file: if opts.config_file:
opts.config_file = os.path.expanduser(opts.config_file) opts.config_file = os.path.expanduser(opts.config_file)
if not opts.export_gcode and not opts.export_task_config: if not opts.export_gcode and not opts.export_task_config:
show_gui(inputfile, opts.config_file) show_gui(inputfile, opts.config_file)
else: else:
# generate toolpath # generate toolpath
tps = pycam.Gui.Settings.ToolpathSettings() tps = pycam.Gui.Settings.ToolpathSettings()
tool_shape = {"cylindrical": "CylindricalCutter", tool_shape = {"cylindrical": "CylindricalCutter",
"spherical": "SphericalCutter", "spherical": "SphericalCutter",
"toroidal": "ToroidalCutter", "toroidal": "ToroidalCutter",
}[opts.tool_shape] }[opts.tool_shape]
tps.set_tool(opts.tool_id, tool_shape, 0.5 * opts.tool_diameter, tps.set_tool(opts.tool_id, tool_shape, 0.5 * opts.tool_diameter,
0.5 * opts.tool_torus_diameter, opts.tool_spindle_speed, 0.5 * opts.tool_torus_diameter, opts.tool_spindle_speed,
opts.tool_feedrate) opts.tool_feedrate)
if opts.support_grid_enabled: if opts.support_grid_enabled:
tps.set_support_grid(opts.support_grid_distance_x, tps.set_support_grid(opts.support_grid_distance_x,
opts.support_grid_distance_y, opts.support_grid_thickness, opts.support_grid_distance_y, opts.support_grid_thickness,
opts.support_grid_height) opts.support_grid_height)
if opts.collision_engine == "ode": if opts.collision_engine == "ode":
tps.set_calculation_backend("ODE") tps.set_calculation_backend("ODE")
tps.set_unit_size(opts.unit_size) tps.set_unit_size(opts.unit_size)
path_generator = {"layer": "PushCutter", path_generator = {"layer": "PushCutter",
"surface": "DropCutter", "surface": "DropCutter",
"engrave": "EngraveCutter", "engrave": "EngraveCutter",
}[opts.process_path_generator] }[opts.process_path_generator]
postprocessor = {"zigzag": "ZigZagCutter", postprocessor = {"zigzag": "ZigZagCutter",
"contour": "ContourCutter", "contour": "ContourCutter",
"polygon": "PolygonCutter", "polygon": "PolygonCutter",
}[opts.process_path_postprocessor] }[opts.process_path_postprocessor]
tps.set_process_settings(path_generator, postprocessor, tps.set_process_settings(path_generator, postprocessor,
opts.process_path_direction, opts.process_material_allowance, opts.process_path_direction, opts.process_material_allowance,
opts.safety_height, opts.process_overlap_percent / 100.0, opts.safety_height, opts.process_overlap_percent / 100.0,
opts.process_step_down, opts.process_engrave_offset) opts.process_step_down, opts.process_engrave_offset)
# set locations of external programs # set locations of external programs
program_locations = {} program_locations = {}
if opts.external_program_inkscape: if opts.external_program_inkscape:
program_locations["inkscape"] = opts.external_program_inkscape program_locations["inkscape"] = opts.external_program_inkscape
if opts.external_program_pstoedit: if opts.external_program_pstoedit:
program_locations["pstoedit"] = opts.external_program_pstoedit program_locations["pstoedit"] = opts.external_program_pstoedit
# load the model # load the model
if inputfile is None: if inputfile is None:
model = get_default_model() model = get_default_model()
# the "get_default_model" function returns a string or a model # the "get_default_model" function returns a string or a model
if isinstance(model, basestring): if isinstance(model, basestring):
model = load_model_file(model, model = load_model_file(model,
program_locations=program_locations, program_locations=program_locations,
unit=opts.unit_size) unit=opts.unit_size)
else: else:
model = load_model_file(inputfile, model = load_model_file(inputfile,
program_locations=program_locations, unit=opts.unit_size) program_locations=program_locations, unit=opts.unit_size)
if model is None: if model is None:
# something went wrong - we quit # something went wrong - we quit
sys.exit(EXIT_CODES["load_model_failed"]) sys.exit(EXIT_CODES["load_model_failed"])
# calculate the processing boundary # calculate the processing boundary
bounds = Bounds() bounds = Bounds()
bounds.set_reference(model.get_bounds()) bounds.set_reference(model.get_bounds())
# set the bounds type and let the default bounding box match the model # set the bounds type and let the default bounding box match the model
if opts.bounds_type == "relative-margin": if opts.bounds_type == "relative-margin":
bounds.set_type(Bounds.TYPE_RELATIVE_MARGIN) bounds.set_type(Bounds.TYPE_RELATIVE_MARGIN)
bounds_default_low = (0, 0, 0) bounds_default_low = (0, 0, 0)
bounds_default_high = (0, 0, 0) bounds_default_high = (0, 0, 0)
elif opts.bounds_type == "fixed-margin": elif opts.bounds_type == "fixed-margin":
bounds.set_type(Bounds.TYPE_FIXED_MARGIN) bounds.set_type(Bounds.TYPE_FIXED_MARGIN)
bounds_default_low = (0, 0, 0) bounds_default_low = (0, 0, 0)
bounds_default_high = (0, 0, 0) bounds_default_high = (0, 0, 0)
else: else:
# custom boundary setting # custom boundary setting
bounds.set_type(Bounds.TYPE_CUSTOM) bounds.set_type(Bounds.TYPE_CUSTOM)
bounds_default_low = (model.minx, model.miny, model.minz) bounds_default_low = (model.minx, model.miny, model.minz)
bounds_default_high = (model.maxx, model.maxy, model.maxz) bounds_default_high = (model.maxx, model.maxy, model.maxz)
# TODO: use the optparse conversion callback instead # TODO: use the optparse conversion callback instead
def parse_triple_float(text): def parse_triple_float(text):
nums = text.split(",") nums = text.split(",")
if len(nums) != 3: if len(nums) != 3:
return None return None
result = [] result = []
for num in nums: for num in nums:
try: try:
result.append(float(num)) result.append(float(num))
except ValueError: except ValueError:
if num == "": if num == "":
result.append(0.0) result.append(0.0)
else: else:
return None return None
return result return result
bounds_lower_nums = parse_triple_float(opts.bounds_lower) bounds_lower_nums = parse_triple_float(opts.bounds_lower)
if opts.bounds_lower and not bounds_lower_nums: if opts.bounds_lower and not bounds_lower_nums:
log.error("Failed to parse the lower boundary limit: %s" \ log.error("Failed to parse the lower boundary limit: %s" \
% opts.bounds_lower) % opts.bounds_lower)
sys.exit(EXIT_CODES["parsing_failed"]) sys.exit(EXIT_CODES["parsing_failed"])
bounds_upper_nums = parse_triple_float(opts.bounds_upper) bounds_upper_nums = parse_triple_float(opts.bounds_upper)
if opts.bounds_upper and not bounds_upper_nums: if opts.bounds_upper and not bounds_upper_nums:
log.error("Failed to parse the upper boundary limit: %s" \ log.error("Failed to parse the upper boundary limit: %s" \
% opts.bounds_upper) % opts.bounds_upper)
sys.exit(EXIT_CODES["parsing_failed"]) sys.exit(EXIT_CODES["parsing_failed"])
if bounds_lower_nums is None: if bounds_lower_nums is None:
bounds_lower_nums = bounds_default_low bounds_lower_nums = bounds_default_low
if bounds_upper_nums is None: if bounds_upper_nums is None:
bounds_upper_nums = bounds_default_high bounds_upper_nums = bounds_default_high
# both lower and upper bounds were specified # both lower and upper bounds were specified
bounds.set_bounds(bounds_lower_nums, bounds_upper_nums) bounds.set_bounds(bounds_lower_nums, bounds_upper_nums)
# adjust the bounding box according to the "boundary_mode" # adjust the bounding box according to the "boundary_mode"
if opts.boundary_mode == "along": if opts.boundary_mode == "along":
offset = (0, 0, 0) offset = (0, 0, 0)
elif opts.boundary_mode == "inside": elif opts.boundary_mode == "inside":
offset = (-0.5 * opts.tool_diameter, -0.5 * opts.tool_diameter, 0) offset = (-0.5 * opts.tool_diameter, -0.5 * opts.tool_diameter, 0)
else: else:
# "outside" # "outside"
offset = (0.5 * opts.tool_diameter, 0.5 * opts.tool_diameter, 0) offset = (0.5 * opts.tool_diameter, 0.5 * opts.tool_diameter, 0)
process_bounds = Bounds(Bounds.TYPE_FIXED_MARGIN, offset, offset) process_bounds = Bounds(Bounds.TYPE_FIXED_MARGIN, offset, offset)
process_bounds.set_reference(bounds) process_bounds.set_reference(bounds)
tps.set_bounds(process_bounds) tps.set_bounds(process_bounds)
if opts.export_gcode: if opts.export_gcode:
# generate the toolpath # generate the toolpath
start_time = time.time() start_time = time.time()
toolpath = pycam.Toolpath.Generator.generate_toolpath_from_settings( toolpath = pycam.Toolpath.Generator.generate_toolpath_from_settings(
model, tps, callback=progress_bar.update) model, tps, callback=progress_bar.update)
progress_bar.finish() progress_bar.finish()
log.info("Toolpath generation time: %f" \ log.info("Toolpath generation time: %f" \
% (time.time() - start_time)) % (time.time() - start_time))
# write result # write result
if isinstance(toolpath, basestring): if isinstance(toolpath, basestring):
# an error occoured # an error occoured
log.error(toolpath) log.error(toolpath)
else: else:
description = "Toolpath generated via PyCAM v%s" % VERSION description = "Toolpath generated via PyCAM v%s" % VERSION
tp_obj = Toolpath(toolpath, description, tps) tp_obj = Toolpath(toolpath, description, tps)
handler, closer = get_output_handler(opts.export_gcode) handler, closer = get_output_handler(opts.export_gcode)
if handler is None: if handler is None:
sys.exit(EXIT_CODES["write_output_failed"]) sys.exit(EXIT_CODES["write_output_failed"])
pycam.Exporters.SimpleGCodeExporter.ExportPathList(handler, pycam.Exporters.SimpleGCodeExporter.ExportPathList(handler,
tp_obj.get_path(), opts.unit_size, opts.tool_feedrate, tp_obj.get_path(), opts.unit_size, opts.tool_feedrate,
opts.tool_spindle_speed, opts.tool_spindle_speed,
safety_height=opts.safety_height, safety_height=opts.safety_height,
max_skip_safety_distance=opts.tool_diameter, max_skip_safety_distance=opts.tool_diameter,
comment=tp_obj.get_meta_data()) comment=tp_obj.get_meta_data())
closer() closer()
if opts.export_task_config: if opts.export_task_config:
handler, closer = get_output_handler(opts.export_task_config) handler, closer = get_output_handler(opts.export_task_config)
if handler is None: if handler is None:
sys.exit(EXIT_CODES["write_output_failed"]) sys.exit(EXIT_CODES["write_output_failed"])
print >>handler, tps.get_string() print >>handler, tps.get_string()
closer() closer()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment