通过发布以前的question,我学会了如何拖放无任何抱怨的形状。现在,我试图添加一个使用滚轮旋转此形状的函数。
到目前为止,该程序执行了应有的操作,但不幸的是出现了无法忍受的错误。两个主要问题是:
通过拖放已经旋转的形状,形状将旋转回零度角。如果我再次使用滚轮,则形状会跳回到应该的位置。
我的建议是换行:
xdx = [i+dx for i,_ in self.geometry]
ydy = [i+dy for _,i in self.geometry]
收件人:
xdx = [i+dx for i,_ in self.newGeometry]
ydy = [i+dy for _,i in self.newGeometry]
希望它不会绘制初始形状。不幸的是,它导致了一种“二次”翻译。
该行:
x0, y0 = self.newGeometry[0]
定义形状的本地原点,该原点应该是旋转中心。因此,不允许在任何旋转过程中更改此坐标。通过比较旋转前后的坐标,我发现偏差在不断增加。
完整的MWE包含以下六个功能:
import matplotlib.pyplot as plt
import numpy as np
class DraggablePolygon:
lock = None
def __init__(self):
print('__init__')
self.press = None
self.angle = 0
fig = plt.figure()
ax = fig.add_subplot(111)
self.geometry = [[0.0,0.0],[0.1,0.05],[0.2,0.15],[0.3,0.20],[0.4,0.25],[0.5,0.30],
[0.6,0.25],[0.7,0.15],[0.8,0.05],[0.9,0.025],[1.0,0.0]]
self.newGeometry = [[0.0,0.0]]
poly = plt.Polygon(self.geometry, closed=True, fill=False, linewidth=3, color='#F97306')
ax.add_patch(poly)
self.poly = poly
def connect(self):
'connect to all the events we need'
print('connect')
self.cidpress = self.poly.figure.canvas.mpl_connect(
'button_press_event', self.on_press)
self.cidrelease = self.poly.figure.canvas.mpl_connect(
'button_release_event', self.on_release)
self.cidmotion = self.poly.figure.canvas.mpl_connect(
'motion_notify_event', self.on_motion)
self.cidscroll = self.poly.figure.canvas.mpl_connect(
'scroll_event', self.rotate_on_scroll)
def on_press(self, event):
'on button press we will see if the mouse is over us and store some data'
print('on_press')
if event.inaxes != self.poly.axes: return
if DraggablePolygon.lock is not None: return
contains, attrd = self.poly.contains(event)
if not contains: return
x0, y0 = self.newGeometry[0]
print('x0 = '+str(x0)+', '+'y0 = '+str(y0)+' -> on_press')
self.press = x0, y0, event.xdata, event.ydata
DraggablePolygon.lock = self
def on_motion(self, event):
'on motion we will move the rect if the mouse is over us'
if DraggablePolygon.lock is not self:
return
if event.inaxes != self.poly.axes: return
x0, y0, xpress, ypress = self.press
dx = event.xdata - xpress
dy = event.ydata - ypress
xdx = [i+dx for i,_ in self.geometry]
ydy = [i+dy for _,i in self.geometry]
self.newGeometry = [[a, b] for a, b in zip(xdx, ydy)]
self.poly.set_xy(self.newGeometry)
self.poly.figure.canvas.draw()
def on_release(self, event):
'on release we reset the press data'
print('on_release')
if DraggablePolygon.lock is not self:
return
self.press = None
DraggablePolygon.lock = None
self.geometry = self.newGeometry
print('x0 = '+str(self.geometry[0][0])+', '+'y0 = '+str(self.geometry[0][1])+' -> on_release')
self.poly.set_xy(self.geometry)
self.poly.figure.canvas.draw()
def rotate_on_scroll(self, event, degree=1):
if event.button == 'up':
self.angle += degree*(np.pi/180)
elif event.button == 'down':
self.angle -= degree*(np.pi/180)
x0, y0 = self.newGeometry[0]
print('x0 = '+str(x0)+', '+'y0 = '+str(y0)+' -> pre_scroll')
qx = []
qy = []
for i in range(len(self.geometry)):
qx.append(x0 + np.cos(self.angle) * (self.geometry[i][0] - x0)
- np.sin(self.angle) * (self.geometry[i][1] - y0))
qy.append(y0 + np.sin(self.angle) * (self.geometry[i][0] - y0)
+ np.cos(self.angle) * (self.geometry[i][1] - y0))
self.newGeometry = np.column_stack((qx, qy))
print('x0 = '+str(self.newGeometry[0][0])+', '+'y0 = '+str(self.newGeometry[0][1])+' -> after_scroll')
print('delta_x = '+str(x0-self.newGeometry[0][0])+', '+'delta_y = '+str(y0-self.newGeometry[0][1])+' -> deviation during scroll')
self.poly.set_xy(self.newGeometry)
self.poly.figure.canvas.draw()
dp = DraggablePolygon()
dp.connect()
plt.show()
我希望形状旋转时不会出现任何“跳跃”,并且会围绕其原点。感谢您的帮助!
答案 0 :(得分:1)
看起来像问题在于newGeometry
和geometry
的角色在这里没有明确定义。不过,以下方法应该可以工作。
import matplotlib.pyplot as plt
import numpy as np
class DraggablePolygon:
lock = None
def __init__(self):
print('__init__')
self.press = None
self.angle = 0
fig = plt.figure()
ax = fig.add_subplot(111)
self.geometry = [[0.0,0.0],[0.1,0.05],[0.2,0.15],[0.3,0.20],[0.4,0.25],[0.5,0.30],
[0.6,0.25],[0.7,0.15],[0.8,0.05],[0.9,0.025],[1.0,0.0]]
self.newGeometry = self.geometry
poly = plt.Polygon(self.geometry, closed=True, fill=False, linewidth=3, color='#F97306')
ax.add_patch(poly)
self.poly = poly
def connect(self):
'connect to all the events we need'
print('connect')
self.cidpress = self.poly.figure.canvas.mpl_connect(
'button_press_event', self.on_press)
self.cidrelease = self.poly.figure.canvas.mpl_connect(
'button_release_event', self.on_release)
self.cidmotion = self.poly.figure.canvas.mpl_connect(
'motion_notify_event', self.on_motion)
self.cidscroll = self.poly.figure.canvas.mpl_connect(
'scroll_event', self.rotate_on_scroll)
def on_press(self, event):
'on button press we will see if the mouse is over us and store some data'
print('on_press')
if event.inaxes != self.poly.axes: return
if DraggablePolygon.lock is not None: return
contains, attrd = self.poly.contains(event)
if not contains: return
self.geometry = self.newGeometry
x0, y0 = self.newGeometry[0]
print('x0 = '+str(x0)+', '+'y0 = '+str(y0)+' -> on_press')
self.press = x0, y0, event.xdata, event.ydata
DraggablePolygon.lock = self
def on_motion(self, event):
'on motion we will move the rect if the mouse is over us'
if DraggablePolygon.lock is not self:
return
if event.inaxes != self.poly.axes: return
x0, y0, xpress, ypress = self.press
dx = event.xdata - xpress
dy = event.ydata - ypress
xdx = [i+dx for i,_ in self.geometry]
ydy = [i+dy for _,i in self.geometry]
self.newGeometry = [[a, b] for a, b in zip(xdx, ydy)]
self.poly.set_xy(self.newGeometry)
self.poly.figure.canvas.draw()
def on_release(self, event):
'on release we reset the press data'
print('on_release')
if DraggablePolygon.lock is not self:
return
self.press = None
DraggablePolygon.lock = None
self.geometry = self.newGeometry
print('x0 = '+str(self.geometry[0][0])+', '+'y0 = '+str(self.geometry[0][1])+' -> on_release')
self.poly.set_xy(self.geometry)
self.poly.figure.canvas.draw()
def rotate_on_scroll(self, event, degree=1):
if event.button == 'up':
self.angle += degree*(np.pi/180)
elif event.button == 'down':
self.angle -= degree*(np.pi/180)
x0, y0 = self.newGeometry[0]
print('x0 = '+str(x0)+', '+'y0 = '+str(y0)+' -> pre_scroll')
qx = []
qy = []
for i in range(len(self.geometry)):
qx.append(x0 + np.cos(self.angle) * (self.newGeometry[i][0] - x0)
- np.sin(self.angle) * (self.newGeometry[i][1] - y0))
qy.append(y0 + np.sin(self.angle) * (self.newGeometry[i][0] - x0)
+ np.cos(self.angle) * (self.newGeometry[i][1] - y0))
self.newGeometry = np.column_stack((qx, qy))
print('x0 = '+str(self.newGeometry[0][0])+', '+'y0 = '+str(self.newGeometry[0][1])+' -> after_scroll')
print('delta_x = '+str(x0-self.newGeometry[0][0])+', '+'delta_y = '+str(y0-self.newGeometry[0][1])+' -> deviation during scroll')
self.poly.set_xy(self.newGeometry)
self.poly.figure.canvas.draw_idle()
self.angle = 0
dp = DraggablePolygon()
dp.connect()
plt.show()