- removed the Open Gerber with 'follow' menu entry and also the open_gerber Tcl Command attribute 'follow'. This is no longer required because now the follow_geometry is stored by default in a Gerber object attribute gerber_obj.follow_geometry

- added a new parameter for the Tcl CommandIsolate, named: 'follow'. When follow = 1 (True) the resulting geometry will follow the Gerber paths.
This commit is contained in:
Marius Stanciu 2019-02-19 14:53:55 +02:00 committed by Marius
parent d998b87601
commit 9d0bcf477a
9 changed files with 176 additions and 154 deletions

View File

@ -1101,7 +1101,6 @@ class App(QtCore.QObject):
self.ui.menufilenewexc.triggered.connect(self.new_excellon_object)
self.ui.menufileopengerber.triggered.connect(self.on_fileopengerber)
self.ui.menufileopengerber_follow.triggered.connect(self.on_fileopengerber_follow)
self.ui.menufileopenexcellon.triggered.connect(self.on_fileopenexcellon)
self.ui.menufileopengcode.triggered.connect(self.on_fileopengcode)
self.ui.menufileopenproject.triggered.connect(self.on_file_openproject)
@ -4864,42 +4863,6 @@ class App(QtCore.QObject):
self.worker_task.emit({'fcn': self.open_gerber,
'params': [filename]})
def on_fileopengerber_follow(self):
"""
File menu callback for opening a Gerber.
:return: None
"""
self.report_usage("on_fileopengerber_follow")
App.log.debug("on_fileopengerber_follow()")
_filter_ = "Gerber Files (*.gbr *.ger *.gtl *.gbl *.gts *.gbs *.gtp *.gbp *.gto *.gbo *.gm1 *.gml *.gm3 *.gko " \
"*.cmp *.sol *.stc *.sts *.plc *.pls *.crc *.crs *.tsm *.bsm *.ly2 *.ly15 *.dim *.mil *.grb" \
"*.top *.bot *.smt *.smb *.sst *.ssb *.spt *.spb *.pho *.gdo *.art *.gbd);;" \
"Protel Files (*.gtl *.gbl *.gts *.gbs *.gto *.gbo *.gtp *.gbp *.gml *.gm1 *.gm3 *.gko);;" \
"Eagle Files (*.cmp *.sol *.stc *.sts *.plc *.pls *.crc *.crs *.tsm *.bsm *.ly2 *.ly15 *.dim *.mil);;" \
"OrCAD Files (*.top *.bot *.smt *.smb *.sst *.ssb *.spt *.spb);;" \
"Allegro Files (*.art);;" \
"Mentor Files (*.pho *.gdo);;" \
"All Files (*.*)"
try:
filename, _ = QtWidgets.QFileDialog.getOpenFileName(caption="Open Gerber with Follow",
directory=self.get_last_folder(), filter=_filter_)
except TypeError:
filename, _ = QtWidgets.QFileDialog.getOpenFileName(caption="Open Gerber with Follow", filter=_filter_)
# The Qt methods above will return a QString which can cause problems later.
# So far json.dump() will fail to serialize it.
# TODO: Improve the serialization methods and remove this fix.
filename = str(filename)
follow = True
if filename == "":
self.inform.emit("[WARNING_NOTCL]Open Gerber-Follow cancelled.")
else:
self.worker_task.emit({'fcn': self.open_gerber,
'params': [filename, follow]})
def on_fileopenexcellon(self):
"""
File menu callback for opening an Excellon file.
@ -5996,7 +5959,7 @@ class App(QtCore.QObject):
self.inform.emit("[success] Opened: " + filename)
self.progress.emit(100)
def open_gerber(self, filename, follow=False, outname=None):
def open_gerber(self, filename, outname=None):
"""
Opens a Gerber file, parses it and creates a new object for
it in the program. Thread-safe.
@ -6020,7 +5983,7 @@ class App(QtCore.QObject):
# Opening the file happens here
self.progress.emit(30)
try:
gerber_obj.parse_file(filename, follow=follow)
gerber_obj.parse_file(filename)
except IOError:
app_obj.inform.emit("[ERROR_NOTCL] Failed to open file: " + filename)
app_obj.progress.emit(0)
@ -6048,10 +6011,7 @@ class App(QtCore.QObject):
# Further parsing
self.progress.emit(70) # TODO: Note the mixture of self and app_obj used here
if follow is False:
App.log.debug("open_gerber()")
else:
App.log.debug("open_gerber() with 'follow' attribute")
App.log.debug("open_gerber()")
with self.proc_container.new("Opening Gerber") as proc:

View File

@ -67,16 +67,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
'Open &Gerber ...\tCTRL+G', self)
self.menufile_open.addAction(self.menufileopengerber)
# Open gerber with follow...
self.menufileopengerber_follow = QtWidgets.QAction(QtGui.QIcon('share/flatcam_icon24.png'),
'Open &Gerber (w/ Follow) ...', self)
self.menufileopengerber_follow.setToolTip(
"Will open a Gerber file with the 'follow' attribute.\n"
"This will actually 'trace' the features of a Gerber file and\n"
"the resulting Gerber geometry will have no volume, it will be\n"
"made out of lines."
)
self.menufile_open.addAction(self.menufileopengerber_follow)
self.menufile_open.addSeparator()
# Open Excellon ...

View File

@ -371,9 +371,11 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
if grb_final.solid_geometry is None:
grb_final.solid_geometry = []
grb_final.follow_geometry = []
if type(grb_final.solid_geometry) is not list:
grb_final.solid_geometry = [grb_final.solid_geometry]
grb_final.follow_geometry = [grb_final.follow_geometry]
for grb in grb_list:
for option in grb.options:
@ -389,8 +391,10 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
else: # If not list, just append
for geos in grb.solid_geometry:
grb_final.solid_geometry.append(geos)
grb_final.follow_geometry.append(geos)
grb_final.solid_geometry = MultiPolygon(grb_final.solid_geometry)
grb_final.follow_geometry = MultiPolygon(grb_final.follow_geometry)
def __init__(self, name):
Gerber.__init__(self, steps_per_circle=int(self.app.defaults["gerber_circle_steps"]))
@ -420,6 +424,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.multigeo = False
self.follow = False
self.apertures_row = 0
# store the source file here
@ -482,6 +488,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.ui.generate_bb_button.clicked.connect(self.on_generatebb_button_click)
self.ui.generate_noncopper_button.clicked.connect(self.on_generatenoncopper_button_click)
self.ui.aperture_table_visibility_cb.stateChanged.connect(self.on_aperture_table_visibility_change)
self.ui.follow_cb.stateChanged.connect(self.on_follow_cb_click)
# Show/Hide Advanced Options
if self.app.defaults["global_advanced"] is False:
@ -675,7 +682,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def on_int_iso_button_click(self, *args):
if self.ui.follow_cb.get_value() == True:
if self.ui.follow_cb.get_value() is True:
obj = self.app.collection.get_active()
obj.follow()
# in the end toggle the visibility of the origin object so we can see the generated Geometry
@ -687,9 +694,9 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def on_iso_button_click(self, *args):
if self.ui.follow_cb.get_value() == True:
if self.ui.follow_cb.get_value() is True:
obj = self.app.collection.get_active()
obj.follow()
obj.follow_geo()
# in the end toggle the visibility of the origin object so we can see the generated Geometry
obj.ui.plot_cb.toggle()
else:
@ -697,7 +704,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.read_form()
self.isolate()
def follow(self, outname=None):
def follow_geo(self, outname=None):
"""
Creates a geometry object "following" the gerber paths.
@ -715,7 +722,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def follow_init(follow_obj, app):
# Propagate options
follow_obj.options["cnctooldia"] = float(self.options["isotooldia"])
follow_obj.solid_geometry = self.solid_geometry
follow_obj.solid_geometry = self.follow_geometry
# TODO: Do something if this is None. Offer changing name?
try:
@ -724,7 +731,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
return "Operation failed: %s" % str(e)
def isolate(self, iso_type=None, dia=None, passes=None, overlap=None,
outname=None, combine=None, milling_type=None):
outname=None, combine=None, milling_type=None, follow=None):
"""
Creates an isolation routing geometry object in the project.
@ -735,6 +742,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
:param outname: Base name of the output object
:return: None
"""
if dia is None:
dia = float(self.options["isotooldia"])
if passes is None:
@ -755,7 +764,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
base_name = self.options["name"] + "_iso"
base_name = outname or base_name
def generate_envelope(offset, invert, envelope_iso_type=2):
def generate_envelope(offset, invert, envelope_iso_type=2, follow=None):
# isolation_geometry produces an envelope that is going on the left of the geometry
# (the copper features). To leave the least amount of burrs on the features
# the tool needs to travel on the right side of the features (this is called conventional milling)
@ -763,7 +772,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# the other passes overlap preceding ones and cut the left over copper. It is better for them
# to cut on the right side of the left over copper i.e on the left side of the features.
try:
geom = self.isolation_geometry(offset, iso_type=envelope_iso_type)
geom = self.isolation_geometry(offset, iso_type=envelope_iso_type, follow=follow)
except Exception as e:
log.debug(str(e))
return 'fail'
@ -803,9 +812,9 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# if milling type is climb then the move is counter-clockwise around features
if milling_type == 'cl':
# geom = generate_envelope (offset, i == 0)
geom = generate_envelope(iso_offset, 1, envelope_iso_type=self.iso_type)
geom = generate_envelope(iso_offset, 1, envelope_iso_type=self.iso_type, follow=follow)
else:
geom = generate_envelope(iso_offset, 0, envelope_iso_type=self.iso_type)
geom = generate_envelope(iso_offset, 0, envelope_iso_type=self.iso_type, follow=follow)
geo_obj.solid_geometry.append(geom)
# detect if solid_geometry is empty and this require list flattening which is "heavy"
@ -855,9 +864,11 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# if milling type is climb then the move is counter-clockwise around features
if milling_type == 'cl':
# geo_obj.solid_geometry = generate_envelope(offset, i == 0)
geo_obj.solid_geometry = generate_envelope(offset, 1, envelope_iso_type=self.iso_type)
geo_obj.solid_geometry = generate_envelope(offset, 1, envelope_iso_type=self.iso_type,
follow=follow)
else:
geo_obj.solid_geometry = generate_envelope(offset, 0, envelope_iso_type=self.iso_type)
geo_obj.solid_geometry = generate_envelope(offset, 0, envelope_iso_type=self.iso_type,
follow=follow)
# detect if solid_geometry is empty and this require list flattening which is "heavy"
# or just looking in the lists (they are one level depth) and if any is not empty
@ -897,6 +908,11 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.read_form_item('multicolored')
self.plot()
def on_follow_cb_click(self):
if self.muted_ui:
return
self.plot()
def on_aperture_table_visibility_change(self):
if self.ui.aperture_table_visibility_cb.isChecked():
self.ui.apertures_table.setVisible(True)
@ -942,7 +958,11 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
else:
face_color = self.app.defaults['global_plot_fill']
geometry = self.solid_geometry
# if the Follow Geometry checkbox is checked then plot only the follow geometry
if self.ui.follow_cb.get_value():
geometry = self.follow_geometry
else:
geometry = self.solid_geometry
# Make sure geometry is iterable.
try:
@ -962,6 +982,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
self.add_shape(shape=g, color=color,
face_color=random_color() if self.options['multicolored']
else face_color, visible=self.options['plot'])
elif type(g) == Point:
pass
else:
for el in g:
self.add_shape(shape=el, color=color,
@ -972,6 +994,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
if type(g) == Polygon or type(g) == LineString:
self.add_shape(shape=g, color=random_color() if self.options['multicolored'] else 'black',
visible=self.options['plot'])
elif type(g) == Point:
pass
else:
for el in g:
self.add_shape(shape=el, color=random_color() if self.options['multicolored'] else 'black',

View File

@ -266,13 +266,12 @@ class GerberObjectUI(ObjectUI):
grid1.addWidget(self.combine_passes_cb, 4, 0)
# generate follow
self.follow_cb = FCCheckBox(label='"Follow" Geo')
self.follow_cb = FCCheckBox(label='"Follow"')
self.follow_cb.setToolTip(
"Generate a 'Follow' geometry.\n"
"This means that it will cut through\n"
"the middle of the trace.\n"
"Requires that the Gerber file to be\n"
"loaded with 'follow' parameter."
"the middle of the trace."
)
grid1.addWidget(self.follow_cb, 4, 1)

View File

@ -15,7 +15,8 @@ CAD program, and create G-Code for Isolation routing.
- made FlatCAM able to load old type (uncompressed) FlatCAM projects
- fixed issue with not loading old projects that do not have certain information's required by the new versions of FlatCAM
- compacted a bit more the GUI for Gerber Object
- removed the Open Gerber with 'follow' menu entry and also the open_gerber Tcl Command attribute 'follow'. This is no longer required because now the follow_geometry is stored by default in a Gerber object attribute gerber_obj.follow_geometry
- added a new parameter for the Tcl CommandIsolate, named: 'follow'. When follow = 1 (True) the resulting geometry will follow the Gerber paths.
18.02.2019
@ -23,14 +24,14 @@ CAD program, and create G-Code for Isolation routing.
- the Paint Tool in Geometry Editor will load the default values from Tool Paint in Preferences
- when the Tools in Geometry Editor are activated, the notebook with the Tool Tab will be unhidden. After execution the notebook will hide again for the Buffer Tool.
- changed the font in Tool names
- added in Geometry Editor a new Tool: Transformation Tool. It still has some bugs, though ...
- added in Geometry Editor a new Tool: Transformation Tool.
- in Geometry Editor by selecting a shape with a selection shape, that object was added multiple times (one per each selection) to the selected list, which is not intended. Bug fixed.
- finished adding Transform Tool in Geometry Editor - everything is working as intended
- fixed a bug in Tool Transform that made the user to not be able to capture the click coordinates with SHIFT + LMB click combo
- added the ability to choose an App QStyle out of the offered choices (different for each OS) to be applied at the next app start (Preferences -> General -> Gui Pref -> Style Combobox)
- added support for FlatCAM usage with High DPI monitors (4k). It is applied on the next app startup after change in Preferences -> General -> Gui Settings -> HDPI Support Checkbox
- made the app not remember the window size if the app is maximized and remember in QSettings if it was maximized. This way we can restore the maximized state but restore the windows size unmaximized
- added a button to clear de GUI preferences in Preferences -> General -> Gui Settings -> Clear GUI Settings
- added a button to clear the GUI preferences in Preferences -> General -> Gui Settings -> Clear GUI Settings
- added key shortcuts for the shape transformations within Geometry Editor: X, Y keys for Flip(mirror), SHIFT+X, SHIFT+Y combo keys for Skew and ALT+X, ALT+Y combo keys for Offset
- adjusted the plotcanvas.zomm_fit() function so the objects are better fit into view (with a border around)
- modified the GUI in Objects Selected Tab to accommodate 2 different modes: basic and Advanced. In Basic mode, some of the functionality's are hidden from the user.

191
camlib.py
View File

@ -92,8 +92,11 @@ class Geometry(object):
# Final geometry: MultiPolygon or list (of geometry constructs)
self.solid_geometry = None
# Final geometry: MultiLineString or list (of LineString or Points)
self.follow_geometry = None
# Attributes to be included in serialization
self.ser_attrs = ["units", 'solid_geometry']
self.ser_attrs = ["units", 'solid_geometry', 'follow_geometry']
# Flattened geometry (list of paths only)
self.flat_geometry = []
@ -500,7 +503,7 @@ class Geometry(object):
#
# return self.flat_geometry, self.flat_geometry_rtree
def isolation_geometry(self, offset, iso_type=2, corner=None):
def isolation_geometry(self, offset, iso_type=2, corner=None, follow=None):
"""
Creates contours around geometry at a given
offset distance.
@ -542,16 +545,24 @@ class Geometry(object):
# the previously commented block is replaced with this block - regression - to solve the bug with multiple
# isolation passes cutting from the copper features
if offset == 0:
geo_iso = self.solid_geometry
else:
if corner is None:
geo_iso = self.solid_geometry.buffer(offset, int(int(self.geo_steps_per_circle) / 4))
if follow:
geo_iso = self.follow_geometry
else:
geo_iso = self.solid_geometry.buffer(offset, int(int(self.geo_steps_per_circle) / 4), join_style=corner)
geo_iso = self.solid_geometry
else:
if follow:
geo_iso = self.follow_geometry
else:
if corner is None:
geo_iso = self.solid_geometry.buffer(offset, int(int(self.geo_steps_per_circle) / 4))
else:
geo_iso = self.solid_geometry.buffer(offset, int(int(self.geo_steps_per_circle) / 4),
join_style=corner)
# end of replaced block
if iso_type == 2:
if follow:
return geo_iso
elif iso_type == 2:
return geo_iso
elif iso_type == 0:
return self.get_exteriors(geo_iso)
@ -1889,8 +1900,12 @@ class Gerber (Geometry):
# Initialize parent
Geometry.__init__(self, geo_steps_per_circle=int(steps_per_circle))
# will store the Gerber geometry's as solids
self.solid_geometry = Polygon()
# will store the Gerber geometry's as paths
self.follow_geometry = []
# Number format
self.int_digits = 3
"""Number of integer digits in Gerber numbers. Used during parsing."""
@ -2113,10 +2128,10 @@ class Gerber (Geometry):
yield line
break
self.parse_lines(line_generator(), follow=follow)
self.parse_lines(line_generator())
#@profile
def parse_lines(self, glines, follow=False):
def parse_lines(self, glines):
"""
Main Gerber parser. Reads Gerber and populates ``self.paths``, ``self.apertures``,
``self.flashes``, ``self.regions`` and ``self.units``.
@ -2143,6 +2158,9 @@ class Gerber (Geometry):
# applying a union for every new polygon.
poly_buffer = []
# store here the follow geometry
follow_buffer = []
last_path_aperture = None
current_aperture = None
@ -2208,10 +2226,11 @@ class Gerber (Geometry):
# --- Buffered ----
width = self.apertures[last_path_aperture]["size"]
if follow:
geo = LineString(path)
else:
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
geo = LineString(path)
if not geo.is_empty:
follow_buffer.append(geo)
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
if not geo.is_empty:
poly_buffer.append(geo)
@ -2222,9 +2241,14 @@ class Gerber (Geometry):
# TODO: Remove when bug fixed
if len(poly_buffer) > 0:
if current_polarity == 'D':
self.follow_geometry = self.solid_geometry.union(cascaded_union(follow_buffer))
self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
else:
self.solid_geometry = self.solid_geometry.difference(cascaded_union(poly_buffer))
self.follow_geometry = self.solid_geometry.difference(cascaded_union(follow_buffer))
self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
follow_buffer = []
poly_buffer = []
current_polarity = match.group(1)
@ -2405,10 +2429,11 @@ class Gerber (Geometry):
# --- Buffered ----
width = self.apertures[last_path_aperture]["size"]
if follow:
geo = LineString(path)
else:
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
geo = LineString(path)
if not geo.is_empty:
follow_buffer.append(geo)
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
if not geo.is_empty:
poly_buffer.append(geo)
@ -2424,10 +2449,11 @@ class Gerber (Geometry):
## --- Buffered ---
width = self.apertures[last_path_aperture]["size"]
if follow:
geo = LineString(path)
else:
geo = LineString(path).buffer(width/1.999, int(self.steps_per_circle / 4))
geo = LineString(path)
if not geo.is_empty:
follow_buffer.append(geo)
geo = LineString(path).buffer(width/1.999, int(self.steps_per_circle / 4))
if not geo.is_empty:
poly_buffer.append(geo)
@ -2445,6 +2471,7 @@ class Gerber (Geometry):
if current_operation_code == 2:
if geo:
if not geo.is_empty:
follow_buffer.append(geo)
poly_buffer.append(geo)
continue
@ -2464,15 +2491,14 @@ class Gerber (Geometry):
# "aperture": last_path_aperture})
# --- Buffered ---
if follow:
region = Polygon()
else:
region = Polygon(path)
region = Polygon()
if not region.is_empty:
follow_buffer.append(region)
region = Polygon(path)
if not region.is_valid:
if not follow:
region = region.buffer(0, int(self.steps_per_circle / 4))
region = region.buffer(0, int(self.steps_per_circle / 4))
if not region.is_empty:
poly_buffer.append(region)
@ -2529,7 +2555,7 @@ class Gerber (Geometry):
if path[-1] != [linear_x, linear_y]:
path.append([linear_x, linear_y])
if follow == 0 and making_region is False:
if making_region is False:
# if the aperture is rectangle then add a rectangular shape having as parameters the
# coordinates of the start and end point and also the width and height
# of the 'R' aperture
@ -2555,29 +2581,35 @@ class Gerber (Geometry):
geo = None
## --- BUFFERED ---
# this treats the case when we are storing geometry as paths only
if making_region:
if follow:
geo = Polygon()
else:
elem = [linear_x, linear_y]
if elem != path[-1]:
path.append([linear_x, linear_y])
try:
geo = Polygon(path)
except ValueError:
log.warning("Problem %s %s" % (gline, line_num))
self.app.inform.emit("[ERROR] Region does not have enough points. "
"File will be processed but there are parser errors. "
"Line number: %s" % str(line_num))
geo = Polygon()
else:
geo = LineString(path)
try:
if self.apertures[last_path_aperture]["type"] != 'R':
if not geo.is_empty:
follow_buffer.append(geo)
except:
follow_buffer.append(geo)
# this treats the case when we are storing geometry as solids
if making_region:
elem = [linear_x, linear_y]
if elem != path[-1]:
path.append([linear_x, linear_y])
try:
geo = Polygon(path)
except ValueError:
log.warning("Problem %s %s" % (gline, line_num))
self.app.inform.emit("[ERROR] Region does not have enough points. "
"File will be processed but there are parser errors. "
"Line number: %s" % str(line_num))
else:
if last_path_aperture is None:
log.warning("No aperture defined for curent path. (%d)" % line_num)
width = self.apertures[last_path_aperture]["size"] # TODO: WARNING this should fail!
#log.debug("Line %d: Setting aperture to %s before buffering." % (line_num, last_path_aperture))
if follow:
geo = LineString(path)
else:
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
try:
if self.apertures[last_path_aperture]["type"] != 'R':
@ -2600,19 +2632,23 @@ class Gerber (Geometry):
# Create path draw so far.
if len(path) > 1:
# --- Buffered ----
# this treats the case when we are storing geometry as paths
geo = LineString(path)
if not geo.is_empty:
try:
if self.apertures[current_aperture]["type"] != 'R':
follow_buffer.append(geo)
except:
follow_buffer.append(geo)
# this treats the case when we are storing geometry as solids
width = self.apertures[last_path_aperture]["size"]
if follow:
geo = LineString(path)
else:
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
if not geo.is_empty:
try:
if self.apertures[current_aperture]["type"] != 'R':
poly_buffer.append(geo)
else:
pass
except:
poly_buffer.append(geo)
@ -2621,11 +2657,12 @@ class Gerber (Geometry):
# --- BUFFERED ---
# Draw the flash
if follow:
continue
# this treats the case when we are storing geometry as paths
follow_buffer.append(Point([linear_x, linear_y]))
# this treats the case when we are storing geometry as solids
flash = Gerber.create_flash_geometry(
Point(
[linear_x, linear_y]),
Point( [linear_x, linear_y]),
self.apertures[current_aperture],
int(self.steps_per_circle)
)
@ -2711,10 +2748,13 @@ class Gerber (Geometry):
# --- BUFFERED ---
width = self.apertures[last_path_aperture]["size"]
if follow:
buffered = LineString(path)
else:
buffered = LineString(path).buffer(width / 1.999, int(self.steps_per_circle))
# this treats the case when we are storing geometry as paths
geo = LineString(path)
if not geo.is_empty:
follow_buffer.append(geo)
# this treats the case when we are storing geometry as solids
buffered = LineString(path).buffer(width / 1.999, int(self.steps_per_circle))
if not buffered.is_empty:
poly_buffer.append(buffered)
@ -2833,19 +2873,24 @@ class Gerber (Geometry):
else:
# EOF, create shapely LineString if something still in path
## --- Buffered ---
# this treats the case when we are storing geometry as paths
geo = LineString(path)
if not geo.is_empty:
follow_buffer.append(geo)
# this treats the case when we are storing geometry as solids
width = self.apertures[last_path_aperture]["size"]
if follow:
geo = LineString(path)
else:
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
geo = LineString(path).buffer(width / 1.999, int(self.steps_per_circle / 4))
if not geo.is_empty:
poly_buffer.append(geo)
# --- Apply buffer ---
if follow:
self.solid_geometry = poly_buffer
return
# this treats the case when we are storing geometry as paths
self.follow_geometry = follow_buffer
# this treats the case when we are storing geometry as solids
log.warning("Joining %d polygons." % len(poly_buffer))
if len(poly_buffer) == 0:

View File

@ -225,7 +225,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
def geo_init(geo_obj, app_obj):
try:
geo = cutout_obj.isolation_geometry((dia / 2), iso_type=0, corner=2)
geo = cutout_obj.isolation_geometry((dia / 2), iso_type=0, corner=2, follow=None)
except Exception as e:
log.debug("TclCommandGeoCutout.execute() --> %s" % str(e))
return 'fail'

View File

@ -28,7 +28,9 @@ class TclCommandIsolate(TclCommandSignaled):
('passes', int),
('overlap', float),
('combine', int),
('outname', str)
('outname', str),
('follow', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
@ -43,7 +45,8 @@ class TclCommandIsolate(TclCommandSignaled):
('passes', 'Passes of tool width.'),
('overlap', 'Fraction of tool diameter to overlap passes.'),
('combine', 'Combine all passes into one geometry.'),
('outname', 'Name of the resulting Geometry object.')
('outname', 'Name of the resulting Geometry object.'),
('follow', 'Create a Geometry that follows the Gerber path.')
]),
'examples': []
}
@ -68,6 +71,9 @@ class TclCommandIsolate(TclCommandSignaled):
else:
timeout = 10000
if 'follow' not in args:
args['follow'] = None
obj = self.app.collection.get_by_name(name)
if obj is None:
self.raise_tcl_error("Object not found: %s" % name)

View File

@ -17,7 +17,6 @@ class TclCommandOpenGerber(TclCommandSignaled):
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
('follow', str),
('outname', str)
])
@ -29,7 +28,6 @@ class TclCommandOpenGerber(TclCommandSignaled):
'main': "Opens a Gerber file.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('follow', 'N If 1, does not create polygons, just follows the gerber path.'),
('outname', 'Name of the resulting Gerber object.')
]),
'examples': []
@ -54,7 +52,7 @@ class TclCommandOpenGerber(TclCommandSignaled):
# Opening the file happens here
self.app.progress.emit(30)
try:
gerber_obj.parse_file(filename, follow=follow)
gerber_obj.parse_file(filename)
except IOError:
app_obj.inform.emit("[ERROR_NOTCL] Failed to open file: %s " % filename)
@ -77,9 +75,8 @@ class TclCommandOpenGerber(TclCommandSignaled):
else:
outname = filename.split('/')[-1].split('\\')[-1]
follow = None
if 'follow' in args:
follow = args['follow']
self.raise_tcl_error("The 'follow' parameter is obsolete. To create 'follow' geometry use the 'follow' parameter for the Tcl Command isolate()")
with self.app.proc_container.new("Opening Gerber"):