我用下面的算法生成的四边形然后将其渲染,使这样一个大纲
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: