2016-04-21 74 views
2

給定XYZ空間中的兩個點(P1和P2),創建一個給定半徑的管。爲了做到這一點,我需要計算兩個點周圍的圓的點數,使得圓與P1→P2垂直(並且彼此平行)。一個圓的dx/dy/dz可用於製作其他圓。代碼的形式如下所示:如何計算垂直於矢量的圓?

function circle(radius, segments, P1, P2) { 
    // 3D circle around the origin, perpendicular to P1P2 
    var circle = []; 
    var Q = [P2[0] - P1[0], P2[1] - P1[1], P2[2] - P1[2]]; 
    for (var i = 0; i < segments; i++) { 
    var theta = 2*Math.PI*segment/i; 
    var dx = mysteryFunctionX(Q, theta, radius); 
    var dy = mysteryFunctionY(Q, theta, radius); 
    var dz = mysteryFunctionZ(Q, theta, radius); 
    circle.push([dx, dy, dz]); 
    } 
    return circle; 
    } 

每個神祕功能需要什麼計算?

回答

0

我發現這是link您可能會發現有用的,因爲這video

,如果你正在處理的角度那麼它看起來像你要個參數的路線。

1

如在埃德的帖子鏈接中指出,如果你有向量u和v是垂直的軸線Q,並且彼此,每個長度爲1,則點

P + cos(theta)*u + sin(theta)*v 

是,因爲θ在0和2pi之間,在與Q垂直的平面上具有中心P的圓上的點。

對於給出Q,找出u和v應該是什麼可能有點棘手。一種方法是使用Householder反射器。找到一個將(1,0,0)映射爲Q的倍數的反射器是直接的。如果我們將這個反射器應用於(0,1,0)和(0,0,1),我們將得到矢量u和v如上所述。代數是有點繁瑣,但下面的C代碼做的工作:

static void make_basis(const double* Q, double* u, double* v) 
{ 
double L = hypot(Q[0], hypot(Q[1], Q[2])); // length of Q 
double sigma = (Q[0]>0.0) ? L : -L; // copysign(l, Q[0]) if you have it 
double h = Q[0] + sigma; // first component of householder vector 
double beta = -1.0/(sigma*h); // householder scale 
    // apply to (0,1,0)' 
double f = beta*Q[1]; 
    u[0] = f*h; 
    u[1] = 1.0+f*Q[1]; 
    u[2] = f*Q[2]; 
    // apply to (0,0,1)' 
double g = beta*Q[2]; 
    v[0] = g*h; 
    v[1] = g*Q[1]; 
    v[2] = 1.0+g*Q[2]; 
} 
+0

明確地說,'[0]','[1]'和[2]是'x','y', z',分別? –

+0

@NicHartley是的 – dmuir

0

謝謝轉發埃德和dmuir - 幫助。這是我所做的似乎工作的代碼:

function addTube(radius, segments, P1, P2) { 
    // Q = P1→P2 moved to origin 
    var Qx = P2[0] - P1[0]; 
    var Qy = P2[1] - P1[1]; 
    var Qz = P2[2] - P1[2]; 
    // Create vectors U and V that are (1) mutually perpendicular and (2) perpendicular to Q 
    if (Qx != 0) { // create a perpendicular vector on the XY plane 
    // there are an infinite number of potential vectors; arbitrarily select y = 1 
    var Ux = -Qy/Qx; 
    var Uy = 1; 
    var Uz = 0; 
    // to prove U is perpendicular: 
    // (Qx, Qy, Qz)·(Ux, Uy, Uz) = Qx·Ux + Qy·Uy + Qz·Uz = Qx·-Qy/Qx + Qy·1 + Qz·0 = -Qy + Qy + 0 = 0 
    } 
    else if (Qy != 0) { // create a perpendicular vector on the YZ plane 
    var Ux = 0; 
    var Uy = -Qz/Qy; 
    var Uz = 1; 
    } 
    else { // assume Qz != 0; create a perpendicular vector on the XZ plane 
    var Ux = 1; 
    var Uy = 0; 
    var Uz = -Qx/Qz; 
    } 
    // The cross product of two vectors is perpendicular to both, so to find V: 
    // (Vx, Vy, Vz) = (Qx, Qy, Qz)×(Ux, Uy, Uz) = (Qy×Uz - Qz×Uy, Qz×Ux - Qx×Uz, Qx×Uy - Qy×Ux) 
    var Vx = Qy*Uz - Qz*Uy; 
    var Vy = Qz*Ux - Qx*Uz; 
    var Vz = Qx*Uy - Qy*Ux; 
    // normalize U and V: 
    var Ulength = Math.sqrt(Math.pow(Ux, 2) + Math.pow(Uy, 2) + Math.pow(Uz, 2)); 
    var Vlength = Math.sqrt(Math.pow(Vx, 2) + Math.pow(Vy, 2) + Math.pow(Vz, 2)); 
    Ux /= Ulength; 
    Uy /= Ulength; 
    Uz /= Ulength; 
    Vx /= Vlength; 
    Vy /= Vlength; 
    Vz /= Vlength; 
    for (var i = 0; i < segments; i++) { 
    var θ = 2*Math.PI*i/segments; // theta 
    var dx = radius*(Math.cos(θ)*Ux + Math.sin(θ)*Vx); 
    var dy = radius*(Math.cos(θ)*Uy + Math.sin(θ)*Vy); 
    var dz = radius*(Math.cos(θ)*Uz + Math.sin(θ)*Vz); 
    drawLine(P1[0] + dx, P1[1] + dy, P1[2] + dz, // point on circle around P1 
      P2[0] + dx, P2[1] + dy, P2[2] + dz) // point on circle around P2 
    } 
    } 

我敢肯定,有很多方法可以縮短代碼並使其更高效。我使用Three.JS在線創建了一個簡短的視覺演示,在http://mvjantzen.com/tools/webgl/cylinder.html