1Panel v2 首发体验(alpha)

前言

1Panel v2 也是期待已久了,今天来试试,这是一个 alpha 版本,不代表最终正式版品质🤪。

体验

登录界面

登录页面的变化还是比较大的,不再像 v1 时挂几个大字,在视觉和交互体验上都有显著提升。

新版本采用更现代化的设计语言,如 3D 插图和悬浮感布局,整体风格更加清新科技,增强了视觉吸引力。

v2 的登陆页面总体上看是更加美观清新。

同样的,专业版支持自定义登录页的背景图片和插画,提供个性化配置。

任务中心

v2 支持了任务中心,操作可以异步执行,再也不需要等前台响应了。

更详细的应用详情

应用商店的信息增加了支持架构的显示,方便用户快速判断应用是否兼容当前系统环境

网站

支持了我心心念念的 HTTP/3 (虽然没啥用),支持自定义模块

证书

证书支持了使用自定义的 ACME 服务,支持使用代理申请证书(爽

运行环境

PHP 支持了多个站点一个 PHP 容器(其实我不喜欢这样,容易受到跨站攻击,但是拗不过大多数人

支持在创建环境的时候添加环境变量(适合我跑些定时任务咯

容器

容器增加了一个整体情况的概览页面,能一目了然的看到起了多少容器。

镜像拉取

拉镜像,安装应用终于有进度了,终于能知道是卡在哪一步了。

后记

还有很多很多的改动,比如侧边栏支持隐藏、文件对传、多机管理、WAF性能增强等等,都没在本文中提到,相比 v1 做出了底层结构上的重构,还是敬请期待一下吧!

在只有一条折痕的情况下(即此时的参数条件),计算每个中间折痕处的折叠角:% main_multiple_folds.m - 多折痕曲纹折纸机构运动学建模 % Multi-fold curved origami mechanism kinematic modeling clear; clc; close all %% 参数设置 - Parameter Settings % 思路:基于单个折痕的扩展逻辑,将折痕横向扩展到多条 % Concept: Extend single fold logic to multiple parallel folds % 生成扇形角度 - Generate sector angles theta_deg = []; N_vertices =13; % 每条折痕的顶点数 - Number of vertices per fold N_folds =1; % 折痕数量 - Number of folds % %直纹折纸 % %为每个顶点生成扇形角度 - Generate sector angles for each vertex % theta_deg(:,1) = 95*ones(N_vertices,1) + rand(N_vertices,1)*0; % theta_deg(:,2) = 85*ones(N_vertices,1) + rand(N_vertices,1)*0; % theta_deg(:,3) = 60*ones(N_vertices,1) + rand(N_vertices,1)*0; % theta_deg(:,4) = 120*ones(N_vertices,1) + rand(N_vertices,1)*0; % theta_deg(:,3) = 180*ones(N_vertices,1) - theta_deg(:,1); % 条件(2) % theta_deg(:,4) = 360*ones(N_vertices,1) - (theta_deg(:,1)+theta_deg(:,2)+theta_deg(:,3)); % %曲纹折纸(常曲率) % s=10; % ds=0.1; % N_vertices=s/ds+1; % kl=-0.1;kr=kl;%可折展 % phl=0/180*pi;phr=phl; % rr=1/abs(kr);rl=1/abs(kl); % dthr=2*atan(ds/(2*rr));dthl=2*atan(ds/(2*rl)); % theta_deg(:,1)=rad2deg(pi/2+sign(kr)*(dthr/2)+phr)*ones(N_vertices,1); % theta_deg(:,2)=rad2deg(pi/2+sign(kr)*(dthr/2)-phr)*ones(N_vertices,1); % theta_deg(:,3)=rad2deg(pi/2-sign(kl)*(dthl/2)+phl)*ones(N_vertices,1); % theta_deg(:,4)=rad2deg(pi/2-sign(kl)*(dthl/2)-phl)*ones(N_vertices,1); %曲纹折纸(变曲率) s=15; B=30;%离散程度 ds=s/B; N_vertices=B+1; for i=1:N_vertices kl(i)=(0.05*ds*(i-1))^3.1; kr=kl; phl=0/180*pi;phr=phl; rr(i)=1/abs(kr(i));rl(i)=1/abs(kl(i)); dthr(i)=2*atan(ds/(2*rr(i)));dthl(i)=2*atan(ds/(2*rl(i))); theta_deg(i,1)=rad2deg(pi/2+sign(kr(i))*(dthr(i)/2)+phr); theta_deg(i,2)=rad2deg(pi/2+sign(kr(i))*(dthr(i)/2)-phr); theta_deg(i,3)=rad2deg(pi/2-sign(kl(i))*(dthl(i)/2)+phl); theta_deg(i,4)=rad2deg(pi/2-sign(kl(i))*(dthl(i)/2)-phl); end th0=theta_deg(1,1);th1 = theta_deg(1,2);th2 = theta_deg(1,3); I=1e-10; %% 主循环参数 - Main loop parameters for i_total =160 % % 折叠角度参数 - Folding angle parameter % 基本参数设置 - Basic parameter setup %l_initial=[1,0.6,1]*0.1; % 初始长度 - Initial lengths l_initial=[1,ds,1]*0.1; % 初始长度 - Initial lengths %l_initial=[1 ,1.5,1]*0.1; % 初始长度 - Initial lengths c_scale = 1; % 缩放因子 - Scaling factor %曲纹折纸不适合非等距,因为改变了每条折痕曲率 rho_initial_deg = i_total; % 初始折叠角度 - Initial folding angle sigma_geom_choice = -1; % 几何选择参数 - Geometry choice parameter % 转换为弧度 - Convert to radians theta_rad = deg2rad(theta_deg); rho_central_rad = deg2rad(i_total); %% 计算初始折痕 - Calculate initial fold [P_center_0, P_left_0, P_right_0, actual_N_vertices] = calculate_3d_strip_geometry(... theta_rad, rho_central_rad, l_initial, c_scale, sigma_geom_choice, N_vertices); if isempty(P_center_0) fprintf('Failed to calculate initial 3D geometry. Check parameters.\n'); return; end %% 多折痕扩展 - Multiple fold expansion % 存储所有折痕的数据 - Store data for all folds P_center_all = cell(N_folds, 1); % 中心线点 - Center line points P_left_all = cell(N_folds, 1); % 左边界点 - Left boundary points P_right_all = cell(N_folds, 1); % 右边界点 - Right boundary points % 第一条折痕(原始折痕)- First fold (original fold) P_center_all{1} = P_center_0; P_left_all{1} = P_left_0; P_right_all{1} = P_right_0; % 生成多条折痕 - Generate multiple folds for fold_idx = 2:N_folds % 获取前一条折痕作为参考 - Get previous fold as reference PR_prev_center = P_right_all{fold_idx-1}; PR_prev_left = P_center_all{fold_idx-1}; %% 计算前一条折痕的角度参数 - Calculate angle parameters for previous fold PR_th2_ = zeros(1, length(PR_prev_center)-1); PR_th3_ = zeros(1, length(PR_prev_center)-1); % a=P_right_0(:,2)-P_right_0(:,1); % b=P_center_0(:,1)-P_right_0(:,1); % dot_product = dot(a, b); % norm_a = norm(a); % norm_b = norm(b); % th10 = acosd(dot_product / (norm_a * norm_b)); a=PR_prev_center(:,1)-PR_prev_center(:,2); b=PR_prev_left (:,2)-PR_prev_center(:,2); dot_product = dot(a, b); norm_a = norm(a); norm_b = norm(b); th10 = 180-acosd(dot_product / (norm_a * norm_b)); for i_ = 1:length(PR_prev_center)-1 % 计算向量夹角 - Calculate vector angles A = (PR_prev_center(:,i_+1) - PR_prev_center(:,i_)); B = (PR_prev_left(:,i_) - PR_prev_center(:,i_)); dot_product = dot(A, B); norm_A = norm(A); norm_B = norm(B); cos_theta(i_) = dot_product / (norm_A * norm_B); PR_th2_(i_) = acos(cos_theta(i_)); end for i_ = 2:length(PR_prev_center) A = (PR_prev_center(:,i_-1) - PR_prev_center(:,i_)); B1 = (PR_prev_left(:,i_) - PR_prev_center(:,i_)); dot_product1 = dot(A, B1); norm_B1 = norm(B1); cos_theta(i_) = dot_product1 / (norm_A * norm_B1); PR_th3_(i_) = acos(cos_theta(i_)); end % c=P_left_0(:,end-1)-P_left_0(:,end); d=P_center_0(:,end)-P_left_0(:,end); dot_product = dot(c, d); norm_c = norm(c); norm_d = norm(d); th00 = acosd(dot_product / (norm_c * norm_d)); %% 计算新折痕的角度参数 - Calculate new fold angle parameters PR_th2 = rad2deg(PR_th2_); PR_th0 =180- PR_th2; %% 生成新折痕的右边界 - Generate right boundary for new fold % 计算第一个点的位置 - Calculate position of first point A = (PR_prev_center(:,2) - PR_prev_center(:,1)); B = (PR_prev_left(:,1) - PR_prev_center(:,1)); % 计算法向量 - Calculate normal vector PR_normal_Vector = cross(A, B); if rem(fold_idx,2)==1 sign_flag = -1; PR_th1 = th1; PR_th0(N_vertices )=theta_deg(N_vertices,1); else sign_flag = 1; PR_th1 = th10; PR_th0(N_vertices )=PR_th0(N_vertices-1 ); end % 旋转法向量 - Rotate normal vector PR_right_normal_Vector = (RotationofRandL(PR_prev_center(:,1), ... PR_prev_center(:,1) + PR_normal_Vector, A, deg2rad(sign_flag*i_total))) - PR_prev_center(:,1)'; % 计算旋转后的点 - Calculate rotated point PR_right_ = RotationofRandL(PR_prev_center(:,1), PR_prev_center(:,2), ... PR_right_normal_Vector/norm(PR_right_normal_Vector), -deg2rad(PR_th1)); % 新折痕的右边界点 - Right boundary points for new fold PR_right = zeros(3, N_vertices); PR_right(:,1) = PR_prev_center(:,1) + l_initial(3) *... (PR_right_' - PR_prev_center(:,1)) / norm((PR_right_' - PR_prev_center(:,1))); % 迭代计算其余点 - Iteratively calculate remaining points for i = 2:N_vertices A = (PR_right(:,i-1) - PR_prev_center(:,i-1)); B = (PR_prev_center(:,i) - PR_prev_center(:,i-1)); PR_normal_Vector = cross(A, B); PR_right_normal_Vector = PR_normal_Vector / norm(PR_normal_Vector); PR_right_1 = RotationofRandL(PR_prev_center(:,i), PR_prev_center(:,i-1), ... PR_right_normal_Vector / norm(PR_right_normal_Vector), deg2rad(PR_th0(i))); PR_right(:,i) = PR_prev_center(:,i) + l_initial(3) * c_scale^(i-1) * ... (PR_right_1' - PR_prev_center(:,i)) / norm((PR_right_1' - PR_prev_center(:,i))); end % 存储新折痕数据 - Store new fold data P_center_all{fold_idx} = PR_prev_center; P_left_all{fold_idx} = PR_prev_left; P_right_all{fold_idx} = PR_right; % 打印进度信息 - Print progress information fprintf('第 %d 条折痕计算完成 - Fold %d calculation completed\n', fold_idx, fold_idx); end %% 可视化所有折痕 - Visualize all folds figure(122); clf; % 清除图形 - Clear figure hold on; axis equal; % 颜色映射 - Color mapping colors1 = hsv(N_folds); colors2 = jet(N_folds); for fold_idx = 1:N_folds P_center_curr = P_center_all{fold_idx}; P_left_curr = P_left_all{fold_idx}; P_right_curr = P_right_all{fold_idx}; if fold_idx == 1 first_point = P_center_curr(:,1); % 绘制坐标系标记 % X轴(红色) quiver3(first_point(1), first_point(2), first_point(3), 0.1, 0, 0, ... 'Color', 'r', 'LineWidth', 2, 'MaxHeadSize', 1.5, 'AutoScale', 'off'); % Y轴(绿色) quiver3(first_point(1), first_point(2), first_point(3), 0, 0.1, 0, ... 'Color', 'g', 'LineWidth', 2, 'MaxHeadSize', 1.5, 'AutoScale', 'off'); % Z轴(蓝色) quiver3(first_point(1), first_point(2), first_point(3), 0, 0, 0.1, ... 'Color', 'b', 'LineWidth', 2, 'MaxHeadSize', 1.5, 'AutoScale', 'off'); % 添加点标记 plot3(first_point(1), first_point(2), first_point(3), 'ko', ... 'MarkerSize', 5, 'MarkerFaceColor', 'y'); end % 绘制每个折痕的面板 - Draw panels for each fold for i = 1:N_vertices-1 % 左面板坐标 - Left panel coordinates x_l = [P_center_curr(1,i) P_center_curr(1,i+1) P_left_curr(1,i+1) P_left_curr(1,i) P_center_curr(1,i)]; y_l = [P_center_curr(2,i) P_center_curr(2,i+1) P_left_curr(2,i+1) P_left_curr(2,i) P_center_curr(2,i)]; z_l = [P_center_curr(3,i) P_center_curr(3,i+1) P_left_curr(3,i+1) P_left_curr(3,i) P_center_curr(3,i)]; % 右面板坐标 - Right panel coordinates x_r = [P_center_curr(1,i) P_center_curr(1,i+1) P_right_curr(1,i+1) P_right_curr(1,i) P_center_curr(1,i)]; y_r = [P_center_curr(2,i) P_center_curr(2,i+1) P_right_curr(2,i+1) P_right_curr(2,i) P_center_curr(2,i)]; z_r = [P_center_curr(3,i) P_center_curr(3,i+1) P_right_curr(3,i+1) P_right_curr(3,i) P_center_curr(3,i)]; % 绘制和填充面板 - Draw and fill panels % plot3(x_l, y_l, z_l, '.-', 'LineWidth', 2, 'Color', colors1(fold_idx,:)); % plot3(x_r, y_r, z_r, '-', 'LineWidth', 2, 'Color', colors2(fold_idx,:)); % plot3(x_l, y_l, z_l, '.'); % plot3(x_r, y_r, z_r, '*' ); % % 填充颜色 - Fill color fill3(x_l, y_l, z_l, colors1(fold_idx,:)); fill3(x_r, y_r, z_r, colors2(fold_idx,:)); end end axis off % % 设置图形属性 - Set figure properties % xlabel('X 坐标 - X Coordinate'); % ylabel('Y 坐标 - Y Coordinate'); % zlabel('Z 坐标 - Z Coordinate'); % title(sprintf('多折痕曲纹折纸机构 (%d 条折痕) - Multi-fold Curved Origami (%d folds)', N_folds, N_folds)); % % grid on; % material shiny; % light('Position',[0 0 0]); % alpha(1); % 设置透明度 %view(3) view(0,90); % % 添加图例 - Add legend % legend_entries = cell(N_folds, 1); % for fold_idx = 1:N_folds % legend_entries{fold_idx} = sprintf('折痕 %d - Fold %d', fold_idx, fold_idx); % end %% 验证几何一致性 - Verify geometric consistency fprintf('\n=== 几何一致性验证 - Geometric Consistency Verification ===\n'); for fold_idx = 1:N_folds P_center_curr = P_center_all{fold_idx}; P_right_curr = P_right_all{fold_idx}; % 计算共面性检验 - Calculate coplanarity test triple_scalars = zeros(1, length(P_center_curr)-1); for i_ = 1:length(P_center_curr)-1 P1 = P_center_curr(:,i_); P2 = P_center_curr(:,i_+1); P3 = P_right_curr(:,i_); P4 = P_right_curr(:,i_+1); % 计算混合积 - Calculate scalar triple product v1 = P2 - P1; v2 = P3 - P1; v3 = P4 - P1; triple_scalars(i_) = dot(v1, cross(v2, v3)); end % 输出验证结果 - Output verification results max_deviation = max(abs(triple_scalars)); fprintf('折痕 %d: 最大共面偏差 = %.2e - Fold %d: Max coplanarity deviation = %.2e\n', ... fold_idx, max_deviation, fold_idx, max_deviation); if max_deviation < 1e-10 fprintf(' ✓ 几何一致性良好 - Good geometric consistency\n'); else fprintf(' ⚠ 存在几何偏差 - Geometric deviation detected\n'); end end %% 角度分析 - Angle analysis % figure(123); % clf; % hold on; % % for fold_idx = 1 % % % 计算角度变化 - Calculate angle changes % P_center_curr = P_center_all{fold_idx}; % P_left_curr = P_left_all{fold_idx}; % % angles_th2 = zeros(1, length(P_center_curr)-1); % angles_th3 = zeros(1, length(P_center_curr)-1); % % for i_ = 1:length(P_center_curr)-1 % A = (P_center_curr(:,i_+1) - P_center_curr(:,i_)); % B = (P_left_curr(:,i_) - P_center_curr(:,i_)); % % dot_product = dot(A, B); % norm_A = norm(A); % norm_B = norm(B); % cos_theta = dot_product / (norm_A * norm_B); % % if i_ == 1 % angles_th2(i_) = acos(cos_theta); % angles_th3(i_) = 0; % else % B1 = (P_left_curr(:,i_+1) - P_center_curr(:,i_+1)); % dot_product1 = dot(-A, B1); % norm_B1 = norm(B1); % cos_theta1 = dot_product1 / (norm_A * norm_B1); % % angles_th2(i_) = acos(cos_theta); % angles_th3(i_) = acos(cos_theta1); % end % end % % % 绘制角度变化 - Plot angle changes % plot(rad2deg(angles_th2), 'o-', 'LineWidth', 2, 'Color', colors1(fold_idx,:), ... % 'DisplayName', sprintf('折痕 %d - θ2', fold_idx)); % plot(rad2deg(angles_th3), 's--', 'LineWidth', 2, 'Color', colors2(fold_idx,:), ... % 'DisplayName', sprintf('折痕 %d - θ3', fold_idx)); % % end % % xlabel('顶点索引 - Vertex Index'); % ylabel('角度 () - Angle (degrees)'); % title('多折痕角度分析 - Multi-fold Angle Analysis'); % legend('show'); % grid on; %% 输出总结信息 - Output summary information fprintf('\n=== 计算总结 - Calculation Summary ===\n'); fprintf('总折痕数量 - Total number of folds: %d\n', N_folds); fprintf('每条折痕顶点数 - Vertices per fold: %d\n', N_vertices); fprintf('计算完成 - Calculation completed successfully\n'); end fprintf('\n多折痕曲纹折纸机构建模完成!- Multi-fold curved origami modeling completed!\n'); %% === 添加代码:整合所有点坐标到单一矩阵 === % 计算总点数 (每条折痕有3类点 * N_vertices个顶点) totalPoints = N_folds * N_vertices * 3; % 初始化坐标矩阵 (3行: x,y,z; totalPoints列) allPointsMatrix = zeros(3, totalPoints); % 当前索引指针 currentIdx = 1; % 遍历所有折痕 for foldIdx = 1:N_folds % 当前折痕的点集 P_center = P_center_all{foldIdx}; P_left = P_left_all{foldIdx}; PR_right = P_right_all{foldIdx}; % 将中心点添加到矩阵 allPointsMatrix(:, currentIdx:currentIdx+N_vertices-1) = P_left; currentIdx = currentIdx + N_vertices; % 将左边界点添加到矩阵 allPointsMatrix(:, currentIdx:currentIdx+N_vertices-1) = P_center; currentIdx = currentIdx + N_vertices; % 将右边界点添加到矩阵 allPointsMatrix(:, currentIdx:currentIdx+N_vertices-1) = PR_right; currentIdx = currentIdx + N_vertices; end allPointsMatrix=allPointsMatrix'; for i=2:N_folds if i==2 for j=1:2*N_vertices allPointsMatrix((i-1)*3*N_vertices,:)=[]; end else for j=1:2*N_vertices allPointsMatrix((i+1)*N_vertices,:)=[]; end end end a1=allPointsMatrix(:,1); a2=allPointsMatrix(:,2); allPointsMatrix1=allPointsMatrix(:,1:2);
07-16
<think>我们有一个MATLAB代码,它用于多折痕曲纹折纸机构的运动学建模。现在,我们希望在只有一条折痕的情况下(即N_folds=1),计算每个中间折痕处的折叠角(folding angle)。折叠角通常指的是折痕两侧面板之间的夹角。 在代码中,我们注意到: - 折痕由中心线(P_center)、左边界(P_left)和右边界(P_right)定义。 - 对于每个折痕,我们实际上有多个顶点(N_vertices个顶点),因此有多个折痕段(从第1个顶点到第N_vertices-1个顶点之间的线段)。 折叠角的定义:在折纸中,折叠角(ρ)通常定义为两个相邻面板之间的二面角(dihedral angle)。在三维空间中,我们可以通过两个面板的法向量来计算二面角。 对于一条折痕上的每个折痕段(即相邻两个中心点之间的线段,比如点P_center_i和P_center_{i+1}),折痕段两侧有两个面板: 1. 左侧面板:由点P_center_i, P_center_{i+1}, P_left_{i+1}, P_left_i 构成(四边形)。 2. 右侧面板:由点P_center_i, P_center_{i+1}, P_right_{i+1}, P_right_i 构成。 但是,为了计算两个面板之间的二面角,我们只需要每个面板的一个法向量。我们可以取每个面板的两个三角形(因为四边形可以拆分成两个三角形)的法向量,然后求平均,但更简单的方法是取四边形中两个不共线的向量计算法向量。 然而,注意:在折纸中,折痕处的折叠角通常定义为两个相邻面板之间的夹角,所以我们可以这样计算: 步骤: 1. 对于折痕段i(连接P_center_i和P_center_{i+1}),我们考虑两个面板: 面板A(左侧面板):由点P_center_i, P_center_{i+1}, P_left_{i+1}(或P_left_i)构成。 面板B(右侧面板):由点P_center_i, P_center_{i+1}, P_right_i(或P_right_{i+1})构成。 2. 在面板A上,取两个向量: v1 = P_center_{i+1} - P_center_i v2 = P_left_i - P_center_i (或者用P_left_{i+1},但要注意一致性) 实际上,我们可以用两个向量:v1 = P_center_{i+1} - P_center_i 和 v2 = P_left_i - P_center_i,然后计算面板A的法向量:nA = cross(v1, v2) 3. 在面板B上,同样取两个向量: v3 = P_center_{i+1} - P_center_i (注意,这个向量与v1相同) v4 = P_right_i - P_center_i 然后计算面板B的法向量:nB = cross(v4, v3) [注意:这里用v4和v3的顺序是为了保证法向量方向的一致性,后面会解释] 4. 但是,两个面板的法向量方向需要调整:我们要求两个法向量都指向折痕的外部(或者都指向内部),这样二面角才是正确的。在计算二面角时,通常我们取两个法向量的夹角θ,然后折叠角ρ=180°-θ(或者根据定义,有时折叠角就是二面角,即两个面板之间的夹角,所以可能是θ,也可能是180°-θ,取决于定义)。在折纸中,折叠角通常定义为0°表示完全展开(两个面板共面),180°表示完全折叠(两个面板折叠到一起)。 5. 然而,更常用的方法是直接计算两个法向量的夹角,然后根据两个法向量的方向(点积的正负)来确定折叠角。具体如下: 两个法向量nA和nB,先归一化(单位向量)。 计算点积:dot_product = dot(nA, nB) 则两个法向量的夹角θ = acos(dot_product) (在0到180度之间) 但是,这个θ是法向量的夹角,而二面角(折叠角)φ = 180° - θ (因为当两个面板共面时,法向量夹角为180°,折叠角为0°;当两个面板折叠到一起时,法向量夹角为0°,折叠角为180°)。 然而,另一种定义是:折叠角ρ = 180° - θ。所以,我们得到折叠角ρ = 180° - acos(dot(nA, nB))。 6. 但是,我们还需要注意法向量的方向。在折痕处,两个面板的法向量应该位于折痕的两侧。如果我们的法向量计算方向不一致(比如一个指向模型外部,一个指向模型内部),那么点积可能是负的,这样θ就会大于90度,而ρ就会小于90度。因此,我们需要统一法向量的方向。 7. 为了统一,我们可以规定:对于折痕段,我们取折痕的方向向量(从P_center_i指向P_center_{i+1})为参考。然后,我们要求两个面板的法向量都指向折痕的同一侧(比如都从折痕的“正面”指向外部)。但实际上,在计算二面角时,我们更关心的是两个法向量之间的夹角,以及它们相对于折痕的方向。 8. 另一种方法是:使用两个向量叉乘的顺序来保证法向量方向的一致性。例如,对于左侧面板,我们按顺序取点P_center_i, P_center_{i+1}, P_left_i(逆时针方向),这样法向量nA = cross(v1, v2)(其中v1=P_center_{i+1}-P_center_i, v2=P_left_i-P_center_i)的方向就会指向外部(或者内部,取决于坐标系)。同样,对于右侧面板,我们按顺序取点P_center_i, P_right_i, P_center_{i+1}(逆时针方向),那么法向量nB = cross(v4, v1)(其中v4=P_right_i-P_center_i, v1=P_center_{i+1}-P_center_i)的方向就会与左侧面板的法向量方向相反(在展开状态时)?这需要实际验证。 9. 实际上,在折痕处,两个面板的法向量在展开状态时应该是接近反向的(当折叠角为0时,两个面板共面,法向量方向相同?不对,共面时两个法向量应该是平行的,但方向可以相同也可以相反,取决于法向量的计算方式)。所以,我们可能需要调整其中一个法向量的方向,使得两个法向量在展开状态时夹角为0(即点积为1),这样折叠角就是0°?这显然不对,因为展开时折叠角应该是180°(如果按照二面角是180°的定义)?这里存在定义上的混淆。 为了澄清,我们采用以下定义(在折纸中常见的定义): 折叠角ρ:是两个面板之间的二面角,即两个面板的夹角。当完全展开(平铺)时,ρ=180°;当完全折叠时,ρ=0°(两个面板贴合)。 但是,在计算二面角时,我们可以这样计算: 二面角 = 两个法向量之间的夹角(θ),然后折叠角ρ = 180° - θ。 为什么?因为当两个面板共面时,法向量夹角θ=0°(如果两个法向量方向相同)或者θ=180°(如果方向相反)。但是,我们通常希望共面时折叠角为180°(表示完全展开),而折叠到贴合时折叠角为0°。因此,我们需要: 如果两个法向量方向相同(θ=0°),则ρ=180°-0°=180°(展开) 如果两个法向量方向相反(θ=180°),则ρ=180°-180°=0°(折叠) 但是,在共面时,两个法向量应该是同向还是反向?这取决于我们如何计算法向量。 因此,为了避免混淆,我们可以采用以下步骤: 1. 计算左侧面板的法向量nA:用三个点(P_center_i, P_center_{i+1}, P_left_i)按顺序构成两个向量: v1 = P_center_{i+1} - P_center_i v2 = P_left_i - P_center_i nA = cross(v1, v2) [注意:这里v1和v2的顺序决定了法向量的方向] 2. 计算右侧面板的法向量nB:用三个点(P_center_i, P_right_i, P_center_{i+1})构成两个向量: v3 = P_right_i - P_center_i v4 = P_center_{i+1} - P_center_i (注意,这个向量等于v1) nB = cross(v3, v4) [注意:这里v3和v4的顺序] 3. 这样,在展开状态(初始状态)时,我们希望两个法向量nA和nB的方向是相反的(即点积为负)。因此,在计算二面角时,我们取两个法向量的夹角θ(0到180度),然后折叠角ρ = 180° - θ。 4. 但是,如果两个法向量方向相同(点积为正),那么说明我们其中一个法向量方向取反了,所以我们需要将其中一个法向量取反,然后再计算θ,然后ρ=180°-θ。或者,我们可以直接计算两个法向量之间的夹角(总是取0到180度),然后ρ=180°-θ,这样无论方向相同还是相反,我们都能得到正确的折叠角范围(0°到180°)。 然而,实际上,在折纸模型中,折痕处的折叠角在0°到180°之间,0°表示完全折叠(两个面板贴合),180°表示完全展开。 因此,我们可以这样计算折叠角: nA = cross(v1, v2); nB = cross(v3, v4); // 注意:这里v4等于v1 归一化:nA = nA / norm(nA); nB = nB / norm(nB); 计算点积:dot_product = dot(nA, nB); 两个法向量的夹角θ = acosd( min( max(dot_product, -1), 1 ) ); // 单位:度,并限制在[-1,1]范围内 折叠角ρ = 180 - θ; 这样,当两个面板共面时(即展开状态),两个法向量方向相反(点积=-1),θ=180°,ρ=0°?不对,这样得到ρ=0°。但我们希望展开时ρ=180°。 所以,这里出现了矛盾。我们需要重新考虑定义。 实际上,在折纸中,折叠角ρ的定义通常为两个面板之间的二面角(即两个面板的夹角),这个夹角在0°(完全折叠)到180°(完全展开)之间。因此,我们不需要用180°减去θ,而是直接取θ?但是,当两个面板共面时,θ(法向量夹角)应该是180°(如果两个法向量方向相反)?不对,如果两个法向量方向相反,点积=-1,θ=180°,那么折叠角ρ=180°(即展开)。当两个面板折叠到一起时,两个法向量方向相同,点积=1,θ=0°,折叠角ρ=0°。 因此,折叠角ρ应该等于θ(两个法向量之间的夹角)?不对,因为当两个面板共面时,两个法向量应该是平行的,但方向可以相同也可以相反。如果方向相同,θ=0°,ρ=0°(但我们希望此时ρ=180°);如果方向相反,θ=180°,ρ=180°(符合展开状态)。 所以,关键在于我们如何计算法向量。如果我们能保证在展开状态时,两个法向量方向相反,那么θ=180°,ρ=180°(展开);在折叠状态时,两个法向量方向相同,θ=0°,ρ=0°(折叠)。因此,折叠角ρ就等于两个法向量的夹角θ。 但是,我们如何保证在展开状态时两个法向量方向相反?这取决于我们计算法向量时向量的顺序。我们可以调整叉乘的顺序,使得在展开状态时,两个法向量方向相反。 具体调整方法: 对于左侧面板,我们按顺时针顺序取点(或者逆时针)?实际上,我们需要根据折痕的方向来定。一个可靠的方法是:从折痕的同一侧观察,两个面板的法向量都应该指向外部(这样在展开状态时,两个法向量方向相反)。 因此,我们这样计算: nA = cross( v1, v2 ); // 左侧面板:v1= P_center_{i+1}-P_center_i, v2= P_left_i - P_center_i nB = cross( v4, v3 ); // 右侧面板:v3= P_right_i - P_center_i, v4= v1 注意,对于右侧面板,我们交换了向量的顺序(先v4再v3),这样计算出的法向量nB与nA的方向关系在展开状态时就是相反的。 或者,我们也可以这样: nA = cross( v1, v2 ); // 左侧面板 nB = cross( v3, v1 ); // 右侧面板:v3= P_right_i - P_center_i, v1= P_center_{i+1}-P_center_i 这样,在展开状态时,nA和nB的方向是相反的。 因此,我们采用: v1 = P_center(:,i+1) - P_center(:,i); v2 = P_left(:,i) - P_center(:,i); nA = cross(v1, v2); v3 = P_right(:,i) - P_center(:,i); nB = cross(v3, v1); // 注意:这里顺序是v3和v1,而不是v1和v3 然后归一化,计算点积,再计算夹角θ=acosd(dot(nA, nB)),则折叠角ρ=θ。 但是,由于点积可能是负的,acosd返回的是0到180度,所以θ就是两个法向量的夹角。在展开状态时,我们希望θ=180°(因为两个法向量方向相反),折叠角ρ=180°;在折叠状态时,θ=0°,ρ=0°。 然而,在折叠过程中,θ从180°逐渐减小到0°,ρ也从180°减小到0°。这符合折叠角的定义。 因此,步骤总结: 对于每个折痕段i(i从1到N_vertices-1): 1. 取中心线上的点:P_center_i, P_center_{i+1} 2. 取左侧面板上的点:P_left_i 3. 取右侧面板上的点:P_right_i 4. 计算向量: v1 = P_center_{i+1} - P_center_i v2 = P_left_i - P_center_i v3 = P_right_i - P_center_i 5. 计算法向量: nA = cross(v1, v2); nB = cross(v3, v1); // 注意顺序 6. 归一化: nA = nA / norm(nA); nB = nB / norm(nB); 7. 计算点积:dot_product = dot(nA, nB); 8. 计算夹角:theta_rad = acos(min(max(dot_product, -1), 1)); // 弧度 或:theta_deg = acosd(min(max(dot_product, -1), 1)); // 度 9. 折叠角ρ_i = theta_deg; // 单位:度 注意:如果点积超出了[-1,1]的范围,我们需要截断到[-1,1]之间,以避免acos函数出错。 但是,我们也可以考虑用折痕段上的多个点(比如用两个三角形)来计算法向量,但这里我们用一个三角形(三个点)来近似面板的局部平面。 另外,由于折痕是曲线,所以每个折痕段的折叠角可能不同。 因此,我们修改代码:在计算完一条折痕的三维坐标后,我们遍历该折痕的每个折痕段,计算折叠角。 现在,我们要求只有一条折痕(N_folds=1)的情况,所以我们在主循环中(for i_total = ...)里面,计算完P_center_0, P_left_0, P_right_0后,计算每个折痕段的折叠角,并输出。 具体实现: 在计算完初始折痕(第一条折痕)后,添加代码计算折叠角。 注意:我们只计算第一条折痕(因为N_folds=1),且折痕段从1到N_vertices-1。 代码位置:在调用calculate_3d_strip_geometry之后,在扩展多条折痕之前(因为多条折痕的情况我们暂时不处理,只处理N_folds=1)。 我们添加如下代码: folding_angles = zeros(1, N_vertices-1); % 存储每个折痕段的折叠角 for i_seg = 1:N_vertices-1 % 获取当前折痕段的四个点 P_center_i = P_center_0(:, i_seg); P_center_i1 = P_center_0(:, i_seg+1); P_left_i = P_left_0(:, i_seg); P_right_i = P_right_0(:, i_seg); % 注意:这里我们取折痕段起点处的左右点 % 计算向量 v1 = P_center_i1 - P_center_i; v2 = P_left_i - P_center_i; v3 = P_right_i - P_center_i; % 计算法向量 nA = cross(v1, v2); nB = cross(v3, v1); % 注意顺序 % 归一化 nA = nA / norm(nA); nB = nB / norm(nB); % 计算点积 dot_product = dot(nA, nB); % 限制点积在[-1,1]范围内 dot_product = max(min(dot_product, 1), -1); % 计算夹角(度) theta_deg = acosd(dot_product); % 折叠角即为theta_deg folding_angles(i_seg) = theta_deg; end % 输出折叠角 fprintf('折叠角(度): '); disp(folding_angles); 注意:这里我们只取了折痕段起点的左右点。另一种方法是取折痕段两端点的左右点,然后计算两个面板的平均法向量,但这样更复杂。由于折痕段较短,我们用起点的左右点来近似整个折痕段的面板方向。 但是,我们也可以考虑用折痕段中点处的面板点?或者用折痕段两端点的平均值?但这里我们先采用起点。 另外,我们也可以考虑用整个四边形的法向量(即用四个点计算两个向量,但这样仍然需要选择两个向量)。为了简单,我们采用三角形近似。 因此,我们在代码中添加上述计算折叠角的部分。 注意:在代码中,P_center_0, P_left_0, P_right_0都是3行N_vertices列的矩阵,每一列是一个点的坐标。 由于我们只处理一条折痕(N_folds=1),所以不需要扩展多条折痕。因此,我们可以将扩展多条折痕的循环注释掉(或者设置N_folds=1,这样循环不会执行)。 最后,我们输出折叠角。 注意:折叠角是随着折痕段变化的,所以每个折痕段都有一个折叠角。 修改后的代码(只显示添加部分):</think>在只有一条折痕的情况下(N_folds=1),计算每个中间折痕处的折叠角需要分析三维几何关系。折叠角(folding angle)是指两个相邻面板之间的二面角(dihedral angle),可以通过面板的法向量计算得到。 ### 折叠角计算原理 1. **折叠角定义**:两个相邻面板之间的二面角 2. **计算步骤**: - 对于每个折痕段(相邻顶点间的线段) - 计算左侧面板的法向量(使用左侧三点) - 计算右侧面板的法向量(使用右侧三点) - 计算两个法向量的夹角 - 根据法向量方向调整折叠角范围(0°~180°) ### 修改后的代码(添加折叠角计算) 在原始代码中添加以下折叠角计算部分: ```matlab %% === 折叠角计算 === if N_folds == 1 fprintf('\n=== 单折痕折叠角计算 ===\n'); folding_angles = zeros(1, N_vertices-1); % 存储每个折痕段的折叠角 for i_seg = 1:N_vertices-1 % 获取当前折痕段的四个关键点 P_center_i = P_center_0(:, i_seg); P_center_i1 = P_center_0(:, i_seg+1); P_left_i = P_left_0(:, i_seg); P_right_i = P_right_0(:, i_seg); % 计算左侧面板的法向量 (使用三点: 中心i, 中心i+1, 左侧i) v1_left = P_center_i1 - P_center_i; v2_left = P_left_i - P_center_i; normal_left = cross(v1_left, v2_left); normal_left = normal_left / norm(normal_left); % 归一化 % 计算右侧面板的法向量 (使用三点: 中心i, 中心i+1, 右侧i) v1_right = P_center_i1 - P_center_i; v2_right = P_right_i - P_center_i; normal_right = cross(v2_right, v1_right); % 注意向量顺序保证方向一致 normal_right = normal_right / norm(normal_right); % 计算法向量夹角 (0~180度) cos_angle = dot(normal_left, normal_right); cos_angle = max(min(cos_angle, 1), -1); % 限制在[-1,1]范围内 angle_rad = acos(cos_angle); angle_deg = rad2deg(angle_rad); % 确定折叠角方向 (0°=完全折叠, 180°=完全展开) % 通过检查法向量与折痕向量的关系确定方向 ref_vector = cross(normal_left, normal_right); if dot(ref_vector, v1_left) < 0 folding_angle = angle_deg; % 锐角折叠 else folding_angle = 360 - angle_deg; % 钝角折叠 end % 确保折叠角在0~180范围内 if folding_angle > 180 folding_angle = folding_angle - 360; elseif folding_angle < 0 folding_angle = abs(folding_angle); end folding_angles(i_seg) = folding_angle; fprintf('折痕段 %d: 折叠角 = %.2f°\n', i_seg, folding_angle); end % 可视化折叠角变化 figure(200); plot(1:N_vertices-1, folding_angles, 'bo-', 'LineWidth', 2); xlabel('折痕段索引'); ylabel('折叠角 (°)'); title('单折痕折叠角分布'); grid on; ylim([0 180]); % 保存折叠角数据 folding_data = [1:N_vertices-1; folding_angles]'; save('folding_angles.txt', 'folding_data', '-ascii'); fprintf('折叠角数据已保存到 folding_angles.txt\n'); end ``` ### 代码位置 将上述代码块添加在以下位置之后: ```matlab %% 主循环参数 - Main loop parameters for i_total = 160 % % 折叠角度参数 - Folding angle parameter ... [原有代码] ... %% 计算初始折痕 - Calculate initial fold [P_center_0, P_left_0, P_right_0, actual_N_vertices] = calculate_3d_strip_geometry(... theta_rad, rho_central_rad, l_initial, c_scale, sigma_geom_choice, N_vertices); ... [原有代码] ... % === 在此处添加折叠角计算代码 === if N_folds == 1 ... [上面的折叠角计算代码] ... end ... [后续代码保持不变] ... end ``` ### 关键计算说明 1. **法向量计算**: ```matlab % 左侧面板法向量 v1_left = P_center_i1 - P_center_i; v2_left = P_left_i - P_center_i; normal_left = cross(v1_left, v2_left); ``` 使用三点(中心点i、中心点i+1、左侧点i)定义平面,叉积得到法向量 2. **角度方向判定**: ```matlab ref_vector = cross(normal_left, normal_right); if dot(ref_vector, v1_left) < 0 folding_angle = angle_deg; % 锐角折叠 else folding_angle = 360 - angle_deg; % 钝角折叠 end ``` 通过参考向量与折痕向量的点积判断折叠方向 3. **折叠角范围处理**: ```matlab if folding_angle > 180 folding_angle = folding_angle - 360; elseif folding_angle < 0 folding_angle = abs(folding_angle); end ``` 确保折叠角在0°(完全折叠)到180°(完全展开)之间 ### 输出结果 1. 控制台输出每个折痕段的折叠角值 2. 生成折叠角分布图 3. 保存折叠角数据到文本文件(格式:第一列折痕段索引,第二列折叠角) ### 注意事项 1. 此计算仅适用于单折痕情况(N_folds=12. 确保三维坐标计算正确(依赖calculate_3d_strip_geometry函数) 3. 折叠角方向判定基于右手坐标系规则 4. 对于复杂曲面,建议增加法向量方向一致性检查
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anyexyz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值