多边形边勾勒并不总是正确的并不、多边形、正确

2023-09-11 01:49:44 作者:你已不再爱我了

我用下面的算法生成的四边形然后将其渲染,使这样一个大纲

  

http://img810.imageshack.us/img810/8530/uhohz.png

所看到的图像上的问题是,有时线条过细时,他们应始终是相同的宽度。我的算法找到了4 verticies为第一个然后顶端2 verticies的下一次是的previous底部2。这造成连接线,但它似乎并不总是工作。我怎么能解决这个问题?

这是我的算法:

 无效OGLENGINEFUNCTIONS :: GenerateLinePoly(常量的std ::矢量<的std ::矢量< GLdouble>>&安培;输入,
     的std ::矢量< GLfloat> &放大器;输出,INT宽)
 {

     output.clear();
     如果(input.size()2)
     {
         返回;
     }
     INT温度;
     浮动dirlen;
     浮动perplen;
     POINTFLOAT启动;
     POINTFLOAT结束;
     POINTFLOAT目录;
     POINTFLOAT NDIR;
     POINTFLOAT PERP;
     POINTFLOAT nperp;

     POINTFLOAT perpoffset;
     POINTFLOAT diroffset;

     POINTFLOAT P0,P1,P2,P3;

     为(unsigned int类型I = 0; I< input.size() -  1 ++ I)
     {

         start.x =&的static_cast其中;浮动>(输入[I] [0]);
         start.y =&的static_cast其中;浮动>(输入[I] [1]);

         end.x =&的static_cast其中;浮动>(输入[I + 1] [0]);
         end.y =&的static_cast其中;浮动>(输入[I + 1] [1]);

         dir.x = end.x  -  start.x;
         dir.y = end.y  -  start.y;

         dirlen = SQRT((dir.x * dir.x)+(dir.y * dir.y));

         ndir.x =的static_cast<浮动>(dir.x * 1.0 / dirlen);
         ndir.y =的static_cast<浮动>(dir.y * 1.0 / dirlen);

         perp.x = dir.y;
         perp.y = -dir.x;

         perplen = SQRT((perp.x * perp.x)+(perp.y * perp.y));

         nperp.x =的static_cast<浮动>(perp.x * 1.0 / perplen);
         nperp.y =的static_cast<浮动>(perp.y * 1.0 / perplen);

         perpoffset.x =的static_cast<浮动>(nperp.x *宽* 0.5);
         perpoffset.y =的static_cast<浮动>(nperp.y *宽* 0.5);

         diroffset.x =的static_cast<浮动>(ndir.x * 0 * 0.5);
         diroffset.y =的static_cast<浮动>(ndir.y * 0 * 0.5);

            // P0 =启动+ perpoffset  -  diroffset
             // P1 =开始 -  perpoffset  -  diroffset
             // P2 =端+ perpoffset + diroffset
            // P3 =结束 -  perpoffset + diroffset

         p0.x = start.x + perpoffset.x  -  diroffset.x;
         p0.y = start.y + perpoffset.y  -  diroffset.y;

         p1.x = start.x  -  perpoffset.x  -  diroffset.x;
         p1.y = start.y  -  perpoffset.y  -  diroffset.y;

         如果(ⅰ大于0)
         {
             临时=(8 *(I  -  1));
             p2.x =输出[温度+ 2];
             p2.y =输出[温度+ 3]。
             p3.x =输出[温度+ 4];
             p3.y =输出[温度+ 5];

         }
         其他
         {
             p2.x = end.x + perpoffset.x + diroffset.x;
             p2.y = end.y + perpoffset.y + diroffset.y;

             p3.x = end.x  -  perpoffset.x + diroffset.x;
             p3.y = end.y  -  perpoffset.y + diroffset.y;
         }



         output.push_back(p2.x);
         output.push_back(p2.y);
         output.push_back(p0.x);
         output.push_back(p0.y);
         output.push_back(p1.x);
         output.push_back(p1.y);
         output.push_back(p3.x);
         output.push_back(p3.y);

     }
 }
 
多边形每个角最多不能超过多少度,最少不能低于多少度

感谢

编辑:

  POINTFLOAT乘法(常量POINTFLOAT&功放;一,浮动B)
 {
     POINTFLOAT结果;
     result.x = a.x * B;
     result.y = a.y * B;
     返回结果;
 }

 POINTFLOAT正常化(常量POINTFLOAT&功放;一)
 {
     返回乘法(一个,1.0F / SQRT(a.x * a.x + a.y * a.y));
 }


 POINTFLOAT slerp2d(常量POINTFLOAT V0,
     常量POINTFLOAT V1,浮动T)
 {
     浮动点=(v0.x * 1.x版+ v1.y * v1.y);
     如果(DOT< -1.0F)点= -1.0F;
     如果(DOT> 1.0F)点= 1.0F;

     浮theta_0 = ACOS(点);
     浮THETA = theta_0 * T;

     POINTFLOAT V2;
     V2.X = -v0.y;
     v2.y = v0.x;

     POINTFLOAT结果;
     result.x = v0.x * COS(THETA)+版本2.x * SIN(THETA);
     result.y = v0.y * COS(THETA)+ v2.y * SIN(THETA);

     返回结果;
 }

 无效OGLENGINEFUNCTIONS :: GenerateLinePoly(常量的std ::矢量<的std ::矢量< GLdouble>>&安培;输入,
     的std ::矢量< GLfloat> &放大器;输出,INT宽)
 {
     output.clear();
     如果(input.size()2)
     {
         返回;
     }



 浮W =宽度/ 2.0f;

 //在glBegin(GL_TRIANGLES);
 用于(为size_t I = 0; I< input.size() -  1 ++ I)
 {
     POINTFLOAT CUR;
     cur.x =输入[I] [0];
     cur.y =输入[Ⅰ] [1];


     POINTFLOAT NXT;
     nxt.x =输入[1 + 1] [0];
     nxt.y =输入[1 + 1] [1];

     POINTFLOAT B:
     b.x = nxt.x  -  cur.x;
     b.y = nxt.y  -  cur.y;

     B =标准化(B);



     POINTFLOAT b_perp;
     b_perp.x = -b.y;
     b_perp.y = b.x;


     POINTFLOAT P0;
     POINTFLOAT P1;
     POINTFLOAT P2;
     POINTFLOAT P3;

     p0.x = cur.x + b_perp.x *宽;
     p0.y = cur.y + b_perp.y *宽;

     p1.x = cur.x  -  b_perp.x *宽;
     p1.y = cur.y  -  b_perp.y *宽;

     p2.x = nxt.x + b_perp.x *宽;
     p2.y = nxt.y + b_perp.y *宽;

     p3.x = nxt.x  -  b_perp.x *宽;
     p3.y = nxt.y  -  b_perp.y *宽;

     output.push_back(p0.x);
     output.push_back(p0.y);
     output.push_back(p1.x);
     output.push_back(p1.y);
    output.push_back(p2.x);
    output.push_back(p2.y);

    output.push_back(p2.x);
    output.push_back(p2.y);
    output.push_back(p1.x);
    output.push_back(p1.y);
    output.push_back(p3.x);
    output.push_back(p3.y);



     //只做联接当我们有一个PRV
     如果(我== 0)继续;

    POINTFLOAT PRV;
    prv.x =输入[I-1] [0];
    prv.y =输入[I-1] [1];

     POINTFLOAT一个;
     a.x = prv.x  -  cur.x;
     a.y = prv.y  -  cur.y;

     一个=规范化(一);

     POINTFLOAT a_perp;
     a_perp.x = a.y;
     a_perp.y = -a.x;

     浮DET = a.x * b.y  -  b.x * a.y;
     如果(DET大于0)
     {
         a_perp.x = -a_perp.x;
         a_perp.y = -a_perp.y;

         b_perp.x = -b_perp.x;
         b_perp.y = -b_perp.y;
     }

     // TODO:做内斜切计算

     //前后翻页法线并计算圆形连接点
     a_perp.x = -a_perp.x;
     a_perp.y = -a_perp.y;

     b_perp.x = -b_perp.x;
     b_perp.y = -b_perp.y;

     为size_t num_pts = 4;

     的std ::矢量< POINTFLOAT>轮(1 + num_pts + 1);
     POINTFLOAT NC;
    nc.x = cur.x +(a_perp.x *宽);
    nc.y = cur.y +(a_perp.y *宽);

     round.front()= NC;

     nc.x = cur.x +(b_perp.x *宽);
     nc.y = cur.y +(b_perp.y *宽);

     round.back()= NC;

     用于(为size_t J = 1; J< num_pts + 1,+ j)条
     {
         浮动T =(浮点)焦/(浮动)(num_pts + 1);
         如果(DET大于0)
         {
             POINTFLOAT宁;
             宁= slerp2d(b_perp,a_perp,1.0F-T);
             nin.x * = W;
             nin.y * = W;

             nin.x + = cur.x;
             nin.y + = cur.y;

              圆[J] =宁;
         }
         其他
         {
             POINTFLOAT宁;
             宁= slerp2d(a_perp,b_perp,T);
             nin.x * = W;
             nin.y * = W;

             nin.x + = cur.x;
             nin.y + = cur.y;

             圆[J] =宁;
         }
     }

     用于(为size_t J = 0; J< round.size() -  1; ++ j)条
     {

         output.push_back(cur.x);
         output.push_back(cur.y);

         如果(DET大于0)
         {
             output.push_back(圆[J + 1] .X);
             output.push_back(圆[J + 1] .Y);
             output.push_back(圆[J] .X);
             output.push_back(圆[J] .Y);
         }
         其他
         {

             output.push_back(圆[J] .X);
             output.push_back(圆[J] .Y);

             output.push_back(圆[J + 1] .X);
             output.push_back(圆[J + 1] .Y);
         }
     }
 }


 }
 

解决方案

需要征书面,但核心业务应该很容易映射到任何载体类,你正在使用。

  // V0和V1被归
// t的0和1之间变化
// http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
Vector2f slerp2d(常量Vector2f和放大器; V0,常量Vector2f和放大器; V1,浮动T)
{
    浮点= v0.dot(V1);
    如果(DOT< -1.0F)点= -1.0F;
    如果(DOT> 1.0F)点= 1.0F;

    浮theta_0 = ACOS(点);
    浮THETA = theta_0 * T;

    Vector2f V2(-v0.y(),v0.x());

    返程(V0 * COS(THETA)+ V2 * SIN(THETA));
}


无效glPolyline(常量矢量< Vector2f>&安培;折线,浮动宽度)
{
    如果(polyline.size()2)返回;
    浮W =宽度/ 2.0f;

    在glBegin(GL_TRIANGLES);
    用于(为size_t I = 0; I< polyline.size() -  1 ++ I)
    {
        常量Vector2f和放大器; CUR =折线[I]
        常量Vector2f和放大器; NXT =折线[I + 1];

        Vector2f B =(NXT  -  CUR).normalized();
        Vector2f b_perp(-b.y(),b.x());

        Vector2f P0(CUR + b_perp *宽);
        Vector2f P1(CUR  -  b_perp *宽);
        Vector2f P2(NXT + b_perp *宽);
        Vector2f P3(NXT  -  b_perp *宽);

        //第一个三角形
        glVertex2fv(p0.data());
        glVertex2fv(p1.data());
        glVertex2fv(p2.data());
        //第二个三角形
        glVertex2fv(p2.data());
        glVertex2fv(p1.data());
        glVertex2fv(p3.data());

        //只做联接当我们有一个PRV
        如果(我== 0)继续;

        常量Vector2f和放大器; PRV =折线[I-1];
        Vector2f A =(PRV  -  CUR).normalized();
        Vector2f a_perp(a.y(),-a.x());

        浮DET = a.x()* b.y() -  b.x()* a.y();
        如果(DET大于0)
        {
            a_perp = -a_perp;
            b_perp = -b_perp;
        }

        // TODO:做内斜切计算

        //前后翻页法线并计算圆形连接点
        a_perp = -a_perp;
        b_perp = -b_perp;

        为size_t num_pts = 4;
        矢量< Vector2f>轮(1 + num_pts + 1);
        为(为size_t J = 0; J&其中; = num_pts + 1; ++ j)条
        {
            浮动T =(浮点)焦/(浮动)(num_pts + 1);
            如果(DET大于0)
                圆[J] = CUR +(slerp2d(b_perp,a_perp,1.0英尺)*宽);
            其他
                圆[J] = CUR +(slerp2d(a_perp,b_perp,T)*宽);
        }

        用于(为size_t J = 0; J< round.size() -  1; ++ j)条
        {
            glVertex2fv(cur.data());
            如果(DET大于0)
            {
                glVertex2fv(圆[J + 1]的.data());
                glVertex2fv(圆[J + 0]的.data());
            }
            其他
            {
                glVertex2fv(圆[J + 0]的.data());
                glVertex2fv(圆[J + 1]的.data());
            }
        }
    }
    glEnd();
}
 

编辑:截图:

I'm using the algorithm below to generate quads which are then rendered to make an outline like this

http://img810.imageshack.us/img810/8530/uhohz.png

The problem as seen on the image, is that sometimes the lines are too thin when they should always be the same width. My algorithm finds the 4 verticies for the first one then the top 2 verticies of the next ones are the bottom 2 of the previous. This creates connected lines, but it seems to not always work. How could I fix this?

This is my algorithm:

 void OGLENGINEFUNCTIONS::GenerateLinePoly(const std::vector<std::vector<GLdouble>> &input,
     std::vector<GLfloat> &output, int width)
 {

     output.clear();
     if(input.size() < 2)
     {
         return;
     }
     int temp;
     float dirlen;
     float perplen;
     POINTFLOAT start;
     POINTFLOAT end;
     POINTFLOAT dir;
     POINTFLOAT ndir;
     POINTFLOAT perp;
     POINTFLOAT nperp;

     POINTFLOAT perpoffset;
     POINTFLOAT diroffset;

     POINTFLOAT p0, p1, p2, p3;

     for(unsigned int i = 0; i < input.size() - 1; ++i)
     {

         start.x = static_cast<float>(input[i][0]);
         start.y = static_cast<float>(input[i][1]);

         end.x = static_cast<float>(input[i + 1][0]);
         end.y = static_cast<float>(input[i + 1][1]);

         dir.x = end.x - start.x;
         dir.y = end.y - start.y;

         dirlen = sqrt((dir.x * dir.x) + (dir.y * dir.y));

         ndir.x = static_cast<float>(dir.x * 1.0 / dirlen);
         ndir.y = static_cast<float>(dir.y * 1.0 / dirlen);

         perp.x = dir.y;
         perp.y = -dir.x;

         perplen = sqrt((perp.x * perp.x) + (perp.y * perp.y));

         nperp.x = static_cast<float>(perp.x * 1.0 / perplen);
         nperp.y = static_cast<float>(perp.y * 1.0 / perplen);

         perpoffset.x = static_cast<float>(nperp.x * width * 0.5);
         perpoffset.y = static_cast<float>(nperp.y * width * 0.5);

         diroffset.x = static_cast<float>(ndir.x * 0 * 0.5);
         diroffset.y = static_cast<float>(ndir.y * 0 * 0.5);

            // p0 = start + perpoffset - diroffset
             //p1 = start - perpoffset - diroffset
             //p2 = end + perpoffset + diroffset
            // p3 = end - perpoffset + diroffset 

         p0.x = start.x + perpoffset.x - diroffset.x;
         p0.y = start.y + perpoffset.y - diroffset.y;

         p1.x = start.x - perpoffset.x - diroffset.x;
         p1.y = start.y - perpoffset.y - diroffset.y;

         if(i > 0)
         {
             temp = (8 * (i - 1));
             p2.x = output[temp + 2];
             p2.y = output[temp + 3];
             p3.x = output[temp + 4];
             p3.y = output[temp + 5];

         }
         else
         {
             p2.x = end.x + perpoffset.x + diroffset.x;
             p2.y = end.y + perpoffset.y + diroffset.y;

             p3.x = end.x - perpoffset.x + diroffset.x;
             p3.y = end.y - perpoffset.y + diroffset.y;
         }



         output.push_back(p2.x);
         output.push_back(p2.y);
         output.push_back(p0.x);
         output.push_back(p0.y);
         output.push_back(p1.x);
         output.push_back(p1.y);
         output.push_back(p3.x);
         output.push_back(p3.y);

     }
 }

Thanks

Edit:

 POINTFLOAT multiply(const POINTFLOAT &a, float b)
 {
     POINTFLOAT result;
     result.x = a.x * b;
     result.y = a.y * b;
     return result;
 }

 POINTFLOAT normalize(const POINTFLOAT &a)
 {
     return multiply(a, 1.0f/sqrt(a.x*a.x+a.y*a.y));
 }


 POINTFLOAT slerp2d( const POINTFLOAT v0, 
     const POINTFLOAT v1, float t )
 {
     float dot = (v0.x * v1.x + v1.y * v1.y);
     if( dot < -1.0f ) dot = -1.0f;
     if( dot > 1.0f ) dot = 1.0f;

     float theta_0 = acos( dot );
     float theta = theta_0 * t;

     POINTFLOAT v2;
     v2.x = -v0.y;
     v2.y = v0.x;

     POINTFLOAT result;
     result.x = v0.x * cos(theta) + v2.x * sin(theta);
     result.y = v0.y * cos(theta) + v2.y * sin(theta);

     return result;
 }

 void OGLENGINEFUNCTIONS::GenerateLinePoly(const std::vector<std::vector<GLdouble> > &input,
     std::vector<GLfloat> &output, int width)
 {
     output.clear();
     if(input.size() < 2)
     {
         return;
     }



 float w = width / 2.0f;

 //glBegin(GL_TRIANGLES);
 for( size_t i = 0; i < input.size()-1; ++i )
 {
     POINTFLOAT cur;
     cur.x = input[i][0];
     cur.y = input[i][1];


     POINTFLOAT nxt;
     nxt.x = input[i+1][0];
     nxt.y = input[i+1][1];

     POINTFLOAT b;
     b.x = nxt.x - cur.x;
     b.y = nxt.y - cur.y;

     b = normalize(b);



     POINTFLOAT b_perp;
     b_perp.x = -b.y;
     b_perp.y = b.x;


     POINTFLOAT p0;
     POINTFLOAT p1;
     POINTFLOAT p2;
     POINTFLOAT p3;

     p0.x = cur.x + b_perp.x * w;
     p0.y = cur.y + b_perp.y * w;

     p1.x = cur.x - b_perp.x * w;
     p1.y = cur.y - b_perp.y * w;

     p2.x = nxt.x + b_perp.x * w;
     p2.y = nxt.y + b_perp.y * w;

     p3.x = nxt.x - b_perp.x * w;
     p3.y = nxt.y - b_perp.y * w;

     output.push_back(p0.x);
     output.push_back(p0.y);
     output.push_back(p1.x);
     output.push_back(p1.y);
    output.push_back(p2.x);
    output.push_back(p2.y);

    output.push_back(p2.x);
    output.push_back(p2.y);
    output.push_back(p1.x);
    output.push_back(p1.y);
    output.push_back(p3.x);
    output.push_back(p3.y);



     // only do joins when we have a prv
     if( i == 0 ) continue;

    POINTFLOAT prv;
    prv.x = input[i-1][0];
    prv.y = input[i-1][1];

     POINTFLOAT a;
     a.x = prv.x - cur.x;
     a.y = prv.y - cur.y;

     a = normalize(a);

     POINTFLOAT a_perp;
     a_perp.x = a.y;
     a_perp.y = -a.x;

     float det = a.x * b.y  - b.x * a.y;
     if( det > 0 )
     {
         a_perp.x = -a_perp.x;
         a_perp.y = -a_perp.y;

         b_perp.x = -b_perp.x;
         b_perp.y = -b_perp.y;
     }

     // TODO: do inner miter calculation

     // flip around normals and calculate round join points
     a_perp.x = -a_perp.x;
     a_perp.y = -a_perp.y;

     b_perp.x = -b_perp.x;
     b_perp.y = -b_perp.y;

     size_t num_pts = 4;

     std::vector< POINTFLOAT> round( 1 + num_pts + 1 );
     POINTFLOAT nc;
    nc.x = cur.x + (a_perp.x * w);
    nc.y = cur.y + (a_perp.y * w);

     round.front() = nc;

     nc.x = cur.x + (b_perp.x * w);
     nc.y = cur.y + (b_perp.y * w);

     round.back() = nc;

     for( size_t j = 1; j < num_pts+1; ++j )
     {
         float t = (float)j/(float)(num_pts+1);
         if( det > 0 )
         {
             POINTFLOAT nin;
             nin = slerp2d( b_perp, a_perp, 1.0f-t );
             nin.x *= w;
             nin.y *= w;

             nin.x += cur.x;
             nin.y += cur.y;

              round[j] = nin;
         }
         else
         {
             POINTFLOAT nin;
             nin = slerp2d( a_perp, b_perp, t );
             nin.x *= w;
             nin.y *= w;

             nin.x += cur.x;
             nin.y += cur.y;

             round[j] = nin;
         }
     }

     for( size_t j = 0; j < round.size()-1; ++j )
     {

         output.push_back(cur.x);
         output.push_back(cur.y);

         if( det > 0 )
         {
             output.push_back(round[j + 1].x);
             output.push_back(round[j + 1].y);
             output.push_back(round[j].x);
             output.push_back(round[j].y);
         }
         else
         {

             output.push_back(round[j].x);
             output.push_back(round[j].y);

             output.push_back(round[j + 1].x);
             output.push_back(round[j + 1].y);
         }
     }
 }


 }

解决方案

Requires Eigen as written, but the core operations should map easily to whatever vector class you're using.

// v0 and v1 are normalized
// t can vary between 0 and 1
// http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
Vector2f slerp2d( const Vector2f& v0, const Vector2f& v1, float t )
{
    float dot = v0.dot(v1);
    if( dot < -1.0f ) dot = -1.0f;
    if( dot > 1.0f ) dot = 1.0f;

    float theta_0 = acos( dot );
    float theta = theta_0 * t;

    Vector2f v2( -v0.y(), v0.x() );

    return ( v0*cos(theta) + v2*sin(theta) );
}


void glPolyline( const vector<Vector2f>& polyline, float width )
{
    if( polyline.size() < 2 ) return;
    float w = width / 2.0f;

    glBegin(GL_TRIANGLES);
    for( size_t i = 0; i < polyline.size()-1; ++i )
    {
        const Vector2f& cur = polyline[ i ];
        const Vector2f& nxt = polyline[i+1];

        Vector2f b = (nxt - cur).normalized();
        Vector2f b_perp( -b.y(), b.x() );

        Vector2f p0( cur + b_perp*w );
        Vector2f p1( cur - b_perp*w );
        Vector2f p2( nxt + b_perp*w );
        Vector2f p3( nxt - b_perp*w );

        // first triangle
        glVertex2fv( p0.data() );
        glVertex2fv( p1.data() );
        glVertex2fv( p2.data() );
        // second triangle
        glVertex2fv( p2.data() );
        glVertex2fv( p1.data() );
        glVertex2fv( p3.data() );

        // only do joins when we have a prv
        if( i == 0 ) continue;

        const Vector2f& prv = polyline[i-1];
        Vector2f a = (prv - cur).normalized();
        Vector2f a_perp( a.y(), -a.x() );

        float det = a.x()*b.y() - b.x()*a.y();
        if( det > 0 )
        {
            a_perp = -a_perp;
            b_perp = -b_perp;
        }

        // TODO: do inner miter calculation

        // flip around normals and calculate round join points
        a_perp = -a_perp;
        b_perp = -b_perp;

        size_t num_pts = 4;
        vector< Vector2f > round( 1 + num_pts + 1 );
        for( size_t j = 0; j <= num_pts+1; ++j )
        {
            float t = (float)j/(float)(num_pts+1);
            if( det > 0 )
                round[j] = cur + (slerp2d( b_perp, a_perp, 1.0f-t ) * w);
            else
                round[j] = cur + (slerp2d( a_perp, b_perp, t ) * w);
        }

        for( size_t j = 0; j < round.size()-1; ++j )
        {
            glVertex2fv( cur.data() );
            if( det > 0 )
            {
                glVertex2fv( round[j+1].data() );
                glVertex2fv( round[j+0].data() );
            }
            else
            {
                glVertex2fv( round[j+0].data() );
                glVertex2fv( round[j+1].data() );
            }
        }
    }
    glEnd();
}

EDIT: Screenshots:

 
精彩推荐
图片推荐