多边形边勾勒并不总是正确的 [英] Edges on polygon outlines not always correct
问题描述
我用下面的算法生成的四边形然后将其渲染,使这样一个大纲
所看到的图像上的问题是,有时线条过细时,他们应始终是相同的宽度。我的算法找到了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
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:
这篇关于多边形边勾勒并不总是正确的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!