本文主要讨论将线扩展成2d线面的算法
如上图所示将p0p1这条直线 扩展成面 很简单
Vec2f line = p1 - p0
Vec2f normal = Vec2f( -line.y, line.x).normalized().
Vec2f a = p0 - thickness * normal;
Vec2f b = p0 + thickness * normal;
Vec2f c = p1 - thickness * normal;
Vec2f d = p1 + thickness * normal;
如果是直线这么处理就可以了,但是如果有多段线,我们还需要计算交点的地方
首先我们先求出 t
Vec2f t = ( (p2-p1).normalized() + (p1-p0).normalized() ).normalized()
其次 在求出m
Vec2f m = Vec2f( -t.y,t.x )
最后再求出d的长度
float d = thickness / miter.dot( normal )
根据上述获得内容就能得到想要的所有顶点,然后根据这些顶点构建三角面片即可
代码大致如下:
效果大致如下
请注意 以上过程在两段线夹角比较小的时候会出问题,所以请慎用..
geos库中 也有方法提供
测试代码如下
注意 以上生成的顶点数组 还要进行三角剖分(推荐使用gpc),然后再以trianglelist的绘制,或者用以下的算法构建顶点数组
如果是直线这么处理就可以了,但是如果有多段线,我们还需要计算交点的地方
首先我们先求出 t
Vec2f t = ( (p2-p1).normalized() + (p1-p0).normalized() ).normalized()
其次 在求出m
Vec2f m = Vec2f( -t.y,t.x )
最后再求出d的长度
float d = thickness / miter.dot( normal )
根据上述获得内容就能得到想要的所有顶点,然后根据这些顶点构建三角面片即可
代码大致如下:
void trianglePolyLine( const Vec2f &p0, const Vec2f &p1, const Vec2f &p2, const Vec2f &p3 , PosArray &vtx, IndexArray &indices,double radius)
{
if(p1 == p2) return;
Vec2f line = (p2 - p1).normalize();
Vec2f normal = Vec2f(-line.Y, line.X).normalize();
Vec2f tangent1 = (p0 == p1) ? line : ((p1-p0).normalize() + line).normalize();
Vec2f tangent2 = (p2 == p3) ? line : ((p3-p2).normalize() + line).normalize();
Vec2f miter1 = Vec2f(-tangent1.Y, tangent1.X);
Vec2f miter2 = Vec2f(-tangent2.Y, tangent2.X);
float length1 = radius / normal.dotProduct(miter1);
float length2 = radius / normal.dotProduct(miter2);
if(true) {
Vec2f bg1(p1 - length1 * miter1);
Vec2f ed1(p2 - length2 * miter2);
Vec2f bg2(p1 + length1 * miter1);
Vec2f ed2(p2 + length2 * miter2);
int len = vtx.size();
vtx.push_back(Vector3df(bg1.X, bg1.Y,0));
vtx.push_back(Vector3df(ed1.X, ed1.Y,0));
vtx.push_back(Vector3df(bg2.X, bg2.Y,0));
vtx.push_back(Vector3df(ed2.X, ed2.Y,0));
indices.push_back( len + 0 );
indices.push_back( len + 1 );
indices.push_back( len + 2 );
indices.push_back( len + 1 );
indices.push_back( len + 2 );
indices.push_back( len + 3 );
}
}
调用代码如下
for(int i = 0;i<vertexes.size();++i) {
int a = ((i-1) < 0) ? 0 : (i-1);
int b = i;
int c = ((i+1) >= vertexes.size()) ? vertexes.size()-1 : (i+1);
int d = ((i+2) >= vertexes.size()) ? vertexes.size()-1 : (i+2);
trianglePolyLine( vertexes[a], vertexes[b], vertexes[c], vertexis[d],pts,indices,raidus );
}
vertexes表示多段线,mesh表示构建的顶点数组 讲次数组直接以GL_Lines绘制
效果大致如下
请注意 以上过程在两段线夹角比较小的时候会出问题,所以请慎用..
geos库中 也有方法提供
测试代码如下
static void createPolyline(PosArray &arr)
{
const float len = 100.0;
geos::geom::GeometryFactory factroy;
CoordinateArraySequenceFactory csf;
CoordinateSequence *cs1 = (csf.create(3,2));
cs1->setAt(Coordinate(-len,0,0),0);
cs1->setAt(Coordinate(-len,len,0),1);
cs1->setAt(Coordinate(len,len,0),2);
std::auto_ptr<LineString> ring1(factroy.createLineString(cs1)) ;
std::auto_ptr<Geometry> p(ring1->buffer(10));
std::auto_ptr<CoordinateSequence> pcs(p->getCoordinates());
for(int i = 0; i < pcs->getSize(); ++i)
{
Coordinate co = pcs->getAt(i);
arr.push_back(Vector3df(co.x,co.y,0));
}
}
注意 以上生成的顶点数组 还要进行三角剖分(推荐使用gpc),然后再以trianglelist的绘制,或者用以下的算法构建顶点数组
struct SDrawVertexColor
{
Vector3df pos;
SColor4f color;
};
typedef std::vector<SDrawVertexColor> PosClrArray;
tpyedef std::vector<int> IndexArray;
void PolyLine( const Vector3df *pPoints, int nPoints, PosClrArray *outarray,
u32 color, IndexArray *idx, float lineWidth,int zidx /*=0*/)
{
if(NULL == pPoints || nPoints<2 || NULL == outarray || lineWidth < 1e-6)
return;
u32 i_idx = outarray->size();
Vector2df a,b,aR,aL,bR,bL;
Vector2df abP,abV,tmp;
Vector3df LindS1[10];
Vector3df LindE1[10];
SDrawVertexColor vertexAcc;
vertexAcc.color =SColor4f(color);
for ( u32 i=1; i < nPoints; ++i )
{
b = ToVector2d(pPoints[i-1]);
a = ToVector2d(pPoints[i]);
abP = a-b;
abP.normalize();
abV = rotateBy90(abP);
aR = a + abV * lineWidth;
aL = a - abV * lineWidth;
bR = b + abV * lineWidth;
bL = b - abV * lineWidth;
// 添加第一个点的左右点
LindS1[0] = ToVector3d(b,zidx);
LindS1[1] = ToVector3d(bR,zidx);
LindS1[2] = ToVector3d(bL,zidx);
LindS1[3] = ToVector3d(b - abP * lineWidth,zidx);
LindS1[4] = ToVector3d(b + (-abP+abV)*0.707f * lineWidth,zidx);
LindS1[5] = ToVector3d(b + (-abP-abV)*0.707f * lineWidth,zidx);
LindS1[6] = ToVector3d(b + ((-abP+abV)*0.707f+abV)*0.541f *lineWidth,zidx);
LindS1[7] = ToVector3d(b + ((-abP+abV)*0.707f-abP)*0.541f *lineWidth,zidx);
LindS1[8] = ToVector3d(b + ((-abP-abV)*0.707f-abP)*0.541f *lineWidth,zidx);
LindS1[9] = ToVector3d(b + ((-abP-abV)*0.707f-abV)*0.541f *lineWidth,zidx);
// 添加最后一个点的左右点
LindE1[0] = ToVector3d(a,zidx);
LindE1[1] = ToVector3d(aR,zidx);
LindE1[2] = ToVector3d(aL,zidx);
LindE1[3] = ToVector3d(a + abP * lineWidth,zidx);
LindE1[4] = ToVector3d(a + (abP-abV)*0.707f * lineWidth,zidx);
LindE1[5] = ToVector3d(a + (abP+abV)*0.707f * lineWidth,zidx);
LindE1[6] = ToVector3d(a + ((abP-abV)*0.707f-abV)*0.541f *lineWidth,zidx);
LindE1[7] = ToVector3d(a + ((abP-abV)*0.707f+abP)*0.541f *lineWidth,zidx);
LindE1[8] = ToVector3d(a + ((abP+abV)*0.707f+abP)*0.541f *lineWidth,zidx);
LindE1[9] = ToVector3d(a + ((abP+abV)*0.707f+abV)*0.541f *lineWidth,zidx);
for (int j=0;j<10;++j)
{
vertexAcc.pos = LindS1[j];outarray->push_back(vertexAcc);
}
idx->push_back(u32(i_idx + 1));
idx->push_back(u32(i_idx + 0));
idx->push_back(u32(i_idx + 6));
idx->push_back(u32(i_idx + 6));
idx->push_back(u32(i_idx + 0));
idx->push_back(u32(i_idx + 4));
idx->push_back(u32(i_idx + 4));
idx->push_back(u32(i_idx + 0));
idx->push_back(u32(i_idx + 7));
idx->push_back(u32(i_idx + 7));
idx->push_back(u32(i_idx + 0));
idx->push_back(u32(i_idx + 3));
idx->push_back(u32(i_idx + 3));
idx->push_back(u32(i_idx + 0));
idx->push_back(u32(i_idx + 8));
idx->push_back(u32(i_idx + 8));
idx->push_back(u32(i_idx + 0));
idx->push_back(u32(i_idx + 5));
idx->push_back(u32(i_idx + 5));
idx->push_back(u32(i_idx + 0));
idx->push_back(u32(i_idx + 9));
idx->push_back(u32(i_idx + 9));
idx->push_back(u32(i_idx + 0));
idx->push_back(u32(i_idx + 2));
u32 m_idx = i_idx+10;
for (int j=0;j<10;++j)
{
vertexAcc.pos = LindE1[j];outarray->push_back(vertexAcc);
}
idx->push_back(u32(m_idx + 1));
idx->push_back(u32(m_idx + 0));
idx->push_back(u32(m_idx + 9));
idx->push_back(u32(m_idx + 9));
idx->push_back(u32(m_idx + 0));
idx->push_back(u32(m_idx + 5));
idx->push_back(u32(m_idx + 5));
idx->push_back(u32(m_idx + 0));
idx->push_back(u32(m_idx + 8));
idx->push_back(u32(m_idx + 8));
idx->push_back(u32(m_idx + 0));
idx->push_back(u32(m_idx + 3));
idx->push_back(u32(m_idx + 3));
idx->push_back(u32(m_idx + 0));
idx->push_back(u32(m_idx + 7));
idx->push_back(u32(m_idx + 7));
idx->push_back(u32(m_idx + 0));
idx->push_back(u32(m_idx + 4));
idx->push_back(u32(m_idx + 4));
idx->push_back(u32(m_idx + 0));
idx->push_back(u32(m_idx + 6));
idx->push_back(u32(m_idx + 6));
idx->push_back(u32(m_idx + 0));
idx->push_back(u32(m_idx + 2));
idx->push_back(u32(i_idx + 1));
idx->push_back(u32(i_idx + 12));
idx->push_back(u32(i_idx + 11));
idx->push_back(u32(i_idx + 1));
idx->push_back(u32(i_idx + 2));
idx->push_back(u32(i_idx + 12));
i_idx += 20;
}
}