You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Turtle透视投影立方体的着色与轮廓绘制问题求助

立方体透视投影的面遮挡问题(Turtle库实现)

我用Python的Turtle库编写了立方体透视投影程序,但Turtle不支持透明效果,导致着色时面会互相覆盖:

  • 最初通过识别最远点过滤填充面,该方法在正交投影中有效,但透视投影中仍存在后方面错误填充的问题
  • 后续尝试按面积排序绘制面,但同时进行X、Y轴旋转时仍有隐患
  • 绘制轮廓线采用类似逻辑,也在透视投影中出现相同问题

以下是实现代码:

#imports
import turtle
import time
from math import *

#turtle and some variables
t = turtle.Turtle()
turtle.tracer(0, 0)
turtle.bgcolor("lightblue")
t.width(20)
t.hideturtle()
angle1 = 0
angle2 = 0
scale = 200

#matrices multiplication
def mult(matrix1, matrix2):
    result = []
    if len(matrix1[0]) == len(matrix2):
        for _ in range(len(matrix1)):
            result += [[0]*len(matrix2[0])]
        for i in range(len(matrix1)):
            for j in range(len(matrix2[0])):
                for k in range(len(matrix2)):
                    result[i][j] += matrix1[i][k] * matrix2[k][j]
        return result           

#forms of points
def point_matrix(point_as_3Dpvector):
    p = point_as_3Dpvector
    return [[p[0]], [p[1]], [p[2]]]
    
def point_3Dpvector(point_as_matrix):
    p = point_as_matrix
    return (p[0][0],p[1][0], p[2][0])
    
def point_2Dpvector(point_as_3Dpvector):
    p = point_as_3Dpvector
    return (p[0], p[1])
        
#make a line
def line(ln):
    t.up()
    t.goto(point_2Dpvector(ln[0]))
    t.down()
    t.goto(point_2Dpvector(ln[1]))
    t.up()
    
#make multiple lines from a list
def line_a_list(list):
    for i in list:
        line(i)
    
#fill a square
def fill(s):
    t.color(s[4])
    t.goto(point_2Dpvector(s[0]))
    t.begin_fill()
    t.goto(point_2Dpvector(s[1]))
    t.goto(point_2Dpvector(s[2]))
    t.goto(point_2Dpvector(s[3]))
    t.end_fill()
    t.up()
    
#fill muliple squares from a list
def fill_a_list(list):
    for i in list:
        fill(i)

#knows if a point is in a list or not
def isthere(point, list):
    r = 0
    for i in list:
        if point == i:
            r += 1
    if r > 0:
        return True
    else:
        return False
        
#calculates the area of a square
def area(se):
    a1 = se[0][0]
    a2 = se[1][0]
    a3 = se[2][0]
    b1 = se[0][1]
    b2 = se[1][1]
    b3 = se[2][1]
    a = a2 * b3 - b2 * a3
    b = -a1 * b3 + b1 * a3
    c = a1 * b2 - b1 * a2
    return abs(a + b + c)

#tell the turtle what squares to fill and the ones not
#by knowing the farest point by the z value 
#and do not fill any square that have this point 
def do_squares(list_squares, list_points):
    
    #variables
    furthest_point = list_points[0]
    do_not_points = []
    do_not_squares = []
    large_square = ()
    do_squares = []
    
    #find the farest point by its z value
    for i in list_points:
        if i[2] < furthest_point[2]:
            furthest_point = i
            
    #find the other points that have the same z value
    for i in list_points:
        if i[2] == furthest_point[2]:
            do_not_points += [i]    
                    
    #find the squares that have this points
    for i in list_squares:
        for j in do_not_points:
            if isthere(j, i) == True:
                do_not_squares += [i]
                
    #remove the squares that have the points from
    #the squares list and leave the rest there
    for i in list_squares:
        if isthere(i, do_not_squares) == False:
            do_squares += [i]
    
    #find the largest square and make it the last
    large = do_squares[0]
    for i in do_squares:
        if area(i) > area(large):
            large = i
            
    large_square = large
    do_squares.remove(large)
    do_squares += [large_square]
    
    return do_squares

#as the def before but for lines
def do_lines(list_lines, list_points):
    
    furthest_point = list_points[0]
    do_not_points = []
    do_not_lines = []
    do_lines = []
    
    for i in list_points:
        if i[2] < furthest_point[2]:
            furthest_point = i
            
    for i in list_points:
        if i[2] == furthest_point[2]:
            do_not_points += [i]    
                
    for i in list_lines:
        for j in do_not_points:
            if isthere(j, i) == True:
                do_not_lines += [i]
                
    for i in list_lines:
        if isthere(i, do_not_lines) == False:
            do_lines += [i]
            
    return do_lines
            
#the cube's points and points' list
p0 = (-0.5, -0.5, -0.5)
p1 = (0.5, -0.5, -0.5)
p2 = (0.5, 0.5, -0.5)
p3 = (-0.5, 0.5, -0.5)
p4 = (-0.5, -0.5, 0.5)
p5 = (0.5, -0.5, 0.5)
p6 = (0.5, 0.5, 0.5)
p7 = (-0.5, 0.5, 0.5)

points_list = [p0, p1, p2, p3, p4, p5, p6, p7]

#the loop of operations that do the work
while True:
    
    #variables
    t.clear()
    l = []   # list of rotated squares
    angle1 += .012 / 3  #radian
    angle2 += .005 / 3
    
    #rotation matrices
    rotateZ = [
    [cos(angle1), -sin(angle1), 0],
    [sin(angle1), cos(angle1), 0],
    [0, 0, 1]
    ]                      #Z axis
    
    rotateX = [
    [1, 0, 0],
    [0, cos(angle1), -sin(angle1)],
    [0, sin(angle1), cos(angle1)]
    ]                      #X axis
    
    rotateY = [
    [cos(angle2), 0, -sin(angle2)],
    [0, 1, 0],
    [sin(angle2), 0, cos(angle2)]
    ]                      #Y axis
    
    
    for point in points_list:
        
        #rotate points
        rotated = mult(rotateY, point_matrix(point))
        rotated = mult(rotateX, rotated)
        rotated = mult(rotateZ, rotated)
        
        #project points
        
        z = 1 / (2 - rotated[2][0]) * 2   #prespective
        #z = 1   #orthographic
        
        projection =[
        [z*scale, 0, 0],
        [0, z*scale, 0],
        [0, 0, 1]
        ]
    
        projected_points = mult(projection, rotated)
        l += [point_3Dpvector(projected_points)]
        
    # list of squares
    squar = [
    (l[0], l[1], l[2], l[3], "pink"),
    (l[4], l[5], l[6], l[7], "#5676AA"),
    (l[1], l[5], l[6], l[2], "#FF7777"),
    (l[0], l[4], l[7], l[3], "cyan"),
    (l[0], l[1], l[5], l[4], "#FFAA55"),
    (l[3], l[2], l[6], l[7], "#DA90F5")
    ]
    fill_a_list(do_squares(squar,l))
    
    #list of lines
    lines = [
    (l[0], l[1]),
    (l[0], l[4]),
    (l[1], l[5]),
    (l[4], l[5]),
    (l[1], l[2]),
    (l[5], l[6]),
    (l[6], l[2]),
    (l[0], l[3]),
    (l[2], l[3]),
    (l[3], l[7]),
    (l[7], l[4]),
    (l[7], l[6])
    ]
    t.color("black")
    line_a_list(do_lines(lines, l)) #you can turn it off to see the coloring problem
    turtle.update()
        
turtle.done()

内容的提问来源于stack exchange,提问作者Ahmed Shshtawy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 18:44:58