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
) 来进一步减少数据,同时考虑扫描位置中的噪声。
所以你想要 (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
第一个基本圆柱体
x=r*cos(2.0*M_PI*u)
y=r*sin(2.0*M_PI*u)
z=h*v
现锥
r=r0+(r1-r0)*v
x=r*cos(2.0*M_PI*u)
y=r*sin(2.0*M_PI*u)
z=h*v
- 只是增加了半径的线性插值
现在|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
坐标是平面内的坐标(例如纹理)
我想展开一个圆锥形的柱子(截锥形)。我该怎么做。
下半径=1.8506米(图中红色) 上半径=1.6849米(图中绿色)
我的柱子坐标
中心: 底圈:xyz:0,0,0 顶圈:xyz:0,0,24.6 请看附图
圆锥顶点:0,0,275(我刚刚计算的)
角度(一半)
圆柱坐标,我可以得到
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
) 来进一步减少数据,同时考虑扫描位置中的噪声。
所以你想要
(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
第一个基本圆柱体
x=r*cos(2.0*M_PI*u) y=r*sin(2.0*M_PI*u) z=h*v
现锥
r=r0+(r1-r0)*v x=r*cos(2.0*M_PI*u) y=r*sin(2.0*M_PI*u) z=h*v
- 只是增加了半径的线性插值
现在
|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
坐标是平面内的坐标(例如纹理)