Major modifications to data/gui interactions. In progress.
This commit is contained in:
495
FlatCAMObj.py
495
FlatCAMObj.py
@@ -11,7 +11,32 @@ from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GObject
|
||||
|
||||
import inspect # TODO: Remove
|
||||
|
||||
from FlatCAMApp import *
|
||||
from camlib import *
|
||||
from ObjectUI import *
|
||||
|
||||
|
||||
class LoudDict(dict):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LoudDict, self).__init__(*args, **kwargs)
|
||||
self.callback = lambda x: None
|
||||
self.silence = False
|
||||
|
||||
def set_change_callback(self, callback):
|
||||
if self.silence:
|
||||
return
|
||||
self.callback = callback
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
super(LoudDict, self).__setitem__(key, value)
|
||||
try:
|
||||
if self.__getitem__(key) == value:
|
||||
return
|
||||
except KeyError:
|
||||
pass
|
||||
self.callback(key)
|
||||
|
||||
|
||||
########################################
|
||||
@@ -28,19 +53,63 @@ class FlatCAMObj(GObject.GObject, object):
|
||||
# The app should set this value.
|
||||
app = None
|
||||
|
||||
def __init__(self, name):
|
||||
# name = GObject.property(type=str)
|
||||
|
||||
def __init__(self, name, ui):
|
||||
"""
|
||||
|
||||
:param name: Name of the object given by the user.
|
||||
:param ui: User interface to interact with the object.
|
||||
:type ui: ObjectUI
|
||||
:return: FlatCAMObj
|
||||
"""
|
||||
GObject.GObject.__init__(self)
|
||||
|
||||
self.options = {"name": name}
|
||||
self.form_kinds = {"name": "entry_text"} # Kind of form element for each option
|
||||
# View
|
||||
self.ui = ui
|
||||
|
||||
self.options = LoudDict(name=name)
|
||||
self.options.set_change_callback(self.on_options_change)
|
||||
|
||||
self.form_fields = {"name": self.ui.name_entry}
|
||||
self.radios = {} # Name value pairs for radio sets
|
||||
self.radios_inv = {} # Inverse of self.radios
|
||||
self.axes = None # Matplotlib axes
|
||||
self.kind = None # Override with proper name
|
||||
|
||||
self.muted_ui = False
|
||||
|
||||
self.ui.name_entry.connect('activate', self.on_name_activate)
|
||||
self.ui.offset_button.connect('clicked', self.on_offset_button_click)
|
||||
self.ui.offset_button.connect('activate', self.on_offset_button_click)
|
||||
self.ui.scale_button.connect('clicked', self.on_scale_button_click)
|
||||
self.ui.scale_button.connect('activate', self.on_scale_button_click)
|
||||
|
||||
def __str__(self):
|
||||
return "<FlatCAMObj({:12s}): {:20s}>".format(self.kind, self.options["name"])
|
||||
|
||||
def on_name_activate(self, *args):
|
||||
old_name = copy(self.options["name"])
|
||||
new_name = self.ui.name_entry.get_text()
|
||||
self.options["name"] = self.ui.name_entry.get_text()
|
||||
self.app.info("Name changed from %s to %s" % (old_name, new_name))
|
||||
|
||||
def on_offset_button_click(self, *args):
|
||||
self.read_form()
|
||||
vect = self.ui.offsetvector_entry.get_value()
|
||||
self.offset(vect)
|
||||
self.plot()
|
||||
|
||||
def on_scale_button_click(self, *args):
|
||||
self.read_form()
|
||||
factor = self.ui.scale_entry.get_value()
|
||||
self.scale(factor)
|
||||
self.plot()
|
||||
|
||||
def on_options_change(self, key):
|
||||
self.form_fields[key].set_value(self.options[key])
|
||||
return
|
||||
|
||||
def setup_axes(self, figure):
|
||||
"""
|
||||
1) Creates axes if they don't exist. 2) Clears axes. 3) Attaches
|
||||
@@ -89,6 +158,7 @@ class FlatCAMObj(GObject.GObject, object):
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
print inspect.stack()[1][3], "--> FlatCAMObj.read_form()"
|
||||
for option in self.options:
|
||||
self.read_form_item(option)
|
||||
|
||||
@@ -100,27 +170,25 @@ class FlatCAMObj(GObject.GObject, object):
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
self.muted_ui = True
|
||||
print inspect.stack()[1][3], "--> FlatCAMObj.build_ui()"
|
||||
|
||||
# Where the UI for this object is drawn
|
||||
box_selected = self.app.builder.get_object("box_selected")
|
||||
# box_selected = self.app.builder.get_object("box_selected")
|
||||
box_selected = self.app.builder.get_object("vp_selected")
|
||||
|
||||
# Remove anything else in the box
|
||||
box_children = box_selected.get_children()
|
||||
for child in box_children:
|
||||
box_selected.remove(child)
|
||||
|
||||
osw = self.app.builder.get_object("offscrwindow_" + self.kind) # offscreenwindow
|
||||
sw = self.app.builder.get_object("sw_" + self.kind) # scrollwindows
|
||||
osw.remove(sw) # TODO: Is this needed ?
|
||||
vp = self.app.builder.get_object("vp_" + self.kind) # Viewport
|
||||
vp.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(1, 1, 1, 1))
|
||||
|
||||
# Put in the UI
|
||||
box_selected.pack_start(sw, True, True, 0)
|
||||
|
||||
# entry_name = self.app.builder.get_object("entry_text_" + self.kind + "_name")
|
||||
# entry_name.connect("activate", self.app.on_activate_name)
|
||||
# box_selected.pack_start(sw, True, True, 0)
|
||||
box_selected.add(self.ui)
|
||||
self.to_form()
|
||||
sw.show()
|
||||
box_selected.show_all()
|
||||
self.ui.show()
|
||||
self.muted_ui = False
|
||||
|
||||
def set_form_item(self, option):
|
||||
"""
|
||||
@@ -130,19 +198,11 @@ class FlatCAMObj(GObject.GObject, object):
|
||||
:type option: str
|
||||
:return: None
|
||||
"""
|
||||
fkind = self.form_kinds[option]
|
||||
fname = fkind + "_" + self.kind + "_" + option
|
||||
|
||||
if fkind == 'entry_eval' or fkind == 'entry_text':
|
||||
self.app.builder.get_object(fname).set_text(str(self.options[option]))
|
||||
return
|
||||
if fkind == 'cb':
|
||||
self.app.builder.get_object(fname).set_active(self.options[option])
|
||||
return
|
||||
if fkind == 'radio':
|
||||
self.app.builder.get_object(self.radios_inv[option][self.options[option]]).set_active(True)
|
||||
return
|
||||
print "Unknown kind of form item:", fkind
|
||||
try:
|
||||
self.form_fields[option].set_value(self.options[option])
|
||||
except KeyError:
|
||||
App.log.warn("Tried to set an option or field that does not exist: %s" % option)
|
||||
|
||||
def read_form_item(self, option):
|
||||
"""
|
||||
@@ -152,22 +212,11 @@ class FlatCAMObj(GObject.GObject, object):
|
||||
:type option: str
|
||||
:return: None
|
||||
"""
|
||||
fkind = self.form_kinds[option]
|
||||
fname = fkind + "_" + self.kind + "_" + option
|
||||
|
||||
if fkind == 'entry_text':
|
||||
self.options[option] = self.app.builder.get_object(fname).get_text()
|
||||
return
|
||||
if fkind == 'entry_eval':
|
||||
self.options[option] = self.app.get_eval(fname)
|
||||
return
|
||||
if fkind == 'cb':
|
||||
self.options[option] = self.app.builder.get_object(fname).get_active()
|
||||
return
|
||||
if fkind == 'radio':
|
||||
self.options[option] = self.app.get_radio_value(self.radios[option])
|
||||
return
|
||||
print "Unknown kind of form item:", fkind
|
||||
try:
|
||||
self.options[option] = self.form_fields[option].get_value()
|
||||
except KeyError:
|
||||
App.log.warning("Failed to read option from field: %s" % option)
|
||||
|
||||
def plot(self):
|
||||
"""
|
||||
@@ -221,14 +270,31 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
|
||||
|
||||
def __init__(self, name):
|
||||
Gerber.__init__(self)
|
||||
FlatCAMObj.__init__(self, name)
|
||||
FlatCAMObj.__init__(self, name, GerberObjectUI())
|
||||
|
||||
self.kind = "gerber"
|
||||
|
||||
self.form_fields.update({
|
||||
"plot": self.ui.plot_cb,
|
||||
"multicolored": self.ui.multicolored_cb,
|
||||
"solid": self.ui.solid_cb,
|
||||
"isotooldia": self.ui.iso_tool_dia_entry,
|
||||
"isopasses": self.ui.iso_width_entry,
|
||||
"isooverlap": self.ui.iso_overlap_entry,
|
||||
"cutouttooldia": self.ui.cutout_tooldia_entry,
|
||||
"cutoutmargin": self.ui.cutout_margin_entry,
|
||||
"cutoutgapsize": self.ui.cutout_gap_entry,
|
||||
"gaps": self.ui.gaps_radio,
|
||||
"noncoppermargin": self.ui.noncopper_margin_entry,
|
||||
"noncopperrounded": self.ui.noncopper_rounded_cb,
|
||||
"bboxmargin": self.ui.bbmargin_entry,
|
||||
"bboxrounded": self.ui.bbrounded_cb
|
||||
})
|
||||
|
||||
# The 'name' is already in self.options from FlatCAMObj
|
||||
# Automatically updates the UI
|
||||
self.options.update({
|
||||
"plot": True,
|
||||
"mergepolys": True,
|
||||
"multicolored": False,
|
||||
"solid": False,
|
||||
"isotooldia": 0.016,
|
||||
@@ -244,33 +310,137 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
|
||||
"bboxrounded": False
|
||||
})
|
||||
|
||||
# The 'name' is already in self.form_kinds from FlatCAMObj
|
||||
self.form_kinds.update({
|
||||
"plot": "cb",
|
||||
"mergepolys": "cb",
|
||||
"multicolored": "cb",
|
||||
"solid": "cb",
|
||||
"isotooldia": "entry_eval",
|
||||
"isopasses": "entry_eval",
|
||||
"isooverlap": "entry_eval",
|
||||
"cutouttooldia": "entry_eval",
|
||||
"cutoutmargin": "entry_eval",
|
||||
"cutoutgapsize": "entry_eval",
|
||||
"gaps": "radio",
|
||||
"noncoppermargin": "entry_eval",
|
||||
"noncopperrounded": "cb",
|
||||
"bboxmargin": "entry_eval",
|
||||
"bboxrounded": "cb"
|
||||
})
|
||||
|
||||
self.radios = {"gaps": {"rb_2tb": "tb", "rb_2lr": "lr", "rb_4": "4"}}
|
||||
self.radios_inv = {"gaps": {"tb": "rb_2tb", "lr": "rb_2lr", "4": "rb_4"}}
|
||||
|
||||
# Attributes to be included in serialization
|
||||
# Always append to it because it carries contents
|
||||
# from predecessors.
|
||||
self.ser_attrs += ['options', 'kind']
|
||||
|
||||
assert isinstance(self.ui, GerberObjectUI)
|
||||
self.ui.plot_cb.connect('clicked', self.on_plot_cb_click)
|
||||
self.ui.plot_cb.connect('activate', self.on_plot_cb_click)
|
||||
self.ui.solid_cb.connect('clicked', self.on_solid_cb_click)
|
||||
self.ui.solid_cb.connect('activate', self.on_solid_cb_click)
|
||||
self.ui.multicolored_cb.connect('clicked', self.on_multicolored_cb_click)
|
||||
self.ui.multicolored_cb.connect('activate', self.on_multicolored_cb_click)
|
||||
self.ui.generate_iso_button.connect('clicked', self.on_iso_button_click)
|
||||
self.ui.generate_iso_button.connect('activate', self.on_iso_button_click)
|
||||
self.ui.generate_cutout_button.connect('clicked', self.on_generatecutout_button_click)
|
||||
self.ui.generate_cutout_button.connect('activate', self.on_generatecutout_button_click)
|
||||
self.ui.generate_bb_button.connect('clicked', self.on_generatebb_button_click)
|
||||
self.ui.generate_bb_button.connect('activate', self.on_generatebb_button_click)
|
||||
self.ui.generate_noncopper_button.connect('clicked', self.on_generatenoncopper_button_click)
|
||||
self.ui.generate_noncopper_button.connect('activate', self.on_generatenoncopper_button_click)
|
||||
|
||||
def on_generatenoncopper_button_click(self, *args):
|
||||
self.read_form()
|
||||
name = self.options["name"] + "_noncopper"
|
||||
|
||||
def geo_init(geo_obj, app_obj):
|
||||
assert isinstance(geo_obj, FlatCAMGeometry)
|
||||
bounding_box = self.solid_geometry.envelope.buffer(self.options["noncoppermargin"])
|
||||
if not self.options["noncopperrounded"]:
|
||||
bounding_box = bounding_box.envelope
|
||||
non_copper = bounding_box.difference(self.solid_geometry)
|
||||
geo_obj.solid_geometry = non_copper
|
||||
|
||||
# TODO: Check for None
|
||||
self.app.new_object("geometry", name, geo_init)
|
||||
|
||||
def on_generatebb_button_click(self, *args):
|
||||
self.read_form()
|
||||
name = self.options["name"] + "_bbox"
|
||||
|
||||
def geo_init(geo_obj, app_obj):
|
||||
assert isinstance(geo_obj, FlatCAMGeometry)
|
||||
# Bounding box with rounded corners
|
||||
bounding_box = self.solid_geometry.envelope.buffer(self.options["bboxmargin"])
|
||||
if not self.options["bboxrounded"]: # Remove rounded corners
|
||||
bounding_box = bounding_box.envelope
|
||||
geo_obj.solid_geometry = bounding_box
|
||||
|
||||
self.app.new_object("geometry", name, geo_init)
|
||||
|
||||
def on_generatecutout_button_click(self, *args):
|
||||
self.read_form()
|
||||
name = self.options["name"] + "_cutout"
|
||||
|
||||
def geo_init(geo_obj, app_obj):
|
||||
margin = self.options["cutoutmargin"] + self.options["cutouttooldia"]/2
|
||||
gap_size = self.options["cutoutgapsize"] + self.options["cutouttooldia"]
|
||||
minx, miny, maxx, maxy = self.bounds()
|
||||
minx -= margin
|
||||
maxx += margin
|
||||
miny -= margin
|
||||
maxy += margin
|
||||
midx = 0.5 * (minx + maxx)
|
||||
midy = 0.5 * (miny + maxy)
|
||||
hgap = 0.5 * gap_size
|
||||
pts = [[midx - hgap, maxy],
|
||||
[minx, maxy],
|
||||
[minx, midy + hgap],
|
||||
[minx, midy - hgap],
|
||||
[minx, miny],
|
||||
[midx - hgap, miny],
|
||||
[midx + hgap, miny],
|
||||
[maxx, miny],
|
||||
[maxx, midy - hgap],
|
||||
[maxx, midy + hgap],
|
||||
[maxx, maxy],
|
||||
[midx + hgap, maxy]]
|
||||
cases = {"tb": [[pts[0], pts[1], pts[4], pts[5]],
|
||||
[pts[6], pts[7], pts[10], pts[11]]],
|
||||
"lr": [[pts[9], pts[10], pts[1], pts[2]],
|
||||
[pts[3], pts[4], pts[7], pts[8]]],
|
||||
"4": [[pts[0], pts[1], pts[2]],
|
||||
[pts[3], pts[4], pts[5]],
|
||||
[pts[6], pts[7], pts[8]],
|
||||
[pts[9], pts[10], pts[11]]]}
|
||||
cuts = cases[self.options['gaps']]
|
||||
geo_obj.solid_geometry = cascaded_union([LineString(segment) for segment in cuts])
|
||||
|
||||
# TODO: Check for None
|
||||
self.app.new_object("geometry", name, geo_init)
|
||||
|
||||
def on_iso_button_click(self, *args):
|
||||
self.read_form()
|
||||
dia = self.options["isotooldia"]
|
||||
passes = int(self.options["isopasses"])
|
||||
overlap = self.options["isooverlap"] * dia
|
||||
|
||||
for i in range(passes):
|
||||
|
||||
offset = (2*i + 1)/2.0 * dia - i*overlap
|
||||
iso_name = self.options["name"] + "_iso%d" % (i+1)
|
||||
|
||||
# TODO: This is ugly. Create way to pass data into init function.
|
||||
def iso_init(geo_obj, app_obj):
|
||||
# Propagate options
|
||||
geo_obj.options["cnctooldia"] = self.options["isotooldia"]
|
||||
|
||||
geo_obj.solid_geometry = self.isolation_geometry(offset)
|
||||
app_obj.info("Isolation geometry created: %s" % geo_obj.options["name"])
|
||||
|
||||
# TODO: Do something if this is None. Offer changing name?
|
||||
self.app.new_object("geometry", iso_name, iso_init)
|
||||
|
||||
def on_plot_cb_click(self, *args):
|
||||
if self.muted_ui:
|
||||
return
|
||||
self.read_form_item('plot')
|
||||
self.plot()
|
||||
|
||||
def on_solid_cb_click(self, *args):
|
||||
if self.muted_ui:
|
||||
return
|
||||
self.read_form_item('solid')
|
||||
self.plot()
|
||||
|
||||
def on_multicolored_cb_click(self, *args):
|
||||
if self.muted_ui:
|
||||
return
|
||||
self.read_form_item('multicolored')
|
||||
self.plot()
|
||||
|
||||
def convert_units(self, units):
|
||||
"""
|
||||
Converts the units of the object by scaling dimensions in all geometry
|
||||
@@ -354,10 +524,20 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
|
||||
|
||||
def __init__(self, name):
|
||||
Excellon.__init__(self)
|
||||
FlatCAMObj.__init__(self, name)
|
||||
FlatCAMObj.__init__(self, name, ExcellonObjectUI())
|
||||
|
||||
self.kind = "excellon"
|
||||
|
||||
self.form_fields.update({
|
||||
"name": self.ui.name_entry,
|
||||
"plot": self.ui.plot_cb,
|
||||
"solid": self.ui.solid_cb,
|
||||
"drillz": self.ui.cutz_entry,
|
||||
"travelz": self.ui.travelz_entry,
|
||||
"feedrate": self.ui.feedrate_entry,
|
||||
"toolselection": self.ui.tools_entry
|
||||
})
|
||||
|
||||
self.options.update({
|
||||
"plot": True,
|
||||
"solid": False,
|
||||
@@ -367,14 +547,14 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
|
||||
"toolselection": ""
|
||||
})
|
||||
|
||||
self.form_kinds.update({
|
||||
"plot": "cb",
|
||||
"solid": "cb",
|
||||
"drillz": "entry_eval",
|
||||
"travelz": "entry_eval",
|
||||
"feedrate": "entry_eval",
|
||||
"toolselection": "entry_text"
|
||||
})
|
||||
# self.form_kinds.update({
|
||||
# "plot": "cb",
|
||||
# "solid": "cb",
|
||||
# "drillz": "entry_eval",
|
||||
# "travelz": "entry_eval",
|
||||
# "feedrate": "entry_eval",
|
||||
# "toolselection": "entry_text"
|
||||
# })
|
||||
|
||||
# TODO: Document this.
|
||||
self.tool_cbs = {}
|
||||
@@ -384,6 +564,23 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
|
||||
# from predecessors.
|
||||
self.ser_attrs += ['options', 'kind']
|
||||
|
||||
self.ui.plot_cb.connect('clicked', self.on_plot_cb_click)
|
||||
self.ui.plot_cb.connect('activate', self.on_plot_cb_click)
|
||||
self.ui.solid_cb.connect('clicked', self.on_solid_cb_click)
|
||||
self.ui.solid_cb.connect('activate', self.on_solid_cb_click)
|
||||
|
||||
def on_plot_cb_click(self, *args):
|
||||
if self.muted_ui:
|
||||
return
|
||||
self.read_form_item('plot')
|
||||
self.plot()
|
||||
|
||||
def on_solid_cb_click(self, *args):
|
||||
if self.muted_ui:
|
||||
return
|
||||
self.read_form_item('solid')
|
||||
self.plot()
|
||||
|
||||
def convert_units(self, units):
|
||||
factor = Excellon.convert_units(self, units)
|
||||
|
||||
@@ -457,7 +654,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
|
||||
feedrate=3.0, z_cut=-0.002, tooldia=0.0):
|
||||
CNCjob.__init__(self, units=units, kind=kind, z_move=z_move,
|
||||
feedrate=feedrate, z_cut=z_cut, tooldia=tooldia)
|
||||
FlatCAMObj.__init__(self, name)
|
||||
FlatCAMObj.__init__(self, name, CNCObjectUI())
|
||||
|
||||
self.kind = "cncjob"
|
||||
|
||||
@@ -466,16 +663,31 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
|
||||
"tooldia": 0.4 / 25.4 # 0.4mm in inches
|
||||
})
|
||||
|
||||
self.form_kinds.update({
|
||||
"plot": "cb",
|
||||
"tooldia": "entry_eval"
|
||||
self.form_fields.update({
|
||||
"name": self.ui.name_entry,
|
||||
"plot": self.ui.plot_cb,
|
||||
"tooldia": self.ui.tooldia_entry
|
||||
})
|
||||
|
||||
# self.form_kinds.update({
|
||||
# "plot": "cb",
|
||||
# "tooldia": "entry_eval"
|
||||
# })
|
||||
|
||||
# Attributes to be included in serialization
|
||||
# Always append to it because it carries contents
|
||||
# from predecessors.
|
||||
self.ser_attrs += ['options', 'kind']
|
||||
|
||||
self.ui.plot_cb.connect('clicked', self.on_plot_cb_click)
|
||||
self.ui.plot_cb.connect('activate', self.on_plot_cb_click)
|
||||
|
||||
def on_plot_cb_click(self, *args):
|
||||
if self.muted_ui:
|
||||
return
|
||||
self.read_form_item('plot')
|
||||
self.plot()
|
||||
|
||||
def plot(self):
|
||||
|
||||
# Does all the required setup and returns False
|
||||
@@ -501,15 +713,29 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
FlatCAMObj.__init__(self, name)
|
||||
FlatCAMObj.__init__(self, name, GeometryObjectUI())
|
||||
Geometry.__init__(self)
|
||||
|
||||
self.kind = "geometry"
|
||||
|
||||
self.form_fields.update({
|
||||
"name": self.ui.name_entry,
|
||||
"plot": self.ui.plot_cb,
|
||||
# "solid": self.ui.sol,
|
||||
# "multicolored": self.ui.,
|
||||
"cutz": self.ui.cutz_entry,
|
||||
"travelz": self.ui.travelz_entry,
|
||||
"feedrate": self.ui.cncfeedrate_entry,
|
||||
"cnctooldia": self.ui.cnctooldia_entry,
|
||||
"painttooldia": self.ui.painttooldia_entry,
|
||||
"paintoverlap": self.ui.paintoverlap_entry,
|
||||
"paintmargin": self.ui.paintmargin_entry
|
||||
})
|
||||
|
||||
self.options.update({
|
||||
"plot": True,
|
||||
"solid": False,
|
||||
"multicolored": False,
|
||||
# "solid": False,
|
||||
# "multicolored": False,
|
||||
"cutz": -0.002,
|
||||
"travelz": 0.1,
|
||||
"feedrate": 5.0,
|
||||
@@ -519,24 +745,105 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
||||
"paintmargin": 0.01
|
||||
})
|
||||
|
||||
self.form_kinds.update({
|
||||
"plot": "cb",
|
||||
"solid": "cb",
|
||||
"multicolored": "cb",
|
||||
"cutz": "entry_eval",
|
||||
"travelz": "entry_eval",
|
||||
"feedrate": "entry_eval",
|
||||
"cnctooldia": "entry_eval",
|
||||
"painttooldia": "entry_eval",
|
||||
"paintoverlap": "entry_eval",
|
||||
"paintmargin": "entry_eval"
|
||||
})
|
||||
# self.form_kinds.update({
|
||||
# "plot": "cb",
|
||||
# "solid": "cb",
|
||||
# "multicolored": "cb",
|
||||
# "cutz": "entry_eval",
|
||||
# "travelz": "entry_eval",
|
||||
# "feedrate": "entry_eval",
|
||||
# "cnctooldia": "entry_eval",
|
||||
# "painttooldia": "entry_eval",
|
||||
# "paintoverlap": "entry_eval",
|
||||
# "paintmargin": "entry_eval"
|
||||
# })
|
||||
|
||||
# Attributes to be included in serialization
|
||||
# Always append to it because it carries contents
|
||||
# from predecessors.
|
||||
self.ser_attrs += ['options', 'kind']
|
||||
|
||||
assert isinstance(self.ui, GeometryObjectUI)
|
||||
self.ui.plot_cb.connect('clicked', self.on_plot_cb_click)
|
||||
self.ui.plot_cb.connect('activate', self.on_plot_cb_click)
|
||||
self.ui.generate_cnc_button.connect('clicked', self.on_generatecnc_button_click)
|
||||
self.ui.generate_cnc_button.connect('activate', self.on_generatecnc_button_click)
|
||||
self.ui.generate_paint_button.connect('clicked', self.on_paint_button_click)
|
||||
self.ui.generate_paint_button.connect('activate', self.on_paint_button_click)
|
||||
|
||||
def on_paint_button_click(self, *args):
|
||||
self.app.info("Click inside the desired polygon.")
|
||||
self.read_form()
|
||||
tooldia = self.options["painttooldia"]
|
||||
overlap = self.options["paintoverlap"]
|
||||
|
||||
# Connection ID for the click event
|
||||
subscription = None
|
||||
|
||||
# To be called after clicking on the plot.
|
||||
def doit(event):
|
||||
self.app.plotcanvas.mpl_disconnect(subscription)
|
||||
point = [event.xdata, event.ydata]
|
||||
poly = find_polygon(self.solid_geometry, point)
|
||||
|
||||
# Initializes the new geometry object
|
||||
def gen_paintarea(geo_obj, app_obj):
|
||||
assert isinstance(geo_obj, FlatCAMGeometry)
|
||||
#assert isinstance(app_obj, App)
|
||||
cp = clear_poly(poly.buffer(-self.options["paintmargin"]), tooldia, overlap)
|
||||
geo_obj.solid_geometry = cp
|
||||
geo_obj.options["cnctooldia"] = tooldia
|
||||
|
||||
name = self.options["name"] + "_paint"
|
||||
self.new_object("geometry", name, gen_paintarea)
|
||||
|
||||
subscription = self.app.plotcanvas.mpl_connect('button_press_event', doit)
|
||||
|
||||
def on_generatecnc_button_click(self, *args):
|
||||
self.read_form()
|
||||
job_name = self.options["name"] + "_cnc"
|
||||
|
||||
# Object initialization function for app.new_object()
|
||||
# RUNNING ON SEPARATE THREAD!
|
||||
def job_init(job_obj, app_obj):
|
||||
assert isinstance(job_obj, FlatCAMCNCjob)
|
||||
# Propagate options
|
||||
job_obj.options["tooldia"] = self.options["cnctooldia"]
|
||||
|
||||
GLib.idle_add(lambda: app_obj.set_progress_bar(0.2, "Creating CNC Job..."))
|
||||
job_obj.z_cut = self.options["cutz"]
|
||||
job_obj.z_move = self.options["travelz"]
|
||||
job_obj.feedrate = self.options["feedrate"]
|
||||
|
||||
GLib.idle_add(lambda: app_obj.set_progress_bar(0.4, "Analyzing Geometry..."))
|
||||
# TODO: The tolerance should not be hard coded. Just for testing.
|
||||
job_obj.generate_from_geometry(self, tolerance=0.0005)
|
||||
|
||||
GLib.idle_add(lambda: app_obj.set_progress_bar(0.5, "Parsing G-Code..."))
|
||||
job_obj.gcode_parse()
|
||||
|
||||
# TODO: job_obj.create_geometry creates stuff that is not used.
|
||||
#GLib.idle_add(lambda: app_obj.set_progress_bar(0.6, "Creating New Geometry..."))
|
||||
#job_obj.create_geometry()
|
||||
|
||||
GLib.idle_add(lambda: app_obj.set_progress_bar(0.8, "Plotting..."))
|
||||
|
||||
# To be run in separate thread
|
||||
def job_thread(app_obj):
|
||||
app_obj.new_object("cncjob", job_name, job_init)
|
||||
GLib.idle_add(lambda: app_obj.info("CNCjob created: %s" % job_name))
|
||||
GLib.idle_add(lambda: app_obj.set_progress_bar(1.0, "Done!"))
|
||||
GLib.timeout_add_seconds(1, lambda: app_obj.set_progress_bar(0.0, "Idle"))
|
||||
|
||||
# Send to worker
|
||||
self.app.worker.add_task(job_thread, [self.app])
|
||||
|
||||
def on_plot_cb_click(self, *args):
|
||||
if self.muted_ui:
|
||||
return
|
||||
self.read_form_item('plot')
|
||||
self.plot()
|
||||
|
||||
def scale(self, factor):
|
||||
"""
|
||||
Scales all geometry by a given factor.
|
||||
|
||||
Reference in New Issue
Block a user