Merged jpcgt/flatcam into master

This commit is contained in:
Marius Stanciu
2018-06-06 03:22:54 +03:00
14 changed files with 544 additions and 18 deletions

View File

@@ -35,8 +35,10 @@ from FlatCAMCommon import LoudDict
from FlatCAMShell import FCShell from FlatCAMShell import FCShell
from FlatCAMDraw import FlatCAMDraw from FlatCAMDraw import FlatCAMDraw
from FlatCAMProcess import * from FlatCAMProcess import *
from MeasurementTool import Measurement from GUIElements import FCInputDialog
from DblSidedTool import DblSidedTool from ToolMeasurement import Measurement
from ToolDblSided import DblSidedTool
from ToolTransform import ToolTransform
import tclCommands import tclCommands
from camlib import * from camlib import *
@@ -580,10 +582,12 @@ class App(QtCore.QObject):
self.dblsidedtool = DblSidedTool(self) self.dblsidedtool = DblSidedTool(self)
self.dblsidedtool.install(icon=QtGui.QIcon('share/doubleside16.png'), separator=True) self.dblsidedtool.install(icon=QtGui.QIcon('share/doubleside16.png'), separator=True)
self.measeurement_tool = Measurement(self) self.measurement_tool = Measurement(self)
self.measeurement_tool.install(icon=QtGui.QIcon('share/measure16.png')) self.measurement_tool.install(icon=QtGui.QIcon('share/measure16.png'))
self.ui.measure_btn.triggered.connect(self.measurement_tool.run)
self.ui.measure_btn.triggered.connect(self.measeurement_tool.run) self.transform_tool = ToolTransform(self)
self.transform_tool.install(icon=QtGui.QIcon('share/transform.png'), pos=self.ui.menuedit)
self.draw = FlatCAMDraw(self, disabled=True) self.draw = FlatCAMDraw(self, disabled=True)

View File

@@ -98,14 +98,16 @@ class FlatCAMGUI(QtGui.QMainWindow):
self.menueditnew = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), 'New Geometry') self.menueditnew = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), 'New Geometry')
self.menueditedit = self.menuedit.addAction(QtGui.QIcon('share/edit16.png'), 'Edit Geometry') self.menueditedit = self.menuedit.addAction(QtGui.QIcon('share/edit16.png'), 'Edit Geometry')
self.menueditok = self.menuedit.addAction(QtGui.QIcon('share/edit_ok16.png'), 'Update Geometry') self.menueditok = self.menuedit.addAction(QtGui.QIcon('share/edit_ok16.png'), 'Update Geometry')
#self.menueditok. # Separator
#self.menueditcancel = self.menuedit.addAction(QtGui.QIcon('share/cancel_edit16.png'), "Cancel Edit") self.menuedit.addSeparator()
self.menueditjoin = self.menuedit.addAction(QtGui.QIcon('share/join16.png'), 'Join Geometry') self.menueditjoin = self.menuedit.addAction(QtGui.QIcon('share/join16.png'), 'Join Geometry')
self.menueditdelete = self.menuedit.addAction(QtGui.QIcon('share/trash16.png'), 'Delete') self.menueditdelete = self.menuedit.addAction(QtGui.QIcon('share/trash16.png'), 'Delete')
self.menuedit.addSeparator()
### Options ### ### Options ###
self.menuoptions = self.menu.addMenu('&Options') self.menuoptions = self.menu.addMenu('&Options')
self.menuoptions_transfer = self.menuoptions.addMenu('Transfer options') self.menuoptions_transfer = self.menuoptions.addMenu(QtGui.QIcon('share/transfer.png'), 'Transfer options')
self.menuoptions_transfer_a2p = self.menuoptions_transfer.addAction("Application to Project") self.menuoptions_transfer_a2p = self.menuoptions_transfer.addAction("Application to Project")
self.menuoptions_transfer_p2a = self.menuoptions_transfer.addAction("Project to Application") self.menuoptions_transfer_p2a = self.menuoptions_transfer.addAction("Project to Application")
self.menuoptions_transfer_p2o = self.menuoptions_transfer.addAction("Project to Object") self.menuoptions_transfer_p2o = self.menuoptions_transfer.addAction("Project to Object")

View File

@@ -80,13 +80,15 @@ class LengthEntry(QtGui.QLineEdit):
self.readyToEdit = True self.readyToEdit = True
def mousePressEvent(self, e, Parent=None): def mousePressEvent(self, e, Parent=None):
super(LengthEntry, self).mousePressEvent(e) # required to deselect on 2e click # required to deselect on 2nd click
super(LengthEntry, self).mousePressEvent(e)
if self.readyToEdit: if self.readyToEdit:
self.selectAll() self.selectAll()
self.readyToEdit = False self.readyToEdit = False
def focusOutEvent(self, e): def focusOutEvent(self, e):
super(LengthEntry, self).focusOutEvent(e) # required to remove cursor on focusOut # required to remove cursor on focusOut
super(LengthEntry, self).focusOutEvent(e)
self.deselect() self.deselect()
self.readyToEdit = True self.readyToEdit = True
@@ -126,13 +128,15 @@ class FloatEntry(QtGui.QLineEdit):
self.readyToEdit = True self.readyToEdit = True
def mousePressEvent(self, e, Parent=None): def mousePressEvent(self, e, Parent=None):
super(FloatEntry, self).mousePressEvent(e) # required to deselect on 2e click # required to deselect on 2nd click
super(FloatEntry, self).mousePressEvent(e)
if self.readyToEdit: if self.readyToEdit:
self.selectAll() self.selectAll()
self.readyToEdit = False self.readyToEdit = False
def focusOutEvent(self, e): def focusOutEvent(self, e):
super(FloatEntry, self).focusOutEvent(e) # required to remove cursor on focusOut # required to remove cursor on focusOut
super(FloatEntry, self).focusOutEvent(e)
self.deselect() self.deselect()
self.readyToEdit = True self.readyToEdit = True
@@ -166,13 +170,15 @@ class IntEntry(QtGui.QLineEdit):
self.readyToEdit = True self.readyToEdit = True
def mousePressEvent(self, e, Parent=None): def mousePressEvent(self, e, Parent=None):
super(IntEntry, self).mousePressEvent(e) # required to deselect on 2e click # required to deselect on 2nd click
super(IntEntry, self).mousePressEvent(e)
if self.readyToEdit: if self.readyToEdit:
self.selectAll() self.selectAll()
self.readyToEdit = False self.readyToEdit = False
def focusOutEvent(self, e): def focusOutEvent(self, e):
super(IntEntry, self).focusOutEvent(e) # required to remove cursor on focusOut # required to remove cursor on focusOut
super(IntEntry, self).focusOutEvent(e)
self.deselect() self.deselect()
self.readyToEdit = True self.readyToEdit = True
@@ -199,13 +205,15 @@ class FCEntry(QtGui.QLineEdit):
self.readyToEdit = True self.readyToEdit = True
def mousePressEvent(self, e, Parent=None): def mousePressEvent(self, e, Parent=None):
super(FCEntry, self).mousePressEvent(e) # required to deselect on 2e click # required to deselect on 2nd click
super(FCEntry, self).mousePressEvent(e)
if self.readyToEdit: if self.readyToEdit:
self.selectAll() self.selectAll()
self.readyToEdit = False self.readyToEdit = False
def focusOutEvent(self, e): def focusOutEvent(self, e):
super(FCEntry, self).focusOutEvent(e) # required to remove cursor on focusOut # required to remove cursor on focusOut
super(FCEntry, self).focusOutEvent(e)
self.deselect() self.deselect()
self.readyToEdit = True self.readyToEdit = True
@@ -222,13 +230,15 @@ class EvalEntry(QtGui.QLineEdit):
self.readyToEdit = True self.readyToEdit = True
def mousePressEvent(self, e, Parent=None): def mousePressEvent(self, e, Parent=None):
super(EvalEntry, self).mousePressEvent(e) # required to deselect on 2e click # required to deselect on 2nd click
super(EvalEntry, self).mousePressEvent(e)
if self.readyToEdit: if self.readyToEdit:
self.selectAll() self.selectAll()
self.readyToEdit = False self.readyToEdit = False
def focusOutEvent(self, e): def focusOutEvent(self, e):
super(EvalEntry, self).focusOutEvent(e) # required to remove cursor on focusOut # required to remove cursor on focusOut
super(EvalEntry, self).focusOutEvent(e)
self.deselect() self.deselect()
self.readyToEdit = True self.readyToEdit = True
@@ -275,6 +285,55 @@ class FCTextArea(QtGui.QPlainTextEdit):
def get_value(self): def get_value(self):
return str(self.toPlainText()) return str(self.toPlainText())
class FCInputDialog(QtGui.QInputDialog):
def __init__(self, parent=None, ok=False, val=None):
super(FCInputDialog, self).__init__(parent)
self.allow_empty = ok
self.empty_val = val
self.readyToEdit = True
def mousePressEvent(self, e, Parent=None):
# required to deselect on 2nd click
super(FCInputDialog, self).mousePressEvent(e)
if self.readyToEdit:
self.selectAll()
self.readyToEdit = False
def focusOutEvent(self, e):
# required to remove cursor on focusOut
super(FCInputDialog, self).focusOutEvent(e)
self.deselect()
self.readyToEdit = True
def get_value(self, title=None, message=None, min=None, max=None, decimals=None):
if title is None:
title = "FlatCAM action"
if message is None:
message = "Please enter the value: "
if min is None:
min = 0.0
if max is None:
max = 100.0
if decimals is None:
decimals = 1
self.val,self.ok = self.getDouble(self, title, message, min=min,
max=max, decimals=decimals)
return [self.val,self.ok]
def set_value(self, val):
pass
class FCButton(QtGui.QPushButton):
def __init__(self, parent=None):
super(FCButton, self).__init__(parent)
def get_value(self):
return self.isChecked()
def set_value(self, val):
self.setText(str(val))
class VerticalScrollArea(QtGui.QScrollArea): class VerticalScrollArea(QtGui.QScrollArea):
""" """

319
ToolTransform.py Normal file
View File

@@ -0,0 +1,319 @@
from PyQt4 import QtGui, QtCore
from PyQt4 import Qt
from GUIElements import FCEntry, FCButton
from FlatCAMTool import FlatCAMTool
from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
class ToolTransform(FlatCAMTool):
toolName = "Object Transformation"
rotateName = "Rotate Transformation"
skewName = "Skew/Shear Transformation"
flipName = "Flip Transformation"
def __init__(self, app):
FlatCAMTool.__init__(self, app)
self.transform_lay = QtGui.QVBoxLayout()
self.layout.addLayout(self.transform_lay)
## Title
title_label = QtGui.QLabel("<font size=4><b>%s</b></font><br>" % self.toolName)
self.transform_lay.addWidget(title_label)
self.empty_label = QtGui.QLabel("")
self.empty_label.setFixedWidth(80)
self.empty_label1 = QtGui.QLabel("")
self.empty_label1.setFixedWidth(80)
self.empty_label2 = QtGui.QLabel("")
self.empty_label2.setFixedWidth(80)
self.transform_lay.addWidget(self.empty_label)
## Rotate Title
rotate_title_label = QtGui.QLabel("<font size=3><b>%s</b></font>" % self.rotateName)
self.transform_lay.addWidget(rotate_title_label)
## Form Layout
form_layout = QtGui.QFormLayout()
self.transform_lay.addLayout(form_layout)
self.rotate_entry = FCEntry()
self.rotate_entry.setFixedWidth(70)
self.rotate_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.rotate_label = QtGui.QLabel("Angle Rotation:")
self.rotate_label.setToolTip(
"Angle for Rotation action, in degrees.\n"
"Float number between -360 and 359.\n"
"Positive numbers for CW motion.\n"
"Negative numbers for CCW motion."
)
self.rotate_label.setFixedWidth(80)
self.rotate_button = FCButton()
self.rotate_button.set_value("Rotate")
self.rotate_button.setToolTip(
"Rotate the selected object(s).\n"
"The point of reference is the middle of\n"
"the bounding box for all selected objects.\n"
)
self.rotate_button.setFixedWidth(70)
form_layout.addRow(self.rotate_label, self.rotate_entry)
form_layout.addRow(self.empty_label, self.rotate_button)
self.transform_lay.addWidget(self.empty_label1)
## Skew Title
skew_title_label = QtGui.QLabel("<font size=3><b>%s</b></font>" % self.skewName)
self.transform_lay.addWidget(skew_title_label)
## Form Layout
form1_layout = QtGui.QFormLayout()
self.transform_lay.addLayout(form1_layout)
self.skewx_entry = FCEntry()
self.skewx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.skewx_entry.setFixedWidth(70)
self.skewx_label = QtGui.QLabel("Angle SkewX:")
self.skewx_label.setToolTip(
"Angle for Skew action, in degrees.\n"
"Float number between -360 and 359."
)
self.skewx_label.setFixedWidth(80)
self.skewx_button = FCButton()
self.skewx_button.set_value("Skew_X")
self.skewx_button.setToolTip(
"Skew/shear the selected object(s).\n"
"The point of reference is the middle of\n"
"the bounding box for all selected objects.\n")
self.skewx_button.setFixedWidth(70)
self.skewy_entry = FCEntry()
self.skewy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.skewy_entry.setFixedWidth(70)
self.skewy_label = QtGui.QLabel("Angle SkewY:")
self.skewy_label.setToolTip(
"Angle for Skew action, in degrees.\n"
"Float number between -360 and 359."
)
self.skewy_label.setFixedWidth(80)
self.skewy_button = FCButton()
self.skewy_button.set_value("Skew_Y")
self.skewy_button.setToolTip(
"Skew/shear the selected object(s).\n"
"The point of reference is the middle of\n"
"the bounding box for all selected objects.\n")
self.skewy_button.setFixedWidth(70)
form1_layout.addRow(self.skewx_label, self.skewx_entry)
form1_layout.addRow(self.empty_label, self.skewx_button)
form1_layout.addRow(self.skewy_label, self.skewy_entry)
form1_layout.addRow(self.empty_label, self.skewy_button)
self.transform_lay.addWidget(self.empty_label2)
## Flip Title
flip_title_label = QtGui.QLabel("<font size=3><b>%s</b></font>" % self.flipName)
self.transform_lay.addWidget(flip_title_label)
## Form Layout
form2_layout = QtGui.QFormLayout()
self.transform_lay.addLayout(form2_layout)
self.flipx_button = FCButton()
self.flipx_button.set_value("Flip_X")
self.flipx_button.setToolTip(
"Flip the selected object(s) over the X axis.\n"
"Does not create a new object.\n "
)
self.flipx_button.setFixedWidth(70)
self.flipy_button = FCButton()
self.flipy_button.set_value("Flip_Y")
self.flipy_button.setToolTip(
"Flip the selected object(s) over the X axis.\n"
"Does not create a new object.\n "
)
self.flipy_button.setFixedWidth(70)
form2_layout.setSpacing(16)
form2_layout.addRow(self.flipx_button, self.flipy_button)
self.transform_lay.addStretch()
## Signals
self.rotate_button.clicked.connect(self.on_rotate)
self.skewx_button.clicked.connect(self.on_skewx)
self.skewy_button.clicked.connect(self.on_skewy)
self.flipx_button.clicked.connect(self.on_flipx)
self.flipy_button.clicked.connect(self.on_flipy)
self.rotate_entry.returnPressed.connect(self.on_rotate)
self.skewx_entry.returnPressed.connect(self.on_skewx)
self.skewy_entry.returnPressed.connect(self.on_skewy)
## Initialize form
self.rotate_entry.set_value('0')
self.skewx_entry.set_value('0')
self.skewy_entry.set_value('0')
def on_rotate(self):
value = float(self.rotate_entry.get_value())
self.on_rotate_action(value)
return
def on_flipx(self):
self.on_flip("Y")
return
def on_flipy(self):
self.on_flip("X")
return
def on_skewx(self):
value = float(self.skewx_entry.get_value())
self.on_skew("X", value)
return
def on_skewy(self):
value = float(self.skewy_entry.get_value())
self.on_skew("Y", value)
return
def on_rotate_action(self, num):
obj_list = self.app.collection.get_selected()
xminlist = []
yminlist = []
xmaxlist = []
ymaxlist = []
if not obj_list:
self.app.inform.emit("WARNING: No object selected.")
msg = "Please Select an object to rotate!"
warningbox = QtGui.QMessageBox()
warningbox.setText(msg)
warningbox.setWindowTitle("Warning ...")
warningbox.setWindowIcon(QtGui.QIcon('share/warning.png'))
warningbox.setStandardButtons(QtGui.QMessageBox.Ok)
warningbox.setDefaultButton(QtGui.QMessageBox.Ok)
warningbox.exec_()
else:
try:
# first get a bounding box to fit all
for obj in obj_list:
xmin, ymin, xmax, ymax = obj.bounds()
xminlist.append(xmin)
yminlist.append(ymin)
xmaxlist.append(xmax)
ymaxlist.append(ymax)
# get the minimum x,y and maximum x,y for all objects selected
xminimal = min(xminlist)
yminimal = min(yminlist)
xmaximal = max(xmaxlist)
ymaximal = max(ymaxlist)
for sel_obj in obj_list:
px = 0.5 * (xminimal + xmaximal)
py = 0.5 * (yminimal + ymaximal)
sel_obj.rotate(-num, point=(px, py))
sel_obj.plot()
self.app.inform.emit('Object was rotated ...')
except Exception as e:
self.app.inform.emit("[ERROR] Due of %s, rotation movement was not executed." % str(e))
return
def on_flip(self, axis):
obj_list = self.app.collection.get_selected()
xminlist = []
yminlist = []
xmaxlist = []
ymaxlist = []
if not obj_list:
self.app.inform.emit("WARNING: No object selected.")
msg = "Please Select an object to flip!"
warningbox = QtGui.QMessageBox()
warningbox.setText(msg)
warningbox.setWindowTitle("Warning ...")
warningbox.setWindowIcon(QtGui.QIcon('share/warning.png'))
warningbox.setStandardButtons(QtGui.QMessageBox.Ok)
warningbox.setDefaultButton(QtGui.QMessageBox.Ok)
warningbox.exec_()
return
else:
try:
# first get a bounding box to fit all
for obj in obj_list:
xmin, ymin, xmax, ymax = obj.bounds()
xminlist.append(xmin)
yminlist.append(ymin)
xmaxlist.append(xmax)
ymaxlist.append(ymax)
# get the minimum x,y and maximum x,y for all objects selected
xminimal = min(xminlist)
yminimal = min(yminlist)
xmaximal = max(xmaxlist)
ymaximal = max(ymaxlist)
px = 0.5 * (xminimal + xmaximal)
py = 0.5 * (yminimal + ymaximal)
# execute mirroring
for obj in obj_list:
if axis is 'X':
obj.mirror('X', [px, py])
obj.plot()
self.app.inform.emit('Flipped on the Y axis ...')
elif axis is 'Y':
obj.mirror('Y', [px, py])
obj.plot()
self.app.inform.emit('Flipped on the X axis ...')
except Exception as e:
self.app.inform.emit("[ERROR] Due of %s, Flip action was not executed.")
return
def on_skew(self, axis, num):
obj_list = self.app.collection.get_selected()
xminlist = []
yminlist = []
if not obj_list:
self.app.inform.emit("WARNING: No object selected.")
msg = "Please Select an object to skew/shear!"
warningbox = QtGui.QMessageBox()
warningbox.setText(msg)
warningbox.setWindowTitle("Warning ...")
warningbox.setWindowIcon(QtGui.QIcon('share/warning.png'))
warningbox.setStandardButtons(QtGui.QMessageBox.Ok)
warningbox.setDefaultButton(QtGui.QMessageBox.Ok)
warningbox.exec_()
else:
try:
# first get a bounding box to fit all
for obj in obj_list:
xmin, ymin, xmax, ymax = obj.bounds()
xminlist.append(xmin)
yminlist.append(ymin)
# get the minimum x,y and maximum x,y for all objects selected
xminimal = min(xminlist)
yminimal = min(yminlist)
for obj in obj_list:
if axis is 'X':
obj.skew(num, 0, point=(xminimal, yminimal))
elif axis is 'Y':
obj.skew(0, num, point=(xminimal, yminimal))
obj.plot()
self.app.inform.emit('Object was skewed on %s axis ...' % str(axis))
except Exception as e:
self.app.inform.emit("[ERROR] Due of %s, Skew action was not executed." % str(e))
return
# end of file

142
camlib.py
View File

@@ -1051,6 +1051,46 @@ class Geometry(object):
self.solid_geometry = mirror_geom(self.solid_geometry) self.solid_geometry = mirror_geom(self.solid_geometry)
def skew(self, angle_x=None, angle_y=None, point=None):
"""
Shear/Skew the geometries of an object by angles along x and y dimensions.
Parameters
----------
xs, ys : float, float
The shear angle(s) for the x and y axes respectively. These can be
specified in either degrees (default) or radians by setting
use_radians=True.
See shapely manual for more information:
http://toblerity.org/shapely/manual.html#affine-transformations
"""
if angle_y is None:
angle_y = 0.0
if angle_x is None:
angle_x = 0.0
if point is None:
self.solid_geometry = affinity.skew(self.solid_geometry, angle_x, angle_y,
origin=(0, 0))
else:
px, py = point
self.solid_geometry = affinity.skew(self.solid_geometry, angle_x, angle_y,
origin=(px, py))
return
def rotate(self, angle, point=None):
"""
Rotate an object by a given angle around given coords (point)
:param angle:
:param point:
:return:
"""
if point is None:
self.solid_geometry = affinity.rotate(self.solid_geometry, angle, origin='center')
else:
px, py = point
self.solid_geometry = affinity.rotate(self.solid_geometry, angle, origin=(px, py))
return
class ApertureMacro: class ApertureMacro:
""" """
@@ -2869,6 +2909,60 @@ class Excellon(Geometry):
# Recreate geometry # Recreate geometry
self.create_geometry() self.create_geometry()
def skew(self, angle_x=None, angle_y=None, point=None):
"""
Shear/Skew the geometries of an object by angles along x and y dimensions.
Tool sizes, feedrates an Z-plane dimensions are untouched.
Parameters
----------
angle_x, angle_y: float, float
The shear angle(s) for the x and y axes respectively. These can be
specified in either degrees (default) or radians by setting
use_radians=True.
point: point of origin for skew, tuple of coordinates
See shapely manual for more information:
http://toblerity.org/shapely/manual.html#affine-transformations
"""
if angle_y is None:
angle_y = 0.0
if angle_x is None:
angle_x = 0.0
if point is None:
# Drills
for drill in self.drills:
drill['point'] = affinity.skew(drill['point'], angle_x, angle_y,
origin=(0, 0))
else:
# Drills
px, py = point
for drill in self.drills:
drill['point'] = affinity.skew(drill['point'], angle_x, angle_y,
origin=(px, py))
self.create_geometry()
def rotate(self, angle, point=None):
"""
Rotate the geometry of an object by an angle around the 'point' coordinates
:param angle:
:param point: point around which to rotate
:return:
"""
if point is None:
# Drills
for drill in self.drills:
drill['point'] = affinity.rotate(drill['point'], angle, origin='center')
else:
# Drills
px, py = point
for drill in self.drills:
drill['point'] = affinity.rotate(drill['point'], angle, origin=(px, py))
self.create_geometry()
def convert_units(self, units): def convert_units(self, units):
factor = Geometry.convert_units(self, units) factor = Geometry.convert_units(self, units)
@@ -3535,6 +3629,54 @@ class CNCjob(Geometry):
self.create_geometry() self.create_geometry()
def skew(self, angle_x=None, angle_y=None, point=None):
"""
Shear/Skew the geometries of an object by angles along x and y dimensions.
Parameters
----------
angle_x, angle_y : float, float
The shear angle(s) for the x and y axes respectively. These can be
specified in either degrees (default) or radians by setting
use_radians=True.
point: tupple of coordinates . Origin for skew.
See shapely manual for more information:
http://toblerity.org/shapely/manual.html#affine-transformations
"""
if angle_y is None:
angle_y = 0.0
if angle_x is None:
angle_x = 0.0
if point == None:
for g in self.gcode_parsed:
g['geom'] = affinity.skew(g['geom'], angle_x, angle_y,
origin=(0, 0))
else:
for g in self.gcode_parsed:
g['geom'] = affinity.skew(g['geom'], angle_x, angle_y,
origin=point)
self.create_geometry()
def rotate(self, angle, point=None):
"""
Rotate the geometrys of an object by an given angle around the coordinates of the 'point'
:param angle:
:param point:
:return:
"""
if point is None:
for g in self.gcode_parsed:
g['geom'] = affinity.rotate(g['geom'], angle, origin='center')
else:
px, py = point
for g in self.gcode_parsed:
g['geom'] = affinity.rotate(g['geom'], angle, origin=(px, py))
self.create_geometry()
def export_svg(self, scale_factor=0.00): def export_svg(self, scale_factor=0.00):
""" """
Exports the CNC Job as a SVG Element Exports the CNC Job as a SVG Element

BIN
share/flipx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

BIN
share/flipy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

BIN
share/rotate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

BIN
share/skewX.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
share/skewY.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

BIN
share/transfer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

BIN
share/transform.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B