Unwrapping/unroll 截锥

Unwrapping/unroll a truncated cone

我想展开一个圆锥形的柱子(截锥形)。我该怎么做。

下半径=1.8506米(图中红色) 上半径=1.6849米(图中绿色)

我的柱子坐标

中心: 底圈:xyz:0,0,0 顶圈:xyz:0,0,24.6 请看附图

圆锥顶点:0,0,275(我刚刚计算的) 角度(一半):0.38 投影半径=1.84(我应该给什么)

圆柱坐标,我可以得到

r=sqrt(x^2+y^2)
theta=atan(y,x)
z=z

如何将它们投影到平面上。

fileexchange 上可能有很多代码或网络上高度优化的解决方案(例如纹理投影),无论如何这是我的解决方案:

我假设支柱数据是大小为 [tcount x zcount] 的矩阵,其中 tcount 是沿 angular 轴的扫描位置数,zcount 是扫描位置数沿高度轴。

代码如下:

%
% PURPOSE:
%
%   Project cone data to plane data
%
% INPUT:
%
%   thetaValues: Angular-scan values (in radians !!)
%   zValues: z-scan values (whathever unit)
%   coneData: Scanned data of size thetaCount-by-zCount
%   zminRadius: Radius at zmin position (same unit as zValues)
%   zmaxRadius: Radius at zmax position (same unit as zValues)
%   xvalues: Values to have along x-axis (by default biggestRadius * thetaValues centered around theta = 0)
%
% OUTPUT:
%
%   xvalues: Positions along x-axis (same unit as zValues)
%   zvalues: Positions along z-axis (same values/unit as input)
%   planeData: Plane data of size xcount-by-zcount 
%
function [xvalues, zValues, planeData] = Cone2Plane(thetaValues, zValues, coneData, zminRadius, zmaxRadius, xvalues)
%[
    % Default arguments
    if (nargin < 6), xvalues = []; end

    % Init
    zmin = min(zValues);
    zmax = max(zValues);    
    smallestRadius = min(zminRadius, zmaxRadius);
    biggestRadius = max(zminRadius, zmaxRadius);

    % Ensure thetaValues range in -pi;+pi;
    thetaValues = mod(thetaValues + pi, 2*pi) - pi;
    [thetaValues, si] = sort(thetaValues);
    coneData = coneData(si, :);

    % Intercept theorem (Thales)
    %
    %      A-------+-------\
    %     /|       |        \
    %    / |       |         \
    %   D--E-------+----------\
    %  /   |       |           \
    % B----C-------+------------\
    BC = biggestRadius - smallestRadius; 
    AE = zmax - zValues(:);
    AC = (zmax - zmin);
    DE = (BC * AE) / AC;
    radiuses = smallestRadius + DE;

    % Projection
    if (isempty(xvalues)), xvalues = biggestRadius * thetaValues; end
    xcount = length(xvalues);
    zcount = length(zValues);
    planeData = zeros(xcount, zcount);        
    for zi = 1:zcount,
        localX = radiuses(zi) * thetaValues;
        localValues = coneData(:, zi);
        planeData(:, zi) = interp1(localX, localValues, xvalues, 'linear', 0);
    end
%]
end
  • 我不会详细介绍 Thales theorem 来计算每个 z 位置的 radiuses

  • 我将 angular 位置重新排序为 [-180°;+180°] 以便具有对称的 x 位置(即 xLocal = radiusLocal * angularPos)。

  • 棘手的部分是将 xLocal 重新插入到某些 xGlobal 位置(我假设是 xLocal = biggestRadius * angularPos,但您当然可以提供您的自己的值作为 Cone2Plane 例程的参数)。

这里是一些测试用例:

function [] = TestCone2Plane()
%[
    % Scanning info
    zminRadius = 1.8506;
    zmaxRadius = 1.6849;
    zValues = linspace(0.0, 24.6, 100); 
    thetaValues = linspace(0, 359, 360) * pi / 180;

    % Build dummy cone data
    tcount = length(thetaValues);
    zcount = length(zValues);    
    coneData = rand(tcount, zcount);

    % Convert to plane data
    xvalues = []; % Means automatic x-positions
    [xvalues, zValues, planeData] = Cone2Plane(thetaValues, zValues, coneData, zminRadius, zmaxRadius, xvalues);

    % Display
    [X, Z] = ndgrid(xvalues, zValues);
    pcolor(X, Z, planeData);  
    shading flat;
%]
end

编辑

不清楚你有什么确切的输入数据,但如果 pillar 是一组 (x,y,z, intensity) 点,你可以将数据集减少到 coneData 如下:

thetas = atan2(y(:), x(:));
thetaValues = unique(thetas); tcount = length(thetaValues);
zValues = unique(z); zcount = length(zValues);    
coneData = zeros(tcount, zcount);
for ti = 1:tcount,
  logict = (thetas == thetaValues(ti));
  for zi = 1:zcount,
     logicz = (z == zValues(zi));
     coneData(ti, zi) = mean(intensity(logict & logicz));
  end
end

注意 在实践中,您可能希望使用一些 unique with tolerance (+ logic = abs(val-pos) < tol) 来进一步减少数据,同时考虑扫描位置中的噪声。

  1. 所以你想要 (x,y,z)=f(u,v) ?

    • u=<0.0,1.0> ...角度坐标
    • v=<0.0,1.0> ... 高度坐标设 v=0.0 为底部
    • 你有 24 个周期的 |sin| 波沿周界
    • 振幅:底部 a0 顶部 a1
    • 柱子底部的半径为 r0,顶部的半径为 r1
    • 柱子有高度h
  2. 第一个基本圆柱体

    x=r*cos(2.0*M_PI*u)
    y=r*sin(2.0*M_PI*u)
    z=h*v
    
  3. 现锥

    r=r0+(r1-r0)*v
    x=r*cos(2.0*M_PI*u)
    y=r*sin(2.0*M_PI*u)
    z=h*v
    
    • 只是增加了半径的线性插值
  4. 现在|sin|

    r=r0+(r1-r0)*v
    a=a0+(a1-a0)*v
    r-=a*fabs(sin(2.0*M_PI*12.0*u))
    x=r*cos(2.0*M_PI*u)
    y=r*sin(2.0*M_PI*u)
    z=h*v
    
    • 只是添加了|sin|波振幅的线性插值
    • 然后 |sin| 波应用于半径

现在 u,v 坐标是平面内的坐标(例如纹理)