- Geometry Editor: modified the intersection (if the selected shapes don't intersects preserve them) and substract functions (delete all shapes that were used in the process)
- work in the ToolSilk
This commit is contained in:
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
|
|||||||
|
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
|
25.04.2019
|
||||||
|
|
||||||
|
- Geometry Editor: modified the intersection (if the selected shapes don't intersects preserve them) and substract functions (delete all shapes that were used in the process)
|
||||||
|
- work in the ToolSilk
|
||||||
|
|
||||||
24.04.2019
|
24.04.2019
|
||||||
|
|
||||||
- PDF import tool: working in making the PDF layer rendering multithreaded in itself (one layer rendered on each worker)
|
- PDF import tool: working in making the PDF layer rendering multithreaded in itself (one layer rendered on each worker)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from FlatCAMTool import FlatCAMTool
|
|||||||
from flatcamGUI.ObjectUI import LengthEntry, RadioSet
|
from flatcamGUI.ObjectUI import LengthEntry, RadioSet
|
||||||
|
|
||||||
from shapely.geometry import LineString, LinearRing, MultiLineString
|
from shapely.geometry import LineString, LinearRing, MultiLineString
|
||||||
from shapely.ops import cascaded_union
|
from shapely.ops import cascaded_union, unary_union
|
||||||
import shapely.affinity as affinity
|
import shapely.affinity as affinity
|
||||||
|
|
||||||
from numpy import arctan2, Inf, array, sqrt, sign, dot
|
from numpy import arctan2, Inf, array, sqrt, sign, dot
|
||||||
@@ -3117,31 +3117,6 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||||||
self.tool_shape.clear(update=True)
|
self.tool_shape.clear(update=True)
|
||||||
self.tool_shape.redraw()
|
self.tool_shape.redraw()
|
||||||
|
|
||||||
def cutpath(self):
|
|
||||||
selected = self.get_selected()
|
|
||||||
tools = selected[1:]
|
|
||||||
toolgeo = cascaded_union([shp.geo for shp in tools])
|
|
||||||
|
|
||||||
target = selected[0]
|
|
||||||
if type(target.geo) == Polygon:
|
|
||||||
for ring in poly2rings(target.geo):
|
|
||||||
self.add_shape(DrawToolShape(ring.difference(toolgeo)))
|
|
||||||
self.delete_shape(target)
|
|
||||||
elif type(target.geo) == LineString or type(target.geo) == LinearRing:
|
|
||||||
self.add_shape(DrawToolShape(target.geo.difference(toolgeo)))
|
|
||||||
self.delete_shape(target)
|
|
||||||
elif type(target.geo) == MultiLineString:
|
|
||||||
try:
|
|
||||||
for linestring in target.geo:
|
|
||||||
self.add_shape(DrawToolShape(linestring.difference(toolgeo)))
|
|
||||||
except:
|
|
||||||
self.app.log.warning("Current LinearString does not intersect the target")
|
|
||||||
self.delete_shape(target)
|
|
||||||
else:
|
|
||||||
self.app.log.warning("Not implemented. Object type: %s" % str(type(target.geo)))
|
|
||||||
|
|
||||||
self.replot()
|
|
||||||
|
|
||||||
def toolbar_tool_toggle(self, key):
|
def toolbar_tool_toggle(self, key):
|
||||||
self.options[key] = self.sender().isChecked()
|
self.options[key] = self.sender().isChecked()
|
||||||
if self.options[key] == True:
|
if self.options[key] == True:
|
||||||
@@ -3781,7 +3756,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||||||
:return: None.
|
:return: None.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
results = cascaded_union([t.geo for t in self.get_selected()])
|
results = unary_union([t.geo for t in self.get_selected()])
|
||||||
|
|
||||||
# Delete originals.
|
# Delete originals.
|
||||||
for_deletion = [s for s in self.get_selected()]
|
for_deletion = [s for s in self.get_selected()]
|
||||||
@@ -3795,9 +3770,9 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
|
|
||||||
def intersection(self):
|
def intersection_2(self):
|
||||||
"""
|
"""
|
||||||
Makes intersectino of selected polygons. Original polygons are deleted.
|
Makes intersection of selected polygons. Original polygons are deleted.
|
||||||
|
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
@@ -3827,11 +3802,67 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
|
|
||||||
|
def intersection(self):
|
||||||
|
"""
|
||||||
|
Makes intersection of selected polygons. Original polygons are deleted.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
|
||||||
|
shapes = self.get_selected()
|
||||||
|
results = []
|
||||||
|
intact = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
intersector = shapes[0].geo
|
||||||
|
except Exception as e:
|
||||||
|
log.debug("FlatCAMGeoEditor.intersection() --> %s" % str(e))
|
||||||
|
self.app.inform.emit(_("[WARNING_NOTCL] A selection of at least 2 geo items is required to do Intersection."))
|
||||||
|
self.select_tool('select')
|
||||||
|
return
|
||||||
|
|
||||||
|
for shape in shapes[1:]:
|
||||||
|
if intersector.intersects(shape.geo):
|
||||||
|
results.append(intersector.intersection(shape.geo))
|
||||||
|
else:
|
||||||
|
intact.append(shape)
|
||||||
|
|
||||||
|
if len(results) != 0:
|
||||||
|
# Delete originals.
|
||||||
|
for_deletion = [s for s in self.get_selected()]
|
||||||
|
for shape in for_deletion:
|
||||||
|
if shape not in intact:
|
||||||
|
self.delete_shape(shape)
|
||||||
|
|
||||||
|
for geo in results:
|
||||||
|
self.add_shape(DrawToolShape(geo))
|
||||||
|
|
||||||
|
# Selected geometry is now gone!
|
||||||
|
self.selected = []
|
||||||
|
self.replot()
|
||||||
|
|
||||||
def subtract(self):
|
def subtract(self):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
try:
|
try:
|
||||||
tools = selected[1:]
|
tools = selected[1:]
|
||||||
toolgeo = cascaded_union([shp.geo for shp in tools])
|
toolgeo = unary_union([shp.geo for shp in tools])
|
||||||
|
result = selected[0].geo.difference(toolgeo)
|
||||||
|
|
||||||
|
for_deletion = [s for s in self.get_selected()]
|
||||||
|
for shape in for_deletion:
|
||||||
|
self.delete_shape(shape)
|
||||||
|
|
||||||
|
self.add_shape(DrawToolShape(result))
|
||||||
|
|
||||||
|
self.replot()
|
||||||
|
except Exception as e:
|
||||||
|
log.debug(str(e))
|
||||||
|
|
||||||
|
def subtract_2(self):
|
||||||
|
selected = self.get_selected()
|
||||||
|
try:
|
||||||
|
tools = selected[1:]
|
||||||
|
toolgeo = unary_union([shp.geo for shp in tools])
|
||||||
result = selected[0].geo.difference(toolgeo)
|
result = selected[0].geo.difference(toolgeo)
|
||||||
|
|
||||||
self.delete_shape(selected[0])
|
self.delete_shape(selected[0])
|
||||||
@@ -3841,6 +3872,30 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug(str(e))
|
log.debug(str(e))
|
||||||
|
|
||||||
|
def cutpath(self):
|
||||||
|
selected = self.get_selected()
|
||||||
|
tools = selected[1:]
|
||||||
|
toolgeo = unary_union([shp.geo for shp in tools])
|
||||||
|
|
||||||
|
target = selected[0]
|
||||||
|
if type(target.geo) == Polygon:
|
||||||
|
for ring in poly2rings(target.geo):
|
||||||
|
self.add_shape(DrawToolShape(ring.difference(toolgeo)))
|
||||||
|
elif type(target.geo) == LineString or type(target.geo) == LinearRing:
|
||||||
|
self.add_shape(DrawToolShape(target.geo.difference(toolgeo)))
|
||||||
|
elif type(target.geo) == MultiLineString:
|
||||||
|
try:
|
||||||
|
for linestring in target.geo:
|
||||||
|
self.add_shape(DrawToolShape(linestring.difference(toolgeo)))
|
||||||
|
except:
|
||||||
|
self.app.log.warning("Current LinearString does not intersect the target")
|
||||||
|
else:
|
||||||
|
self.app.log.warning("Not implemented. Object type: %s" % str(type(target.geo)))
|
||||||
|
return
|
||||||
|
|
||||||
|
self.delete_shape(target)
|
||||||
|
self.replot()
|
||||||
|
|
||||||
def buffer(self, buf_distance, join_style):
|
def buffer(self, buf_distance, join_style):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import numpy as np
|
|||||||
|
|
||||||
import zlib
|
import zlib
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
@@ -201,8 +202,11 @@ class ToolPDF(FlatCAMTool):
|
|||||||
self.pdf_decompressed[short_name] = ''
|
self.pdf_decompressed[short_name] = ''
|
||||||
|
|
||||||
# removal from list is done in a multithreaded way therefore not always the removal can be done
|
# removal from list is done in a multithreaded way therefore not always the removal can be done
|
||||||
|
# try to remove until it's done
|
||||||
try:
|
try:
|
||||||
self.parsing_promises.remove(short_name)
|
while True:
|
||||||
|
self.parsing_promises.remove(short_name)
|
||||||
|
time.sleep(0.1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.app.inform.emit(_("[success] Opened: %s") % filename)
|
self.app.inform.emit(_("[success] Opened: %s") % filename)
|
||||||
@@ -1057,7 +1061,7 @@ class ToolPDF(FlatCAMTool):
|
|||||||
# with the final point P3. Intermediate values of t generate intermediate points along the curve.
|
# with the final point P3. Intermediate values of t generate intermediate points along the curve.
|
||||||
# The curve does not, in general, pass through the two control points P1 and P2
|
# The curve does not, in general, pass through the two control points P1 and P2
|
||||||
|
|
||||||
:return: LineString geometry
|
:return: A list of point coordinates tuples (x, y)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# here we store the geometric points
|
# here we store the geometric points
|
||||||
|
|||||||
@@ -173,46 +173,48 @@ class ToolSilk(FlatCAMTool):
|
|||||||
ap_size = self.silk_obj.apertures[apid]['size']
|
ap_size = self.silk_obj.apertures[apid]['size']
|
||||||
geo_list = self.silk_obj.apertures[apid]['solid_geometry']
|
geo_list = self.silk_obj.apertures[apid]['solid_geometry']
|
||||||
self.app.worker_task.emit({'fcn': self.aperture_intersection,
|
self.app.worker_task.emit({'fcn': self.aperture_intersection,
|
||||||
'params': [apid, ap_size, geo_list]})
|
'params': [apid, geo_list]})
|
||||||
|
|
||||||
def aperture_intersection(self, aperture_id, aperture_size, geo_list):
|
def aperture_intersection(self, apid, geo_list):
|
||||||
self.promises.append(aperture_id)
|
self.promises.append(apid)
|
||||||
new_solid_geometry = []
|
new_solid_geometry = []
|
||||||
|
for g in geo_list:
|
||||||
|
print(g.exterior.wkt)
|
||||||
|
|
||||||
with self.app.proc_container.new(_("Parsing aperture %s geometry ..." % str(aperture_id))):
|
with self.app.proc_container.new(_("Parsing aperture %s geometry ..." % str(apid))):
|
||||||
for geo_silk in geo_list:
|
for geo_silk in geo_list:
|
||||||
for sm_ap in self.sm_obj.apertures:
|
if geo_silk.exterior.intersects(self.solder_union.exterior):
|
||||||
for key in self.sm_obj.apertures[sm_ap]:
|
print("yes")
|
||||||
if key == 'solid_geometry':
|
new_geo = geo_silk.exterior.difference(self.solder_union.exterior)
|
||||||
if geo_silk.intersects(self.solder_union):
|
# if the resulting geometry is not empty add it to the new_apertures solid_geometry
|
||||||
new_geo = geo_silk.symmetric_difference(self.solder_union)
|
try:
|
||||||
# if the resulting geometry is not empty add it to the new_apertures solid_geometry
|
for g in new_geo:
|
||||||
if type(new_geo) == MultiPolygon:
|
new_solid_geometry.append(g)
|
||||||
for g in new_geo:
|
except TypeError:
|
||||||
new_solid_geometry.append(g)
|
new_solid_geometry.append(new_geo)
|
||||||
else:
|
|
||||||
new_solid_geometry.append(new_geo)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
new_solid_geometry.append(geo_silk)
|
print("no")
|
||||||
|
new_solid_geometry.append(geo_silk)
|
||||||
|
|
||||||
try:
|
if new_solid_geometry:
|
||||||
while not self.new_apertures[aperture_id]['solid_geometry']:
|
try:
|
||||||
self.new_apertures[aperture_id]['solid_geometry'] = new_solid_geometry
|
while not self.new_apertures[apid]['solid_geometry']:
|
||||||
time.sleep(0.1)
|
self.new_apertures[apid]['solid_geometry'] = new_solid_geometry
|
||||||
except:
|
time.sleep(0.1)
|
||||||
pass
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
# removal from list is done in a multithreaded way therefore not always the removal can be done
|
# removal from list is done in a multithreaded way therefore not always the removal can be done
|
||||||
# so we keep trying until it's done
|
# so we keep trying until it's done
|
||||||
self.promises.remove(aperture_id)
|
self.promises.remove(apid)
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def periodic_check(self, check_period):
|
def periodic_check(self, check_period, reset=False):
|
||||||
"""
|
"""
|
||||||
This function starts an QTimer and it will periodically check if intersections are done
|
This function starts an QTimer and it will periodically check if intersections are done
|
||||||
|
|
||||||
@@ -227,11 +229,12 @@ class ToolSilk(FlatCAMTool):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.check_thread.setInterval(check_period)
|
if reset:
|
||||||
try:
|
self.check_thread.setInterval(check_period)
|
||||||
self.check_thread.timeout.disconnect(self.periodic_check_handler)
|
try:
|
||||||
except:
|
self.check_thread.timeout.disconnect(self.periodic_check_handler)
|
||||||
pass
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
self.check_thread.timeout.connect(self.periodic_check_handler)
|
self.check_thread.timeout.connect(self.periodic_check_handler)
|
||||||
self.check_thread.start(QtCore.QThread.HighPriority)
|
self.check_thread.start(QtCore.QThread.HighPriority)
|
||||||
|
|||||||
Reference in New Issue
Block a user