





具体的数据结构采用半边数据结构实现,希望对于学习CAD/CG方面的朋友有所帮助~~~
具体的实现功能是:
通过绘制一个基本的面,然后通过该面通过指定的向量和距离就可以扫成为一个体。
具体的实现关键代码为:
CSolid* CEulerDoc::mvfs(GLdouble *point)
{
CSolid *newSolid;
CFace *newFace;
CLoop *newLoop;
CVertex *newVert;
newSolid = new CSolid;
newFace = new CFace;
newLoop = new CLoop;
newVert = new CVertex;
// Set the coordinate of the new vertex
newVert->SetCoord(point);
// Add the new face to the new solid
newSolid->AddFace(newFace);
// Add the new vertex to the new solid
newSolid->AddVertex(newVert);
// Add the new loop to the new face
newFace->AddLoop(newLoop);
return newSolid;
}
CHalfEdge* CEulerDoc::mev(GLdouble *point1, GLdouble *point2, CLoop* lp)
{
CSolid *pSolid = lp->host_f->host_s;
CVertex *v1, *newVert;
CEdge *newEdge;
CHalfEdge *he1, *he2;
newVert = new CVertex;
newEdge = new CEdge;
he1 = new CHalfEdge;
he2 = new CHalfEdge;
// Find the start vertex of the edge
v1 = pSolid->FindVertex(point1);
if(!v1)
{
AfxMessageBox("Can't find the point1!");
return NULL;
}
// Set the coordinate of the new vertex
newVert->SetCoord(point2);
// Set v1 as the start vertex of halfedge1
he1->SetVertex(v1);
// Set v2 as the start vertex of halfedge2
he2->SetVertex(newVert);
// Add two new halfedges to the loop
lp->AddHalfEdge(he1, he2);
// Set the new edge to new halfedges
he1->edge = he2->edge = newEdge;
newEdge->he1 = he1;
newEdge->he2 = he2;
// Add the new edge to the solid
pSolid->AddEdge(newEdge);
// Add the new vertex to the solid
pSolid->AddVertex(newVert);
return he1;
}
CLoop* CEulerDoc::mef(GLdouble *point1, GLdouble *point2, CLoop* lp)
{
CSolid *pSolid = lp->host_f->host_s;
CVertex *v1, *v2;
// Find the two given vertex
v1 = pSolid->FindVertex(point1);
if(!v1)
{
AfxMessageBox("Can't find the point1!");
return NULL;
}
v2 = pSolid->FindVertex(point2);
if(!v2)
{
AfxMessageBox("Can't find the point2!");
return NULL;
}
// two vertex must in the same loop
if(!lp->IsVertexIn(v1) && !lp->IsVertexIn(v2))
{
AfxMessageBox("该两点不位于同一个loop中");
return NULL;
}
CFace *newFace;
CLoop *newLoop;
CEdge *newEdge;
CHalfEdge *he1, *he2, *temphe1, *temphe2;
newFace = new CFace;
newLoop = new CLoop;
newEdge = new CEdge;
he1 = new CHalfEdge;
he2 = new CHalfEdge;
// Find two halfedges start with two vertexs
temphe1 = lp->FindHostHalfEdge(v1);
temphe2 = lp->FindHostHalfEdge(v2);
// Change halfedges' host loop to new loop
temphe1->prev->next = NULL;
newLoop->AddHalfEdge(temphe1, NULL);
while(temphe1 != temphe2)
temphe1 = temphe1->next;
temphe1->prev->next = he2;
he2->prev = temphe1->prev;
he2->next = newLoop->GetHalfEdgeHead();
newLoop->GetHalfEdgeHead()->prev = he2;
temphe1->prev = NULL;
// Add halfedge start with vertex one to the old loop % close this loop
lp->AddHalfEdge(he1, NULL);
he1->next = temphe2;
temphe2->prev = he1;
// Set two halfedges' start vertex and adjacent
he1->SetVertex(v1);
he2->SetVertex(v2);
he1->adj = he2;
he2->adj = he1;
// Set the new edge and add to the solid
newEdge->he1 = he1;
newEdge->he2 = he2;
pSolid->AddEdge(newEdge);
// Add new face to the solid
pSolid->AddFace(newFace);
// Add new loop to the new face
newFace->AddLoop(newLoop);
return newLoop;
}
CLoop* CEulerDoc::kemr(GLdouble *point1, GLdouble *point2, CLoop* lp)
{
CSolid *pSolid = lp->host_f->host_s;
CVertex *v1, *v2;
// Find the two given vertex
v1 = pSolid->FindVertex(point1);
if(!v1)
{
AfxMessageBox("Can't find the point1!");
return NULL;
}
v2 = pSolid->FindVertex(point2);
if(!v2)
{
AfxMessageBox("Can't find the point2!");
return NULL;
}
// two vertex must in the same loop
if(!lp->IsVertexIn(v1) && !lp->IsVertexIn(v2))
return NULL;
CLoop *newLoop;
CHalfEdge *he1, *he2;
CEdge *edge;
newLoop = new CLoop;
// Find two halfedges start with two vertexs
he1 = lp->GetHalfEdgeHead();
while(he1)
{
if(he1->GetVertex() == v1 && he1->next->GetVertex() == v2)
break;
he1 = he1->next;
}
he2 = he1->adj;
// Make a newloop and delete two halfedges
newLoop->AddHalfEdge(he1->next, NULL);
he2->prev->next = he1->next;
he1->next->prev = he2->prev;
he1->prev->next = he2->next;
he2->next->prev = he1->prev;
he1->next = he1->prev = he2->next = he2->prev = NULL;
delete he1;
delete he2;
// Find the edge and delete it
edge = pSolid->GetEdgeHead();
while(edge)
{
if(edge->he1 == he1)
break;
edge = edge->next;
}
edge->prev->next = edge->next;
edge->next->prev = edge->prev;
edge->next = edge->prev = NULL;
// Add new loop to the face
lp->host_f->AddLoop(newLoop);
return newLoop;
}
void CEulerDoc::kfmrh(CLoop* outlp, CLoop* lp)
{
if(!outlp || !lp)
{
AfxMessageBox("The loop is NULL!");
return;
}
CSolid *pSolid = lp->host_f->host_s;
// Add the loop to the face
outlp->host_f->AddLoop(lp);
// Get the face need to be killed
CFace* pFace = pSolid->GetFaceEnd();
// Delete it
pFace->prev->next = NULL;
delete pFace;
}
void CEulerDoc::sweep(CFace* pFace, GLdouble dx, GLdouble dy, GLdouble dz)
{
CFace *pEnd;
CHalfEdge *pHe, *pHead;
CLoop *pLoop, *newLoop, *pOutLoop;
GLdouble *pPoint;
GLdouble point1[3], point2[3], first[3], last[3];
BOOL bOut = TRUE; // Show that if is the outloop of the top face
// Remember the last inside loop's face
pEnd = pFace->host_s->GetFaceEnd();
// Start with the second face, because the first face is for buttom
pFace = pFace->next;
while(pFace)
{
// Get the first point of the loop
newLoop = pLoop = pFace->GetLoopHead();
pHe = pHead = pLoop->GetHalfEdgeHead();
pPoint = pHe->GetVertex()->vcoord;
point1[0] = pPoint[0];
point1[1] = pPoint[1];
point1[2] = pPoint[2];
// first[] is used for close the top face
// last[] is used for side face
first[0] = last[0] = point2[0] = point1[0] + dx;
first[1] = last[1] = point2[1] = point1[1] + dy;
first[2] = last[2] = point2[2] = point1[2] + dz;
// Make the new edge
mev(point1, point2, pLoop);
// Goto next halfedge
pHe = pHe->next;
while(pHe->GetVertex() != pHead->GetVertex())
{
// Get the point
pPoint = pHe->GetVertex()->vcoord;
point1[0] = pPoint[0];
point1[1] = pPoint[1];
point1[2] = pPoint[2];
point2[0] = point1[0] + dx;
point2[1] = point1[1] + dy;
point2[2] = point1[2] + dz;
// Make the new edge
mev(point1, point2, newLoop);
// Make a new side face
newLoop = mef(point2, last, newLoop);
// Remember the lastest point
last[0] = point2[0];
last[1] = point2[1];
last[2] = point2[2];
pHe = pHe->next;
}
// Close the top face
newLoop = mef(first, last, newLoop);
if(bOut)
{
pOutLoop = newLoop;
bOut = FALSE;
}
else
kfmrh(pOutLoop, newLoop);
if(pFace == pEnd)
break;
pFace = pFace->next;
}
}
CSolid* CEulerDoc::MakeSolid(GLdouble point[][3], GLint* pointnum, GLint loopnum, GLdouble* vector, GLdouble len)
{
CSolid *pSolid, *pTemp;
CLoop *pLoop, *pHead;
int i, j, pos;
// Create the solid
pSolid = mvfs(point[1]);
pHead = pLoop = pSolid->GetFaceHead()->GetLoopHead();
// Create the out loop
for(i = 1;i < pointnum[1]-1;i ++)
{
mev(point[i], point[i+1], pLoop);
}
mef(point[i], point[1], pLoop);
pos = i+1;
// Create the inside loops
for(i = 2;i < loopnum; i ++)
{
mev(point[1], point[pos+1], pHead);
for(j = 1;j < pointnum[i]-1;j ++)
{
mev(point[pos+j], point[pos+j+1], pHead);
}
mef(point[pos+j], point[pos+1], pHead);
kemr(point[1], point[pos+1], pHead);
pos = pos+j+1;
}
sweep(pSolid->GetFaceHead(), vector[0] * len, vector[1] * len, vector[2] * len);
// Insert the new solid
if(!solid)
solid = pSolid;
else
{
pTemp = solid;
while(pTemp->next)
pTemp = pTemp->next;
pTemp->next = pSolid;
}
return pSolid;
}
void CEulerView::RenderScene(void)
{
CEulerDoc *pDoc = GetDocument();
CSolid *pSolid;
CFace *pFace;
CLoop *pLoop;
CHalfEdge *pHalfEdge, *pHeHead;
GLint i, j, pos = 0;
GLfloat draw_ambient[] = { 1.0, 1.0, 1.0},
mat_ambient[] = { 0.5, 0.5, 0.5 },
mat_specular[] = { 1.0, 1.0, 1.0, 1.0 },
shininess[] = { 50.0 };
GLfloat position1[] = { 10.0, 10.0, 10.0, 0.0 };
glLoadIdentity();
glTranslatef(m_xPos, m_yPos, m_zPos);
glRotatef(m_xAngle, 1.0f,0.0f,0.0f);
glRotatef(m_yAngle, 0.0f,1.0f,0.0f);
if(m_bCoord)
RenderCoordinate(1);
glLightfv(GL_LIGHT0, GL_POSITION, position1);
//////////////////////////////////////////////////////////////////////////
// Draw
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, draw_ambient);
for(i = 1; i <= m_iLoopNum ;i ++)
{
pos += m_iLoopPointNum[i-1];
glBegin(GL_LINE_STRIP);
for(j = 1;j <= m_iLoopPointNum[i]; j++)
glVertex3d(m_dPoint[pos + j][0], m_dPoint[pos + j][1], m_dPoint[pos + j][2]);
glEnd();
}
//////////////////////////////////////////////////////////////////////////
pSolid = pDoc->solid;
if(m_bWire)
{
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, draw_ambient);
glLineWidth(2.0);
glBegin(GL_LINES);
while(pSolid)
{
pFace = pSolid->GetFaceHead();
while(pFace)
{
pLoop = pFace->GetLoopHead();
while(pLoop)
{
pHalfEdge = pHeHead = pLoop->GetHalfEdgeHead();
while(pHalfEdge)
{
glVertex3dv(pHalfEdge->GetVertex()->vcoord);
glVertex3dv(pHalfEdge->next->GetVertex()->vcoord);
pHalfEdge = pHalfEdge->next;
if(pHalfEdge == pHeHead)
break;
}
pLoop = pLoop->next;
}
pFace = pFace->next;
}
pSolid = pSolid->next;
}
glEnd();
}
else
{
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
glEnable(GL_NORMALIZE);
while(pSolid)
{
pFace = pSolid->GetFaceHead();
while(pFace)
{
gluTessBeginPolygon(tessobj, NULL);
glNormal3dv(pFace->feq);
pLoop = pFace->GetLoopHead();
while(pLoop)
{
gluTessBeginContour(tessobj);
pHalfEdge = pHeHead = pLoop->GetHalfEdgeHead();
while(pHalfEdge)
{
gluTessVertex(tessobj, pHalfEdge->GetVertex()->vcoord, pHalfEdge->GetVertex()->vcoord);
pHalfEdge = pHalfEdge->next;
if(pHalfEdge == pHeHead)
break;
}
gluTessEndContour(tessobj);
pLoop = pLoop->next;
}
gluTessEndPolygon(tessobj);
pFace = pFace->next;
}
pSolid = pSolid->next;
}
}
}
这篇博客介绍了一种采用欧拉操作实现扫成的方法,适用于CAD/CG领域的学习者。通过绘制基础面,结合指定向量和距离,可以创建出三维体。主要涉及到的数据结构为半边数据结构,并提供了关键代码实现包括:添加顶点(mvfs)、添加边(mev)、添加面(mef)以及合并环(kemr)等操作。
11万+

被折叠的 条评论
为什么被折叠?



