基于结束正常应用旋转到圆柱体 [英] Apply Rotation to Cylinder based on Tube Ending Normal

查看:198
本文介绍了基于结束正常应用旋转到圆柱体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在three.js中制作一个弯曲的3D箭头。为完成此任务,我创建了



我试图将箭头(圆柱体形状为锥体)定位在管的末端,如下所示:(Photoshopped)





我的数学能力并不强,对three.js也很新颖。有人可以帮我理解如何连接两者吗?



以下是我目前的代码:

 从'three'导入T; 
$ b $ var findY = function(r,x)
{
return Math.sqrt((r * r) - (x * x));
}

var radius = 25;
var x = 0;
var z = 0;
var numberOfPoints = 10;
var interval =(radius / numberOfPoints);
var points = [];

for(var i = numberOfPoints; i> = 0; i--)
{
var y = findY(radius,x);
points.push(new T.Vector3(x,y,z))
x = x + interval;
}

x = x - interval;

for(var i = numberOfPoints - 1; i> = 0; i--)
{
y = findY(radius,x)* -1;
points.push(new T.Vector3(x,y,z));
x = x - interval;
}

var path = new T.CatmullRomCurve3(points);

var tubeGeometry = new T.TubeGeometry(
path,//路径
10,//段
radius / 10,//半径
8 ,// radiusSegments
false //关闭
);

var coneGeometry = new T.CylinderGeometry(
radiusTop = 0.1,
radiusBottom = radius / 5,
height = 10,
radialSegments = 10,
heightSegments = 10,
openEnded = 1
);

var material = new T.MeshBasicMaterial({color:0x00ff00});

var tube = new T.Mesh(tubeGeometry,material);
var cone = new T.Mesh(coneGeometry,material);

//翻译并旋转锥体?

如果有人可以尝试简单地解释什么是数学上的和程序上完成的必要条件, p>


  • 找到位于管末端的法线
  • 将圆锥移到正确的位置
  • li>


获得任何帮助!

解决方案

当您可以直接在适当位置创建箭头时,请不要使用旋转。同样,弯曲管也可以这样做。只有你需要的是由 A,B 端点定义的最后一行。



A 是尖端点, B 是光盘基座中心。要创建箭头,您需要2个额外的基础矢量,让它们调用基础光盘的 U,V 和半径 r 。从他们你可以使用简单的圆形公式创建圆盘点: rel =nofollow noreferrer>


  1. 获得 AB 端点

  2. compute U,V 基本向量 U,V 应位于箭头的光盘底部,并且应该互相垂直。箭头的方向(线 | BA | )是光盘基本正常的,所以利用跨产品,它将垂直向量返回到乘法的向量:

      W = BA; 
    W / = | W |; //单位向量
    T =(1,0,0); //如果(|(W.T)|> 0.75),任何非零矢量不平行于W
    ,则T =(0,1,0); //如果T和W的abs点乘积接近1,则表示它们接近平行,因此选择不同的T
    U =(T x W)// U垂直于T,W
    V =(U×W)// V垂直于U,W


  3. 创建/渲染箭头几何



    这就是简单的展台 A,B 需要2),并且盘基点计算如下:

    pre $ P $(P)(ang)= B + Urcos(ang)+ Vrsin(ang)

    因此,循环 ang 通过整个圈子一步,所以你有足够的分数(通常是36就够了),并从他们那里做三个粉丝。不要忘记最后一个光盘点必须与第一个光盘点相同,否则你会看起来很丑,或者在 ang = 0 360 deg。


如果您仍然想要轮换,那么这是可行的。按照上述相同的方式计算 U,V,W ,并从中构建变换矩阵。原点 O 将指向 B 和轴 X,Y,Z 将是 U,V,W 顺序取决于您的箭头模型。 W 应该与模型轴相匹配。 U,V 可以以任何顺序。所以只需将所有矢量复制到它们的位置并使用此矩阵进行渲染。欲了解更多信息,请参阅:




  •   void glArrowRoundxy(GLfloat x0,GLfloat y0 ,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat a2)
    {
    const int _glCircleN = 50; //每个圆圈的点数
    const int n = 3 * _glCircleN;
    int i,j,ix,e;
    float x,y,z,x1,y1,z1,a,b,da,db = pi2 /(_ glCircleN-1);
    float ux,uy,uz,vx,vy,vz,u,v;
    // buffers
    GLfloat ptab [6 * _glCircleN],* p0,* p1,* n0,* n1,* p;
    p0 = ptab +(0 * _glCircleN); //以前的管段圆点
    p1 = ptab +(3 * _glCircleN); //实际管段圆点
    da = + db;如果(a0> a1)da = -db; //主角度步进方向
    ux = 0.0; // U与箭头平面正常
    uy = 0.0;
    uz = 1.0;
    //圆弧插值a =< a0,a1> ((da> 0.0))的结束条件

    对于(e = 1,j = 0,a = a0; e; j ++,a + = da)
    { &&(a> = a1)){a = a1; E = 0; ((da <0.0)&(a< = a1)){a = a1;}
    。 E = 0; }
    //计算实际管道数量
    x1 = x0 +(r * cos(a));
    y1 = y0 +(r * sin(a));
    z1 = z0;
    // V是从(x0,y0,z0)到(x1,y1,z1)
    vx = x1-x0的方向;
    vy = y1-y0;
    vz = z1-z0;
    //和粗单位
    b = sqrt((vx * vx)+(vy * vy)+(vz * vz));
    if(b> 1e-6)b = 1.0 / b;否则b = 0.0;
    vx * = b;
    vy * = b;
    vz * = b; (ix = 0,b = 0.0,i = 0; i <_glCircleN; i ++,b + = db)
    //管段

    {
    u = r0 * cos二);
    v = r0 * sin(b);
    p1 [ix] = x1 +(ux * u)+(vx * v); IX ++;
    p1 [ix] = y1 +(uy * u)+(vy * v); IX ++;
    p1 [ix] = z1 +(uz * u)+(vz * v); IX ++;
    }
    if(!j)
    {
    glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x1,y1,z1); (ix = 0; ix< n; ix + = 3)glVertex3fv(p1 + ix)的
    ;
    glEnd();
    }
    else {
    glBegin(GL_QUAD_STRIP); (ix = 0; ix< n; ix + = 3)
    {
    glVertex3fv(p0 + ix);
    glVertex3fv(p1 + ix);
    }
    glEnd();
    }
    //交换缓冲区
    p = p0; P0 = P1; P1 = P;
    p = n0; N0 = N1; N1 = P;
    }
    //箭头a =< a1,a2> (b);(b)为(ix = 0,b = 0.0,i = 0; i< _glCircleN; i ++,b + = db)

    v = r1 * sin(b);
    p1 [ix] = x1 +(ux * u)+(vx * v); IX ++;
    p1 [ix] = y1 +(uy * u)+(vy * v); IX ++;
    p1 [ix] = z1 +(uz * u)+(vz * v); IX ++;
    }
    glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x1,y1,z1); (ix = 0; ix< n; ix + = 3)glVertex3fv(p1 + ix)的
    ;
    glEnd();
    x1 = x0 +(r * cos(a2));
    y1 = y0 +(r * sin(a2));
    z1 = z0;
    glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x1,y1,z1); (ix = n-3; ix> = 0; ix- = 3)glVertex3fv(p1 + ix)的
    ;
    glEnd();

    $ / code>

    这使得XY平面上的弯曲箭头以 x ,y,z 和大半径 r r0 是管半径, r1 是箭头底部半径。由于我没有曲线定义,我选择了XY平面中的圆。 a0,a1,a2 是箭头开始的角度( a0 ),箭头开始( a1 )并结束( a2 )。 pi2 只是常数 pi2 = 6.283185307179586476925286766559



    这个想法是记住实际和以前的管段圆点,所以对于 ptab,p0,p1 来说,否则你需要计算两次所有东西。



    由于我直接选择了XY平面,因此我知道一个基本矢量与其垂直。其次是垂直于它和箭头的方向幸运的是,圆形属性自己提供了这一点,因此在这种情况下不需要交叉产品。



    希望如果没有评论我,就足够清楚了。 $ b

    [Edit2]

    我需要将其添加到我的引擎中,因此这里是3D版本(不仅限于轴对齐的箭头,锥体也会弯曲)。除了基矢量计算以外,它也是一样的,我也在头部< a0,a1> 中改变了角度,并且 aa 是箭头大小,但后者在代码中转换为原始大小。我还为照明计算添加了法线。我还添加了线性箭头,在这种情况下,如果您获得了不同的曲线,则基向量的计算没有充分利用圆的属性。结果如下:

      // --------------------- -------------------------------------------------- ---- 
    const int _glCircleN = 50; //每圈的点数
    // --------------------------------------- ------------------------------------
    void glCircleArrowxy(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa)
    {
    double pos [3] = {x0,y0,z0};
    double或[3] = {0.0,0.0,1.0};
    double bin [3] = {1.0,0.0,0.0};
    glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa);
    }
    // --------------------------------------- ------------------------------------
    void glCircleArrowyz(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa)
    {
    double pos [3] = {x0,y0,z0};
    double也不是[3] = {1.0,0.0,0.0};
    double bin [3] = {0.0,1.0,0.0};
    glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa);
    }
    // --------------------------------------- ------------------------------------
    void glCircleArrowxz(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa)
    {
    double pos [3] = {x0,y0,z0};
    double或[3] = {0.0,1.0,0.0};
    double bin [3] = {0.0,0.0,1.0};
    glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa);
    }
    // --------------------------------------- ------------------------------------
    void glCircleArrow3D(double * pos,double * nor ,double * bin,double r,double r0,double r1,double a0,double a1,double aa)
    {
    // const int _glCircleN = 20; //每圈点数
    int e,i,j,N = 3 * _glCircleN;
    double U [3],V [3],u,v;
    double a,b,da,db = pi2 / double(_glCircleN-1),a2,rr;
    double * ptab,* p0,* p1,* n0,* n1,* pp,p [3],q [3],c [3],n [3],tan [3]
    // buffers
    ptab = new double [12 * _glCircleN]; if(ptab == NULL)return;
    p0 = ptab +(0 * _glCircleN);
    n0 = ptab +(3 * _glCircleN);
    p1 = ptab +(6 * _glCircleN);
    n1 = ptab +(9 * _glCircleN);
    //准备角度
    a2 = a1; DA =分贝; AA =晶圆厂(AA);
    if(a0> a1){da = -da; AA = -aa; }
    a1- = aa;
    //计算缺失基向量
    vector_copy(U,nor); // U与箭头平面正常
    vector_mul(tan,nor,bin); //正切垂直于正常并且正常
    //圆弧插值a =< a0,a2> (e = 0,j = 0,a = a0; e <5; j ++,a + = da)
    {
    //结束条件
    if(e == 0)// e = 0
    {
    if((da> 0.0)&(a> = a1)){a = a1; È++; ((da <0.0)&(a< = a1)){a = a1;}
    。 È++; }
    rr = r0; ((da> 0.0)&&(a> = a2)){a = a2;
    }
    else {// e = 1,2,3,4
    if È++; ((da <0.0)&(a <= a2)){a = a2;}
    。 È++; }
    rr = r1 * fabs(除(a-a2,a2-a1));
    }
    //计算实际管段中心c [3]
    u = r * cos(a);
    v = r * sin(a);
    vector_mul(p,bin,u);
    vector_mul(q,tan,v);
    vector_add(c,p,q);
    vector_add(c,c,pos);
    // V是从箭头中心到管段中心的单位方向
    vector_sub(V,c,pos);
    vector_one(V,V); (b = 0.0,i = 0; i //管段插值

    {
    u = cos(b)
    v = sin(b);
    vector_mul(p,U,u); // normal
    vector_mul(q,V,v);
    vector_add(n1 + i,p,q);
    vector_mul(p,n1 + i,rr); //顶点
    vector_add(p1 + i,p,c); (e> 1)//针对(i = 3; i< N; i + = 3)
    ($)重新计算锥体
    {
    的法线b $ b vector_sub(p,p0 + i,p1 + i);
    vector_sub(q,p1 + i-3,p1 + i);
    vector_mul(p,p,q);
    vector_one(n1 + i,p);
    }
    vector_sub(p,p0,p1);
    vector_sub(q,p1 + N-3,p1);
    vector_mul(p,q,p);
    vector_one(n1,p); (i = 0; i if(da> 0.0) (i = 0; i }
    //渲染基盘
    if(!j)
    {
    vector_mul(n,U,V);
    glBegin(GL_TRIANGLE_FAN);
    glNormal3dv(n);
    glVertex3dv(c); (i = N-3; i> = 0; i- = 3)glVertex3dv(p1 + i);(b)
    else for(i = 0; i glEnd();
    }
    //渲染管
    其他{
    glBegin(GL_QUAD_STRIP); (i = 0; i {
    glNormal3dv(n1 + i);
    if(da <0.0) glVertex3dv(P1 + I);
    glNormal3dv(n0 + i); glVertex3dv(P0 + I);
    }
    else for(i = 0; i {
    glNormal3dv(n0 + i); glVertex3dv(P0 + I);
    glNormal3dv(n1 + i); glVertex3dv(P1 + I);
    }
    glEnd();
    }
    //交换缓冲区
    pp = p0; P0 = P1; P1 = PP;
    pp = n0; N0 = N1; N1 = PP;
    //句柄r0 - > r1边缘
    if(e == 1)a- = da;如果((e == 1)||(e == 2)||(e == 3))e ++;

    }
    //释放缓冲区
    delete [] ptab;
    }
    // --------------------------------------- ------------------------------------
    void glLinearArrow3D(double * pos,double * dir ,double r0,double r1,double l,double al)
    {
    // const int _glCircleN = 20; //每圈点数
    int e,i,N = 3 * _glCircleN;
    double U [3],V [3],W [3],u,v;
    double a,da = pi2 / double(_glCircleN-1),r,t;
    double * ptab,* p0,* p1,* n1,* pp,p [3],q [3],c [3],n [3];
    // buffers
    ptab = new double [9 * _glCircleN]; if(ptab == NULL)return;
    p0 = ptab +(0 * _glCircleN);
    p1 = ptab +(3 * _glCircleN);
    n1 = ptab +(6 * _glCircleN);
    //计算基向量
    vector_one(W,dir);
    vector_ld(p,1.0,0.0,0.0);
    vector_ld(q,0.0,1.0,0.0);
    vector_ld(n,0.0,0.0,1.0);
    a = fabs(vector_mul(W,p)); PP = P; T = A;
    a = fabs(vector_mul(W,q)); if(t> a){pp = q; T = A; }
    a = fabs(vector_mul(W,n)); if(t> a){pp = n; T = A; }
    vector_mul(U,W,pp);
    vector_mul(V,U,W);
    vector_mul(U,V,W); (e = 0; e <4; e ++)
    {
    //段中心
    if(e == 0){t = 0.0; r = r0; }
    if(e == 1){t = l-al; r = r0; }
    if(e == 2){t = l-al; r = r1; }
    if(e == 3){t = 1; R = 0.0; }
    vector_mul(c,W,t);
    vector_add(c,c,pos);对于(a = 0.0,i = 0; i {
    u = cos(a);
    //管段内插

    v = sin(a);
    vector_mul(p,U,u); // normal
    vector_mul(q,V,v);
    vector_add(n1 + i,p,q);
    vector_mul(p,n1 + i,r); //顶点
    vector_add(p1 + i,p,c); (e> 2)//针对(i = 3; i< N; i + = 3)
    ($)重新计算锥体
    {
    的法线b $ b vector_sub(p,p0 + i,p1 + i);
    vector_sub(q,p1 + i-3,p1 + i);
    vector_mul(p,p,q);
    vector_one(n1 + i,p);
    }
    vector_sub(p,p0,p1);
    vector_sub(q,p1 + N-3,p1);
    vector_mul(p,q,p);
    vector_one(n1,p);

    //渲染基盘
    if(!e)
    {
    vector_neg(n,W);
    glBegin(GL_TRIANGLE_FAN);
    glNormal3dv(n);
    glVertex3dv(c); (i = 0; i ;
    glEnd();
    }
    //渲染管
    其他{
    glBegin(GL_QUAD_STRIP); (i = 0; i {
    glNormal3dv(n1 + i);
    glVertex3dv(p0 + i);
    glVertex3dv(p1 + i);
    }
    glEnd();
    }
    //交换缓冲区
    pp = p0; P0 = P1; P1 = PP;
    }
    //释放缓冲区
    delete [] ptab;
    }
    // --------------------------------------- ------------------------------------

    用法:

      glColor3f(0.5,0.5,0.5); 

    glCircleArrowyz(+ 3.5,0.0,0.0,0.5,0.1,0.2,0.0 * deg,+ 270.0 * deg,45.0 * deg);

    glCircleArrowyz(-3.5,0.0,0.0,0.5,0.1,0.2,0.0 * deg,-270.0 * deg,45.0 * deg);
    glCircleArrowxz(0.0,+ 3.5,0.0,0.5,0.1,0.2,0.0 * deg,+ 270.0 * deg,45.0 * deg);
    glCircleArrowxz(0.0,-3.5,0.0,0.5,0.1,0.2,0.0 * deg,-270.0 * deg,45.0 * deg);
    glCircleArrowxy(0.0,0.0,+ 3.5,0.5,0.1,0.2,0.0 * deg,+ 270.0 * deg,45.0 * deg);
    glCircleArrowxy(0.0,0.0,-3.5,0.5,0.1,0.2,0.0 * deg,-270.0 * deg,45.0 * deg);
    glColor3f(0.2,0.2,0.2);
    glLinearArrow3D(vector_ld(+2.0,0.0,0.0),vector_ld(+1,0,0,0,0.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(-2.0,0.0,0.0),vector_ld(-1.0,0.0,0.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(0.0,+ 2.0,0.0),vector_ld(0.0,+ 1.0,0.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(0.0,-2.0,0.0),vector_ld(0.0,-1.0,0.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(0.0,0.0,+ 2.0),vector_ld(0.0,0.0,+ 1.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(0.0,0.0,-2.0),vector_ld(0.0,0.0,-1.0),0.1,0.2,2.0,0.5);

    以及图片右侧的概览:



    我使用我的矢量库,所以这里有一些解释:



    $ vector_mul(a [3],b [3],c [3])是交叉乘积 a = bxc

    vector_mul(a [3],b [3],c)是简单的乘以标量 a = bc

    a = vector_mul(b [3],c [3])是点积 a =(bc)

    vector_one(a [3],b [3])是单位向量 a = b / | b |


    vector_copy(a [3],b [3] )只是复制 a = b

    vector_add(a [3],b [3 ],c [3])正在添加 a = b + c

    vector_sub(a [3],b [3],c [3])正在减去 a = b - c

    vector_neg(a [3],b [3])为否定 a = -b

    vector_ld(a [3],x,y,z)正在加载 a =(x,y,z)



    pos 是你的圆形箭头的中心位置和都是箭头所在平面的法线。 bin 是双正态的,角度从该轴开始。应该垂直于 r,r0,r1 是箭头(弯曲,管,圆锥)的半径。

    线性箭头是类似的 dir 是箭头的方向, l 是箭头大小, al 是箭头大小。

    I am attempting to make a curved 3D arrow in three.js. To accomplish this task, I have created a Tube that follows a curved path and a Cylinder shaped as a cone (by setting radiusTop to be tiny). They currently look like so:

    I am attempting to position the Arrow Head (Cylinder shaped as a cone) at the end of the Tube like so: (Photoshopped)

    I am not terribly strong in math and pretty new to three.js. Could someone help me understand how to connect the two?

    Here is my current code:

            import T from 'three';
    
            var findY = function(r, x)
            {
               return Math.sqrt((r * r) - (x * x));
            }
    
            var radius = 25;
            var x = 0;
            var z = 0;
            var numberOfPoints = 10;
            var interval =  (radius/numberOfPoints);
            var points = [];
    
            for (var i = numberOfPoints; i >= 0; i--) 
            {
               var y = findY(radius, x);
               points.push(new T.Vector3(x, y, z))
               x = x + interval;
            }
    
            x = x - interval;
    
            for (var i = numberOfPoints - 1 ; i >= 0; i--) 
            {
               y = findY(radius, x) * -1;
               points.push(new T.Vector3(x, y, z));
               x = x - interval;
            }
    
            var path = new T.CatmullRomCurve3(points);
    
            var tubeGeometry = new T.TubeGeometry(
                path,  //path
                10,    //segments
                radius / 10,     //radius
                8,     //radiusSegments
                false  //closed
            );
    
            var coneGeometry = new T.CylinderGeometry(
                radiusTop = 0.1,
                radiusBottom = radius/5,
                height = 10,
                radialSegments = 10,
                heightSegments = 10,
                openEnded = 1
            );
    
            var material = new T.MeshBasicMaterial( { color: 0x00ff00 } );
    
            var tube = new T.Mesh( tubeGeometry, material );
            var cone = new T.Mesh( coneGeometry, material );
    
            // Translate and Rotate cone?
    

    I would greatly appreciate if someone could attempt a simple explanation of what is necessary mathematically and programmatically accomplish

    • Finding the normal located at the end of the tube
    • Shifting the Cone to the correct location

    Any help is appreciated!

    解决方案

    Do not use rotation for this when you can create the arrowhead directly in place. Similarly the bended tube can be done this way too. Only thing you need for it is the last line segment defined by A,B endpoints.

    Let A be the sharp point and B the disc base center. To create arrowhead you need 2 additional basis vectors let call them U,V and radius r of base disc. From them you can create disc points with simple circle formula like this:

    1. obtain AB endpoints

    2. compute U,V basis vectors

      The U,V should lie in the disc base of arrowhead and should be perpendicular to each other. direction of the arrowhead (line |BA|) is the disc base normal so exploit cross product which returns perpendicular vector to the multiplied ones so:

      W = B-A;
      W /= |W|;    // unit vector
      T = (1,0,0); // temp any non zero vector not parallel to W
      if ( |(W.T)|>0.75 ) T = (0,1,0); // if abs dot product of T and W is close to 1 it means they are close to parallel so chose different T
      U = (T x W) // U is perpendicular to T,W
      V = (U x W) // V is perpendicular to U,W
      

    3. create/render arrowhead geometry

      That is easy booth A,B are centers of triangle fan (need 2) and the disc base points are computed like this:

      P(ang) = B + U.r.cos(ang) + V.r.sin(ang)
      

      So just loop ang through the whole circle with some step so you got enough points (usually 36 is enough) and do both triangle fans from them. Do not forget the last disc point must be the same as the first one otherwise you will got ugly seems or hole on the ang = 0 or 360 deg.

    If you still want to go for rotations instead then this is doable like this. compute U,V,W in the same way as above and construct transformation matrix from them. the origin O will be point B and axises X,Y,Z will be U,V,W the order depends on your arrowhead model. W should match the model axis. U,V can be in any order. So just copy all the vectors to their places and use this matrix for rendering. For more info see:

    [Notes]

    If you do not know how to compute vector operations like cross/dot products or absolute value see:

    // cross product: W = U x V
    W.x=(U.y*V.z)-(U.z*V.y)
    W.y=(U.z*V.x)-(U.x*V.z)
    W.z=(U.x*V.y)-(U.y*V.x)
    // dot product: a = (U.V)
    a=U.x*V.x+U.y*V.y+U.z*V.z
    // abs of vector a = |U|
    a=sqrt((U.x*U.x)+(U.y*U.y)+(U.z*U.z))
    

    [Edit1] simple GL implementation

    I do not code in your environment but as downvote and comment suggest you guys are not able to put this together on your own which is odd considering you got this far so here simple C++/GL exmaple of how to do this (you can port this to your environment):

    void glArrowRoundxy(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat a2)
        {
        const int _glCircleN=50;    // points per circle
        const int n=3*_glCircleN;
        int i,j,ix,e;
        float x,y,z,x1,y1,z1,a,b,da,db=pi2/(_glCircleN-1);
        float ux,uy,uz,vx,vy,vz,u,v;
        // buffers
        GLfloat ptab[6*_glCircleN],*p0,*p1,*n0,*n1,*p;
        p0=ptab+(0*_glCircleN);     // previous tube segment circle points
        p1=ptab+(3*_glCircleN);     // actual tube segment circle points
        da=+db; if (a0>a1) da=-db;  // main angle step direction
        ux=0.0;                     // U is normal to arrow plane
        uy=0.0;
        uz=1.0;
        // arc interpolation a=<a0,a1>
        for (e=1,j=0,a=a0;e;j++,a+=da)
            {
            // end conditions
            if ((da>0.0)&&(a>=a1)) { a=a1; e=0; }
            if ((da<0.0)&&(a<=a1)) { a=a1; e=0; }
            // compute actual tube ceneter
            x1=x0+(r*cos(a));
            y1=y0+(r*sin(a));
            z1=z0;
            // V is direction from (x0,y0,z0) to (x1,y1,z1)
            vx=x1-x0;
            vy=y1-y0;
            vz=z1-z0;
            // and unit of coarse
            b=sqrt((vx*vx)+(vy*vy)+(vz*vz));
            if (b>1e-6) b=1.0/b; else b=0.0;
            vx*=b;
            vy*=b;
            vz*=b;
            // tube segment
            for (ix=0,b=0.0,i=0;i<_glCircleN;i++,b+=db)
                {
                u=r0*cos(b);
                v=r0*sin(b);
                p1[ix]=x1+(ux*u)+(vx*v); ix++;
                p1[ix]=y1+(uy*u)+(vy*v); ix++;
                p1[ix]=z1+(uz*u)+(vz*v); ix++;
                }
            if (!j)
                {
                glBegin(GL_TRIANGLE_FAN);
                glVertex3f(x1,y1,z1);
                for (ix=0;ix<n;ix+=3) glVertex3fv(p1+ix);
                glEnd();
                }
            else{
                glBegin(GL_QUAD_STRIP);
                for (ix=0;ix<n;ix+=3)
                    {
                    glVertex3fv(p0+ix);
                    glVertex3fv(p1+ix);
                    }
                glEnd();
                }
            // swap buffers
            p=p0; p0=p1; p1=p;
            p=n0; n0=n1; n1=p;
            }
        // arrowhead a=<a1,a2>
        for (ix=0,b=0.0,i=0;i<_glCircleN;i++,b+=db)
            {
            u=r1*cos(b);
            v=r1*sin(b);
            p1[ix]=x1+(ux*u)+(vx*v); ix++;
            p1[ix]=y1+(uy*u)+(vy*v); ix++;
            p1[ix]=z1+(uz*u)+(vz*v); ix++;
            }
        glBegin(GL_TRIANGLE_FAN);
        glVertex3f(x1,y1,z1);
        for (ix=0;ix<n;ix+=3) glVertex3fv(p1+ix);
        glEnd();
        x1=x0+(r*cos(a2));
        y1=y0+(r*sin(a2));
        z1=z0;
        glBegin(GL_TRIANGLE_FAN);
        glVertex3f(x1,y1,z1);
        for (ix=n-3;ix>=0;ix-=3) glVertex3fv(p1+ix);
        glEnd();
        }
    

    This renders bended arrow in XY plane with center x,y,z and big radius r. The r0 is tube radius and r1 is arrowhead base radius. As I do not have your curve definition I choose circle in XY plane. The a0,a1,a2 are angles where arrow starts (a0), arrowhead starts (a1) and ends (a2). The pi2 is just constant pi2=6.283185307179586476925286766559.

    The idea is to remember actual and previous tube segment circle points so there for the ptab,p0,p1 otherwise you would need to compute everything twice.

    As I chose XY plane directly then I know that one base vector is normal to it. and second is perpendicular to it and to arrow direction luckily circle properties provides this on its own therefore no need for cross products in this case.

    Hope it is clear enough if not comment me.

    [Edit2]

    I needed to add this to my engine so here is the 3D version (not bound just to axis aligned arrows and the cone is bended too). It is the same except the basis vector computation and I also change the angles a bit in the header <a0,a1> is the whole interval and aa is the arrowhead size but latter in code it is converted to the original convention. I added also normals for lighting computations. I added also linear Arrow where the computation of basis vectors is not taking advantage of circle properties in case you got different curve. Here result:

    //---------------------------------------------------------------------------
    const int _glCircleN=50;    // points per circle
    //---------------------------------------------------------------------------
    void glCircleArrowxy(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa)
        {
        double pos[3]={ x0, y0, z0};
        double nor[3]={0.0,0.0,1.0};
        double bin[3]={1.0,0.0,0.0};
        glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa);
        }
    //---------------------------------------------------------------------------
    void glCircleArrowyz(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa)
        {
        double pos[3]={ x0, y0, z0};
        double nor[3]={1.0,0.0,0.0};
        double bin[3]={0.0,1.0,0.0};
        glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa);
        }
    //---------------------------------------------------------------------------
    void glCircleArrowxz(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa)
        {
        double pos[3]={ x0, y0, z0};
        double nor[3]={0.0,1.0,0.0};
        double bin[3]={0.0,0.0,1.0};
        glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa);
        }
    //---------------------------------------------------------------------------
    void glCircleArrow3D(double *pos,double *nor,double *bin,double r,double r0,double r1,double a0,double a1,double aa)
        {
    //  const int _glCircleN=20;    // points per circle
        int e,i,j,N=3*_glCircleN;
        double U[3],V[3],u,v;
        double a,b,da,db=pi2/double(_glCircleN-1),a2,rr;
        double *ptab,*p0,*p1,*n0,*n1,*pp,p[3],q[3],c[3],n[3],tan[3];
        // buffers
        ptab=new double [12*_glCircleN]; if (ptab==NULL) return;
        p0=ptab+(0*_glCircleN);
        n0=ptab+(3*_glCircleN);
        p1=ptab+(6*_glCircleN);
        n1=ptab+(9*_glCircleN);
        // prepare angles
        a2=a1; da=db; aa=fabs(aa);
        if (a0>a1) { da=-da; aa=-aa; }
        a1-=aa;
        // compute missing basis vectors
        vector_copy(U,nor);         // U is normal to arrow plane
        vector_mul(tan,nor,bin);    // tangent is perpendicular to normal and binormal
        // arc interpolation a=<a0,a2>
        for (e=0,j=0,a=a0;e<5;j++,a+=da)
            {
            // end conditions
            if (e==0)   // e=0
                {
                if ((da>0.0)&&(a>=a1)) { a=a1; e++; }
                if ((da<0.0)&&(a<=a1)) { a=a1; e++; }
                rr=r0;
                }
            else{       // e=1,2,3,4
                if ((da>0.0)&&(a>=a2)) { a=a2; e++; }
                if ((da<0.0)&&(a<=a2)) { a=a2; e++; }
                rr=r1*fabs(divide(a-a2,a2-a1));
                }
            // compute actual tube segment center c[3]
            u=r*cos(a);
            v=r*sin(a);
            vector_mul(p,bin,u);
            vector_mul(q,tan,v);
            vector_add(c,p,  q);
            vector_add(c,c,pos);
            // V is unit direction from arrow center to tube segment center
            vector_sub(V,c,pos);
            vector_one(V,V);
            // tube segment interpolation
            for (b=0.0,i=0;i<N;i+=3,b+=db)
                {
                u=cos(b);
                v=sin(b);
                vector_mul(p,U,u);      // normal
                vector_mul(q,V,v);
                vector_add(n1+i,p,q);
                vector_mul(p,n1+i,rr);  // vertex
                vector_add(p1+i,p,c);
                }
            if (e>1)                    // recompute normals for cone
                {
                for (i=3;i<N;i+=3)
                    {
                    vector_sub(p,p0+i  ,p1+i);
                    vector_sub(q,p1+i-3,p1+i);
                    vector_mul(p,p,q);
                    vector_one(n1+i,p);
                    }
                vector_sub(p,p0    ,p1);
                vector_sub(q,p1+N-3,p1);
                vector_mul(p,q,p);
                vector_one(n1,p);
                if (da>0.0) for (i=0;i<N;i+=3) vector_neg(n1+i,n1+i);
                if (e==  3) for (i=0;i<N;i+=3) vector_copy(n0+i,n1+i);
                }
            // render base disc
            if (!j)
                {
                vector_mul(n,U,V);
                glBegin(GL_TRIANGLE_FAN);
                glNormal3dv(n);
                glVertex3dv(c);
                if (da<0.0) for (i=N-3;i>=0;i-=3) glVertex3dv(p1+i);
                else        for (i=  0;i< N;i+=3) glVertex3dv(p1+i);
                glEnd();
                }
            // render tube
            else{
                glBegin(GL_QUAD_STRIP);
                if (da<0.0) for (i=0;i<N;i+=3)
                    {
                    glNormal3dv(n1+i); glVertex3dv(p1+i);
                    glNormal3dv(n0+i); glVertex3dv(p0+i);
                    }
                else for (i=0;i<N;i+=3)
                    {
                    glNormal3dv(n0+i); glVertex3dv(p0+i);
                    glNormal3dv(n1+i); glVertex3dv(p1+i);
                    }
                glEnd();
                }
            // swap buffers
            pp=p0; p0=p1; p1=pp;
            pp=n0; n0=n1; n1=pp;
            // handle r0 -> r1 edge
            if (e==1) a-=da;
            if ((e==1)||(e==2)||(e==3)) e++;
            }
        // release buffers
        delete[] ptab;
        }
    //---------------------------------------------------------------------------
    void glLinearArrow3D(double *pos,double *dir,double r0,double r1,double l,double al)
        {
    //  const int _glCircleN=20;    // points per circle
        int e,i,N=3*_glCircleN;
        double U[3],V[3],W[3],u,v;
        double a,da=pi2/double(_glCircleN-1),r,t;
        double *ptab,*p0,*p1,*n1,*pp,p[3],q[3],c[3],n[3];
        // buffers
        ptab=new double [9*_glCircleN]; if (ptab==NULL) return;
        p0=ptab+(0*_glCircleN);
        p1=ptab+(3*_glCircleN);
        n1=ptab+(6*_glCircleN);
        // compute basis vectors
        vector_one(W,dir);
        vector_ld(p,1.0,0.0,0.0);
        vector_ld(q,0.0,1.0,0.0);
        vector_ld(n,0.0,0.0,1.0);
        a=fabs(vector_mul(W,p));            pp=p; t=a;
        a=fabs(vector_mul(W,q)); if (t>a) { pp=q; t=a; }
        a=fabs(vector_mul(W,n)); if (t>a) { pp=n; t=a; }
        vector_mul(U,W,pp);
        vector_mul(V,U,W);
        vector_mul(U,V,W);
        for (e=0;e<4;e++)
            {
            // segment center
            if (e==0) { t=0.0;  r= r0; }
            if (e==1) { t=l-al; r= r0; }
            if (e==2) { t=l-al; r= r1; }
            if (e==3) { t=l;    r=0.0; }
            vector_mul(c,W,t);
            vector_add(c,c,pos);
            // tube segment interpolation
            for (a=0.0,i=0;i<N;i+=3,a+=da)
                {
                u=cos(a);
                v=sin(a);
                vector_mul(p,U,u);      // normal
                vector_mul(q,V,v);
                vector_add(n1+i,p,q);
                vector_mul(p,n1+i,r);   // vertex
                vector_add(p1+i,p,c);
                }
            if (e>2)                    // recompute normals for cone
                {
                for (i=3;i<N;i+=3)
                    {
                    vector_sub(p,p0+i  ,p1+i);
                    vector_sub(q,p1+i-3,p1+i);
                    vector_mul(p,p,q);
                    vector_one(n1+i,p);
                    }
                vector_sub(p,p0    ,p1);
                vector_sub(q,p1+N-3,p1);
                vector_mul(p,q,p);
                vector_one(n1,p);
                }
            // render base disc
            if (!e)
                {
                vector_neg(n,W);
                glBegin(GL_TRIANGLE_FAN);
                glNormal3dv(n);
                glVertex3dv(c);
                for (i=0;i<N;i+=3) glVertex3dv(p1+i);
                glEnd();
                }
            // render tube
            else{
                glBegin(GL_QUAD_STRIP);
                for (i=0;i<N;i+=3)
                    {
                    glNormal3dv(n1+i);
                    glVertex3dv(p0+i);
                    glVertex3dv(p1+i);
                    }
                glEnd();
                }
            // swap buffers
            pp=p0; p0=p1; p1=pp;
            }
        // release buffers
        delete[] ptab;
        }
    //---------------------------------------------------------------------------
    

    usage:

    glColor3f(0.5,0.5,0.5);
    
    glCircleArrowyz(+3.5,0.0,0.0,0.5,0.1,0.2,0.0*deg,+270.0*deg,45.0*deg);
    
    glCircleArrowyz(-3.5,0.0,0.0,0.5,0.1,0.2,0.0*deg,-270.0*deg,45.0*deg);
    glCircleArrowxz(0.0,+3.5,0.0,0.5,0.1,0.2,0.0*deg,+270.0*deg,45.0*deg);
    glCircleArrowxz(0.0,-3.5,0.0,0.5,0.1,0.2,0.0*deg,-270.0*deg,45.0*deg);
    glCircleArrowxy(0.0,0.0,+3.5,0.5,0.1,0.2,0.0*deg,+270.0*deg,45.0*deg);
    glCircleArrowxy(0.0,0.0,-3.5,0.5,0.1,0.2,0.0*deg,-270.0*deg,45.0*deg);
    glColor3f(0.2,0.2,0.2);
    glLinearArrow3D(vector_ld(+2.0,0.0,0.0),vector_ld(+1.0,0.0,0.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(-2.0,0.0,0.0),vector_ld(-1.0,0.0,0.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(0.0,+2.0,0.0),vector_ld(0.0,+1.0,0.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(0.0,-2.0,0.0),vector_ld(0.0,-1.0,0.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(0.0,0.0,+2.0),vector_ld(0.0,0.0,+1.0),0.1,0.2,2.0,0.5);
    glLinearArrow3D(vector_ld(0.0,0.0,-2.0),vector_ld(0.0,0.0,-1.0),0.1,0.2,2.0,0.5);
    

    and overview of the arows (on the right side of image):

    I am using my vector lib so here are some explanations:


    vector_mul(a[3],b[3],c[3]) is cross product a = b x c
    vector_mul(a[3],b[3],c) is simple multiplication by scalar a = b.c
    a = vector_mul(b[3],c[3]) is dot product a = (b.c)
    vector_one(a[3],b[3]) is unit vector a = b/|b|
    vector_copy(a[3],b[3]) is just copy a = b
    vector_add(a[3],b[3],c[3]) is adding a = b + c
    vector_sub(a[3],b[3],c[3]) is substracting a = b - c
    vector_neg(a[3],b[3]) is negation a = -b
    vector_ld(a[3],x,y,z) is just loading a = (x,y,z)

    The pos is the center position of your circle arrow and nor is normal of the plane in which the arrow lies. bin is bi-normal and the angles are starting from this axis. should be perpendicular to nor. r,r0,r1 are the radiuses of the arrow (bend,tube,cone)

    The linear arrow is similar the dir is direction of the arrow, l is arrow size and al is arrowhead size.

    这篇关于基于结束正常应用旋转到圆柱体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆