- NCC Tool - fixed the non-rest copper clearing to work as expected: each tool in the tool table will make it's own copper clearing without interference from the rest of the tools

This commit is contained in:
Marius Stanciu
2020-06-12 22:26:17 +03:00
committed by Marius
parent 0a125ea75f
commit 1ea168fd4b
3 changed files with 88 additions and 114 deletions

View File

@@ -13,6 +13,7 @@ CHANGELOG for FlatCAM beta
- NCC Tool optimization - optimized the Tool edit method - NCC Tool optimization - optimized the Tool edit method
- NCC Tool - allow no tool at NCC Tool start (the Preferences have no tool) - NCC Tool - allow no tool at NCC Tool start (the Preferences have no tool)
- NCC Tool - optimized tool reset code - NCC Tool - optimized tool reset code
- NCC Tool - fixed the non-rest copper clearing to work as expected: each tool in the tool table will make it's own copper clearing without interference from the rest of the tools
11.06.2020 11.06.2020

View File

@@ -525,7 +525,7 @@ class NonCopperClear(AppTool, Gerber):
'offset': 'Path', 'offset': 'Path',
'offset_value': 0.0, 'offset_value': 0.0,
'type': 'Iso', 'type': 'Iso',
'tool_type': self.ui.tool_type_radio.get_value(), 'tool_type': self.app.defaults["tools_ncctool_type"],
'data': deepcopy(self.default_data), 'data': deepcopy(self.default_data),
'solid_geometry': [] 'solid_geometry': []
} }
@@ -578,42 +578,27 @@ class NonCopperClear(AppTool, Gerber):
for tooluid_key, tooluid_value in self.ncc_tools.items(): for tooluid_key, tooluid_value in self.ncc_tools.items():
if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted: if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted:
tool_id += 1 tool_id += 1
id_ = QtWidgets.QTableWidgetItem('%d' % int(tool_id)) id_ = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
id_.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) id_.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
row_no = tool_id - 1 row_no = tool_id - 1
self.ui.tools_table.setItem(row_no, 0, id_) # Tool name/id self.ui.tools_table.setItem(row_no, 0, id_) # Tool name/id
# Make sure that the drill diameter when in MM is with no more than 2 decimals # Make sure that the drill diameter when in MM is with no more than self.decimals decimals
# There are no drill bits in MM with more than 2 decimals diameter
# For INCH the decimals should be no more than 4. There are no drills under 10mils
dia = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, tooluid_value['tooldia'])) dia = QtWidgets.QTableWidgetItem('%.*f' % (self.decimals, tooluid_value['tooldia']))
dia.setFlags(QtCore.Qt.ItemIsEnabled) dia.setFlags(QtCore.Qt.ItemIsEnabled)
self.ui.tools_table.setItem(row_no, 1, dia) # Diameter
tool_type_item = FCComboBox() tool_type_item = FCComboBox()
tool_type_item.addItems(self.tool_type_item_options) tool_type_item.addItems(self.tool_type_item_options)
# tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
idx = tool_type_item.findText(tooluid_value['tool_type']) idx = tool_type_item.findText(tooluid_value['tool_type'])
tool_type_item.setCurrentIndex(idx) tool_type_item.setCurrentIndex(idx)
tool_uid_item = QtWidgets.QTableWidgetItem(str(int(tooluid_key)))
# operation_type = FCComboBox()
# operation_type.addItems(['iso_op', 'clear_op'])
#
# # operation_type.setStyleSheet('background-color: rgb(255,255,255)')
# op_idx = operation_type.findText(tooluid_value['operation'])
# operation_type.setCurrentIndex(op_idx)
self.ui.tools_table.setItem(row_no, 1, dia) # Diameter
self.ui.tools_table.setCellWidget(row_no, 2, tool_type_item) self.ui.tools_table.setCellWidget(row_no, 2, tool_type_item)
tool_uid_item = QtWidgets.QTableWidgetItem(str(int(tooluid_key)))
# ## REMEMBER: THIS COLUMN IS HIDDEN IN OBJECTUI.PY # ## # ## REMEMBER: THIS COLUMN IS HIDDEN IN OBJECTUI.PY # ##
self.ui.tools_table.setItem(row_no, 3, tool_uid_item) # Tool unique ID self.ui.tools_table.setItem(row_no, 3, tool_uid_item) # Tool unique ID
# self.ui.tools_table.setCellWidget(row_no, 4, operation_type)
# make the diameter column editable # make the diameter column editable
for row in range(tool_id): for row in range(tool_id):
self.ui.tools_table.item(row, 1).setFlags( self.ui.tools_table.item(row, 1).setFlags(
@@ -925,7 +910,7 @@ class NonCopperClear(AppTool, Gerber):
'offset': 'Path', 'offset': 'Path',
'offset_value': 0.0, 'offset_value': 0.0,
'type': 'Iso', 'type': 'Iso',
'tool_type': self.ui.tool_type_radio.get_value(), 'tool_type': self.app.defaults["tools_ncctool_type"],
'data': deepcopy(self.default_data), 'data': deepcopy(self.default_data),
'solid_geometry': [] 'solid_geometry': []
} }
@@ -957,22 +942,21 @@ class NonCopperClear(AppTool, Gerber):
# identify the tool that was edited and get it's tooluid # identify the tool that was edited and get it's tooluid
if new_tool_dia not in tool_dias: if new_tool_dia not in tool_dias:
self.ncc_tools[editeduid]['tooldia'] = new_tool_dia self.ncc_tools[editeduid]['tooldia'] = deepcopy(float('%.*f' % (self.decimals, new_tool_dia)))
self.app.inform.emit('[success] %s' % _("Tool from Tool Table was edited.")) self.app.inform.emit('[success] %s' % _("Tool from Tool Table was edited."))
self.blockSignals(False) self.blockSignals(False)
self.build_ui() self.build_ui()
return return
else:
# identify the old tool_dia and restore the text in tool table
for k, v in self.ncc_tools.items():
if k == editeduid:
old_tool_dia = v['tooldia']
restore_dia_item = self.ui.tools_table.item(edited_row, 1)
restore_dia_item.setText(str(old_tool_dia))
break
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. " # identify the old tool_dia and restore the text in tool table
"New diameter value is already in the Tool Table.")) for k, v in self.ncc_tools.items():
if k == editeduid:
old_tool_dia = v['tooldia']
restore_dia_item = self.ui.tools_table.item(edited_row, 1)
restore_dia_item.setText(str(old_tool_dia))
break
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. New diameter value is already in the Tool Table."))
self.blockSignals(False) self.blockSignals(False)
self.build_ui() self.build_ui()
@@ -1039,13 +1023,20 @@ class NonCopperClear(AppTool, Gerber):
:return: None :return: None
""" """
# init values for the next usage self.app.defaults.report_usage("on_ncc_click")
self.set_tool_ui()
self.app.defaults.report_usage("on_paint_button_click") self.first_click = False
self.cursor_pos = None
self.mouse_is_dragging = False
prog_plot = True if self.app.defaults["tools_ncc_plotting"] == 'progressive' else False
if prog_plot:
self.temp_shapes.clear(update=True)
self.sel_rect = []
self.grb_circle_steps = int(self.app.defaults["gerber_circle_steps"]) self.grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
self.obj_name = self.object_combo.currentText() self.obj_name = self.ui.object_combo.currentText()
# Get source object. # Get source object.
try: try:
@@ -1102,7 +1093,8 @@ class NonCopperClear(AppTool, Gerber):
self.clear_copper(ncc_obj=self.ncc_obj, self.clear_copper(ncc_obj=self.ncc_obj,
ncctooldia=self.ncc_dia_list, ncctooldia=self.ncc_dia_list,
isotooldia=self.iso_dia_list, isotooldia=self.iso_dia_list,
outname=self.o_name) outname=self.o_name,
tools_storage=self.ncc_tools)
elif self.select_method == _("Area Selection"): elif self.select_method == _("Area Selection"):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area.")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
@@ -1493,7 +1485,7 @@ class NonCopperClear(AppTool, Gerber):
:param has_offset: :param has_offset:
:param ncc_offset: :param ncc_offset:
:param ncc_margin: :param ncc_margin:
:param bounding_box: :param bounding_box: only this area is kept
:param tools_storage: :param tools_storage:
:return: :return:
""" """
@@ -1521,13 +1513,11 @@ class NonCopperClear(AppTool, Gerber):
self.app.inform.emit('[success] %s ...' % _("Buffering finished")) self.app.inform.emit('[success] %s ...' % _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail': if empty == 'fail' or empty.is_empty:
msg = '[ERROR_NOTCL] %s' % _("Could not get the extent of the area to be non copper cleared.")
self.app.inform.emit(msg)
return 'fail' return 'fail'
if empty.is_empty:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Could not get the extent of the area to be non copper cleared."))
return 'fail'
elif ncc_obj.kind == 'gerber' and isotooldia: elif ncc_obj.kind == 'gerber' and isotooldia:
isolated_geo = [] isolated_geo = []
@@ -1550,7 +1540,7 @@ class NonCopperClear(AppTool, Gerber):
else: else:
isolated_geo = self.generate_envelope(tool_iso / 2, 0) isolated_geo = self.generate_envelope(tool_iso / 2, 0)
if isolated_geo == 'fail': if isolated_geo == 'fail' or isolated_geo.is_empty:
self.app.inform.emit('[ERROR_NOTCL] %s %s' % self.app.inform.emit('[ERROR_NOTCL] %s %s' %
(_("Isolation geometry could not be generated."), str(tool_iso))) (_("Isolation geometry could not be generated."), str(tool_iso)))
continue continue
@@ -1611,7 +1601,6 @@ class NonCopperClear(AppTool, Gerber):
warning_flag += 1 warning_flag += 1
break break
current_uid = 0
for k, v in tools_storage.items(): for k, v in tools_storage.items():
if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
tool_iso)): tool_iso)):
@@ -1620,8 +1609,8 @@ class NonCopperClear(AppTool, Gerber):
# and then reset the temporary list that stored that solid_geometry # and then reset the temporary list that stored that solid_geometry
v['solid_geometry'] = deepcopy(new_geometry) v['solid_geometry'] = deepcopy(new_geometry)
v['data']['name'] = name v['data']['name'] = name
geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
break break
geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
sol_geo = cascaded_union(isolated_geo) sol_geo = cascaded_union(isolated_geo)
if has_offset is True: if has_offset is True:
@@ -1630,13 +1619,11 @@ class NonCopperClear(AppTool, Gerber):
self.app.inform.emit('[success] %s ...' % _("Buffering finished")) self.app.inform.emit('[success] %s ...' % _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail': if empty == 'fail' or empty.is_empty:
msg = '[ERROR_NOTCL] %s' % _("Could not get the extent of the area to be non copper cleared.")
self.app.inform.emit(msg)
return 'fail' return 'fail'
if empty.is_empty:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Isolation geometry is broken. Margin is less than isolation tool diameter."))
return 'fail'
elif ncc_obj.kind == 'geometry': elif ncc_obj.kind == 'geometry':
sol_geo = cascaded_union(ncc_obj.solid_geometry) sol_geo = cascaded_union(ncc_obj.solid_geometry)
if has_offset is True: if has_offset is True:
@@ -1644,12 +1631,9 @@ class NonCopperClear(AppTool, Gerber):
sol_geo = sol_geo.buffer(distance=ncc_offset) sol_geo = sol_geo.buffer(distance=ncc_offset)
self.app.inform.emit('[success] %s ...' % _("Buffering finished")) self.app.inform.emit('[success] %s ...' % _("Buffering finished"))
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box) empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
if empty == 'fail': if empty == 'fail' or empty.is_empty:
return 'fail' msg = '[ERROR_NOTCL] %s' % _("Could not get the extent of the area to be non copper cleared.")
self.app.inform.emit(msg)
if empty.is_empty:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Could not get the extent of the area to be non copper cleared."))
return 'fail' return 'fail'
else: else:
self.app.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.')) self.app.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
@@ -1822,17 +1806,8 @@ class NonCopperClear(AppTool, Gerber):
else: else:
pass pass
cleared_geo = []
cleared = MultiPolygon() # Already cleared area
app_obj.poly_not_cleared = False # flag for polygons not cleared app_obj.poly_not_cleared = False # flag for polygons not cleared
# Generate area for each tool
offset = sum(sorted_clear_tools)
current_uid = int(1)
# try:
# tool = eval(self.app.defaults["tools_ncctools"])[0]
# except TypeError:
# tool = eval(self.app.defaults["tools_ncctools"])
if ncc_select == _("Reference Object"): if ncc_select == _("Reference Object"):
bbox_geo, bbox_kind = self.calculate_bounding_box( bbox_geo, bbox_kind = self.calculate_bounding_box(
@@ -1860,6 +1835,9 @@ class NonCopperClear(AppTool, Gerber):
) )
app_obj.proc_container.update_view_text(' %d%%' % 0) app_obj.proc_container.update_view_text(' %d%%' % 0)
# store here the geometry generated by clear operation
cleared_geo = []
tool_uid = 0 # find the current tool_uid tool_uid = 0 # find the current tool_uid
for k, v in self.ncc_tools.items(): for k, v in self.ncc_tools.items():
if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool)): if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals, tool)):
@@ -1875,25 +1853,17 @@ class NonCopperClear(AppTool, Gerber):
has_offset = self.ncc_tools[tool_uid]["data"]["tools_ncc_offset_choice"] has_offset = self.ncc_tools[tool_uid]["data"]["tools_ncc_offset_choice"]
ncc_offset = float(self.ncc_tools[tool_uid]["data"]["tools_ncc_offset_value"]) ncc_offset = float(self.ncc_tools[tool_uid]["data"]["tools_ncc_offset_value"])
# Get remaining tools offset
offset -= (tool - 1e-12)
# Bounding box for current tool # Bounding box for current tool
bbox = self.apply_margin_to_bounding_box(bbox=bbox_geo, box_kind=bbox_kind, bbox = self.apply_margin_to_bounding_box(bbox=bbox_geo, box_kind=bbox_kind,
ncc_select=ncc_select, ncc_margin=ncc_margin) ncc_select=ncc_select, ncc_margin=ncc_margin)
# Area to clear # Area to clear
empty, warning_flag = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj, area, warning_flag = self.get_tool_empty_area(name=name, ncc_obj=ncc_obj, geo_obj=geo_obj,
isotooldia=isotooldia, ncc_margin=ncc_margin, isotooldia=isotooldia, ncc_margin=ncc_margin,
has_offset=has_offset, ncc_offset=ncc_offset, has_offset=has_offset, ncc_offset=ncc_offset,
tools_storage=tools_storage, bounding_box=bbox) tools_storage=tools_storage, bounding_box=bbox)
area = empty.buffer(-offset)
try:
area = area.difference(cleared)
except Exception:
continue
# Transform area to MultiPolygon # Transform area to MultiPolygon
if isinstance(area, Polygon): if isinstance(area, Polygon):
area = MultiPolygon([area]) area = MultiPolygon([area])
@@ -1904,7 +1874,6 @@ class NonCopperClear(AppTool, Gerber):
old_disp_number = 0 old_disp_number = 0
log.warning("Total number of polygons to be cleared. %s" % str(geo_len)) log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
cleared_geo[:] = []
if area.geoms: if area.geoms:
if len(area.geoms) > 0: if len(area.geoms) > 0:
pol_nr = 0 pol_nr = 0
@@ -1966,12 +1935,6 @@ class NonCopperClear(AppTool, Gerber):
# check if there is a geometry at all in the cleared geometry # check if there is a geometry at all in the cleared geometry
if cleared_geo: if cleared_geo:
cleared = empty.buffer(-offset * (1 + ncc_overlap)) # Overall cleared area
cleared = cleared.buffer(-tool / 1.999999).buffer(tool / 1.999999)
# clean-up cleared geo
cleared = cleared.buffer(0)
# find the tooluid associated with the current tool_dia so we know where to add the tool # find the tooluid associated with the current tool_dia so we know where to add the tool
# solid_geometry # solid_geometry
for k, v in tools_storage.items(): for k, v in tools_storage.items():
@@ -1983,10 +1946,11 @@ class NonCopperClear(AppTool, Gerber):
# and then reset the temporary list that stored that solid_geometry # and then reset the temporary list that stored that solid_geometry
v['solid_geometry'] = deepcopy(cleared_geo) v['solid_geometry'] = deepcopy(cleared_geo)
v['data']['name'] = name v['data']['name'] = name
geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
break break
geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
else: else:
log.debug("There are no geometries in the cleared polygon.") log.debug("There are no geometries in the cleared polygon.")
# clean the progressive plotted shapes if it was used # clean the progressive plotted shapes if it was used
if self.app.defaults["tools_ncc_plotting"] == 'progressive': if self.app.defaults["tools_ncc_plotting"] == 'progressive':
self.temp_shapes.clear(update=True) self.temp_shapes.clear(update=True)
@@ -1997,6 +1961,14 @@ class NonCopperClear(AppTool, Gerber):
try: try:
# if the solid_geometry (type=list) is empty # if the solid_geometry (type=list) is empty
if not uid_val['solid_geometry']: if not uid_val['solid_geometry']:
msg = '%s %s: %s %s: %s' % (
_("Could not use the tool for copper clear."),
_("Tool"),
str(uid),
_("with diameter"),
str(uid_val['tooldia']))
self.app.inform.emit(msg)
log.debug("Empty geometry for tool: %s with diameter: %s" % (str(uid), str(uid_val['tooldia'])))
tools_storage.pop(uid, None) tools_storage.pop(uid, None)
except KeyError: except KeyError:
tools_storage.pop(uid, None) tools_storage.pop(uid, None)
@@ -2004,7 +1976,6 @@ class NonCopperClear(AppTool, Gerber):
geo_obj.options["cnctooldia"] = str(tool) geo_obj.options["cnctooldia"] = str(tool)
geo_obj.multigeo = True geo_obj.multigeo = True
geo_obj.tools.clear()
geo_obj.tools = dict(tools_storage) geo_obj.tools = dict(tools_storage)
# test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception # test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
@@ -2013,10 +1984,10 @@ class NonCopperClear(AppTool, Gerber):
if geo_obj.tools[tid]['solid_geometry']: if geo_obj.tools[tid]['solid_geometry']:
has_solid_geo += 1 has_solid_geo += 1
if has_solid_geo == 0: if has_solid_geo == 0:
app_obj.inform.emit('[ERROR] %s' % msg = '[ERROR] %s' % _("There is no NCC Geometry in the file.\n"
_("There is no NCC Geometry in the file.\n" "Usually it means that the tool diameter is too big for the painted geometry.\n"
"Usually it means that the tool diameter is too big for the painted geometry.\n" "Change the painting parameters and try again.")
"Change the painting parameters and try again.")) app_obj.inform.emit(msg)
return 'fail' return 'fail'
# check to see if geo_obj.tools is empty # check to see if geo_obj.tools is empty

View File

@@ -1339,16 +1339,16 @@ class Geometry(object):
valid cuts. Finalizes by cutting around the inside edge of valid cuts. Finalizes by cutting around the inside edge of
the polygon. the polygon.
:param polygon_to_clear: Shapely.geometry.Polygon :param polygon_to_clear: Shapely.geometry.Polygon
:param steps_per_circle: how many linear segments to use to approximate a circle :param steps_per_circle: how many linear segments to use to approximate a circle
:param tooldia: Diameter of the tool :param tooldia: Diameter of the tool
:param seedpoint: Shapely.geometry.Point or None :param seedpoint: Shapely.geometry.Point or None
:param overlap: Tool fraction overlap bewteen passes :param overlap: Tool fraction overlap bewteen passes
:param connect: Connect disjoint segment to minumize tool lifts :param connect: Connect disjoint segment to minumize tool lifts
:param contour: Cut countour inside the polygon. :param contour: Cut countour inside the polygon.
:return: List of toolpaths covering polygon. :param prog_plot: boolean; if True use the progressive plotting
:rtype: FlatCAMRTreeStorage | None :return: List of toolpaths covering polygon.
:param prog_plot: boolean; if True use the progressive plotting :rtype: FlatCAMRTreeStorage | None
""" """
# log.debug("camlib.clear_polygon2()") # log.debug("camlib.clear_polygon2()")
@@ -1368,7 +1368,7 @@ class Geometry(object):
path_margin = polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle)) path_margin = polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle))
if path_margin.is_empty or path_margin is None: if path_margin.is_empty or path_margin is None:
return return None
# Estimate good seedpoint if not provided. # Estimate good seedpoint if not provided.
if seedpoint is None: if seedpoint is None:
@@ -1411,12 +1411,12 @@ class Geometry(object):
# Clean inside edges (contours) of the original polygon # Clean inside edges (contours) of the original polygon
if contour: if contour:
outer_edges = [ buffered_poly = autolist(polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle)))
x.exterior for x in autolist(polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle))) outer_edges = [x.exterior for x in buffered_poly]
]
inner_edges = [] inner_edges = []
# Over resulting polygons # Over resulting polygons
for x in autolist(polygon_to_clear.buffer(-tooldia / 2, int(steps_per_circle))): for x in buffered_poly:
for y in x.interiors: # Over interiors of each polygon for y in x.interiors: # Over interiors of each polygon
inner_edges.append(y) inner_edges.append(y)
# geoms += outer_edges + inner_edges # geoms += outer_edges + inner_edges
@@ -1450,14 +1450,14 @@ class Geometry(object):
This algorithm draws horizontal lines inside the polygon. This algorithm draws horizontal lines inside the polygon.
:param polygon: The polygon being painted. :param polygon: The polygon being painted.
:type polygon: shapely.geometry.Polygon :type polygon: shapely.geometry.Polygon
:param tooldia: Tool diameter. :param tooldia: Tool diameter.
:param steps_per_circle: how many linear segments to use to approximate a circle :param steps_per_circle: how many linear segments to use to approximate a circle
:param overlap: Tool path overlap percentage. :param overlap: Tool path overlap percentage.
:param connect: Connect lines to avoid tool lifts. :param connect: Connect lines to avoid tool lifts.
:param contour: Paint around the edges. :param contour: Paint around the edges.
:param prog_plot: boolean; if to use the progressive plotting :param prog_plot: boolean; if to use the progressive plotting
:return: :return:
""" """
@@ -1570,12 +1570,14 @@ class Geometry(object):
try: try:
for line in lines_trimmed: for line in lines_trimmed:
if isinstance(line, LineString) or isinstance(line, LinearRing): if isinstance(line, LineString) or isinstance(line, LinearRing):
geoms.insert(line) if not line.is_empty:
geoms.insert(line)
else: else:
log.debug("camlib.Geometry.clear_polygon3(). Not a line: %s" % str(type(line))) log.debug("camlib.Geometry.clear_polygon3(). Not a line: %s" % str(type(line)))
except TypeError: except TypeError:
# in case lines_trimmed are not iterable (Linestring, LinearRing) # in case lines_trimmed are not iterable (Linestring, LinearRing)
geoms.insert(lines_trimmed) if not lines_trimmed.is_empty:
geoms.insert(lines_trimmed)
# Add margin (contour) to storage # Add margin (contour) to storage
if contour: if contour:
@@ -1633,7 +1635,7 @@ class Geometry(object):
""" """
# log.debug("camlib.fill_with_lines()") # log.debug("camlib.fill_with_lines()")
if not isinstance(line, LineString) and not isinstance(line, MultiLineString): if not isinstance(line, LineString):
log.debug("camlib.Geometry.fill_with_lines() --> Not a LineString/MultiLineString but %s" % str(type(line))) log.debug("camlib.Geometry.fill_with_lines() --> Not a LineString/MultiLineString but %s" % str(type(line)))
return None return None