当前位置:网站首页 > Java基础 > 正文

毕向东java基础大纲



点击上方“机械电子工程技术”关注我们





本文档的目的是为 Open CASCADE Technology 定义一种通用的编程风格。
通用风格有助于理解和维护由几个程序员合作开发的代码。此外,它还使得可以构建包含这些标准知识的工具,以帮助编程。
OCCT 编程风格遵循常见和适当的**实践,因此一些指南摘自公共领域。
随着新想法和增强功能的添加,本指南将来可能会得到改进。


文档的范围

本文档中的规则适用于 C++ 代码。然而,由于语言限制,除了一些小的例外,它们适用于 Open CASCADE Technology 框架中的任何源代码,包括:

•C/C++

•GLSL 程序

•OpenCL 内核

•TCL 脚本和测试用例

命名约定

一般命名规则

本节中考虑的名称主要指 Open CASCADE Technology 库的接口或源代码本身。

国际语言 [强制性]

Open CASCADE Technology 是一个面向国际社区的开源平台,因此所有名称都需要由英文单词或其缩写组成。

有意义的名称

名称应该富有意义,或者至少包含一个有意义的部分。为了更好地理解这一要求,让我们来审视一下现有的工具包、包、类和方法的名称:

•包含单词 Geom 或 Geom2d 的包与几何数据和操作有关。

•包含单词 TopoDS 或 BRep 的包与拓扑数据和操作有关。

•以 ...Test 结尾的包定义了 Draw Harness 插件。

•以 Get... 和 Set... 开头的方法通常分别负责检索和存储数据。


相关名称

与逻辑上相互关联的功能相关的名称应该具有相同的前缀(以相同的字母开头),或者至少有其他任何共同的部分。例如,方法 GetCoord 返回一个实数三元组,并且为方向、向量和点定义。逻辑联系是显而易见的。


驼峰式大小写

驼峰式大小写是首选的命名方式。例如:
Standard_Integer awidthofbox;  // this is badStandard_Integer width_of_box; // this is badStandard_Integer aWidthOfBox;  // this is OK

开发单元的名称

通常,一个单元(例如一个包)是一组类、方法、枚举或其他实现共同功能的源代码,它是自包含的,并且独立于库的其他部分。

单元名称中不使用下划线 [强制性]

单元的名称不应包含下划线,除非明确允许使用下划线。

文件扩展名 [强制性]

根据源文件的类型,应使用以下扩展名:

•.cxx – C++ 源文件

•.hxx – C++ 头文件

•.lxx – 包含内联方法定义和辅助代码的附加头文件

请注意,在大多数情况下应避免使用 .lxx 文件 - 内联方法应放在头文件中。

工具包名称的前缀 [强制性]

工具包名称应以前缀 TK 开头,后面跟着一个有意义的部分,解释工具包所涵盖的功能领域(例如 TKOpenGl)。

公共类型的名称

公共类和其他类型(结构体、枚举、typedef)的名称应符合通用模式:包的名称后面跟着下划线和后缀(类型的自己的名称):
<package-name>_<class-name>
与整个包相关的静态方法在与包同名的类中定义(不包括后缀)。
每种类型都应该在其自己的头文件中定义,文件名是类型的名称加上 ".hxx" 扩展名。实现应该放在同名的文件中,扩展名为 ".cxx";对于大型类,可以将实现分割到多个源文件中,文件名中包含额外的后缀(通常是数字,例如 BSplCLib_1.cxx)。
例如,类 Adaptor2d_Curve2d 属于 Adaptor2d 包;它在头文件 Adaptor2d_Curve2d.hxx 中定义,并在源文件 Adaptor2d_Curve2d.cxx 中实现。
这个规则也适用于通过模板实例化构建的复杂类型。这些类型应该使用 typedef 语句赋予自己的名称,位于同名的头文件中。
例如,参见文件 TColStd_IndexedDataMapOfStringString.hxx 中的定义:
typedef NCollection_IndexedDataMap<TCollection_AsciiString,TCollection_AsciiString,TCollection_AsciiString> TColStd_IndexedDataMapOfStringString;

函数名称

这里的“函数”一词定义为:

• 任何类方法

• 任何包方法

• 任何非成员过程或函数

建议将公共方法的名称以大写字母开头,并将受保护和私有方法的名称以小写字母开头。
class MyPackage_MyClass{
public:
Standard_Integer Value() const; void SetValue (const Standard_Integer theValue);
private:
void setIntegerValue (const Standard_Integer theValue);
};

变量名称

有几项规则描述了目前公认的变量命名实践。

变量命名

毕向东java基础大纲变量的名称不应与现有的或可能的全局名称(包括包、宏、函数、全局变量等)冲突。
变量的名称不应以下划线开头。
以下是一些示例:
Standard_Integer Elapsed_Time = 0; // this is bad - possible class   nameStandard_Integer gp = 0;           // this is bad - existing package nameStandard_Integer aGp = 0;          // this is OKStandard_Integer _KERNEL = 0;      // this is badStandard_Integer THE_KERNEL = 0;   // this is OK


函数参数名称

函数(过程、类方法)参数的名称应该以前缀开头,后面跟着以大写字母开头的有意义的部分。
以下是一些示例:
void Package_MyClass::MyFunction (const gp_Pnt& p);        // this is badvoid Package_MyClass::MyFunction (const gp_Pnt& theP);     // this is OKvoid Package_MyClass::MyFunction (const gp_Pnt& thePoint); // this is preferred

类成员变量名称

类成员变量的名称应该以前缀 my 开头,后面跟着以大写字母开头的有意义的部分。
以下是一些示例:
Standard_Integer counter;   // This is badStandard_Integer myC;       // This is OKStandard_Integer myCounter; // This is preferred

全局变量名称

强烈建议避免定义任何全局变量。然而,一旦需要全局变量,其名称应该以定义它的类或包的名称为前缀,后面跟着 _my。
以下是一些示例:
Standard_Integer MyPackage_myGlobalVariable = 0;Standard_Integer MyPackage_MyClass_myGlobalVariable = 0;

文件内的静态常量应使用大写字母编写,并以前缀 THE_ 开头:

namespace{  static const Standard_Real THE_CONSTANT_COEF = 3.14;};

局部变量名称

局部变量的名称应与函数参数、类成员变量和全局变量的名称有所区别。
建议在局部变量名称前加上 a 和 an(或对于布尔变量使用 is、to 和 has)作为前缀。
以下是一些示例:
Standard_Integer theI;    // this is badStandard_Integer i;       // this is badStandard_Integer index;   // this is badStandard_Integer anIndex; // this is OK

避免使用虚拟名称

避免使用虚拟名称,如 i、j、k。这样的名称没有意义,且容易混淆。

当多次使用这样的虚拟名称时,代码变得越来越复杂,或者在不同的迭代范围内使用时,等等。

以下是首选风格的一些示例:

void Average (const Standard_Real** theArray,              Standard_Integer      theRowsNb,              Standard_Integer      theRowLen,              Standard_Real&        theResult){  theResult = 0.0;  for (Standard_Integer aRow = 0; aRow < aRowsNb; ++aRow)  {    for (Standard_Integer aCol = 0; aCol < aRowLen; ++aCol)    {      theResult += theArray[aRow][aCol];    }    theResult /= Standard_Real(aRowsNb * aRowLen);  }}

格式化规则

为了提高开源代码的可读性,从而提高可维护性,以下是应用的一组规则。

国际语言 [强制性]

所有源代码中的注释必须使用英文。

行长度

尽量在所有源代码中保持每行120个字符的限制。

C++风格注释

在 C++ 源代码中,推荐使用 C++ 风格的注释。

注释掉未使用的代码

删除未使用的代码,而不是注释掉或使用 #define。

源代码中的缩进 [强制性]

所有源代码的缩进应设置为两个空格字符。禁止使用制表符字符进行缩进。

分隔空格

标点规则遵循英语语言的规则。

•C/C++ 保留字、逗号、冒号和分号后面如果不是行尾,应跟一个空格字符。

•'(' 后面和 ')' 前面不应有空格字符。闭合和开放括号之间应有一个空格字符。

•为了更好的可读性,还建议在常规运算符周围加上一个空格字符。例如:

在布尔表达式中,建议在逻辑运算符周围使用空格:

在控制流语句(如 if、for、while)中,条件和语句体之间应有一个空格字符,但括号内不应有:
在函数声明和定义中,函数名和括号之间不应有空格,参数名和参数类型之间应有一个空格:
在模板声明中,尖括号内不应有空格:
在枚举和类型定义中,冒号后面应有一个空格:
这些规则有助于保持代码的一致性和清晰度,使得其他开发者能够更容易地理解和维护代码。
while (true)                            // NOT: while( true ) ...{  DoSomething (theA, theB, theC, theD); // NOT: DoSomething(theA,theB,theC,theD);}for (anIter = 0; anIter < 10; ++anIter) // NOT: for (anIter=0;anIter<10;++anIter){{  theA = (theB + theC) * theD;          // NOT: theA=(theB+theC)*theD}


指针和引用的声明

在简单指针和引用的声明中,星号(*)或和号(&)应紧随类型之后,没有额外的空格。
由于声明几个具有混合指针类型的变量违反了这一规则,应避免这样做。相反,应独立声明每个变量,并使用完全限定的类型。
示例:
Standard_Integer   *theVariable;      // not recommendedStandard_Integer *  theVariable;      // not recommendedStandard_Integer*   theVariable;      // this is OK
Standard_Integer *&theVariable; // not recommendedStandard_Integer *& theVariable; // not recommendedStandard_Integer*& theVariable; // this is OK
Standard_Integer **theVariable; // not recommendedStandard_Integer ** theVariable; // not recommendedStandard_Integer** theVariable; // this is OK
Standard_Integer *theA, theB, **theC; // not recommended (declare each variable independently)

分隔逻辑块

使用一个空行和注释来分隔代码的逻辑块。
参见以下示例:
// check argumentsStandard_Integer anArgsNb = argCount();if (anArgsNb < 3 || isSmthInvalid){  return THE_ARG_INVALID;}
// read and check header......
// do our job......

注意应避免使用多个空行。

分隔函数体 [强制性]

使用函数描述块将函数体相互分隔。每个描述块应至少包含函数名称和目的描述。
参见以下示例:
// =======================================================================// function : TellMeSmthGood// purpose  : Gives me good news// =======================================================================void TellMeSmthGood(){  ...}
// =======================================================================// function : TellMeSmthBad// purpose : Gives me bad news// =======================================================================void TellMeSmthBad(){ ...}

代码块布局 [强制性]

图括号 { } 和每个操作符(for、if、else、try、catch)应写在专用行。
通常,布局应如下:
while (expression){  ...}
进入一个块会增加,离开一个块会减少一个制表符的缩进。


单行操作符

单行条件操作符(if、while、for 等)可以不用括号写在下一行。
if (!myIsInit) return Standard_False; // bad
if (thePtr == NULL) // OK return Standard_False;
if (!theAlgo.IsNull()) // preferred{ DoSomething();}
将所有代码写在同一行对于调试来说不太方便。

常量比较表达式

在比较中,将变量(当前上下文中的)放在表达式的左侧,将常量放在右侧。也就是说,应避免所谓的“Yoda风格”。
if (NULL != thePointer)    // Yoda style, not recommendedif (thePointer != NULL)    // OK
if (34 < anIter) // Yoda style, not recommendedif (anIter > 34) // OK
if (theNbValues >= anIter) // bad style (constant function argument vs. local variable)if (anIter <= theNbValues) // OK
if (THE_LIMIT == theValue) // bad style (global constant vs. variable)if (theValue == THE_LIMIT) // OK

对齐

在提高可读性的地方使用对齐。参见以下示例:
MyPackage_MyClass anObject;Standard_Real     aMinimum = 0.0;Standard_Integer  aVal     = theVal;switch (aVal){  case 0:  computeSomething();              break;  case 12: computeSomethingElse (aMinimum); break;  case 3:  default: computeSomethingElseYet();       break;}

注释的缩进

注释应与它们引用的代码以相同的方式缩进,或者如果它们很短,可以与代码在同一行。
注释文本应与斜杠字符之间用一个空格字符分隔。
参见以下示例:
while (expression)   //bad comment{  // this is a long multi-line comment  // which is really required  DoSomething();     // maybe, enough  DoSomethingMore(); // again}

早期返回语句

使用早期返回条件而不是收集缩进。
这样写:
Standard_Integer ComputeSumm (const Standard_Integer* theArray,                              const Standard_Size     theSize){  Standard_Integer aSumm = 0;  if (theArray == NULL || theSize == 0)  {    return 0;  }
... computing summ ... return aSumm;}
而不是这样:
Standard_Integer ComputeSumm (const Standard_Integer* theArray,                              const Standard_Size     theSize){  Standard_Integer aSumm = 0;  if (theArray != NULL && theSize != 0)  {    ... computing summ ...  }  return aSumm;}
这有助于提高可读性并减少不必要的缩进深度。

尾随空格

应尽可能移除尾随空格。行尾的空格是无用的,并且不影响功能。

头文件顺序

将头文件分为几组:系统头文件、每个框架的头文件、项目头文件;将包含的列表按字母顺序排序。在类源文件中,类头文件应首先包含。
这条规则提高了可读性,允许检测到无用的多重头文件包含,并使第三方依赖关系清晰可见。顶部包含类头文件可以验证头文件的一致性(例如,头文件不使用由于缺少依赖项包含而未定义的声明)。
对于生成宏声明冲突的系统头文件(如 "windows.h" 或 "X11/Xlib.h")的排序规则是一个例外——这些头文件的放置应该解决冲突。
源文件或头文件应仅包含编译所需的最小集合的头文件,且不重复(考虑嵌套包含)。
// the header file of implemented class#include <PackageName_ClassName.hxx>
// OCCT headers#include <gp_Pnt.hxx>#include <gp_Vec.hxx>#include <NCollection_List.hxx>
// Qt headers#include <QDataStream>#include <QString>
// system headers#include <iostream>#include <windows.h>

文档规则

源代码是文档的重要参考之一。源代码中的注释应该足够完整,以便能够理解相应的代码,并作为其他文档的基础。
将注释视为文档并应维护的主要原因是:

•注释易于获取 - 它们总是与源代码一起;

•在源代码修改时,很容易更新注释中的描述;

•源代码本身是描述各种细节的好上下文,这些细节在单独的文档中需要更多的解释;

•总之,这是最具成本效益的文档。

注释应与 Doxygen 工具兼容,以自动生成文档(因此应使用兼容的标签)。

记录类 [强制性]

每个类应在其头文件(.hxx)中记录。注释应提供足够的细节,以便读者理解类的目的和与其主要的工作方式。

记录类方法 [强制性]

每个类或包方法应在头文件(.hxx)中记录。
注释应解释方法的目的、其参数和返回值。接受的风格是:
//! Method computes the square value.//! @param theValue the input value//! @return squared valueStandard_Export Standard_Real Square (Standard_Real theValue);

记录 C/C++ 源代码

非常建议在包/类中放入 C/C++ 源代码的注释。
注释应足够详细,以使任何人能够理解代码的每个部分的作用。
建议对所有静态函数(如头文件中的方法)进行注释,并在函数体中每10-100行至少插入一条注释。
还有一些规则定义了注释应如何格式化,参见格式化规则。
遵循这些规则对于良好理解注释非常重要。此外,这种方法允许直接从注释过的源代码自动生成面向用户的文档。

应用程序设计

以下规则定义了任何为开源贡献的开发者应遵守的通用风格。

允许可能的继承

尝试设计通用类(对象),同时考虑到可能的继承。这条规则意味着,使用你的类进行可能的扩展的用户不应该遇到私有实现的问题。尽量使用受保护的成员和虚拟方法,无论你期望未来的扩展在哪里。

避免友元声明

除非是一些特定情况(例如,迭代),否则避免使用 'friend' 类或函数。'友元' 声明增加了耦合。

设置/获取方法

避免为类的所有字段提供设置/获取方法。过多的设置/获取函数破坏了封装。

隐藏虚拟函数 [强制性]

避免通过具有不同签名的重新定义函数隐藏基类虚拟函数。大多数编译器对此会发出警告。

避免混合错误报告策略

尝试不要在同一应用程序级别混合使用不同的错误指示/处理策略(异常或返回值)。

最小化编译器警告 [强制性]

在编译源代码时注意并尽量最小化编译器警告。

避免不必要的包含

尝试通过删除不必要的包含来最小化编译依赖。

通用 C/C++ 规则

这一节定义了编写可移植和可维护的 C/C++ 源代码的规则。

包装全局变量 [强制性]

使用包或类方法返回引用来包装全局变量,以减少可能的名称空间冲突。

避免私有成员

在合理的情况下,使用受保护的成员代替私有成员,以支持未来的扩展。如果应该禁用未来的扩展,则使用私有字段。

常量和内联函数超过定义 [强制性]

使用常量变量(const)和内联函数代替定义(#define)。

避免显式数值 [强制性]

避免使用显式数值。使用命名常量和枚举代替。数字使阅读和维护变得困难。

三个强制性方法

如果一个类有析构函数、赋值运算符或复制构造函数,它通常需要另外两个方法。

虚拟析构函数

具有虚拟函数的类应该有一个虚拟析构函数。

覆盖虚拟方法

覆盖方法的声明应包含 "virtual" 和 "override" 指定符(使用 Standard_OVERRIDE 别名以兼容旧编译器)。
class MyPackage_BaseClass{
public:
Standard_EXPORT virtual Standard_Boolean Perform();
};
class MyPackage_MyClass : public MyPackage_BaseClass{
public:
Standard_EXPORT virtual Standard_Boolean Perform() Standard_OVERRIDE;
};
这使得类定义更加清晰(虚拟方法变得更加突出)。
使用纯虚函数声明接口可以防止第一级继承时的不完整继承,但在嵌套继承中方法被多次覆盖,或者基类中的方法本意是可选时,它并没有帮助。
在这里,“override”指定符引入了额外的保护,以防错过接口变更的情况(类可能包含旧的方法,这些方法将永远不会被调用)。

默认参数值

不要在继承的函数中重新定义默认参数值。

使用 const 修饰符

尽可能地使用 const 修饰符(函数参数、返回值等)。

使用 goto 的情况 [强制性]

除非真的需要,否则避免使用 goto 语句。

在 for() 头声明变量

如果不在循环外使用,应在 for() 语句的头中声明循环变量。
Standard_Real aMinDist = Precision::Infinite();for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter (theSequence);     aPntIter.More(); aPntIter.Next()){  aMinDist = Min (aMinDist, theOrigin.Distance (aPntIter.Value()));

零值条件语句

避免对非布尔变量使用 C 风格的比较:
void Function (Standard_Integer theValue,               Standard_Real*   thePointer){  if (!theValue)          // bad style - ambiguous logic  {    DoSome();  }
if (theValue == 0) // OK { DoSome(); }
if (thePointer != NULL) // OK, predefined NULL makes pointer comparison cleaner to reader { // (nullptr should be used instead as soon as C++11 will be available) DoSome2(); }}


可移植性问题

本章包含对跨平台可移植性至关重要的规则。

提供代码可移植性 [强制性]

源代码必须能够移植到官方“技术要求”中列出的所有平台。这里的“可移植性”意味着“能够从源代码构建”。
C++ 源代码应符合 C++03 标准。任何使用特定编译器特性或更高版本语言的特性(例如,C++11,在所有支持的平台上的所有主要编译器实现其所有特性之前)应该是可选的(仅在适当的预处理器检查后使用)且非排他的(应提供与其他编译器兼容的替代实现)。

避免使用全局变量 [强制性]

避免使用全局变量。全局变量的使用可能会导致在另一个共享库中访问时出现问题。
使用全局(包或类)函数返回此函数局部的静态变量引用,而不是使用全局变量。
另一个可能的问题是不同库中定义的全局变量的初始化顺序可能因平台、编译器和环境而异。

避免显式使用基本类型

避免显式使用基本类型(int、float、double 等),使用 Open CASCADE Technology 包 Standard 中的类型:Standard_Integer、Standard_Real、Standard_ShortReal、Standard_Boolean、Standard_CString 等,或特定的 typedef。

使用 sizeof() 计算大小 [强制性]

不要假设类型的尺寸。使用 sizeof() 来计算大小。

文件末尾的空行 [强制性]

根据 C++03 标准,源文件应以一个空行结束。建议所有纯文本文件都遵循这一规则,以保持一致性,并确保 git 差异工具的正确工作。

稳定性问题

本章列出的规则对于使用 Open CASCADE Technology 库的程序的稳定性至关重要。

使用 OSD::SetSignal() 捕获异常

在应用程序中使用 Open CASCADE Technology 时,在应用程序初始化时调用 OSD::SetSignal() 函数。
这将为运行时中断信号和异常安装 C 处理程序,以便低级异常(如访问违规、除以零等)将重定向到使用 try {...} catch (Standard_Failure) {...} 块的 C++ 异常。
上述规则对于建模算法的鲁棒性尤为重要。

交叉引用的句柄

注意处理引用的循环,以避免形成永远不会被释放的链。为此目的,在一个(从属)侧使用指针。
以下是示例:
class Slave;
class Master : public Standard_Transient{... void SetSlave (const Handle(Slave)& theSlave){ mySlave = theSlave; }...private: Handle(Slave) theSlave; // smart pointer...}
class Slave : public Standard_Transient{... void SetMaster (const Handle(Master)& theMaster){ myMaster = theMaster.get(); }...private: Master* theMaster; // simple pointer...}

C++ 内存分配

在 C++ 中使用 new 和 delete 操作符代替 malloc() 和 free()。尽量不要混合使用不同的内存分配技术。

匹配 new 和 delete [强制性]

使用相同形式的 new 和 delete。
aPtr1 = new TypeA[n];              ... ; delete[]        aPtr1;aPtr2 = new TypeB();               ... ; delete          aPtr2;aPtr3 = Standard::Allocate (4096); ... ; Standard::Free (aPtr3);


管理动态分配的方法 [强制性]

为具有动态分配内存的类定义析构函数、复制构造函数和赋值运算符。

未初始化变量 [强制性]

每个变量都应初始化。
Standard_Integer aTmpVar1;     // badStandard_Integer aTmpVar2 = 0; // OK
未初始化变量只能在性能敏感的代码块中保留,并且只有在随后的代码保证初始化时才可。

不要隐藏全局 new

避免隐藏全局 new 操作符。

赋值运算符

在 operator=() 中为所有数据成员赋值,并检查是否自我赋值。

浮点数比较

不要检查浮点数的等价性或不等价性;检查 GT(大于)、GE(大于等于)、LT(小于)或 LE(小于等于)。
if (Abs (theFloat1 - theFloat2) < theTolerance){  DoSome();}
包 Precision 提供了 SI 单位的标准值,并被现有的建模算法广泛采用:

•Precision::Confusion() 用于以米为单位的长度;

•Precision::Angular() 用于以弧度为单位的角度。


以及在双精度正常范围内定义无限值:

•Precision::Infinite()

•Precision::IsInfinite()

•Precision::IsPositiveInfinite()

•Precision::IsNegativeInfinite()


非索引迭代

避免使用非索引对象集合的迭代。如果使用了这种迭代,请确保算法的结果不依赖于迭代项的顺序。
由于非索引对象集合的迭代顺序不可预测,它经常导致应用程序在不同运行中的不同行为,从而使调试过程变得尴尬。
这主要涉及映射对象,其中指针涉及计算哈希函数。例如,TopoDS_Shape 的哈希函数涉及 TopoDS_TShape 对象的地址。因此,在不同应用程序会话中 TopTools_MapOfShape 中相同形状的顺序会变化。

不要在析构函数中抛出异常

不要在析构函数内抛出异常。

赋值给引用 [强制性]

避免将临时对象赋值给引用。这会导致在不同平台上的不同编译器上有不同的行为。


性能问题

这些规则定义了避免因编程效率低下而导致的可能的性能损失的方法。

类字段对齐

按照字段大小的递减顺序声明类的字段,以获得更好的对齐。一般来说,尽量减少未对齐访问,因为它们会影响性能(例如,在 Intel 机器上)。

字段初始化顺序 [强制性]

在构造函数的初始化列表中按照它们声明的顺序列出类数据成员。
class MyPackage_MyClass{
public:
MyPackage_MyClass() : myPropertyA (1), myPropertyB (2) {}
// NOT// : myPropertyB (2),// myPropertyA (1) {}
private:
Standard_Integer myPropertyA; Standard_Integer myPropertyB;
};

初始化优于赋值

在类构造函数中优先使用初始化而不是赋值。
MyPackage_MyClass(): myPropertyA (1)  // preferred{  myPropertyB = 2; // not recommended}

优化缓存

在编写涉及大量内存访问的程序时,尝试根据缓存行为进行优化。以下是缓存行为可能受到影响的一个示例:
在 x86 上,这段代码
Standard_Real anArray[4096][2];for (Standard_Integer anIter = 0; anIter < 4096; ++anIter){  anArray[anIter][0] = anArray[anIter][1];}
比这段代码更高效
Standard_Real anArray[2][4096];for (Standard_Integer anIter = 0; anIter < 4096; ++anIter){  anArray[0][anIter] = anArray[1][anIter];}
因为线性访问不会太频繁地使缓存失效。


Draw Harness 命令

Draw Harness 为 OCCT 算法提供了 TCL 接口。
OCCT C++ 类没有 TCL 包装,而是通过在 C++ 中实现的一组 TCL 命令提供接口。
有一份通用规则列表,实现 Draw Harness 命令时应遵循以形成良好的命令。

返回值

命令在大多数情况下应返回 0,即使执行的算法失败也是如此。返回 1 会导致 TCL 异常,因此应在命令行语法错误和类似问题时使用。

验证输入参数

在使用之前应验证命令参数。用户应看到一个人类可读的错误描述,而不是执行算法的运行时异常。

验证输入参数的数量

命令应警告用户关于未知参数,包括当为具有固定参数数量的命令推送了额外参数的情况。
if (theArgsNb != 3){  std::cout << "Syntax error - wrong number of arguments!\n";  return 1;}
Standard_Integer anArgIter = 1;Standard_CString aResName = theArgVec[anArgIter++];Standard_CString aFaceName = theArgVec[anArgIter++];TopoDS_Shape aFaceShape = DBRep::Get (aFaceName);if (aFaceShape.IsNull() || aFaceShape.ShapeType() != TopAbs_FACE){ std::cout << "Shape " << aFaceName << " is empty or not a Face!\n"; return 1;}DBRep::Set (aResName, aFaceShape);return 0;


消息打印

信息性消息应打印到标准输出 std::cout,而命令结果(如果有)——打印到 Draw Interpreter。
打印到 Draw Interpreter 的信息应结构良好,以允许在 TCL 脚本中使用。

参数列表

任何带有一长串必选参数的命令都应被视为设计不良。可选参数应以标志名称开始(带有 '-' 前缀),后跟其值:
myCommand -flag1 value1 value2 -flag2 value3

参数解析器

• 整数值应使用 Draw::Atoi() 函数读取。

• 实数值应使用 Draw::Atof() 函数读取。

• 标志名称应以不区分大小写的方式检查。

函数 Draw::Atof() 和 Draw::Atoi() 支持表达式,并以 C-locale 读取值。
Standard_Real aPosition[3] = {0.0, 0.0, 0.0};for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter){  Standard_CString anArg = theArgVec[anArgIter];  TCollection_AsciiString aFlag (anArg);  aFlag.LowerCase(); //!< for case insensitive comparison  if (aFlag == "position")  {    if ((anArgIt + 3) >= theArgsNb)    {      std::cerr << "Wrong syntax at argument '" << anArg << "'!\n";      return 1;    }    aPosition[0] = Draw::Atof (theArgVec[++anArgIt]);    aPosition[1] = Draw::Atof (theArgVec[++anArgIt]);    aPosition[2] = Draw::Atof (theArgVec[++anArgIt]);  }  else  {    std::cout << "Syntax error! Unknown flag '" << anArg << "'\n";    return 1;  }}

示例

示例记录类

class Package_Class{
public: //! @name public methods
//! Method computes the square value. //! @param theValue the input value //! @return squared value Standard_Export Standard_Real Square (const Standard_Real theValue);
private: //! \@name private methods
//! Auxiliary method void increment();
private: //! \@name private fields
Standard_Integer myCounter; //!< usage counter
};#include <Package_Class.hxx>// ==========================================================// function : Square// purpose : Method computes the square value// ==========================================================Standard_Real Package_Class::Square (const Standard_Real theValue){ increment(); return theValue * theValue;}
// ==========================================================// function : increment// purpose :// ==========================================================void Package_Class::increment(){ ++myCounter;}

Draw Harness 的 TCL 脚本

    1 # show fragments (solids) in shading with different colors    2 proc DisplayColored {theShape} {    3   set aSolids [uplevel #0 explode $theShape so]    4   set aColorIter 0    5   set THE_COLORS {red green blue1 magenta1 yellow cyan1 brown}    6   foreach aSolIter $aSolids {    7     uplevel #0 vdisplay         $aSolIter    8     uplevel #0 vsetcolor        $aSolIter [lindex $THE_COLORS [expr [incr aColorIter] % [llength $THE_COLORS]]]    9     uplevel #0 vsetdispmode     $aSolIter 1   10     uplevel #0 vsetmaterial     $aSolIter plastic   11     uplevel #0 vsettransparency $aSolIter 0.5   12   }   13 }   14    15 # load modules   16 pload MODELING VISUALIZATION   17    18 # create boxes   19 box bc  0 0 0 1 1 1   20 box br  1 0 0 1 1 2   21 compound bc br c   22    23 # show fragments (solids) in shading with different colors   24 vinit View1   25 vclear   26 vaxo   27 vzbufftrihedron   28 DisplayColored c   29 vfit   30 vdump $imagedir/${casename}.png 512 512

GLSL 程序:

vec3 Ambient;  //!< Ambient  contribution of light sourcesvec3 Diffuse;  //!< Diffuse  contribution of light sourcesvec3 Specular; //!< Specular contribution of light sources
//! Computes illumination from light sourcesvec4 ComputeLighting (in vec3 theNormal, in vec3 theView, in vec4 thePoint){ // clear the light intensity accumulators Ambient = occLightAmbient.rgb; Diffuse = vec3 (0.0); Specular = vec3 (0.0); vec3 aPoint = thePoint.xyz / thePoint.w; for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex) { int aType = occLight_Type (anIndex); if (aType == OccLightType_Direct) { directionalLight (anIndex, theNormal, theView); } else if (aType == OccLightType_Point) { pointLight (anIndex, theNormal, theView, aPoint); } }
return vec4 (Ambient, 1.0) * occFrontMaterial_Ambient() + vec4 (Diffuse, 1.0) * occFrontMaterial_Diffuse() + vec4 (Specular, 1.0) * occFrontMaterial_Specular();}
//! Entry point to the Fragment Shadervoid main(){ gl_FragColor = computeLighting (normalize (Normal), normalize (View), Position);}

想了解更多

赶紧扫码关注

版权声明


相关文章:

  • 怎样学习java基础2024-10-14 17:50:06
  • java基础语言难吗2024-10-14 17:50:06
  • 乐山java基础学校2024-10-14 17:50:06
  • 尚硅谷java基础课程2024-10-14 17:50:06
  • 女生java基础薄弱2024-10-14 17:50:06
  • 0基础java毕业设计要多久2024-10-14 17:50:06
  • java基础集合2024-10-14 17:50:06
  • java数据基础大全2024-10-14 17:50:06
  • java数学基础讲解2024-10-14 17:50:06
  • java 基础篇答案2024-10-14 17:50:06