在学习任何CAD几何内核的时候,首先需要学习的是这个几何内核的几何拓扑数据结构,学习完毕后,一个很好的练习是自己采用底层的几何、拓扑构建API,创建一个box。通过这个练习,可以加深初学者对所学几何内核数据结构的理解和认识。
https://www.cnblogs.com/opencascade/p/4102570.html这篇博客介绍了在Open cascade中,采用自底向上的方式如何构建box,本文以ACIS为例,介绍ACIS中,如何采用自底向上的方式创建box。
构建需要的注意事项如下:
1. 首先需要构造出了四面体几何元素,4个Apoint,6个Straight类型的Curve,以及4个Pane类型的Surface;
2. 然后构造出vertex、edge、coedge、loop、face、shell、lump、body这些拓扑,设置vertex、edge、coedge、face指钎指向对应的几何,再把拓扑关系的指针设置好;
3.还要注意curve与edge之间,edge与coedge之间,coedge与edge之间,face与surface之间的方同关系。
代码如下:
BODY* block(SPAposition& min, SPAposition& max)
{
BODY* body = NULL;
// initialize bulletin board
API_BEGIN //初始化了异常处理和事务管理环境
//设置异常检查机制,确保在建模操作中捕获和处理异常,防止程序崩溃
// ***********************
// CREATE THE GEOMETRY.
// ***********************
// create 8 points
APOINT* p0 = new APOINT(min.x(), min.y(), min.z());
APOINT* p1 = new APOINT(max.x(), min.y(), min.z());
APOINT* p2 = new APOINT(min.x(), max.y(), min.z());
APOINT* p3 = new APOINT(max.x(), max.y(), min.z());
APOINT* p4 = new APOINT(min.x(), min.y(), max.z());
APOINT* p5 = new APOINT(max.x(), min.y(), max.z());
APOINT* p6 = new APOINT(min.x(), max.y(), max.z());
APOINT* p7 = new APOINT(max.x(), max.y(), max.z());
// create 12 straight lines
//为了简化边的构建,我们选择了直线的方向与图示中的边方向一致
STRAIGHT* s0 = new STRAIGHT(p0->coords(), SPAunit_vector(1.0, 0.0, 0.0));
STRAIGHT* s1 = new STRAIGHT(p1->coords(), SPAunit_vector(0.0, 1.0, 0.0));
STRAIGHT* s2 = new STRAIGHT(p3->coords(), SPAunit_vector(-1.0, 0.0, 0.0));
STRAIGHT* s3 = new STRAIGHT(p2->coords(), SPAunit_vector(0.0, -1.0, 0.0));
STRAIGHT* s4 = new STRAIGHT(p4->coords(), SPAunit_vector(1.0, 0.0, 0.0));
STRAIGHT* s5 = new STRAIGHT(p5->coords(), SPAunit_vector(0.0, 1.0, 0.0));
STRAIGHT* s6 = new STRAIGHT(p7->coords(), SPAunit_vector(-1.0, 0.0, 0.0));
STRAIGHT* s7 = new STRAIGHT(p6->coords(), SPAunit_vector(0.0, -1.0, 0.0));
STRAIGHT* s8 = new STRAIGHT(p0->coords(), SPAunit_vector(0.0, 0.0, 1.0));
STRAIGHT* s9 = new STRAIGHT(p1->coords(), SPAunit_vector(0.0, 0.0, 1.0));
STRAIGHT* s10 = new STRAIGHT(p3->coords(), SPAunit_vector(0.0, 0.0, 1.0));
STRAIGHT* s11 = new STRAIGHT(p2->coords(), SPAunit_vector(0.0, 0.0, 1.0));
// create 6 planar surfaces
//所有的平面的法线方向都被定义为指向体的外部,这将简化后续面定义的过程
PLANE* pln0 = new PLANE(p0->coords(), SPAunit_vector(0.0, 0.0, -1.0));
PLANE* pln1 = new PLANE(p4->coords(), SPAunit_vector(0.0, 0.0, 1.0));
PLANE* pln2 = new PLANE(p0->coords(), SPAunit_vector(0.0, -1.0, 0.0));
PLANE* pln3 = new PLANE(p1->coords(), SPAunit_vector(1.0, 0.0, 0.0));
PLANE* pln4 = new PLANE(p3->coords(), SPAunit_vector(0.0, 1.0, 0.0));
PLANE* pln5 = new PLANE(p2->coords(), SPAunit_vector(-1.0, 0.0, 0.0));
// ***********************
// CREATE THE TOPOLOGY.
// ***********************
// create 8 verticies
VERTEX* v0 = new VERTEX(p0);
VERTEX* v1 = new VERTEX(p1);
VERTEX* v2 = new VERTEX(p2);
VERTEX* v3 = new VERTEX(p3);
VERTEX* v4 = new VERTEX(p4);
VERTEX* v5 = new VERTEX(p5);
VERTEX* v6 = new VERTEX(p6);
VERTEX* v7 = new VERTEX(p7);
// create 12 edges
//EDGE类的构造函数需要起始顶点、结束顶点、曲线(CURVE)以及边相对于曲线的方向
EDGE* e0 = new EDGE(v0, v1, s0, FORWARD);
EDGE* e1 = new EDGE(v1, v3, s1, FORWARD);
EDGE* e2 = new EDGE(v3, v2, s2, FORWARD);
EDGE* e3 = new EDGE(v2, v0, s3, FORWARD);
EDGE* e4 = new EDGE(v4, v5, s4, FORWARD);
EDGE* e5 = new EDGE(v5, v7, s5, FORWARD);
EDGE* e6 = new EDGE(v7, v6, s6, FORWARD);
EDGE* e7 = new EDGE(v6, v4, s7, FORWARD);
EDGE* e8 = new EDGE(v0, v4, s8, FORWARD);
EDGE* e9 = new EDGE(v1, v5, s9, FORWARD);
EDGE* e10 = new EDGE(v3, v7, s10, FORWARD);
EDGE* e11 = new EDGE(v2, v6, s11, FORWARD);
// create loops of coedges
// loop of coedges on the low-z plane
//COEDGE类的构造函数需要一个EDGE、coedge相对于边的方向、前一个coedge和下一个coedge。
//(coedge环形成一个双向链表,每个coedge中都有前一个和下一个指针。)
COEDGE* c0 = new COEDGE(e0, REVERSED, NULL, NULL);
COEDGE* c3 = new COEDGE(e3, REVERSED, c0, NULL);
COEDGE* c2 = new COEDGE(e2, REVERSED, c3, NULL);
COEDGE* c1 = new COEDGE(e1, REVERSED, c2, c0);
LOOP* l0 = new LOOP(c0, NULL);
// loop of coedges on the high-z plane
COEDGE* c4 = new COEDGE(e4, FORWARD, NULL, NULL);
COEDGE* c5 = new COEDGE(e5, FORWARD, c4, NULL);
COEDGE* c6 = new COEDGE(e6, FORWARD, c5, NULL);
COEDGE* c7 = new COEDGE(e7, FORWARD, c6, c4);
LOOP* l1 = new LOOP(c4, NULL);
// loop of coedges on the low-y plane
c0 = new COEDGE(e0, FORWARD, NULL, NULL);
COEDGE* c9 = new COEDGE(e9, FORWARD, c0, NULL);
c4 = new COEDGE(e4, REVERSED, c9, NULL);
COEDGE* c8 = new COEDGE(e8, REVERSED, c4, c0);
LOOP* l2 = new LOOP(c0, NULL);
// loop of coedges on the high-x plane
c1 = new COEDGE(e1, FORWARD, NULL, NULL);
COEDGE* c10 = new COEDGE(e10, FORWARD, c1, NULL);
c5 = new COEDGE(e5, REVERSED, c10, NULL);
c9 = new COEDGE(e9, REVERSED, c5, c1);
LOOP* l3 = new LOOP(c1, NULL);
// loop of coedges on the high-y plane
c2 = new COEDGE(e2, FORWARD, NULL, NULL);
COEDGE* c11 = new COEDGE(e11, FORWARD, c2, NULL);
c6 = new COEDGE(e6, REVERSED, c11, NULL);
c10 = new COEDGE(e10, REVERSED, c6, c2);
LOOP* l4 = new LOOP(c2, NULL);
// loop of coedges on the low-x plane
c3 = new COEDGE(e3, FORWARD, NULL, NULL);
c8 = new COEDGE(e8, FORWARD, c3, NULL);
c7 = new COEDGE(e7, REVERSED, c8, NULL);
c11 = new COEDGE(e11, REVERSED, c7, c3);
LOOP* l5 = new LOOP(c3, NULL);
// create 6 faces
//FACE类的构造函数需要一个指向环的指针、一个指向下一个面的指针、
// 一个指向基础表面的指针以及面相对于表面的方向。
FACE* f0 = new FACE(l0, NULL, pln0, FORWARD);
FACE* f1 = new FACE(l1, f0, pln1, FORWARD);
FACE* f2 = new FACE(l2, f1, pln2, FORWARD);
FACE* f3 = new FACE(l3, f2, pln3, FORWARD);
FACE* f4 = new FACE(l4, f3, pln4, FORWARD);
FACE* f5 = new FACE(l5, f4, pln5, FORWARD);
// create 1 shell, 1 lump, and 1 body
//SHELL类的构造函数需要一个指向面链表中第一个面的指针f5,
//一个指向子壳列表的指针,以及一个指向块中下一个壳的指针
body = new BODY(new LUMP(new SHELL(f5, NULL, NULL), NULL));
// terminate bulletin board
API_END
return body;
}
通过与Open cascade的构建过程对比,有如下主要不同:
1. OCC创建Edge时,创建接口只需要传入几何Geom_Line,然后再把顶点Vertex关联上,ACIS的接口就比较完善,EDGE类的构造函数需要起始顶点、结束顶点、曲线(CURVE)以及边相对于曲线的方向;
2. OCC创建Wire或者Shell的时候,需要手动一个一个添加对应的Edge和Face,但是ACIS不需要,ACIS中EDGE、COEDGE、FACE都在一个链表中,只需要把链表头传递进去就可以了;
3. OCC创建的时候,PCurve需要手动创建并添加,但是ACIS中,默认在new FACE的时候,就把对应的PCurve创建好了,不需要人工创建了。
最终结果如图: