TclCommandBbox.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import collections
  2. from tclCommands.TclCommand import TclCommand
  3. from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
  4. from shapely.ops import cascaded_union
  5. import gettext
  6. import FlatCAMTranslation as fcTranslate
  7. import builtins
  8. fcTranslate.apply_language('strings')
  9. if '_' not in builtins.__dict__:
  10. _ = gettext.gettext
  11. class TclCommandBbox(TclCommand):
  12. """
  13. Tcl shell command to follow a Gerber file
  14. """
  15. # array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
  16. aliases = ['bounding_box', 'bbox']
  17. description = '%s %s' % ("--", "Creates a rectangular Geometry object that surrounds the object.")
  18. # dictionary of types from Tcl command, needs to be ordered
  19. arg_names = collections.OrderedDict([
  20. ('name', str)
  21. ])
  22. # dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
  23. option_types = collections.OrderedDict([
  24. ('outname', str),
  25. ('margin', float),
  26. ('rounded', str)
  27. ])
  28. # array of mandatory options for current Tcl command: required = {'name','outname'}
  29. required = ['name']
  30. # structured help for current command, args needs to be ordered
  31. help = {
  32. 'main': "Creates a rectangular Geometry object that surrounds the object.",
  33. 'args': collections.OrderedDict([
  34. ('name', 'Object name for which to create bounding box. String'),
  35. ('margin', "Distance of the edges of the box to the nearest polygon."
  36. "Float number."),
  37. ('rounded', "If the bounding box is to have rounded corners their radius is equal to the margin. "
  38. "True (1) or False (0)."),
  39. ('outname', 'Name of the resulting Geometry object. String.')
  40. ]),
  41. 'examples': ['bbox name -outname name_bbox']
  42. }
  43. def execute(self, args, unnamed_args):
  44. """
  45. execute current TCL shell command
  46. :param args: array of known named arguments and options
  47. :param unnamed_args: array of other values which were passed into command
  48. without -somename and we do not have them in known arg_names
  49. :return: None or exception
  50. """
  51. name = args['name']
  52. if 'outname' not in args:
  53. args['outname'] = name + "_bbox"
  54. obj = self.app.collection.get_by_name(name)
  55. if obj is None:
  56. self.raise_tcl_error("%s: %s" % (_("Object not found"), name))
  57. if not isinstance(obj, FlatCAMGerber) and not isinstance(obj, FlatCAMGeometry):
  58. self.raise_tcl_error('%s %s: %s.' % (
  59. _("Expected FlatCAMGerber or FlatCAMGeometry, got"), name, type(obj)))
  60. if 'margin' not in args:
  61. args['margin'] = float(self.app.defaults["gerber_bboxmargin"])
  62. margin = args['margin']
  63. if 'rounded' in args:
  64. try:
  65. par = args['rounded'].capitalize()
  66. except AttributeError:
  67. par = args['rounded']
  68. rounded = bool(eval(par))
  69. else:
  70. rounded = bool(eval(self.app.defaults["gerber_bboxrounded"]))
  71. del args['name']
  72. try:
  73. def geo_init(geo_obj, app_obj):
  74. assert isinstance(geo_obj, FlatCAMGeometry)
  75. # Bounding box with rounded corners
  76. geo = cascaded_union(obj.solid_geometry)
  77. bounding_box = geo.envelope.buffer(float(margin))
  78. if not rounded: # Remove rounded corners
  79. bounding_box = bounding_box.envelope
  80. geo_obj.solid_geometry = bounding_box
  81. self.app.new_object("geometry", args['outname'], geo_init, plot=False)
  82. except Exception as e:
  83. return "Operation failed: %s" % str(e)