如何在 Kivy 中使用等距/正交视图?
How to work with a isometric / orthogonal view in Kivy?
下图是带按钮的 GridLayout 10 x 10。
我想创建相同的网格,但在 等距/正交 2d 视图 中。
意思是每个按钮不是正方形,而是菱形,如下图:
我该怎么做?
我认为你实际上不能在 kivy UIX 小部件上进行 3D 旋转,但你可以进行 2D 旋转和缩放。这是在 build()
方法中执行此操作的 App
示例:
from kivy.app import App
from kivy.graphics.context_instructions import PushMatrix, Rotate, Scale, PopMatrix
from kivy.properties import BooleanProperty
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
import numpy as np
def matrixToNumpy(mat):
a = []
for i in range(4):
b = []
for j in range(4):
b.append(mat[i*4+j])
a.append(b)
npmat = np.mat(a)
return npmat
class MyButton(Button):
def on_touch_down(self, touch):
if not self.parent.touched:
self.parent.touched = True
if self.parent.mat is None:
scale = matrixToNumpy(self.parent.sca.matrix)
rotate = matrixToNumpy(self.parent.rot.matrix)
self.parent.mat = np.matmul(rotate, scale)
self.parent.inv_mat = self.parent.mat.I
npTouch = np.mat([touch.x, touch.y, 0, 1.0])
convTouch = np.matmul(npTouch, self.parent.inv_mat)
touch.x = convTouch[0,0]
touch.y = convTouch[0,1]
return super(MyButton, self).on_touch_down(touch)
def on_touch_up(self, touch):
self.parent.touched = False
return super(MyButton, self).on_touch_up(touch)
class MyGridLayout(GridLayout):
touched = BooleanProperty(False)
def __init__(self, **kwargs):
super(MyGridLayout, self).__init__(**kwargs)
self.mat = None
self.inv_mat = None
class MyApp(App):
def build(self):
layout = MyGridLayout(cols=10)
with layout.canvas.before:
PushMatrix()
layout.sca = Scale(1.0, 0.5, 1.0)
layout.rot = Rotate(angle=45, axis=(0,0,1), origin=(400,300,0))
with layout.canvas.after:
PopMatrix()
for i in range (1, 101):
layout.add_widget(MyButton(text=str(i)))
return layout
MyApp().run()
我怀疑通过巧妙地应用这两个 kivy.graphics.context_instructions
,您可以模拟您想要的东西。 PushMatrix()
和 PopMatrix()
将 Scale
和 Rotate
的效果限制在 MyGridLayout
中。您应该能够使用 layout.sca
和 layout.rot
参考来调整这些值。
我在最初的回答后注意到 Buttons
看起来不错,但不再有效。我添加了一堆代码来解决这个问题。所有 numpy
矩阵的东西只是为了让鼠标按下位置与 MyGridLayout
相同的坐标。不幸的是,Kivy 事件不会自动考虑应用 Canvas
缩放和旋转,因此需要额外的代码。
这是它的样子:
下图是带按钮的 GridLayout 10 x 10。
我想创建相同的网格,但在 等距/正交 2d 视图 中。
意思是每个按钮不是正方形,而是菱形,如下图:
我该怎么做?
我认为你实际上不能在 kivy UIX 小部件上进行 3D 旋转,但你可以进行 2D 旋转和缩放。这是在 build()
方法中执行此操作的 App
示例:
from kivy.app import App
from kivy.graphics.context_instructions import PushMatrix, Rotate, Scale, PopMatrix
from kivy.properties import BooleanProperty
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
import numpy as np
def matrixToNumpy(mat):
a = []
for i in range(4):
b = []
for j in range(4):
b.append(mat[i*4+j])
a.append(b)
npmat = np.mat(a)
return npmat
class MyButton(Button):
def on_touch_down(self, touch):
if not self.parent.touched:
self.parent.touched = True
if self.parent.mat is None:
scale = matrixToNumpy(self.parent.sca.matrix)
rotate = matrixToNumpy(self.parent.rot.matrix)
self.parent.mat = np.matmul(rotate, scale)
self.parent.inv_mat = self.parent.mat.I
npTouch = np.mat([touch.x, touch.y, 0, 1.0])
convTouch = np.matmul(npTouch, self.parent.inv_mat)
touch.x = convTouch[0,0]
touch.y = convTouch[0,1]
return super(MyButton, self).on_touch_down(touch)
def on_touch_up(self, touch):
self.parent.touched = False
return super(MyButton, self).on_touch_up(touch)
class MyGridLayout(GridLayout):
touched = BooleanProperty(False)
def __init__(self, **kwargs):
super(MyGridLayout, self).__init__(**kwargs)
self.mat = None
self.inv_mat = None
class MyApp(App):
def build(self):
layout = MyGridLayout(cols=10)
with layout.canvas.before:
PushMatrix()
layout.sca = Scale(1.0, 0.5, 1.0)
layout.rot = Rotate(angle=45, axis=(0,0,1), origin=(400,300,0))
with layout.canvas.after:
PopMatrix()
for i in range (1, 101):
layout.add_widget(MyButton(text=str(i)))
return layout
MyApp().run()
我怀疑通过巧妙地应用这两个 kivy.graphics.context_instructions
,您可以模拟您想要的东西。 PushMatrix()
和 PopMatrix()
将 Scale
和 Rotate
的效果限制在 MyGridLayout
中。您应该能够使用 layout.sca
和 layout.rot
参考来调整这些值。
我在最初的回答后注意到 Buttons
看起来不错,但不再有效。我添加了一堆代码来解决这个问题。所有 numpy
矩阵的东西只是为了让鼠标按下位置与 MyGridLayout
相同的坐标。不幸的是,Kivy 事件不会自动考虑应用 Canvas
缩放和旋转,因此需要额外的代码。
这是它的样子: