目录
简介:
sgCore是由Geometros公司开发的一款轻量级跨平台库实体造型库,该库适用于Windows 、MacOS、iOS 和 Android。实现了二维和三维造型中的部分算法;提供了常见的二三维图形以及几何体(点、线、面球、立方体、圆柱体等)。官网提供试用了试用版,可从Geometros Solid Geometry Engine for C++, C#, Objective-C, Java - sgCore获取。
结构
下载的SDK中包含了Windows 、MacOS、iOS 和 Android各个版本的头文件、lib库、测试Demo以及一份帮助文档。
SDK非常轻量化,windows版本包含一个c++demo以及c#demo。包含了14个头文件,32/64位的dll以及lib文件,总大小也只有两兆多,非常轻量化
对象概念及结构
对象和几何概念是sgCore的主要概念。几何是一种精确的数学描述,对象是在计算机屏幕上反映可能性的近似值;换句话说,几何是以参数描述的,而对象则是可以离散化为三角面或多边形的具有行为的“物体”。sgCore中的所有操作都是使用对象而不是几何图形进行的。从头文件也可以看出来这点,如:SG_BOX表示的是几何,只有SizeX, SizeY, SizeZ三个成员变量:
typedef struct
{
sgFloat SizeX;
sgFloat SizeY;
sgFloat SizeZ;
} SG_BOX;
然后sgCBox则是对象,定义了一些行为以及一些其他特征,比如Triangulate,SetMaterial/ GetMaterial,CalcUV、ApplyTempMatrix等。这和我之前做的一些设计是一致的。
二维对象(实际也是在三维空间中)在sgCore中只是一些线段。而三维物体是由许多三角形组成的。不像几何概念是完全充分的,对象概念不是完全充分的,它直接取决于它的基本几何。我们总能通过几何学得到给定精度的物体。这就是为什么每个sgCore对象都存储自己的几何形状。根据所实现的几何类型,将对象分为以下几类:
对象类图:
基本二三维对象
二维对象:point、line segment、circle、arc、spline、contour,其实准确的说这些也是三维对象,毕竟世界是三维的。
三维对象:box、sphere、cylinder、cone、torus、ellipsoid、Sphericband(球带体)
三维对象提供了三角化的接口,可以将对象离散化为三角面。三角化接口如下
static void AutoTriangulate(bool,SG_TRIANGULATION_TYPE, SG_TRIANGLES_BUFFER_TYPE);
bool Triangulate(SG_TRIANGULATION_TYPE, SG_TRIANGLES_BUFFER_TYPE);
其中AutoTriangulate()用来设置三维对象全局的三角化标志。帮助文档提示,当创建复杂三维对象时,建议将此标志关闭,可以提高算法速度。并使用函数sgC3DObject::Triangulate来对最终对象进行三角化。
SG_TRIANGULATION_TYPE枚举有两个值
SG_VERTEX_TRIANGULATION,
SG_DELAUNAY_TRIANGULATION
以下是两种模式的效果,可以看出,第一种模式不会加点,直接剖分,这样会导致狭长三角形;第二种会加点,三角形比较均匀。
SG_VERTEX_TRIANGULATION | SG_DELAUNAY_TRIANGULATION |
| |
SG_TRIANGLES_BUFFER_TYPE参数文档没提到,应该是文档没更新(该库2.0版本都发了很久了,但这么久文档没更新,可能该库已经被放弃了,团队可能忙着其他定制开发了)。
边界表示法表示几何体sgCBRep
在sgCore库中,所有3D实体都以多边形表面表示(边界表示)的形式存储。这种表示方式通过描述其边界表面隐式定义了一个实体。每个表面都被近似为一组面片。碎片化是按照这样的方式进行的,使得每个面片都有一个紧凑的数学表示。
面边界由边表示。边的选择类似于面片,这样每个边都有一个紧凑的数学描述。形成边的一部分曲线被终止于顶点。引入循环(描述每个面轮廓)的概念是必要的,因为每个面都可以是一个非凸多边形,具有任意数量的洞。
只有平面面的模型被称为多边形模型——这种类型的描述在sgCore中使用。因此,每个面片都是一个由顶点坐标序列组成的多边形。一个对象由一组面片组成。
SgCore还引入了BReppiece这个术语。BReppiece是一个简单连通边界体表面的片段。这个术语是为了加速某些算法(如布尔运算)的工作而引入的。每个BRep piece都有一个有限维平行六面体。它被设计成避免在循环中遍历每个BRep pieces的面片。将所有BRep pieces连接在一起形成完整的BRep。
让我们看一下由挤压一个平面非凸轮廓并带有一个洞创建的实体的BRep描述示例。这个BRep被分成4个部分——2个基底、一个侧面和一个洞表面。
BRep Piece序号和 描述 | 顶点 | 边 | |||||
名称 | 序号 | 坐标 | 名称 | 序号 | 起始 | 终止 | |
0 Bottom base | v0 v1 v2 v3 v4 v5 v6 v7 | 0 1 2 3 4 5 6 7 | (-2.0,0.0,0.0) (1.0,2.0,0.0) (0.0,0.0,0.0) (0.0,-2.0,0.0) (-1.0,-0.6,0.0) (-0.4,-0.8,0.0) (-0.5,0.0,0.0) (-1.0,0.0,0.0) | e0 e1 e2 e3 e4 e5 e6 e7 | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | 1 2 3 0 5 6 7 4 |
1 Side face | v0 v8 v1 v9 v2 v10 v3 v11 | 0 1 2 3 4 5 6 7 | (-2.0,0.0,0.0) (-2.0,0.0,1.0) (1.0,2.0,0.0) (1.0,2.0,1.0) (0.0,0.0,0.0) (0.0,0.0,1.0) (0.0,-2.0,0.0) (0.0,-2.0,1.0) | e0 e16 e8 e1 e19 e9 e2 e18 e10 e3 e17 e11 | 0 1 2 3 4 5 6 7 8 9 10 11 | 0 0 1 2 2 3 4 4 5 6 6 7 | 2 1 3 4 3 5 6 5 7 0 7 1 |
2 Top base | v8 v9 v10 v11 v12 v13 v14 v15 | 0 1 2 3 4 5 6 7 | (-2.0,0.0,1.0) (1.0,2.0,1.0) (0.0,0.0,1.0) (0.0,-2.0,1.0) (-1.0,-0.6,1.0) (-0.4,-0.8,1.0) (-0.5,0.0,1.0) (-1.0,0.0,1.0) | e8 e9 e10 e11 e12 e13 e14 e15 | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | 1 2 3 0 5 6 7 4 |
3 Hole surface | v4 v12 v5 v13 v6 v14 v7 v15 | 0 1 2 3 4 5 6 7 | (-1.0,-0.6,0.0) (-1.0,-0.6,1.0) (-0.4,-0.8,0.0) (-0.4,-0.8,1.0) (-0.5,0.0,0.0) (-0.5,0.0,1.0) (-1.0,0.0,0.0) (-1.0,0.0,1.0) | e4 e20 e12 e5 e21 e13 e6 e22 e14 e7 e23 e15 | 0 1 2 3 4 5 6 7 8 9 10 11 | 0 0 1 2 2 3 4 4 5 6 6 7 | 2 1 3 4 3 5 6 5 7 0 7 1 |
建模算法
sgCore提供了一些常用建模算法。
布尔运算
提供了常用的交并差以及交线,对象与平面相交。接口也比较简单
sgCGroup* sgBoolean::Intersection(const sgC3DObject& aOb,
const sgC3DObject& bOb)//布尔交
sgCGroup* sgBoolean::Union(const sgC3DObject& aOb, const
sgC3DObject& bOb) //布尔并
sgCGroup* sgBoolean::Sub(const sgC3DObject& aOb, const
sgC3DObject& bOb) //布尔差
sgCGroup* sgBoolean::IntersectionContour(const sgC3DObject&
aOb, const sgC3DObject& bOb)//相交线
sgCGroup* sgBoolean::Section(const sgC3DObject& obj, const
SG_VECTOR& planeNormal, double planeD) //对象与平面相交
效果如下:
sgKinematic
姑且叫运动学运算吧,实际上就是截面/线按照路径所形成的空间或表面。包括扫掠、拉伸及旋转,可以构造实体(solid),也可以构造表面(surface)。
相关接口
gCObject* Rotation(const sgC2DObject& rotObj,
const SG_POINT& axePnt1,
const SG_POINT& axePnt2,
sgFloat angl_degree,
bool isClose,
short meridians_count=24);
接口描述:
通过旋转指定轮廓来创建旋转实体或表面。
参数
rotObj: 轮廓。必须是平面的,不能自相交;
axePnt1:旋转轴上的第一个点。必须位于旋转的轮廓平面上;
axePnt2:-旋转轴上的第二点。必须位于旋转的轮廓平面上。如果旋转的轮廓是线性的,旋转轴线不能与轮廓线重合
angle_degree:轴旋转角度(以度为单位)。一定不等于零。从axePnt1到axePnt2的顺时针角度方向为正。如果这个角小于-360度,它仍然是-360度,如果大于360等于360度。
isClose: 是否闭合。如果旋转的轮廓不闭合,则忽略该参数。
Meridians_count:子午线的数量,最后的实体包含旋转轮廓的个数,影响实体精细度。
返回值:返回指向新创建对象的指针。如果函数失败(参数不符合要求),则返回NULL。
注意:如果旋转轮廓与旋转轴相交,则会创建出自相交实体。
效果如下:
sgCObject* Extrude(const sgC2DObject& outContour,
const sgC2DObject** holes,
int holes_count,
const SG_VECTOR& extrDir,
bool isClose);
接口描述:
通过沿指定向量挤压物体来创建一个实体或挤压表面
参数:
outContour:外轮廓。必须是平面的(由IsPlane函数检查),闭合(由IsClosed函数检查)并且不自相交(通过IsSelfIntersecting函数)检查;
holes:洞的数组。孔必须是平的、闭合且不自相交的,这些洞必须在外轮廓所在平面上,并且严格地在它内部且这些孔不能相交,们也不能在彼此内部(检查)
Holes_count -孔数组中孔的数量。
extrDir:挤压矢量。不能为零
isClose:是否闭合
返回值:返回指向新创建对象的指针。如果函数失败,返回NULL
sgCObject* Spiral(const sgC2DObject& outContour,
const sgC2DObject** holes,
int holes_count,
const SG_POINT& axePnt1,
const SG_POINT& axePnt2,
sgFloat screw_step,
sgFloat screw_height,
short meridians_count,
bool isClose);
接口描述:
用指定孔数和指定螺旋参数创建螺旋实体或表面。
参数:
outContour:外轮廓。必须是平面的(由IsPlane函数检查),闭合(由IsClosed函数检查)并且不自相交(通过IsSelfIntersecting函数)检查;
holes:洞的数组。孔必须是平的、闭合且不自相交的,这些洞必须在外轮廓所在平面上,并且严格地在它内部且这些孔不能相交,们也不能在彼此内部(检查)
Holes_count -孔数组中孔的数量。
axePnt1:旋转轴上的第一个点。必须位于旋转的轮廓平面上;
axePnt2:-旋转轴上的第二点。必须位于旋转的轮廓平面上。
screw_step: 螺旋步长。
screw_height: -螺旋长度
Meridians_count :一个螺旋步骤的圆圈中子午线的数量
isClose :是否闭合
sgCObject* Pipe(const sgC2DObject& outContour,
const sgC2DObject** holes,
int holes_count,
const sgC2DObject& guideContour,
const SG_POINT& point_in_outContour_plane,
sgFloat angle_around_point_in_outContour_plane,
bool& isClose);
接口描述:
通过沿另一个物体挤压一个物体来创建一个实体或挤压表面对象
参数:
outContour:外轮廓。必须是平面的(由IsPlane函数检查),闭合(由IsClosed函数检查)并且不自相交(通过IsSelfIntersecting函数)检查;
holes:洞的数组。孔必须是平的、闭合且不自相交的,这些洞必须在外轮廓所在平面上,并且严格地在它内部且这些孔不能相交,们也不能在彼此内部
Holes_count 孔数组中孔的数量;
guideContour:路径;
point_in_outContour_plane:外轮廓平面上的一点;
angle_around_point_in_outContour_plane:外轮廓和洞沿轮廓点转动的角度;
isClose :是否闭合
Surfaces
sgCore库实现了许多从现有2D对象创建3D表面和实体的功能。有以下接口
sgCObject* Face(const sgC2DObject& outContour,
const sgC2DObject** holes,
int holes_count);
直接从二维外轮廓及洞构建face,过于简单,不做多说明。
sgCObject* Coons(const sgC2DObject& firstSide,
const sgC2DObject& secondSide,
const sgC2DObject& thirdSide,
const sgC2DObject* fourthSide,
short uSegments,
short vSegments,
short uVisEdges,
short vVisEdges);
接口描述:
从三个或四个边界轮廓创建一个Coons曲面。轮廓不能闭合,也不能自相交。等高线的端点必须与相邻等高线的端点重合,即形成一个封闭区域。
参数:
firstSide:第一个边界轮廓;
secondSide: 第二个边界轮廓,一端必须和第一个轮廓的一端重合;
thirdSide: 第三个边界轮廓,一端必须和第二个轮廓的一端重合,如果第四个轮廓为空,则另一端必须和第一个轮廓自由端重合;
fourthSide:第四边界轮廓。可能为NULL。一端必须与前一条轮廓的终点重合,另一端与第一个轮廓的自由端点。
sgCObject* Mesh(short dimens_1,
short dimens_2,
const SG_POINT* pnts);
接口描述:
从数组创建mesh
参数:
dimens_1:顶点数据第一维度
dimens_1: 顶点数据第二维度
pnts:顶点数组
sgCObject* SewSurfaces(const sgC3DObject** surfaces, int surf_count);
接口描述:
将多个表面缝成一个表面,如果这些表面限制了封闭区域,则尝试创建一个实体。这些表面必须互相倾斜。如果没有,则从参数创建一组对象。
参数:
surfaces:表面数组
surf_count: 表面个数
sgCObject* LinearSurfaceFromSections(const sgC2DObject& firstSide,
const sgC2DObject& secondSide,
sgFloat firstParam,
bool isClose);
接口描述:
通过沿着两条不同的曲线移动线段的端点来创建一个表面或实体。
参数:
firstSide:控制线段第一个端点的路径曲线,
secondSide:控制线段第二个端点的路径曲线,
firstParam:第一路径曲线上与第二路径曲线上起始点相连的点的参数;该参数定义新对象的螺旋度,取值范围为0到1。可以使用GetPointFromCoefficient()函数找到对象上的点。如果firstSide对象未闭合,则忽略此参数。
isClose: 当firstSide和secondSide为无自交的平坦闭合曲线时,是否创建实体。
红色点为起点,不同的参数不同的情况
注意两条曲线顺序不一致可能导致错误结果,如下:
接口正确效果如下:
sgCObject* SplineSurfaceFromSections(const sgC2DObject** sections,
const sgFloat* params,
int sections_count,
bool isClose);
接口描述:
从三个或更多截面创建光滑表面或实体。
参数:
sections:截面数组
params: 将在其上创建新对象的基线点的参数数组;该参数定义新对象的螺旋度,取值范围为0到1。可以使用GetPointFromCoefficient()函数找到对象上的点。如果section数组中的对应对象未闭合,则忽略此参数。
sections_count: 截面个数
isClose:结果是否闭合
其他
sgCore是一款非常轻量级的实体造型库,能满足一般用户的造型需求。官网提供了不同的许可,报价从299刀到2500刀(源码版本),此外该团队可定制开发。本人年底准备推出一款类似于该库的工具,大部分功能已经实现,暂命名为acTorus.
参考:
Geometros Solid Geometry Engine for C++, C#, Objective-C, Java - sgCorehttps://www.geometros.com/