zhong (钟鹏群) 3 tuần trước cách đây
mục cha
commit
6278092722
1 tập tin đã thay đổi với 182 bổ sung26 xóa
  1. 182 26
      src/ball-demo.py

+ 182 - 26
src/ball-demo.py

@@ -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()