python中的透视投影和旋转

2024-09-30 18:22:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我试过搜索,但其他问题似乎都不像我的。我或多或少在python中尝试透视投影和旋转,但遇到了一个问题。我确信我的投影方程和旋转方程都是准确的;但是,当我运行它时,旋转开始正常,但开始向内旋转,直到向量与Z轴(我正在旋转的轴)处于同一位置。在

''' Imports '''
from tkinter import Tk, Canvas, TclError
from threading import Thread
from math import cos, sin, radians, ceil
from time import sleep

''' Points class '''
class pPoint:
    def __init__(self, fPoint, wWC, wHC):
        self.X = 0
        self.Y = 0
        self.Z = 0
        self.xP = 0
        self.yP = 0
        self.fPoint = fPoint
        self.wWC = wWC
        self.wHC = wHC

    def pProject(self):
        self.xP = (self.fPoint * (self.X + self.wWC)) / (self.fPoint + self.Z)
        self.yP = (self.fPoint * (self.Y + self.wHC)) / (self.fPoint + self.Z)

''' Main class '''
class Main:
    def __init__(self):
        ''' Declarations '''
        self.wWidth = 640
        self.wHeight = 480

        self.fPoint = 256

        ''' Generated declarations '''
        self.wWC = self.wWidth / 2
        self.wHC = self.wHeight / 2

        ''' Misc declarations '''
        self.gWin = Tk()

        self.vPoint = pPoint(self.fPoint, self.wWC, self.wHC)

        self.vPoint.X = 50
        self.vPoint.Y = 60
        self.vPoint.Z = -25
        self.vPoint.pProject()

        self.ang = 0

    def initWindow(self):
        self.gWin.minsize(self.wWidth, self.wHeight)
        self.gWin.maxsize(self.wWidth, self.wHeight)

        ''' Create canvas '''
        self.gCan = Canvas(self.gWin, width = self.wWidth, height = self.wHeight, background = "black")
        self.gCan.pack()

    def setAxis(self):
        ''' Create axis points '''
        self.pXax = pPoint(self.fPoint, self.wWC, self.wHC)
        self.pXbx = pPoint(self.fPoint, self.wWC, self.wHC)
        self.pYax = pPoint(self.fPoint, self.wWC, self.wHC)
        self.pYbx = pPoint(self.fPoint, self.wWC, self.wHC)
        self.pZax = pPoint(self.fPoint, self.wWC, self.wHC)
        self.pZbx = pPoint(self.fPoint, self.wWC, self.wHC)

        ''' Set axis points '''
        self.pXax.X = -(self.wWC)
        self.pXax.Y = 0
        self.pXax.Z = 1
        self.pXbx.X = self.wWC
        self.pXbx.Y = 0
        self.pXbx.Z = 1
        self.pYax.X = 0
        self.pYax.Y = -(self.wHC)
        self.pYax.Z = 1
        self.pYbx.X = 0
        self.pYbx.Y = self.wHC
        self.pYbx.Z = 1
        self.pZax.X = 0
        self.pZax.Y = 0
        self.pZax.Z = -(self.fPoint) / 2
        self.pZbx.X = 0
        self.pZbx.Y = 0
        self.pZbx.Z = (self.fPoint * self.wWC) - self.fPoint

    def projAxis(self):
        ''' Project the axis '''
        self.pXax.pProject()
        self.pXbx.pProject()
        self.pYax.pProject()
        self.pYbx.pProject()
        self.pZax.pProject()
        self.pZbx.pProject()

    def drawAxis(self):
        ''' Draw the axis '''
        self.gCan.create_line(self.pXax.xP, self.pXax.yP, self.pXbx.xP, self.pXbx.yP, fill = "white")
        self.gCan.create_line(self.pYax.xP, self.pYax.yP, self.pYbx.xP, self.pYbx.yP, fill = "white")
        self.gCan.create_line(self.pZax.xP, self.pZax.yP, self.pZbx.xP, self.pZbx.yP, fill = "white")

    def prePaint(self):
        self.vA = self.gCan.create_line(self.wWC, self.wHC, self.vPoint.xP, self.vPoint.yP, fill = "red")

    def paintCanvas(self):
        try:
            while True:
                self.ang += 1
                if self.ang >= 361:
                    self.ang = 0

                self.vPoint.X = (self.vPoint.X * cos(radians(self.ang))) - (self.vPoint.Y * sin(radians(self.ang))) 
                self.vPoint.Y = (self.vPoint.X * sin(radians(self.ang))) + (self.vPoint.Y * cos(radians(self.ang)))
                self.vPoint.pProject()

                self.gCan.coords(self.vA, self.wWC, self.wHC, self.vPoint.xP, self.vPoint.yP)

                self.gWin.update_idletasks()
                self.gWin.update()

                sleep(0.1)
        except TclError:
            pass

mMain = Main()

mMain.initWindow()
mMain.setAxis()
mMain.projAxis()
mMain.drawAxis()
mMain.prePaint()
mMain.paintCanvas()

感谢您的任何意见:)

编辑:对不起,我刚意识到我忘了提问题。我只想知道为什么它会向内吸引,而不仅仅是“正常”旋转?在


Tags: selfdefxpypangwwcgcanpyax
2条回答

与您的问题没有实际联系,但我强烈建议您使用Numpy来执行几何变换,特别是当它涉及到3D点时。在

下面,我发布了一个示例片段,希望对您有所帮助:

import numpy
from math import radians, cos, sin

## suppose you have a Nx3 cloudpoint (it might even be a single row of x,y,z coordinates)
cloudpoint = give_me_a_cloudpoint()

## this will be a rotation around Y azis:
yrot = radians(some_angle_in_degrees)

## let's create a rotation matrix using a numpy array
yrotmatrix = numpy.array([[cos(yrot), 0, -sin(yrot)],
                          [0,         1,          0],
                          [sin(yrot), 0,  cos(yrot)]], dtype=float)


## apply the rotation via dot multiplication
rotatedcloud = numpy.dot(yrotmatrix, pointcloud.T).T   # .T means transposition

这一部分是错误的:

self.ang += 1
if self.ang >= 361:
    self.ang = 0

self.vPoint.X = (self.vPoint.X * cos(radians(self.ang))
               - self.vPoint.Y * sin(radians(self.ang))) 
self.vPoint.Y = (self.vPoint.X * sin(radians(self.ang))
               + self.vPoint.Y * cos(radians(self.ang)))
self.vPoint.pProject()

有两个原因:

  1. self.ang将取开放范围[0-360]中的整数,这意味着角度360(=0)重复。在
  2. 在每次迭代中,将点从上一次迭代的角度旋转。结果,你的第一帧是1度,第二帧是1+2=3,第三帧是1+2+3。。。你应该是:
    • 每次以恒定角度(1°)旋转上次迭代的点。这与我在评论中提到的问题有关
    • 每次按当前旋转角度旋转初始点

相关问题 更多 >