|
|
@@ -81,9 +81,9 @@ info = pygame.display.Info()
|
|
|
screen_width = info.current_w
|
|
|
screen_height = info.current_h
|
|
|
|
|
|
-# 设置窗口大小(高度为屏幕高度的80%,保持原始宽高比)
|
|
|
-height = int(screen_height * 0.8)
|
|
|
-width = int(height * (800 / 600)) # 保持原始宽高比 800:600
|
|
|
+# 设置窗口大小(固定宽度为1000px,固定高度为1080px)
|
|
|
+width = 1000 # 固定宽度为1000像素
|
|
|
+height = 1800 # 固定高度为1080像素
|
|
|
display = pygame.display.set_mode((width, height), DOUBLEBUF | OPENGL)
|
|
|
pygame.display.set_caption('3D Yellow Ball')
|
|
|
|
|
|
@@ -162,7 +162,7 @@ def generate_mock_tree():
|
|
|
return
|
|
|
|
|
|
if node_id == 0: # 根节点
|
|
|
- positions[node_id] = [0.0, max_depth_found * 0.4, 0.0]
|
|
|
+ positions[node_id] = [0.0, max_depth_found * 0.8, 0.0]
|
|
|
else:
|
|
|
parent_id = nodes[node_id][2]
|
|
|
if parent_id >= 0:
|
|
|
@@ -178,13 +178,79 @@ def generate_mock_tree():
|
|
|
|
|
|
node_children = children[node_id]
|
|
|
if node_children:
|
|
|
- angle_range = math.pi * 1.5
|
|
|
- angle_start = -angle_range / 2
|
|
|
- angle_step = angle_range / len(node_children)
|
|
|
- for i, child_id in enumerate(node_children):
|
|
|
- child_angle_start = angle_start + i * angle_step
|
|
|
- child_angle_end = angle_start + (i + 1) * angle_step
|
|
|
- calculate_positions(child_id, child_angle_start, child_angle_end, depth + 1)
|
|
|
+ # 分离文件夹和文件节点
|
|
|
+ dir_children = []
|
|
|
+ file_children = []
|
|
|
+ for child_id in node_children:
|
|
|
+ if nodes[child_id][1]: # is_dir is True
|
|
|
+ dir_children.append(child_id)
|
|
|
+ else:
|
|
|
+ file_children.append(child_id)
|
|
|
+
|
|
|
+ # 如果有文件夹节点,将它们均匀分布在圆周上
|
|
|
+ if len(dir_children) > 0:
|
|
|
+ # 计算子节点的角度范围
|
|
|
+ angle_range = math.pi * 1.5 # 270度范围
|
|
|
+ angle_start = -angle_range / 2
|
|
|
+
|
|
|
+ # 如果只有文件没有文件夹,将文件均匀分布
|
|
|
+ if len(dir_children) == 0:
|
|
|
+ angle_step = angle_range / len(node_children)
|
|
|
+ for i, child_id in enumerate(node_children):
|
|
|
+ child_angle_start = angle_start + i * angle_step
|
|
|
+ child_angle_end = angle_start + (i + 1) * angle_step
|
|
|
+ calculate_positions(child_id, child_angle_start, child_angle_end, depth + 1)
|
|
|
+ else:
|
|
|
+ # 将文件夹节点均匀分布在圆周上
|
|
|
+ dir_angle_step = angle_range / len(dir_children)
|
|
|
+
|
|
|
+ # 创建一个包含所有子节点的新排序列表,其中文件夹节点均匀分布,文件节点插入到它们之间
|
|
|
+ reordered_children = []
|
|
|
+
|
|
|
+ # 如果也有文件节点,将它们均匀分配到文件夹之间
|
|
|
+ if len(file_children) > 0:
|
|
|
+ # 计算每个文件夹之间的文件数
|
|
|
+ files_per_section = len(file_children) // len(dir_children)
|
|
|
+ extra_files = len(file_children) % len(dir_children)
|
|
|
+
|
|
|
+ file_idx = 0
|
|
|
+ for i, dir_child_id in enumerate(dir_children):
|
|
|
+ # 添加文件夹节点
|
|
|
+ reordered_children.append(dir_child_id)
|
|
|
+
|
|
|
+ # 计算这个部分应该有多少文件
|
|
|
+ files_for_this_section = files_per_section
|
|
|
+ if i < extra_files:
|
|
|
+ files_for_this_section += 1
|
|
|
+
|
|
|
+ # 添加对应数量的文件到这一部分
|
|
|
+ for j in range(files_for_this_section):
|
|
|
+ if file_idx < len(file_children):
|
|
|
+ reordered_children.append(file_children[file_idx])
|
|
|
+ file_idx += 1
|
|
|
+
|
|
|
+ else:
|
|
|
+ # 没有文件,只添加文件夹
|
|
|
+ reordered_children = dir_children[:]
|
|
|
+
|
|
|
+ # 现在为重新排序的子节点分配角度
|
|
|
+ total_children = len(reordered_children)
|
|
|
+ angle_step = angle_range / total_children
|
|
|
+
|
|
|
+ for i, child_id in enumerate(reordered_children):
|
|
|
+ child_angle_start = angle_start + i * angle_step
|
|
|
+ child_angle_end = angle_start + (i + 1) * angle_step
|
|
|
+ calculate_positions(child_id, child_angle_start, child_angle_end, depth + 1)
|
|
|
+ else:
|
|
|
+ # 没有文件夹,只有文件,均匀分布
|
|
|
+ angle_range = math.pi * 1.5 # 270度范围
|
|
|
+ angle_start = -angle_range / 2
|
|
|
+ angle_step = angle_range / len(node_children)
|
|
|
+
|
|
|
+ for i, child_id in enumerate(node_children):
|
|
|
+ child_angle_start = angle_start + i * angle_step
|
|
|
+ child_angle_end = angle_start + (i + 1) * angle_step
|
|
|
+ calculate_positions(child_id, child_angle_start, child_angle_end, depth + 1)
|
|
|
|
|
|
calculate_positions(0, -math.pi, math.pi, 0)
|
|
|
return nodes, edges, positions, children
|
|
|
@@ -266,7 +332,7 @@ def build_directory_tree(root_path, max_depth=3, max_children_per_node=30):
|
|
|
# 计算当前节点位置
|
|
|
if node_id == 0: # 根节点
|
|
|
# positions[node_id] = [0.0, max_depth_found * 0.4, 0.0] # 顶部,高度减半
|
|
|
- positions[node_id] = [0.0, max_depth_found * 0.6, 0.0] # 顶部,高度减半
|
|
|
+ positions[node_id] = [0.0, max_depth_found * 0.8, 0.0] # 更靠近顶部
|
|
|
else:
|
|
|
parent_id = nodes[node_id][2]
|
|
|
if parent_id >= 0:
|
|
|
@@ -297,15 +363,79 @@ def build_directory_tree(root_path, max_depth=3, max_children_per_node=30):
|
|
|
# 为子节点递归计算位置
|
|
|
node_children = children[node_id]
|
|
|
if node_children:
|
|
|
- # 计算子节点的角度范围
|
|
|
- angle_range = math.pi * 1.5 # 270度范围
|
|
|
- angle_start = -angle_range / 2
|
|
|
- angle_step = angle_range / len(node_children)
|
|
|
+ # 分离文件夹和文件节点
|
|
|
+ dir_children = []
|
|
|
+ file_children = []
|
|
|
+ for child_id in node_children:
|
|
|
+ if nodes[child_id][1]: # is_dir is True
|
|
|
+ dir_children.append(child_id)
|
|
|
+ else:
|
|
|
+ file_children.append(child_id)
|
|
|
|
|
|
- for i, child_id in enumerate(node_children):
|
|
|
- child_angle_start = angle_start + i * angle_step
|
|
|
- child_angle_end = angle_start + (i + 1) * angle_step
|
|
|
- calculate_positions(child_id, child_angle_start, child_angle_end, depth + 1)
|
|
|
+ # 如果有文件夹节点,将它们均匀分布在圆周上
|
|
|
+ if len(dir_children) > 0:
|
|
|
+ # 计算子节点的角度范围
|
|
|
+ angle_range = math.pi * 1.5 # 270度范围
|
|
|
+ angle_start = -angle_range / 2
|
|
|
+
|
|
|
+ # 如果只有文件没有文件夹,将文件均匀分布
|
|
|
+ if len(dir_children) == 0:
|
|
|
+ angle_step = angle_range / len(node_children)
|
|
|
+ for i, child_id in enumerate(node_children):
|
|
|
+ child_angle_start = angle_start + i * angle_step
|
|
|
+ child_angle_end = angle_start + (i + 1) * angle_step
|
|
|
+ calculate_positions(child_id, child_angle_start, child_angle_end, depth + 1)
|
|
|
+ else:
|
|
|
+ # 将文件夹节点均匀分布在圆周上
|
|
|
+ dir_angle_step = angle_range / len(dir_children)
|
|
|
+
|
|
|
+ # 创建一个包含所有子节点的新排序列表,其中文件夹节点均匀分布,文件节点插入到它们之间
|
|
|
+ reordered_children = []
|
|
|
+
|
|
|
+ # 如果也有文件节点,将它们均匀分配到文件夹之间
|
|
|
+ if len(file_children) > 0:
|
|
|
+ # 计算每个文件夹之间的文件数
|
|
|
+ files_per_section = len(file_children) // len(dir_children)
|
|
|
+ extra_files = len(file_children) % len(dir_children)
|
|
|
+
|
|
|
+ file_idx = 0
|
|
|
+ for i, dir_child_id in enumerate(dir_children):
|
|
|
+ # 添加文件夹节点
|
|
|
+ reordered_children.append(dir_child_id)
|
|
|
+
|
|
|
+ # 计算这个部分应该有多少文件
|
|
|
+ files_for_this_section = files_per_section
|
|
|
+ if i < extra_files:
|
|
|
+ files_for_this_section += 1
|
|
|
+
|
|
|
+ # 添加对应数量的文件到这一部分
|
|
|
+ for j in range(files_for_this_section):
|
|
|
+ if file_idx < len(file_children):
|
|
|
+ reordered_children.append(file_children[file_idx])
|
|
|
+ file_idx += 1
|
|
|
+
|
|
|
+ else:
|
|
|
+ # 没有文件,只添加文件夹
|
|
|
+ reordered_children = dir_children[:]
|
|
|
+
|
|
|
+ # 现在为重新排序的子节点分配角度
|
|
|
+ total_children = len(reordered_children)
|
|
|
+ angle_step = angle_range / total_children
|
|
|
+
|
|
|
+ for i, child_id in enumerate(reordered_children):
|
|
|
+ child_angle_start = angle_start + i * angle_step
|
|
|
+ child_angle_end = angle_start + (i + 1) * angle_step
|
|
|
+ calculate_positions(child_id, child_angle_start, child_angle_end, depth + 1)
|
|
|
+ else:
|
|
|
+ # 没有文件夹,只有文件,均匀分布
|
|
|
+ angle_range = math.pi * 1.5 # 270度范围
|
|
|
+ angle_start = -angle_range / 2
|
|
|
+ angle_step = angle_range / len(node_children)
|
|
|
+
|
|
|
+ for i, child_id in enumerate(node_children):
|
|
|
+ child_angle_start = angle_start + i * angle_step
|
|
|
+ child_angle_end = angle_start + (i + 1) * angle_step
|
|
|
+ calculate_positions(child_id, child_angle_start, child_angle_end, depth + 1)
|
|
|
|
|
|
# 从根节点开始计算位置
|
|
|
calculate_positions(0, -math.pi, math.pi, 0)
|
|
|
@@ -368,14 +498,19 @@ rotation_angle = 0.0
|
|
|
# 相机控制变量
|
|
|
camera_z = -5 # 相机的 Z 轴位置,初始值为 -5
|
|
|
|
|
|
+# 鼠标控制旋转变量
|
|
|
+mouse_dragging = False
|
|
|
+last_mouse_x, last_mouse_y = 0, 0
|
|
|
+rotation_x, rotation_y = 0.0, 0.0 # 分别控制上下和左右旋转
|
|
|
+
|
|
|
# 主循环
|
|
|
running = True
|
|
|
while running:
|
|
|
# 获取当前时间(用于闪烁效果)
|
|
|
current_time = pygame.time.get_ticks()
|
|
|
|
|
|
- # 更新旋转角度(每30秒旋转一圈)
|
|
|
- rotation_angle = (current_time * 0.012) % 360.0
|
|
|
+ # 更新旋转角度(降低旋转速度,现在大约每60秒旋转一圈)
|
|
|
+ rotation_angle = (current_time * 0.001) % 360.0
|
|
|
|
|
|
# 检查剪贴板内容是否变化(如果剪贴板功能可用)
|
|
|
if clipboard_available:
|
|
|
@@ -439,13 +574,30 @@ while running:
|
|
|
new_index = (current_index_in_siblings + 1) % len(siblings)
|
|
|
selected_node_index = siblings[new_index]
|
|
|
elif event.type == pygame.MOUSEBUTTONDOWN:
|
|
|
- if event.button == 4: # 鼠标滚轮向上滚动,放大
|
|
|
+ if event.button == 1: # 左键按下,开始拖拽旋转
|
|
|
+ mouse_dragging = True
|
|
|
+ last_mouse_x, last_mouse_y = pygame.mouse.get_pos()
|
|
|
+ elif event.button == 4: # 鼠标滚轮向上滚动,放大
|
|
|
camera_z += 0.5 # 相机向Z轴正方向移动,放大视图
|
|
|
elif event.button == 5: # 鼠标滚轮向下滚动,缩小
|
|
|
camera_z -= 0.5 # 相机向Z轴负方向移动,缩小视图
|
|
|
|
|
|
# 限制相机的Z轴范围,防止过度放大或缩小
|
|
|
camera_z = max(-10, min(-2, camera_z))
|
|
|
+ elif event.type == pygame.MOUSEBUTTONUP:
|
|
|
+ if event.button == 1: # 左键释放,停止拖拽
|
|
|
+ mouse_dragging = False
|
|
|
+ elif event.type == pygame.MOUSEMOTION:
|
|
|
+ if mouse_dragging:
|
|
|
+ # 获取鼠标移动距离
|
|
|
+ mouse_dx, mouse_dy = pygame.mouse.get_rel()
|
|
|
+
|
|
|
+ # 更新旋转角度(水平旋转绕Y轴,垂直旋转绕X轴)
|
|
|
+ rotation_y += mouse_dx * 0.5 # 水平拖拽影响Y轴旋转
|
|
|
+ rotation_x += mouse_dy * 0.5 # 垂直拖拽影响X轴旋转
|
|
|
+
|
|
|
+ # 限制垂直旋转范围,防止翻转
|
|
|
+ rotation_x = max(-90, min(90, rotation_x))
|
|
|
|
|
|
# 清除屏幕
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
|
|
@@ -453,7 +605,11 @@ while running:
|
|
|
# 重置模型视图矩阵并设置相机位置
|
|
|
glLoadIdentity()
|
|
|
glTranslatef(0.0, 0.0, camera_z) # 相机位置,可通过鼠标滚轮调整
|
|
|
- glRotatef(rotation_angle, 0.0, 1.0, 0.0) # 绕竖直中线/Y轴旋转
|
|
|
+
|
|
|
+ # 应用鼠标控制的旋转(先应用手动旋转,再应用自动旋转)
|
|
|
+ glRotatef(rotation_x, 1.0, 0.0, 0.0) # 绕X轴旋转(上下视角)
|
|
|
+ glRotatef(rotation_y, 0.0, 1.0, 0.0) # 绕Y轴旋转(左右视角)
|
|
|
+ glRotatef(rotation_angle, 0.0, 1.0, 0.0) # 绕竖直中线/Y轴自动旋转
|
|
|
|
|
|
# 目录树可视化
|
|
|
ball_radius = 0.0667 # 节点球的半径(默认大小)
|
|
|
@@ -534,8 +690,8 @@ while running:
|
|
|
|
|
|
# 交换缓冲区
|
|
|
pygame.display.flip()
|
|
|
- # 控制帧率
|
|
|
- pygame.time.wait(10)
|
|
|
+ # 控制帧率 - 增加等待时间使动画更慢
|
|
|
+ pygame.time.wait(20)
|
|
|
|
|
|
# 退出 Pygame
|
|
|
pygame.quit()
|