cad in civil engineering -...
TRANSCRIPT
CAD in Civil Engineering
Script
(Book of Examples)
2015
University of Duisburg-Essen
Faculty of Engineering
Department of Civil Engineering
Structural Analysis of Plate and Shell Structures
Dr. E. Baeck
10.6.2015
Contents
I Introduction to VBA 2
1 General Statements 3
1.1 AutoCad - Versions and VBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 VB-IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Macro Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 Basics in VBA 6
2.1 Data Types, Variables and Constants . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.1 Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.2 Declaration of Variables and Constants in VBA . . . . . . . . . . . . . . . 7
2.1.2.1 Explicit Declarations . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.2.2 Implicit Declarations . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.1 Unary Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.2 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.3 Comparison Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.3 Assigning Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4 FOR-Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5 Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.6 Calculation of Precision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.7 Newton Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.7.1 Pure VBA Version with Smart Slope . . . . . . . . . . . . . . . . . . . . . 15
2.7.2 EXCEL VBA Version with EXCEL-Sheet-GUI . . . . . . . . . . . . . . . 18
2.8 Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.9 Text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.10 Class Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.10.1 A Mass Point Class Module . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.10.2 Create and Delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3 Using EXCEL as GUI 31
3.1 EXCEL Type Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2 Import of an EXCEL File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
II AutoCAD-Objects 34
4 User Command Dialog 35
iii
Page iv CAD in Civil Engineering / 2015
4.1 Command Window Interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1.1 Prompting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1.2 Get Integer Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1.3 Get Real Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.1.4 Get Point Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.2 Examples for Get-Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2.1 Creating some MassObj-Instances . . . . . . . . . . . . . . . . . . . . . . 38
4.2.1.1 The Line Dialogs Layout . . . . . . . . . . . . . . . . . . . . . . 38
4.2.2 Used Object Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2.3 Helper Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2.4 Visual Basic Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5 Primitives in Modelspace 42
5.1 AcadLine Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.2 Delete Objects from ModelSpace . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.3 AcadSphere Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
III Sample Projects 48
6 Random Masspoints 49
6.1 Class Modul Mass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.1.1 Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.1.2 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
6.2 Class Modul Masses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
6.2.1 Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
6.2.2 Methodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
6.3 Frame Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
6.3.1 EXCEL-Sheet, Input Section . . . . . . . . . . . . . . . . . . . . . . . . . 55
6.3.2 EXCEL-Sheet, Output Section . . . . . . . . . . . . . . . . . . . . . . . . 55
6.3.3 Sample, Step 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6.3.4 Sample, Step 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
IV .NET Linking with C# 62
7 Motivation to Use .NET 63
7.1 Scripting in AutoCAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
7.2 Hello World in C# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
7.2.1 The Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
7.2.2 Some Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
7.3 Our Hellos in C# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
7.3.1 The Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
7.3.2 Main Differences between C# and C++ . . . . . . . . . . . . . . . . . . 69
7.3.3 Implementation of OurHellos . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.3.4 Created Files and Folders . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
E. Baeck
CONTENTS Page v
8 Basics in C# 76
8.1 The Preprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
8.2 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
8.3 Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
8.3.1 A List of Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
8.3.2 Little Example to Check some Data Types . . . . . . . . . . . . . . . . . 78
8.4 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
8.4.1 Assignment Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
8.4.2 Arthmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
8.4.3 Compound Arithmetic Assignment . . . . . . . . . . . . . . . . . . . . . . 83
8.4.4 Increment - Decrement Operators . . . . . . . . . . . . . . . . . . . . . . 83
8.4.5 Relational and Equality Operators . . . . . . . . . . . . . . . . . . . . . . 84
8.4.6 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
8.4.7 Bitwise Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
8.4.8 Compound Bitwise Assignment . . . . . . . . . . . . . . . . . . . . . . . . 85
8.4.9 Explicit Type Casting Operator . . . . . . . . . . . . . . . . . . . . . . . . 85
8.4.10 sizeof Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
8.4.11 Address and Value Operator . . . . . . . . . . . . . . . . . . . . . . . . . 85
8.4.12 Verbatim Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
8.5 Branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
8.5.1 Filtering with an if Statement . . . . . . . . . . . . . . . . . . . . . . . . 87
8.6 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
8.6.1 for Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
8.6.2 do - while Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
8.6.3 while Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
8.6.4 foreach Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
8.7 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
8.7.1 One Dimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
8.7.2 Multidimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
8.8 OOP and Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
8.8.1 Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
8.8.2 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
8.8.2.1 class Implementation . . . . . . . . . . . . . . . . . . . . . . . . 92
8.8.2.2 Constructor and Destructor . . . . . . . . . . . . . . . . . . . . 93
8.8.2.3 Access Specifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
8.8.2.4 Rectangle class Example . . . . . . . . . . . . . . . . . . . . . . 94
8.8.2.5 Inheritance Example . . . . . . . . . . . . . . . . . . . . . . . . . 94
8.8.3 Some UML Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
8.9 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
8.9.1 try and catch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
8.9.2 The finally Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
8.10 Floatingpoint Precision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
8.10.1 Description of the Application . . . . . . . . . . . . . . . . . . . . . . . . 99
8.10.2 Exercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
10.6.2015
Page vi CAD in Civil Engineering / 2015
9 Using EXCEL from C# 100
9.1 First Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
9.2 My Hello within an EXCEL-Sheet . . . . . . . . . . . . . . . . . . . . . . . . . . 101
9.3 Some Useful EXCEL Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
9.3.1 Excel’s Application Class . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
9.3.2 Excel’s Workbook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
9.3.3 Excel’s Worksheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
9.3.4 The Garbage Collector’s Problem . . . . . . . . . . . . . . . . . . . . . . . 104
9.3.5 The Folder Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
9.4 RootFinder Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
9.4.1 A Logger Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
9.4.2 The Roots Data, the Class Root . . . . . . . . . . . . . . . . . . . . . . . 109
9.4.3 The RootFinder Class and Newton’s Algorithm . . . . . . . . . . . . . . . 110
9.4.4 Newton’s Algorithm to calculate a Root . . . . . . . . . . . . . . . . . . . 110
9.4.5 Sorting an ArrayList Class . . . . . . . . . . . . . . . . . . . . . . . . . . 112
9.4.6 Applying the RootFinder Class . . . . . . . . . . . . . . . . . . . . . . . . 116
9.4.7 The RootFinder’s XLSWriter Class . . . . . . . . . . . . . . . . . . . . . 118
10 AutoCAD Extensions written in C# 123
10.1 First Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
10.2 A little Hello . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
10.3 A little MText Hello . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
10.4 Project Plate with Hole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
10.4.1 Project Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
10.4.2 Helper Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
10.4.2.1 The Logger Class . . . . . . . . . . . . . . . . . . . . . . . . . . 132
10.4.2.2 The AcLogger Class . . . . . . . . . . . . . . . . . . . . . . . . . 133
10.4.2.3 The AcTrans Class . . . . . . . . . . . . . . . . . . . . . . . . . 133
10.4.3 Plate Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
10.4.4 OpenFileDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
10.4.5 AutoCAD Object Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
10.4.5.1 Geometry - Objects . . . . . . . . . . . . . . . . . . . . . . . . . 141
10.4.5.2 DatabaseService - Objects . . . . . . . . . . . . . . . . . . . . . . 141
10.4.6 Plate Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
10.4.7 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
V Solutions 150
11 C#-Applications 151
11.1 Precision-Finder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
11.1.1 The Frame Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
11.1.2 The Precision Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
11.1.3 Running the PrecisionFinder . . . . . . . . . . . . . . . . . . . . . . . . . 153
A Used Software 155
A.1 The Visual-Studio IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
E. Baeck
CONTENTS Page vii
10.6.2015
CONTENTS Page 1
10.6.2015
Part I
Introduction to VBA
2
1
General Statements
1.1 AutoCad - Versions and VBA
If you want to write VBA extensions to the AutoCad application, you have to install an
addon, if you use an AutoCAD version 2010 and higher. The addon has to be selected from the
AutoCAD service download page1 for the used AutoCAD version and the applied platform.
Figure 1.1 shows the download page for the VBA development extension.
Figure 1.1: VBA Download Page
Within a first step the self extracting archive file is executed. All files of the setup are stored in
a work folder. The setup application is started automatically and the VBA extension will be
installed. After the installation the steps of the following sections can be executed.
1.2 VB-IDE
The VBA-IDE2 can be started with the command vbaide.
1The VBA development package can be downloaded from the following link.
http://usa.autodesk.com/adsk/servlet/item?siteID=123112&id=12715668&linkID=92406182IDE: Integrated Development Environment
3
Page 4 CAD in Civil Engineering / 2015
1.3 Macro Manager
The Macro-Manager (figure 1.2) can be started with the command vbarun. A macro (vba
script) can be started with the methode Ausfuhren. The command Bearbeiten starts the
VBA-IDE. The command VBA-Manager starts the VBA-Manager (see figure 1.3).
Figure 1.2: Macro Manager
VBA scripts or macros live in modules of a AutoCAD project. An AutoCAD project is stored
in an dvb-file. With the command Laden a dvb-file is loaded. The methode Makros returns
to the Makro Manager (see above). A new project is created by the methode Neu and saved
to the disc by the methode Speichern unter.
E. Baeck
1.3. MACRO MANAGER Page 5
Figure 1.3: VBA Manager
10.6.2015
2
Basics in VBA
2.1 Data Types, Variables and Constants
Within the following section we will discuss the available data types for the variables of VBA.
We will discuss how to declare and initialize variables and constants.
2.1.1 Data Types
Table 2.1 shows the available data types of VBA.
Type Comment Range
Byte one byte integer, no negative values 0, 1, 2, · · · , 255
Integer two byte integer number −32768, · · · ,+32767
Long four byte integer number −231, · · · , 231 − 1
Single four byte float number ±1, 4 · 10−45 · · · 3, 4 · 10+38
Double eight byte float number ±4, 9 · 10−324 · · · 1, 8 · 10+308
Boolean two byte flag only True and False
String text stream up to 2GBytes "This is an Example"
Object 4 byte address of an object instance set s = new Line
Variant a container for all data types
Table 2.1: VBA Data Types
6
2.1. DATA TYPES, VARIABLES AND CONSTANTS Page 7
2.1.2 Declaration of Variables and Constants in VBA
2.1.2.1 Explicit Declarations
A constant is simple declared by the key word const. The following example shows the decla-
ration of two integer constants and one string constant. An error occur, if you try to assign a
value to a constant.
1 Const A = 1
2 Const B = 2
3 Const N = "Harry"
An explicit declaration of a variable is set with the key word Dim and As. Dim is followed by
the variables name. After the variable’s name the data type is set after the key word As.
1 Dim A As Integer
2 Dim B As Integer
3 Dim N As String
You need not declare the constants and variables in a header section of a block of code like in
C. In VBA declarations can be used like in C++ in any position of the code.
An explicit declaration can be forced by the statement option explicit. If so, this statement
should be the first statement within the VBA module. If option explicit is set, the use of
not explicit declared variables causes a runtime error.
2.1.2.2 Implicit Declarations
If option explicit is not set and a variable is introduced in a statement at the left side of
the assign operator, VBA allocates a variable of the type variant. That means, that VBA
creates a container for everything. So we can assign every data type to a variant variable. The
variant data type especially is used as interface data type to the EXCEL application within
a call of user functions.
If a special data type should be used implementing a variable, the variables name can be used
like in the FORTRAN language. In VBA we can extend the variables name by a character,
which sets up the variables data type. The following declarations are available (see table 2.2).
Type Character Example
Byte not available
Integer % a% = 1
Long & b& = 2
Single ! c! = 3.1
Double # d# = 4.1
String $ s$ = "So What"’
Table 2.2: VBA Implicit Declaration
10.6.2015
Page 8 CAD in Civil Engineering / 2015
2.2 Operators
VBA offers a set of operators, which are offered from the most computer languages. VBA
uses the same precedence as we know form the mathematics. The power operation has the
strongest binding followed by the point operators (products and divisions) followed by the line
operators (plus and minus). Unary operators will always be applied first. To change the standard
precedence of the operators we use like in mathematics parenthesis to dictate the way a formula
should be evaluated.
2.2.1 Unary Operators
Unary operators are working only on one value, therefor unary. In VBA there are the following
unary operators available.
Operator Comment Example
+ plus operator a = 2 >>> x = +a >>> +2
- minus operator a = 2 >>> x = -a >>> -2
not logical inverse a = False >>> x = not a >>> True
2.2.2 Arithmetic Operators
VBA offers the following arithmetic operators. You should be careful with the usage of data
types especially within divisions. If you use integers, the result generally will be truncated.
Operator Comment Example
+ sum operator x = 2+3 >>> 5
- substraction operator x = 4-2 >>> 2
* product operator x = 2*4 >>> 8
/ division operator x = 9/2 >>> 4
x = 9./2. >>> 4.5
^ power operator x = a^2
& concatenate of strings with values s = "a = " & a
2.2.3 Comparison Operators
Boolean operators are used to branch and to make decisions. The comparing operators of VBA
are now nearly identical to the C comparing operators.
E. Baeck
2.2. OPERATORS Page 9
Operator Comment Example
< less than x = 23 < 13 >>> False
<= less equal x = 23 <= 23 >>> True
> greater x = 23 > 13 >>> True
>= left shift of bits x = 23 >= 23 >>> True
= equal x = 23 = 23 >>> True
<> non equal x = 23 <> 23 >>> False
The result of a boolean expression like above are the boolean values False or True. To combine
comparing expressions the following logical operators can be used.1
Operator Comment Example
and logical and x = 1 < 2 and 2 < 3 >>> True
or logical or x = 1 < 2 or 2 > 3 >>> True
xor logical or x = True >>> y = False >>> x xor y >>> True
not logical not x = not (1 < 2) >>> False
The truth table for the and operator ∧ is given as follows.
True ∧ True = True (2.1)
True ∧ False = False
False ∧ True = False
False ∧ False = False
The truth table for the or operator ∨ is given as follows.
True ∨ True = True (2.2)
True ∨ False = True
False ∨ True = True
False ∨ False = False
The truth table for the xor operator is given as follows.
True xor True = False (2.3)
True xor False = True
False xor True = True
False xor False = False
1To make expressions clear parenthesis should be used. A term within a parenthesis is evaluated first and it’s
result then is used in further evaluations outside the parenthesis. With parenthesis the order of the evaluation
can be set.
10.6.2015
Page 10 CAD in Civil Engineering / 2015
2.3 Assigning Values
Assigning a value to a variable is done with the operator =. Dump output for program testing
is written in the immediate window by the Debug object using the object method Print.
Listing 2.1: How to assign values to variables
1 ’ Example of the session on 09-04-28
2
3 ’ Example 1
4 ’ Summing up 2 values and writing a log to the output window
5
6 ’ >> Theme: Assigning a value
7
8 Sub Example_1 ()
9
10 Dim a As Integer
11 Dim b As Integer
12
13 a = 1
14 Debug.Print "a = " & a
15
16 b = 2
17 Debug.Print "b = " & b
18
19 a = a + b
20 Debug.Print "a = " & a
21
22 End Sub
E. Baeck
2.4. FOR-LOOPS Page 11
2.4 FOR-Loops
The following example shows the usage of a for loop. A for -loop starts with the key word for
and ends with the key word next. A for loop needs a counter variable which is initialized by the
first value and runs up to the To-value under consideration of the step width.
Listing 2.2: Simple loop to add up some numbers
1 ’ Example of the session on 09-04-28
2
3 ’ Example 2
4 ’ Summing up all odd integers from 1 to 10
5 ’ Writing the log for i-Values graeter 5
6
7 ’ >> Theme: For -loop with conditional logging
8
9 Sub Example_2 ()
10
11 Dim s As Integer
12 Dim i As Integer
13
14 s = 0
15 For i = 1 To 10 Step 2
16
17 s = s + i
18
19 If i > 5 Then
20 Debug.Print "i = " & i & " s = " & s
21 End If
22
23 Next
24
25 End Sub
10.6.2015
Page 12 CAD in Civil Engineering / 2015
2.5 Data Types
The next example shows the difference between several data types using them in the context of
a program which calculates the faculty. It can be easily shown that the use of double as data
type for the faculty is the best choice to avoid an overflow problem.
Listing 2.3: Checking data types applying the factorial
1 ’ Example of the session on 09-04-28
2
3 ’ Example 3
4
5 ’ Calculating the faculty for several data types
6
7 ’ >> Theme: For -loop and overflow
8
9 Sub Example_3 ()
10
11 ’ Dim f As integer
12 ’ Dim f As long
13 ’ Dim f as single
14 Dim f As Double
15 Dim i As Integer
16 Dim n As Integer
17
18 ’ n! is calculated with the following value
19 n = 170
20
21 ’ be carefull with the initialization
22 f = 1
23 For i = 1 To n
24
25 f = f * i
26 Debug.Print " i = " & i & " f = " & f
27 Next
28
29 End Sub
E. Baeck
2.6. CALCULATION OF PRECISION Page 13
2.6 Calculation of Precision
The following example shows the usage of an implicit do loop. The infinite loop ends with a
break condition witch checks the visibility of an ε-value in the numeric noise.
The input data are captured by the VBA input box function. The user can select single or
double as precision key. If a unknown key is given the function precision returns an error value.
The results are shown by a Message Box using the function MsgBox .
The relative precision is returned by the function as return value.
Listing 2.4: Main program to calculate a data types precision
1 ’ main -program of precision
2
3 Sub prec_main ()
4
5 Dim key As String ’ "text"-variable < 2 * 10^9 characters
6 Dim pre As Double ’ (largest number in long with sign)
7
8 ’ input key value using an inputbox
9 key = "single"
10
11 ’ call of the inputbox
12 key = InputBox("Input of data type (single/double ):", "Input", key)
13
14 MsgBox "Selected key value :" + key , vbInformation , "Information"
15
16 pre = precision(key)
17 Debug.Print "precision = " & pre
18
19 End Sub
10.6.2015
Page 14 CAD in Civil Engineering / 2015
To check the precision of a 4-byte (single) and a 8-byte floating point variable, we have to
introduce complete sets of variables with the desired data type, to produce correct precision
cutting.
If there is a iterative reduced ε-value added to the variable content of one, this ε-value vanishes
if the relative precision is reached. The step before ε-value vanishes gives the relative precision.
Listing 2.5: Subroutine to calculate a data types precision
1 ’ calculation of the precision
2
3 Function precision(k As String) As Double
4
5 ’ single type variables
6 Dim x1s As Single
7 Dim x2s As Single
8 Dim epss As Single
9
10 ’ evaluate single case
11 If k = "single" Then
12
13 x1s = 1! ’ single constant
14 epss = 1!
15
16 ’ impclicit loop
17 Do
18
19 epss = epss / 2! ’ reduce the eps
20 x2s = x1s + epss
21
22 Debug.Print "x1s = " & x1s & ", epss = " & epss
23 ’ check if eps still exists
24 If x1s = x2s Then Exit Do
25
26 Loop
27
28 ’ setup return value with one step backward
29 precision = epss * 2!
30
31 ’ evaluate double case
32 ElseIf k = "double" Then
33
34
35
36 ’ error case: return = -1 because -1 is not a precision value
37 Else
38 MsgBox "Key ’" + k + "’ is not supported!", vbCritical , "Error"
39 precision = -1
40 End If
41
42 End Function
E. Baeck
2.7. NEWTON ALGORITHM Page 15
2.7 Newton Algorithm
The following example implements the algorithm of newton to search the roots of a given func-
tion.
A pure VBA - Version is given in the first program version
2.7.1 Pure VBA Version with Smart Slope
The only parameters, which are given by the user are the maximal number of iteration to avoid
an endless loop and the precision of the break condition.
The function newton returns the root value, if found. If an error happened the function will
return zero and will give an error flag of 1 or 2.
Listing 2.6: Main routine of the implementation of Newton’s algorithm in a simple version
1 ’ Newton algorithm
2 ’
3 Sub example_5 ()
4
5 Dim nmax As Integer ’ maximum iterations
6 Dim iter As Integer ’ number of iterations
7 Dim flag As Integer ’ return flag
8 Dim eps As Double ’ precision
9 Dim x0 As Double ’ Solution value
10
11 nmax = 20
12 nmax = InputBox("Maximum of iterations", "Input", nmax)
13
14 eps = 0.000001
15 x0 = newton(iter , nmax , eps , flag)
16
17 ’ case: solution found
18 If flag = 0 Then
19
20 MsgBox "result = " & x0 & " (Iterations: " & iter & ")"
21
22 ’ case: no solution found
23 Else
24
25 MsgBox "Error " & flag & ". No solution found (Iterations: " & iter & ")"
26
27 End If
28
29 End Sub
10.6.2015
Page 16 CAD in Civil Engineering / 2015
The user function should be implemented in the frame of the following function f.
Listing 2.7: Newton function of the implementation of Newton’s algorithm in a simple version
1 ’ Newton algorithm
2 ’ all functions
3
4 ’ user function f(x)
5
6 Function f(x As Double) As Double
7
8 f = x ^ 2 + 1
9
10 End Function
11
12 Function fs(x As Double) As Double
13
14 Dim delx As Double
15
16 delx = 0.000001
17
18 fs = (f(x + delx / 2#) - f(x - delx / 2#)) / delx
19
20 End Function
21
22
23 ’ Newton algorithm
24
25 Function newton(n As Integer , nmax As Integer , eps As Double , flag As Integer) As Double
26
27 Dim x As Double
28 Dim fx As Double ’ function value
29 Dim fsx As Double ’ slop of the function
30 Dim stp As Double ’ step in case of error 1
31
32 ’ counter
33 n = 1
34 stp = 0.1
35
36 ’ 0: solution found
37 flag = 0
38
39 ’ iteration loop
40 Do
41
42 ’ solution found
43 start:
44 fx = f(x)
45 fsx = fs(x)
46
47 ’ debug information
48 Debug.Print " f(" & x & ")= " & fx & " fs(" & x & ")= " & fsx
49
50 If Abs(fx) < eps Then
51 newton = x
52 Exit Function
E. Baeck
2.7. NEWTON ALGORITHM Page 17
53 End If
54
55 ’ f’(x) = 0 ?
56 If Abs(fsx) < eps Then
57 newton = 0
58
59 x = x + stp
60
61 ’ if max. iterations are reached , then exit
62 ’ vanishing slope
63 If n >= nmax Then
64 flag = 1
65 Exit Function
66 End If
67
68 n = n + 1 ’ Step besides as a new try
69 GoTo start ’ start againt , next try
70
71 End If
72
73 ’ max of iteration reached , then exit (Error 2)
74 If n >= nmax Then
75 newton = 0
76 flag = 2
77 Exit Function
78 End If
79
80 ’ next x-value
81 x = x - fx / fsx
82 n = n + 1
83 Loop
84
85 End Function
10.6.2015
Page 18 CAD in Civil Engineering / 2015
2.7.2 EXCEL VBA Version with EXCEL-Sheet-GUI
The following version of newton implements the algorithm with an excel-sheet gui (see figure
2.1) . In the input section there are input cells for the initial value of x , the desired precision
and the maximum number of iterations hightligthed in yellow. Result information is printed in
the result cells highligthed in light blue. After execution of newton the root and the number
of performed iterations are printed. If newton dedectes problems the root result cell is used
for further informations.
Figure 2.1: XLS-Sheet GUI
The command button supports a click event. If the command button is clicked in layout mode,
a click event function frame is created called commandbutton1 click (see figure 2.2). This
function is call from EXCEL if the command button is clickt and the VB code of the function
is executed.
Figure 2.2: Click Event Function for a Command Button
The event code of a sheets button lives in the sheets code file. To support a more general usable
newton function, the code of newton is set into a modul called newtonlib2. The code in
newtonlib is designed without explicit links to excel specific features. So it’s possible to use
this code simply by copying it into other VBA driven applications like AutoCAD.
2A new module can be inserted into the EXCEL project by use of the context menu of the project browser.
E. Baeck
2.7. NEWTON ALGORITHM Page 19
The event function for the command button is given by the following code.3
Listing 2.8: Event Function for a Run Button
1 ’ Event function to start the newton calculation
2 Private Sub CommandButton1_Click ()
3
4 Dim x0 As Double ’ starting position
5 Dim eps As Double ’ Precision
6 Dim iterX As Integer ’ max. number of iterations
7 Dim iter As Integer ’ number of performed iterations
8 Dim flag As Integer ’ return code flag
9
10 ’ loading data
11 x0 = Range("X_0")
12 eps = Range("Precision")
13 iterX = Range("MaxIter")
14
15 ’ start calculation
16 ’ - flag = 0: root found
17 ’ = 1: vanishing slop
18 ’ = 2: no root found
19 x0 = newton(x0, iterX , eps , flag , iter)
20
21 ’ output to the xls sheet
22 ’ case: result
23 If flag = 0 Then
24 Range("Root") = x0
25 Range("Iterations") = iter
26
27 ’ case: slop problem
28 ElseIf flag = 1 Then
29 Range("Root") = "Error: vanishing slop"
30 Range("Iterations") = iter
31
32 ’ case: no result found
33 ElseIf flag = 2 Then
34 Range("Root") = "Error: No root found"
35 Range("Iterations") = iter
36
37 ’ case: unsupported flag
38 Else
39 Range("Root") = "Error: unknown error"
40 Range("Iterations") = iter
41
42 End If
43
44 End Sub
3The object range of the EXCEL-type library can be used for VBA-EXCEL communication. It’s useful to
write data from VBA into an EXCEL-cell or to read data from an EXCEL-cell into a VBA variable.
10.6.2015
Page 20 CAD in Civil Engineering / 2015
The code of the general newton functions is set into a module, which is called newtonlib.
Because the function newton should be callable from outside of the module, the function should
have the attribute public. All other functions, which are in this context private functions, that
means which are not called from outside, are set to private functions. To check the iteration
data, a debug.print command is set at the end of the iteration loop, to print the actual data
into the intermediate window.
Listing 2.9: Code of the Newton Lib
1 Option Explicit
2
3 ’ function of newton
4 Private Function f(x As Double) As Double
5
6 f = x ^ 2 - 1
7
8 End Function
9
10 ’ calculation of slop
11
12 Private Function fs(x As Double) As Double
13
14 Dim h As Double
15 h = 0.00001 * x
16
17 fs = (f(x + h / 2) - f(x - h / 2)) / h
18
19 End Function
20
21 ’ newton sceem
22
23 Public Function newton(x0 As Double , iterX As Integer , _
24 eps As Double , _
25 flag As Integer , iter As Integer) As Double
26
27 Dim fx As Double ’ function value
28 Dim fsx As Double ’ functions slop
29
30 iter = 0 ’ initialization of the iteration counter
31 flag = 0 ’ case of success
32
33
34 ’ iteration loop
35 Do
36
37 fx = f(x0)
38 fsx = fs(x0)
39
40 ’ case: root found
41 If Abs(fx) <= eps Then
42
43 newton = x0 ’ set the return value
44 Exit Function
45
46 ’ case: min/max point vanishing slop
E. Baeck
2.7. NEWTON ALGORITHM Page 21
47 ElseIf Abs(fsx) <= eps Then
48
49 newton = x0
50 flag = 1
51 Exit Function
52
53 ’ case: root not found
54 ElseIf iter > iterX Then
55
56 newton = x0
57 flag = 2
58 Exit Function
59
60 End If
61
62 ’ case: perform iteration
63 x0 = x0 - fx / fsx
64 iter = iter + 1
65
66 Debug.Print " i=" & iter & ", x0=" & x0 & ", f(x)=" & fx & ", f’(x)=" & fsx
67
68 Loop
69
70 End Function
10.6.2015
Page 22 CAD in Civil Engineering / 2015
2.8 Data Structures
The goal of the following example is to describe a set of mass points given by their coordinates
and mass value using data structures4, that means user defined data types as a compound of
basic data types and user defined data types. The mass data should be stored in arrays. The
center of mass as well as the total mass should be calculated.
Outside the main program the new data type Mass is declared as user defined data type for
the mass points. Within the main program an array is declared, to store the data of all mass
points. the array is first allocated as an dynamical array without an given index range. Later
after setting the count of the mass points the length of the array is set dynamical by the use
of the Redim statement. After having committed the input data the routine to calculate the
total mass as well as the center of mass vector is called. After the calculation a list is presented
in a message box.
Please note that the option explicit is set, which means, that all variables have to be declared
explicitly. If there is an error in a variable name, the compiler often is able to find the error
checking the declarations.
Listing 2.10: Data Structures of a Mass Point, Example Masspoint
1 Option Explicit ’ every variable has to be declared explicitly
2
3 ’ data type for a mass point
4 Type Mass
5 x(1 To 3) As Double ’ coordinates: x,y,z
6 M As Double ’ mass value
7 c As Integer ’ colour index (etc.)
8 End Type
9
10
11 ’ Masspoints version 1
12
13 Sub masspoints1 ()
14
15 Dim nMass As Integer ’ number masspoints
16 Dim M() As Mass ’ array of masspoints
17 Dim i As Integer ’ for counter variable
18 Dim xc(1 To 3) As Double ’ vector of the center of mass
19 Dim Ms As Double ’ sum of the masses
20
21 ’ data input
22 nMass = 4
23
24 ’ allocate the memory for the masspoints
25 ReDim M(1 To nMass) ’ Mass 1,2,3,4
26
27 ’ setup masspoint 1
28 M(1).c = 1
29 M(1).M = 20#
4Data structures can be interpreted as objects without methods and only public attributes. In VBA objects
can be accessed as class modules only using pointers, but structures are accessed by value, that means like simple
variables of basic types.
E. Baeck
2.8. DATA STRUCTURES Page 23
30 M(1).x(1) = 0 ’ x value of mass 1
31 M(1).x(2) = 0 ’ y value of mass 1
32 M(1).x(3) = 0 ’ z value of mass 1
33
34 ’ Initialization of the masspoint 2-4 using data of point 1
35 For i = 2 To nMass
36 M(i) = M(1) ’ total data of point 1 is copied
37 Next
38
39 ’ Overwrite special data for points 2-4
40 ’ - setup masspoint 2
41 M(2).x(1) = 10 ’ x value of mass 2
42
43 ’ - setup masspoint 3
44 M(3).x(1) = 10 ’ x value of mass 3
45 M(3).x(2) = 10 ’ y value of mass 3
46
47 ’ - setup masspoint 4
48 M(4).x(2) = 10 ’ y value of mass 4
49
50 ’ calculation of the center of mass
51 Call GetCenterOfMass(M, xc, Ms)
52
53 ’ list results into a Messagebox
54 Call ListResults(M, xc, Ms)
55
56 End Sub
After the assignment of the input data the subprogram GetCenterOfMass is called to perform
the desired calculation of the total mass and the vector of the center of mass. As parameters the
array of the masses and the array of the center of mass vector is passed as well as the total mass.
The array ranges need not to be passed because we have the VBA functions LBound and
UBound, which are able to determine the lower and the upper bound of an array. Therefore
this functions are used to perform the loop ranges in the following example.
Listing 2.11: Calculation of the Center of Mass
1 ’ calculation of the center of mass
2
3 Sub GetCenterOfMass(M() As Mass , xc() As Double , Mt As Double)
4
5 Dim i As Integer
6 Dim j As Integer
7
8 ’ calculation of the total mass
9 Mt = 0#
10 For i = LBound(M) To UBound(M)
11 Mt = Mt + M(i).M
12 Next
13
14 ’ calculation of mean values for the coordinates
15 ’ loop of the components
16 For i = 1 To 3
17
18 xc(i) = 0 ’ initialization of the component
10.6.2015
Page 24 CAD in Civil Engineering / 2015
19 ’ in this case VERY important
20
21 ’ loop over all masses
22 For j = LBound(M) To UBound(M)
23 xc(i) = xc(i) + M(j).M * M(j).x(i)
24 Next
25 xc(i) = xc(i) / Mt
26
27 Next
28
29 End Sub
After having calculated the result data the result will be printed into a message box. Doing this
we have to think about line breaks. A line break is performed in VBA bei appending the control
codes carrage return and line feed. In VBA the respective constants vbCr and vbLf an be
used. After closing the messagebox the result string is also printed into the AutoCAD command
window using the method prompt of the AutoCAD object ThisDrawing.Utility (see section
4.1.1).
Listing 2.12: List the Results in a Message Box
1 ’ list results into a messagebox
2
3 Sub ListResults(M() As Mass , xc() As Double , Mt As Double)
4
5
6 Dim s As String ’ content of the messagebox
7 Dim i As Integer ’ loop counter
8
9 ’ title: masses
10 s = "Masses:" & vbCr & vbLf
11
12 ’ output of mass values
13 For i = LBound(M) To UBound(M)
14 s = s + " Mass " & i & " : " & M(i).M & vbCr & vbLf
15 Next
16
17 ’ title: coordinates
18 s = s + "Coordinates:" & vbCr & vbLf
19
20 ’ output coordinates of the masses
21 For i = LBound(M) To UBound(M)
22 s = s + " Mass " & i & " : " & M(i).x(1) & "; " _
23 & M(i).x(2) & "; " _
24 & M(i).x(3) & "; " & vbCr & vbLf
25 Next
26
27 ’ title: coordinates
28 s = s + "Results:" & vbCr & vbLf
29
30 ’ total Mass
31 s = s + " total mass: " & Mt & vbCr & vbLf
32
33 ’ center of Mass
34 s = s + " Center of mass: " & xc(1) & "; " _
E. Baeck
2.8. DATA STRUCTURES Page 25
35 & xc(2) & "; " _
36 & xc(3) & "; " & vbCr & vbLf
37
38 ’ output into the messagebox
39 MsgBox s, vbInformation , "Masses"
40
41 ’ printout in command window (see below)
42 s = vbCr & vbLf & s
43 ThisDrawing.Utility.Prompt s
44
45 End Sub
10.6.2015
Page 26 CAD in Civil Engineering / 2015
2.9 Text Files
If we want to work with files we have to talk about four basic file functions. A little example
which implements logging is given below, see also section 4.2.2.
• Open a File
A file is opened using the statement Open. The open statement has three parameters. The
first is the filename, a string. The second is the file access mode and the third parameter
sets the access channel number.5
– We can open a file for reading data, it’s called For Input.
– We can open a file for writing data, it’s called For Output. If a file is opened for
output, an old file with the same name is first deleted.
– We can open a file for appending data, it’s called For Append. If a file is opened
for append, an old file with the same name is not deleted. Data to write are written
to the end of an existing file. If no file exists with the same name, open for append
has the same effect as open for output.
• Close a File
An opened file should be closed after the work is done because the file handles of the
operating system (windows, linux, etc.) are limited. The close method has only one
parameter which is the access channel.
• Writing into a File
If text data should be written into a file, the print method can be used. The print method
has two parameter. The first parameter sets the file access channel. The second parameter
passes a the output string.
• Reading from a File
If text data should be read from a file, the line input method can be used. The line
input method has two parameter. The first parameter sets the file access channel. The
second parameter passes a string variable which is used to receive the input data.
5This file access mode is like in FORTRAN.
E. Baeck
2.10. CLASS MODULES Page 27
2.10 Class Modules
Class Modules are inserted into the vb-project tree. Each class module has it’s own node in
the tree. Within the class module all attribute and methods of an vb-object are declared. The
class modules attributes are like global variables, which are declared in the header of the class
module6
The fundamental difference between a variable of a standard type (integer, double, etc.) and
an instance7 of a class is, that Visual Basic offers an address pointer only for class instances
and not for standard data types. Therefore only instances of class modules can be handled with
so-called buildin container classes like the collection class and only instances of class modules
can be part of so-called type libraries (like the EXCEL or AutoCAD type library).
Instance addresses can only be assigned using the set operator (The use of the set operator is
described in the following examples). An instance of a class module is created by the use of
the new operator. An instance of a class module is deleted explicitly by the assignment of the
nothing address if the instance is only referenced once, i.e. by this address pointer.
Attributes and methods of a class module can be set to private and public. A private member
of a class module is only visible within its own class module. A public member however is visible
form outside of the class module and can be accessed using the general dot notation like members
of a type structure (see section 2.8 and the following examples).
2.10.1 A Mass Point Class Module
In the following example a mass point will be modelled by a class module.
The class module MassObj - this is the name of the class modules node in the vb project tree
- has three attributes:
• a double array of its coordinates,8.
• a double mass value and
• a double value for the density of the sphere’s material
Listing 2.13: Class Modules’ Attributes
1 ’ Attributes of the object
2
3 Dim xi(2) As Double ’ coordinates
4 ’ arrays are PRIVATE in VBA
5 ’ therefor we need access -functions (get/set)
6 Public m As Double ’ mass value
7 Public rho As Double ’ density of the mass
6I.e. in front of the first method outside of all methods.7This is the implementation of a class module in memory.8In the AutoCAD type library arrays generally starts with the lower bound index zero and therefore this array
will be declared only by specifying the upper bound index
10.6.2015
Page 28 CAD in Civil Engineering / 2015
The attribute section is followed by the section of the classes methods. If an instance is created
by an new operator call, the so-called constructor Class Initialize is called. This method
is usually used for initializations. In our example we set the density of the mass point to the
density of steel. The method Class Terminate, the so-called destructor, is called if an instance
of the class module is deleted. The content of a desctrutor method can be used for clearing. An
instance of a class module can be deleted by the assignment of the nothing address.
Listing 2.14: Class Module’s Constructor and Destructor
1 Private Sub Class_Initialize ()
2
3 rho = 0.00000784 ’ density of steel by default
4
5 End Sub
6
7 ’ destructor is called if the object is deleted from the memory
8 ’ by assigning "nothing"
9
10 Private Sub Class_Terminate ()
11
12 End Sub
In our little class module example we use a double array to store the mass points coordinates.
Unfortunately an array attribute of a class module can not be set public. So we have to
implement access functions to pass data into the instance (set9 method) and pass data out of
the instance (get methode). To access to an array we use the index range. Each array knows its
index range and its index range can be red form the array using the LBound and UBound vb
function. The LBound provides the lower bound of the index range and the UBound provides
the upper bound of the index range.
The advantage of an access method comparing it to direct accesses is the possible error checking.
Therefore index errors can be handled by the class module itself (see the following example code).
Listing 2.15: Class Module’s Set and Get Methods
1 ’ pass data to the x-array
2
3 Public Function setX(x() As Double) As Boolean
4
5 setX = False
6
7 ’ check the parameters
8 If LBound(x) < 0 Then Exit Function
9 If UBound(x) > 2 Then Exit Function
10
11 ’ copy the values
12 setX = True
13 For i = 0 To 2
14 xi(i) = x(i)
15 Next
16
17 End Function
18
9We cannot use the set name because the set is used as a key word for the set operator.
E. Baeck
2.10. CLASS MODULES Page 29
19 ’ get function of the coordinates vector
20 ’ ... = m.x(i)
21
22 Public Function x(i As Integer) As Double
23 x = 0#
24 If i < 0 Or i > 2 Then Exit Function
25 x = x(i)
26 End Function
2.10.2 Create and Delete
Within the following example the creation and the clearing of an instance of the MassObj
instances are discussed. We use the class module within a procedure of a standard module. The
procedure is executed with the following steps.
• The address variable m1 and m2 are declared to get the address pointers of the desired
MassObj instances.
• The first mass m1 is created using the new operator. The address of the instance is
assigned to m1 using the address assign operator set. A mass value of 3 is assigned to the
public attribute m using the dot access.
• The second mass m2 is created like m1 and a mass value of 4 is assigned.
• An instance of a collection container is created and its address is assigned to the address
variable list.
• The addresses of the two masses are stored in the container using the keys10 M1 and
M2. Before we have stored the addresses in the container class the MassObj instances are
referenced only once. After having stored the addresses in the collection the addresses are
referenced twice. Addresses can be stored in a collection using the Add function. The
item parameter passes the instance address, the optional parameter key passes the key of
the instance, which is used for reading.
• Within the next step the address of mass 1 is assigned to the address pointer of mass 2.
Now mass 1 is referenced three times and mass 2 is referenced only once. If an address
looses all its references, the memory of this address is freed and the destructor of this
instance is called and executed. The memory cleaning is performed by the so-called garbage
collector11.
10Addresses of instances can be stored in a collection with an optional key name.11The garbage collector frees all memory blocks which have loosed their references and are unaccessible. This
is an advantage comparing it with the situation of C/C++. In C/C++ unaccessible memory blocks are not freed
and therefore results memory leaks.
10.6.2015
Page 30 CAD in Civil Engineering / 2015
Listing 2.16: Create and Delete Mass Objects
1 ’ create and delete a MassObj
2 Sub CreateAndDeleteAMass ()
3 ’ only create an address variable
4 Dim m1 As MassObj
5 Dim m2 As MassObj
6
7 ’ create an object in memory
8 Set m1 = New MassObj
9 m1.m = 3
10
11 ’ create 2nd mass object
12 Set m2 = New MassObj
13 m2.m = 4
14
15 ’ create a collection instance (object)
16 Dim list As New Collection
17
18 ’ insert the 1st mass object into the container
19 list.Add Item:=m1, key:="M1"
20
21 ’ insert the 2nd mass object into the container
22 list.Add Item:=m2, key:="M2"
23
24 ’ assign object addresses
25 Set m2 = m1
26
27 ’ make changes on m1
28 m1.m = 5
29
30 ’ delete the mass object
31 Set m1 = Nothing
32 End Sub
E. Baeck
3
Using EXCEL as GUI
One of the greatest advantages of VBA is the easy mechanism which is available to combine
different applications using their type libraries.
In our case it’s often very useful to have a common AutoCAD user-interface which offers a
wide range comfort for the user as well as for the software developer. If we try to implement
an EXCEL user-interface, we fulfil both boundary conditions. We can implement an EXCEL
user-interface first by simply using an EXCEL file as AutoCAD input file. As a second step we
implement an import method, to read the desired input data from the EXCEL input sheet.
To do this, we have to link the EXCEL type library to our AutoCAD project.
3.1 EXCEL Type Library
To use the COM-objects of EXCEL which are available in the EXCEL type library, we have
to set the link to the type library in our AutoCAD IDE.
Figure 3.1: Set up the EXCEL Type Library Link
The link can be set within the link man-
ager of the project, which can be called
from the extras menu of AutoCAD. In
figure 3.1 we see the type library of
the Microsoft EXCEL 11.0. This link
should be set by checking the corre-
sponding check button. If the link is set,
the COM-objects of EXCEL are avail-
able in our program.
31
Page 32 CAD in Civil Engineering / 2015
3.2 Import of an EXCEL File
To import the data of an EXCEL-file, we should do the following steps.
• Create an EXCEL application object.
• Specify the import files name with the common open file dialogue, which is available as
method of the EXCEL application object. Calling the method GetOpenFileName. We
can set-up a filtering by passing a filter string, in this example the filter mask *.xls.
• Check the return of the common open file dialogue. If the dialogue is cancelled the return
will be False as string.1
• Get the input sheets pointer by calling it from the Worksheets container. The container
Worksheets is simular to the build-in Collection. We get the desired sheet by calling it
with it’s name.
• Access to the worksheets data by using the methods Cells or Range. If we want to access
to the sheets data by the use of an absolute row and column index, we can use the Cells
method.2 On the other hand if we want to access to the sheet by the use of a name, we
should use the Range method. The Range method has in it’s simple version only one
parameter, which is the range’s name. We can also extend the Range call by relativ row
and column index values. 3
• Quit the EXCEL application. You should not forget to quit the EXCEL application,
because otherwise the object, i.e. the EXCEL application, will be still active hidden in
the background and can only be closed with a taskmanager’s kill method.
Listing 3.1: How to Use Excel As Frontend
1 ’ How to use EXCEL as GUI -Frontend
2
3 Sub ExcelImportTest ()
4
5 ’ start EXCEL
6 Set e = New Excel.Application
7
8 ’ specify XLS -input file
9 file = e.GetOpenFileName(fileFilter :="Input (*. xls),*.xls")
10
11 ’ handle canceling of the dialog
12 If file = "False" Then Exit Sub
13
14 ’ open the specified XLS file , the Workbook
15 e.Workbooks.Open FileName :=file
16
17 ’ get the address of the desired Worksheet
18 Set s = Excel.Worksheets("Input")
1In a german version the return is Falsch as a string.2The first argument is like the row label, the secound argument is the column label which starts also with 1.3In the following example we access to the content of the second row and the third column of the range
MyRange: x = Range(”MyRange”)(2,3)
E. Baeck
3.2. IMPORT OF AN EXCEL FILE Page 33
19
20 ’ read the content of A3 (row: 1 / column 3)
21 t = s.Cells(1, 3)
22
23 ’ quit the EXCEL application
24 ’ !!! don ’t forget it !!!
25 e.Application.Quit
26
27
28 End Sub
10.6.2015
Part II
AutoCAD-Objects
34
4
User Command Dialog
4.1 Command Window Interaction
Everything on AutoCAD has changed since AutoCAD version 13, working with the command
window remained nearly unchanged. In the context of the next sections some functions of
the AutoCAD’s Drawing Utility object are explained which can be used to communicate with
AutoCAD.
To read data from the input window AutoCAD offers a helper function, which lives in the
Utility item of the ThisDrawing object. The object ThisDrawing is the basic VBA object
which contains all the AutoCAD type library objects.
4.1.1 Prompting
To write a string to the command window the subobject Utility of the AutoCAD object This-
Drawing can be used. The method Prompt of Utility passes a specified string to the command
window.
The following example passes the string Hello AutoCAD world to the command window. The
constants vbCr and vbLf add a carriage return and a line feed character to the end of the string.
1 ThisDrawing.Utility.Prompt "Hello AutoCAD World!" & vbCr & vbLf
4.1.2 Get Integer Values
In the following example an integer value is red form the input screen. The method GetInteger
gets an optional parameter which is used as prompt in the input window. The GetInteger has
a built in error handler, which accepts only integer values as input data. But there is one
problem with the usual ESC break of the function. If GetInteger and other input functions
are canceled by ESC, the VBA kernel throws an exception1 To catch the exception in VBA in
a first step we have to hide local errors by On Local Error Resume Next If an error ocurre
an error object is created, the error is ignored and the next line is executed. So the calling
program is able to check the error number of the object. After the call of GetInteger the
1An exception is a controlled break of a code. An exception can be caught and therefor handled by the calling
program.
35
Page 36 CAD in Civil Engineering / 2015
error number has to be checked. If the error number is equal zero, no error has ocurred. If the
error number is not equal zero, the ESC has be used and the input routine was canceled. Even
though the GetInteger uses an integer as a return value, the return should be assigned to a
variant variable. A canceled call to GetInteger doesn’t return an integer and would produce
an error in an double assignment.
Listing 4.1: Reading an Integer from the Prompt
1 ’ Test of GetInteger
2 Sub GetIntegerTest ()
3 Dim inp As Variant
4
5 On Local Error Resume Next
6 inp = ThisDrawing.Utility.GetInteger(vbCr & vbLf & "Type an integer:")
7 If Err.Number <> 0 Then
8 MsgBox "Input error number: " & Err.Number
9 Else
10 MsgBox "Input ok: " & inp
11 End If
12 End Sub
4.1.3 Get Real Values
In the following example a real value is red form the input screen. The method GetReal gets
an optional parameter which is used as prompt in the input window. The GetReal has a built
in error handler, which accepts only real values as input data. But there is one problem with
the usual ESC break of the function. If GetReal and other input functions are canceled by
ESC, the VBA kernel throws an exception2 To catch the exception in VBA in a first step we
have to hide local errors by On Local Error Resume Next If an error ocurre an error object
is created, the error is ignored and the next line is executed. So the calling program is able to
check the error number of the object. After the call of GetReal the error number has to be
checked. If the error number is equal zero, no error has ocurred. If the error number is not equal
zero, the ESC has be used and the input routine was canceled. Even though the GetReal uses
a double as a return value, the return should be assigned to a variant variable. A canceled call
to GetReal doesn’t return a double and would produce an error in an double assignment.
Listing 4.2: Reading a Real from the Prompt
1 ’ Test of GetReal
2 Sub GetRealTest ()
3 Dim inp As Variant
4
5 ’ Local Error Resume Next
6 inp = ThisDrawing.Utility.GetReal(vbCr & vbLf & "Input of Real value:")
7 If Err.Number <> 0 Then
8 MsgBox "Error number: " & Err.Number
9 Else
10 MsgBox "Real value = " & inp
11 End If
12 End Sub
2An exception is a controlled break of a code. An exception can be caught and therefor handled by the calling
program.
E. Baeck
4.1. COMMAND WINDOW INTERACTION Page 37
4.1.4 Get Point Values
In the following example a point data set is red form the input screen. The method GetPoint
gets two parameters, the first is the starting point to draw a connecting line to the cursor
position, the second parameter passes the prompt for the command line. The second parameter
is like in other Get-functions optional. After selection is done the method returns an array of
the dimension (0 to 2) with the three coordinate values.
The GetPoint has a built in error handler, which accepts only point data values as input data.
The general input procedure of AutoCad is called and offers the whole palett of interactive
functions to select a points data. If GetPoint and other input functions are canceled by ESC,
the VBA kernel throws an exception3 To catch the exception in VBA in a first step we have
to hide local errors by On Local Error Resume Next If an error ocurre an error object is
created, the error is ignored and the next line is executed. So the calling program is able to
check the error number of the object. After the call of GetPoint the error number has to be
checked. If the error number is equal zero, no error has ocurred. If the error number is not equal
zero, the ESC has be used and the input routine was canceled. Even though the GetPoint uses
an double array as a return, the return should be assigned to a variant variable. A canceled
call to GetPoint doesn’t return an double array and would produce an error in an assignment.
Listing 4.3: Reading a Point from the Prompt
1 ’ Test of GetPoint
2 Sub GetPointTest ()
3 Dim inp As Variant
4
5 On Local Error Resume Next
6 inp = ThisDrawing.Utility.GetPoint(, "Where is the position: ")
7 If Err.Number <> 0 Then
8 MsgBox "Input error number: " & Err.Number
9 Else
10 ’ inp: dim inp (2) as double >> 0,1,2
11 MsgBox " Point: " & inp(0) & " - " & inp(1) & " - " & inp(2)
12 End If
13 End Sub
3An exception is a controlled break of a code. An exception can be caught and therefor handled by the calling
program.
10.6.2015
Page 38 CAD in Civil Engineering / 2015
4.2 Examples for Get-Functions
The AutoCAD Get-functions can be used to build up AutoCAD like line dialogs.
4.2.1 Creating some MassObj-Instances
The following example shows a user input driven creation of some instances of the MassObj
class module (see section 2.10.1).
4.2.1.1 The Line Dialogs Layout
The input dialog runs in the following steps.
1. Read the number of mass points to create with GetInteger.
2. Read the mass value of the mass point with GetReal.
3. Read the coordinates of the mass point with GetPoint.
4. If the number of mass points to create is not reached jump to the second step and read
the next mass points data.
4.2.2 Used Object Pointer
The following object pointers are used.
• m stores the address of a mass object instance. This instances are created step by step
during the input line dialog.
• list It’s possible to create more than one mass object instance. Therefore we have to store
the instance addresses in a container object. This container object instance is created from
the build-in vb collection class module. After the creation of the mass object instances a
for loop is performed over all stored object instances. The data of each instance are listed
using the object’s method list. Then the object’s are removed form the collection using
subsequent calls of it’s method remove removing the first object pointer in the list.
E. Baeck
4.2. EXAMPLES FOR GET-FUNCTIONS Page 39
4.2.3 Helper Procedures
To check the behavior of the programs execution we implement two helper procedures to write
subsequent messages into a log file. This two procedures live in a module4 which is called Lib.
Lib means library and is a box for non specific helper code.
• The log files name is stored in the public global variable tracefile. The initialization is
done within the procedure InitLog assigning the value of the constant string tracedefault
to the variable tracefile.
1 ’ default filename for logging
2 Public Const tracedefault = "c:\ vbalog.txt"
3
4 ’ logfilename
5 Public tracefile As String
• InitLog initializes the log file. That means an old one is deleted and a time stamp is
written into the new one. tracedefault is a constant string which contents the default
name of the log file. The log file is opened with the flag Output. The time stamp is
created with the vb build-in function now. We should not forget to close the file after we
have done our work with the statement close.
1 ’ Initalization for logging
2 Public Sub InitLog ()
3
4 ’ use the default filename
5 tracefile = tracedefault
6
7 ’ initalize the logfile
8 Open tracefile For Output As #1
9 Print #1, Now & " Start logging ..."
10 Close #1
11
12 End Sub
• AppendLog prints the next message into the log file. To hold the old information of the
log file, the log file has to be opened using the flag Append. Printing the message into
the file we also use a time stamp calling the function now. We should not forget to close
the file after we have done our work with the statement close.
1 ’ Append log information
2 Public Sub AppendLog(s As String)
3 Open tracefile For Append As #1
4 Print #1, Now & ": " + s
5 Close #1
6 End Sub
4The module is inserted by a right click on the project tree. The standard name should be changed to Lib.
10.6.2015
Page 40 CAD in Civil Engineering / 2015
4.2.4 Visual Basic Code
Listing 4.4: Create Mass Object from Command Line
1 ’ create a mass object from ACad command window
2
3 Public Sub CreateMassFromCommandWnd ()
4
5
6 Dim m As MassObj ’ MassObj - address variable
7
8 Dim list As New Collection ’ List of mass data
9 Dim inp As Variant ’ Input from command window
10
11 ’ Initialize logging
12 Call InitLog
13
14 ’ Read the number of the masses
15 On Local Error Resume Next
16 inp = ThisDrawing.Utility.GetInteger(vbCr & vbLf & "Number of Masses:")
17 If Err.Number <> 0 Then GoTo cancellabel
18
19 ’ log the number of masses
20 Call AppendLog("Create " & inp & " mass objects.")
21
22 ’ loop over all masses
23 nmasses = inp
24 For i = 1 To nmasses
25
26 Set m = New MassObj ’ create the next mass
27
28 ’ read the mass value
29 inp = ThisDrawing.Utility.GetReal(vbCr & vbLf & "Mass value of mass " & _
30 i & ":")
31 If Err.Number <> 0 Then GoTo cancellabel
32 m.m = inp
33
34 ’ log the number of masses
35 Call AppendLog("Mass " & i & ": " & m.m)
36
37 ’ read the mass position
38 inp = ThisDrawing.Utility.GetPoint(, vbCr & vbLf & "Mass position: ")
39 If Err.Number <> 0 Then GoTo cancellabel
40 If Not m.setXV(inp) Then
41 Call MsgBox("Can not copy data to coordinate array!", _
42 vbCritical , "Error")
43 End If
44
45 ’ log the number of masses
46 Call AppendLog("Mass " & i & ": " & m.x(0) & ", " & m.x(1) & _
47 ", " & m.x(2))
48
49 ’ store the mass object in the collection
50 list.Add Item:=m, key:="Mass -" & i
51
52 Next
E. Baeck
4.2. EXAMPLES FOR GET-FUNCTIONS Page 41
53
54 ’ List the mass data
55 Call AppendLog("List of " & list.Count & " mass objects:")
56 For i = 1 To list.Count
57
58 ’ get the mass address of item i
59 Set m = list(i) ’ List.Item(i)
60
61 ’ log the number of masses
62 Call AppendLog("Mass " & i & ": " & m.m)
63 Call AppendLog("Mass " & i & ": " & m.x(0) & ", " & m.x(1) & _
64 ", " & m.x(2))
65 Next
66
67 ’ Delete the collection
68 AppendLog ("Delete the Collection")
69 For i = 1 To list.Count
70
71 ’ delete the 1st item
72 Set m = list (1)
73
74 ’ delete the content
75 Set m = Nothing
76
77 ’ delete the address
78 list.Remove (1)
79
80 Next
81
82 Exit Sub
83
84 cancellabel:
85
86 Call ThisDrawing.Utility.Prompt(vbCr & vbLf & "*** canceled by the user ***")
87
88 End Sub
10.6.2015
5
Primitives in Modelspace
All two or three dimensional model objects like lines, arcs, spheres etc. live in the ModelSpace
object of the AutoCAD type library. The ModelSpace object is part of the fundamental
AutoCAD object ThisDrawing which can be seen as a container for all visual basic objects.
5.1 AcadLine Object
The AcadLine object is part of the ModelSpace object and can be created by calling the
specific add function AddLine. The AddLine function is a method of the ModelSpace object
and needs two Double arrays containing the 3d-coordinates for the starting and the endpoint.
A line can be created interactively with the command line.
A little example is given below. First we allocate two double arrays for the data of the start and
endpoint of a line. Then in three code blocks three lines are created changing the coordinates of
the endpoint before creating them. The address of the created line instance is assigned to the
object variable lineobj. To change the line’s color, the color index value should be assigned to
the color attribute of the line object. To show the assigned color the lines visualization should
be updated using the method Update.
Listing 5.1: Create a Line
1 ’ Create a AutoCad line object
2 Sub CreateLineTest ()
3
4 Dim x1(2) As Double ’ 1st point: 0:x / 1:y / 2:z
5 Dim x2(2) As Double ’ 2nd point: 0:x / 1:y / 2:z
6
7 ’ set up point 2
8 x2(0) = 100
9
10 ’ create a line
11 Set lineObj = ThisDrawing.ModelSpace.AddLine(x1, x2)
12 lineObj.color = 1
13 lineObj.Update
14
15 x2(0) = 100
16 x2(1) = 100
42
5.1. ACADLINE OBJECT Page 43
17 Set lineObj = ThisDrawing.ModelSpace.AddLine(x1 , x2)
18 lineObj.color = 2
19 lineObj.Update
20
21 x2(0) = 0
22 Set lineObj = ThisDrawing.ModelSpace.AddLine(x1 , x2)
23 lineObj.color = 3
24 lineObj.Update
25
26 End Sub
Figure 5.1: Result of the Examples Code
To delete lines from the drawing we can filter all objects with the type IAcadLine1 using an For
Each ... next iterator on the basis ThisDrawing.ModelSpace. An object can be deleted
calling the Delete method of the object. This is shown in the following example.
Listing 5.2: Delete Lines from the Model Space
1 Sub DeleteLinesFromDrawing ()
2 For Each obj In ThisDrawing.ModelSpace
3 If TypeName(obj) = "IAcadLine" Then
4 obj.Delete
5 ThisDrawing.Utility.Prompt vbCr + vbLf + "Line deleted."
6 End If
7 Next
8 End Sub
1If we don’t know the TypeName of an object, we can create this object. After the object is created, we will
see it’s type name in the so-called intermediate window of the vbaide.
10.6.2015
Page 44 CAD in Civil Engineering / 2015
5.2 Delete Objects from ModelSpace
Like we have seen in section 5.1 we can delete objects from the model space by iterating the
object space object by object. Within this section a library function is presented, which deletes
all objects from the ThisDrawing.ModelSpace container, the model space.
The following procedure ResetModelSpace deletes all objects from the model space and can
be applied as an initialization routine.
Listing 5.3: Reset the Model Space
1 ’ Delete all objects in modelspace
2 Public Sub ResetModelspace ()
3
4 ’ iterate all objects in modelspace
5 For Each obj In ThisDrawing.ModelSpace
6
7 ’ delete the found object
8 obj.Delete
9 Next
10
11 End Sub
5.3 AcadSphere Object
The AcadSphere object is a special Acad3DSolid object and is part of the ModelSpace
object and can be created by calling the specific add function AddSphere. The AddSphere
function is a method of the ModelSpace object and needs one Double arrays containing the
3d-coordinates for the center point and one Double which specifies the radius of the sphere.
A sphere can be created interactively with the command sphere.
In the following example lines and spheres are created in model space in a plan circular and
star-like distribution. There result is given in figure 5.2.
The procedure has the following structure.
• In the header section some declaration are made. We need two Double arrays for the start-
and endpoint coordinates of a line. Then we need a variable to hold the radius and the π
value.
• Then we calculate pi as a result of an arctan call as follows.2
π = 4 · arctan(1.) (5.1)
• After having created AutoCAD’s true color object AcadAcCmColor the model
space is reseted, to start with a new drawing calling our library helper procedure
ResetModelSpace.
2You should avoid to setup π with only some digits or use the crude approximation 227
, because if you do this,
you will introduce a methodical relative error of in the last case 10−3.
E. Baeck
5.3. ACADSPHERE OBJECT Page 45
• Then we set up the drawing’s parameter which are the radius of the lines endpoints with
respect to the starting point, which is the center of the system as well as the radius of the
spheres and the angle increment.
• Within a loop over all angle increments we create for every increment a line and a sphere
at the endpoint of the line. So we have to calculate the polar coordinates of the lines’s
endpoints, which describes a circle around the center with the given radius r .
x (ϕ) = r · cos(ϕ) (5.2)
y(ϕ) = r · sin(ϕ)
A line is created and the color of the line is established by the given red, green, blue values.
Because we want to draw only red lines the blue and green part of the color are set to
zero. We only have a red part and the red part is starting from 50 and increases up to it’s
maximum with 255.3
After having calculated the color’s intensity we call the SetRGB-Methode of the color
object and assign it to the line’s TrueColor attribute.
In the last step we create a sphere using the AddSphere methode of the ThisDraw-
ing.ModelSpace object. The calculated color value of the increment now is used to
create green spheres. Therefore we assign a zero value to the red and the blue part of the
RGB value and use the calculated color only for the green part for the AcadAcCmColor
object.
The example’s code is given below.
Listing 5.4: Create Lines and Spheres
1 ’ Lines and Spheres
2 Sub LinesAndSpheres ()
3
4 Dim x1(2) As Double ’ Starting point
5 Dim x2(2) As Double ’ End point
6
7 Dim i As Integer
8 Dim r As Double
9 Dim phi As Double
10 Dim pi As Double ’ pi constant
11
12 DegRad = Atn (1#) / 45#
13
14 ’ create Truecolor object
15 Set col = New AcadAcCmColor
16
17 ’ Reset the modelspace
18 Call ResetModelspace
19
20 ’ initialisation
21 r = 100 ’ Radius
22 rs = 10 ’ Radius of the spheres
3A RGB color has a minimum value of 0 and a maximum value of 255. This is exactly the range of one byte
without considering the sign.
10.6.2015
Page 46 CAD in Civil Engineering / 2015
23 del = 30 ’ step angle
24
25 ’ walk around the origin x1(2)
26 For i = 1 To 360 / del ’ 30 ◦ steps
27
28 ’ calculaltion of the endpoint coordinates
29 phi = del * (i - 1) * DegRad
30 x2(0) = r * Cos(phi)
31 x2(1) = r * Sin(phi)
32
33 ’ Create the line object
34 Set line = ThisDrawing.ModelSpace.AddLine(x1 , x2)
35
36 ’ set up the color using RGB -values
37 ’ black : 0, 0, 0
38 ’ white : 255 ,255 ,255
39 ’ dark red: 128, 0, 0
40 rcol = 50 + (i - 1) / (360 / del) * 205 * 12 / 11
41 Call col.SetRGB(rcol , 0, 0)
42 line.TrueColor = col
43 line.Update
44
45 ’ Create the sphere object
46 Set sphere = ThisDrawing.ModelSpace.AddSphere(x2, rs)
47 Call col.SetRGB(0, rcol , 0)
48 sphere.TrueColor = col
49 sphere.Update
50
51 Next
52
53 End Sub
E. Baeck
5.3. ACADSPHERE OBJECT Page 47
Figure 5.2 shows a line and a sphere with dark colors at the position 0◦. At the end position we
see a line and a sphere with the maximum color value of it’s used RGB color.
Figure 5.2: Lines and Spheres
10.6.2015
Part III
Sample Projects
48
6
Random Masspoints
Within this chapter a program is developed for the creation of a random distribution of mass
points. The mass value of a point as well as the position of the mass point is calculated as
random. Several distribution spaces are implemented. At the end an effective mass point is
calculated with a mean mass value and a mean position, the so-called centre of mass.
The data of a mass point is handled within a class module. To handle all the created mass
points a container class module is introduced basing on the vba build-in class module collection.
6.1 Class Modul Mass
The class module for our mass point object will be an extension of the class module of section
2.10.1.
6.1.1 Attributes
The Double array for the mass points position as well as the value for the mass value adopted.
The color index value is substituted by AutoCAD’s true color class module AcadAcCmColor.
Because we will have sqheres as mass point’s volumns, we specify the density of the mass point,
which is stored in a Double value. The address pointer of the class module’s instance is stored
in a variable of Acad3DSolid.
Listing 6.1: Class of a Mass
1 ’ Attributes of the object
2 Dim xi(2) As Double ’ coordinates
3 ’ arrays are PRIVATE in VBA
4 ’ therefor we need access -functions (get/set)
5 Public m As Double ’ mass value
6 Public rho As Double ’ density of the mass
7 Public rs As Double ’ radius of the sphere
8 Private col As AcadAcCmColor ’ TrueColor object
9 Private s As Acad3DSolid ’ pointer to the sphere object
49
Page 50 CAD in Civil Engineering / 2015
The following methods are adopted form the class module of section 2.10.1.
• Class Initialize to performe special initializations.
• Class Terminate to performe special clearings.
• setX and setXV, to assign the coordinates of the mass point.
• x, to get a mass point’s coordinate values.
6.1.2 Methods
Within the Constructor we create the true color object AcadAcCmColor.
Listing 6.2: Constructor of a Mass
1 ’ constructor is called with the new operator
2 Private Sub Class Initialize ()
3 rho = 0.00000784 ’ density of steel by default
4 Set col = New AcadAcCmColor ’ create the color object
5 End Sub
If we want to clear up created instances we can do that within the destructor. Because vba uses
a garbage controller which deletes objects which are no longer referenced. Therefore the explicit
clearing of unused instances is not really needed.
Listing 6.3: Destructor of a Mass
1 ’ destructor is called if the object is deleted from the memory
2 ’ by assigning "nothing"
3 Private Sub Class Terminate ()
4 Set col = Nothing ’ ... not realy needed
5 End Sub
To be able to visualize the mass point’s volume, we have to calculate the radius from the given
density. This can be done with the following formula.1
r =
(3 ·m
4 · π · ρ
) 13
(6.1)
Listing 6.4: Calculate the Radius
1 ’ calculate the radius
2 Public Sub SetRadius ()
3 pi = Atn (1) * 4#
4 rs = ((3# * m) / (4# * pi * rho)) ^ (1# / 3#)
5 End Sub
1Note that π is calculated with the arctan function.
E. Baeck
6.1. CLASS MODUL MASS Page 51
The following method create creates the sphere of a mass point. As input parameter the red,
green, blue parts of the true color are passed. The error checker of the function checks the mass
value and the density value. The function returns False if the error checking of the function
detects an error. If no error is found the function returns True.
After the error checking the true color object is prepared with SetRGB. Then the radius of
the sphere is calculated and a sphere object is created at the position of the mass point. After
assigning the true color to the sphere object the function returns the True return code.
Listing 6.5: Create the Sphere
1 ’ create a sphere in modelspace
2 Public Function Create(r As Integer , g As Integer , b As Integer) As Boolean
3 ’ error checking , mass value ok?
4 If m < 0.0000000001 Then
5 Create = False
6 Exit Function
7 End If
8
9 ’ density ok
10 If rho < 1E-20 Then
11 Create = False
12 Exit Function
13 End If
14
15 ’ setup the color value
16 Call col.SetRGB(r, g, b)
17
18 ’ caculate the radius of the sphere
19 Call SetRadius
20
21 ’ create the ACad3dSolid sphere object
22 Set s = ThisDrawing.ModelSpace.AddSphere(xi , rs)
23
24 ’ assign the color to the sphere
25 s.TrueColor = col
26
27 ’ every ok!
28 Create = True
29 End Function
10.6.2015
Page 52 CAD in Civil Engineering / 2015
6.2 Class Modul Masses
The instances of the MassObj are stored in the container class module Masses. Masses will
handle the creation of random mass point objects. Information of the stored data should be
printed into a log file.
6.2.1 Attributes
The class modul has only two attributes.
• The address of the center of mass object CoM.
• The address of the used collection List.
Listing 6.6: Class of Masses, Container
1 ’ Container for our mass point objects
2 Public CoM As MassObj ’ Address of Center of Mass Object
3 Public List As Collection ’ Address of the Mass Object List / Container
6.2.2 Methodes
The constructor is used to create the centre of mass object CoM and the collection object List.
The destructor is not used for clearing.
Listing 6.7: Class of Masses, Constructor
1 ’ initializations
2 Private Sub Class Initialize ()
3 Set CoM = New MassObj ’ create the Mass Object
4 Set List = New Collection ’ create the List/Collection
5 End Sub
The method CreateRndMassesInCube creates a random point distribution in a cube. The
routines parameters are the following.
• MCount, the number of mass points to create.
• MMin, the minimum value of the mass distribution.
• MMax, the maximum value of the mass distribution.
• LBox, the edge length of the cube.
E. Baeck
6.2. CLASS MODUL MASSES Page 53
The method initializes first the random number generator calling the build-in routine
Randomize. The random numbers are calculated by a call of the function Rnd. The range
of the random numbers is given by the interval 0 to 1. Therefore the random mass values are
given by
mrandom = mMin + (mMax −mMin) ·Rnd (6.2)
The random position in a cube with edge length L is given by
xrandom = −L
2+ L ·Rnd (6.3)
After having calculated the random parameters a MassObj instance is created and the param-
eters are assigned. Then the instance is stored in the collection list using the Add function of
the collection.
Listing 6.8: Create Random Mass Points in a Cube
1 ’ Create random Mass Points in a Cube
2 ’
3 ’ MCount: Number of Masses to create
4 ’ MMin : Minimum Mass Value
5 ’ MMax : Maximum Mass Value
6 Public Sub CreateRndMassesInCube(MCount As Integer ,
7 MMin As Double , MMax As Double ,
8 LBox As Double)
9 Dim MObj As MassObj ’ Address of a mass object
10 Dim x(2) As Double ’ Position of the mass object (random)
11 Dim M As Double ’ Mass value (random)
12
13 ’ initialize the random number generator
14 Call Randomize
15
16 ’ loop over all mass points
17 For i = 1 To MCount
18 ’ calculate the random mass value
19 ’ Rnd : [0..1]
20 M = MMin + (MMax - MMin) * Rnd
21
22 ’ calculate the random position
23 ’ over all directions
24 For j = 0 To 2
25 x(j) = -LBox / 2# + LBox * Rnd
26 Next
27
28 ’ Create the mass object
29 Set MObj = New MassObj
30 MObj.M = M
31 Call MObj.setX(x)
32 Call MObj.SetRadius
33
34 ’ Add the pointer to the list/collection
35 List.Add Item:=MObj
36 Next
37 End Sub
10.6.2015
Page 54 CAD in Civil Engineering / 2015
The mass points spheres can be created using the method CreateSpheres. The method iterates
all available mass point instances stored in the container List and call their method Create. As
parameters we pass the RGB color values to the Create method. The coding of CreateSpheres
is given below.
Listing 6.9: Create the Spheres
1 ’ Create Spheres of all Mass Points
2 Public Sub CreateSpheres ()
3 ’ Address of a MassObj instance
4 Dim MObj As MassObj
5
6 ’ Add spheres to the modelspace
7 For i = 1 To List.Count
8 ’ get an item from list
9 Set MObj = List(i)
10
11 ’ R G B
12 If MObj.Create (255, 0, 0) Then
13 s = "Mass sphere " & i & " is created."
14 Else
15 s = "Mass sphere " & i & " is not created."
16 End If
17
18 ’ write status to the command window
19 ThisDrawing.Utility.Prompt vbCr & vbLf & s
20 Next
21 End Sub
E. Baeck
6.3. FRAME APPLICATION Page 55
6.3 Frame Application
To test the class modules of this chapter, we write a little frame subroutine for testing. The
subroutine should read the input data from an excel file and should perform the creation of the
mass objects as well as it’s creation as AutoCad sphere objects.
6.3.1 EXCEL-Sheet, Input Section
To create our random mass point distribution we need the following input parameters.
• Number of mass points to create.
• Minimum mass value.
• Maximum mass value.
• Length of the cube region or diameter of the sphere region.
Figure 6.1: Input Sheet for the Mass Point Appli-
cation
Figure 6.1 shows the excel sheet for the in-
put data. To be able to access to the input
data cells without the usage of global row/col-
umn index values we have to introduce range
names. We use the following names for the
ranges: MNumber for the number of the mass
points, MassMin for the minimum and Mass-
Max for the maximum mass value. Length is
used as name for the region’s dimension.
6.3.2 EXCEL-Sheet, Output Section
To check the creation of the random mass distribution we need some output data, which are
written into the EXCEL-sheet’s protocol section. The following data for every mass point are
printed.
• 1st column, the mass number starting from one,
• 2nd column, the mass’s random value and
• 3rd till 5th column, the mass’s random position.
10.6.2015
Page 56 CAD in Civil Engineering / 2015
Figure 6.2: Output section of the EXCEL-Sheet
Figure 6.2 shows the last input cell of the
sheets input section. With the title Output
the sheet’s output sections starts. The con-
tainer of the mass objects will be iterated from
the first to the last object. The objects data
are printed into the objects output line.
Figure 6.3: Output section of the EXCEL-Sheet,
Control Values
Figure 6.3 shows the footer region of the excel-
output. As control values we find the extrem
values of the random distribution (maximal
and minimal value of mass value and position)
and their mean values.
6.3.3 Sample, Step 1
The sample application performs the steps we have discussed in section 3.2. First we start
an EXCEL application object.. Then we call it’s GetOpenFileName method to specify the
EXCEL file with the input data. After that we select the EXCEL sheet with the input data
from the Worksheets container. The next step will give us the desired input data by the use
of the sheets Range object. Here we have to be very carefully with the usage of the range’s
name. If a unknown name is used the code is crashing and the EXCEL application object will
hang.2
The next statement resets the modelspace. The container for the mass points is created. The
method CreateRndMasses of the container creates a random mass point distribution within
a cube range. After that the AutoCAD sphere objects are created. The last step closes the
EXCEL input file and quites the EXCEL task.
Listing 6.10: Get Data form Excel Sheet
1 ’ Create a random mass point distribution
2 Sub CreateSomeRandomMassPoints ()
3 Dim MNum As Integer
4 Dim MMin As Double
5 Dim MMax As Double
6 Dim LBox As Double
7
8 ’ linking to EXCEL
9 Set e = New Excel.Application
10
11 ’ specify the filename
12 FileName = e.GetOpenFileName(
2Such problems can be solved by applying an errorhandler, which catches the problem and avoid the crashing
of the program.
E. Baeck
6.3. FRAME APPLICATION Page 57
13 fileFilter :="Excel -Inputfile (*.xls),*.xls")
14
15 ’ check if dialog is canceled
16 If FileName = "Falsch" Then Exit Sub
17
18 ’ Open the specified file
19 e.Workbooks.Open FileName := FileName
20
21 ’ get EXCEL -Sheet
22 Set s = e.Worksheets("Masses")
23
24 ’ get EXCEL -Sheet input
25 MNum = s.Range("MNumber")
26 MMin = s.Range("MassMin")
27 MMax = s.Range("MassMax")
28 LBox = s.Range("Length")
29
30 ’ Reset the modelspace
31 Call ResetModelspace
32
33 ’ create the masses container
34 Set MList = New Masses
35
36 ’ create mass distribution
37 Call MList.CreateRndMasses(MNum , MMin , MMax , LBox)
38
39 ’ create spheres
40 Call MList.CreateSpheres
41
42 ’ schlie~AYen der Data
43 e.ActiveWorkbook.Save
44 e.ActiveWindow.Close
45 e.Application.Quit
46 Set e = Nothing
47 End Sub
10.6.2015
Page 58 CAD in Civil Engineering / 2015
Figure 6.4 shows two random distributions with 200 mass points in a cube with edge length
2000. The left figure shows a mass range from 2 to 100, the right figure a range from 10 to 200.
Figure 6.4: Distribution 1
6.3.4 Sample, Step 2
In the 2nd step of the implementation of sample 1, we don’t want to close the excel-sheet,
because we want to check the control-values of the output section immediately. Therefore we
set the closing section of the excel application on comment.
Listing 6.11: Comment Excel’s Shut Down
1 ’ create mass distribution
2 ’>>
3 Call MList.CreateRndMassesInCube(MNum , mmin , mmax , LBox)
4
5 ’ create spheres
6 Call MList.CreateSpheres(s)
7
8 ’ close the input file
9 ’>> close EVERYTHING
10 ’ e.ActiveWorkbook.Save
11 ’ e.ActiveWindow.Close
12
13 ’ and quit the excel application
14 ’ e.Application.Quit
15 Set e = Nothing
After that we want to create and visualize the sphere of the effective mass at the centre of mass’s
position. This we will implement in the method CreateSpheres. This methode also will get a
new parameter, which contents the pointer to the excel-sheet. The excel-sheet pointer is used
for the printing of the output data discussed above. After the excel output is done, the sphere
for the effective mass is created. The code of the extended version of CreateSpheres is given
below.
E. Baeck
6.3. FRAME APPLICATION Page 59
Listing 6.12: Create the Spheres and Do the Analysis
1 ’ Create Spheres of all Mass Points
2 ’ s: pointer to the excel -sheet
3 Public Sub CreateSpheres(s)
4 ’ Address of a MassObj instance
5 Dim MObj As MassObj
6 Dim j As Integer
7
8 ’ helper variables to calculate the
9 ’ maximum and minimum values
10 Dim xmin (2) As Double
11 Dim xmax (2) As Double
12 Dim mmax As Double
13 Dim mmin As Double
14
15 ’ ... sums
16 Dim xs(2) As Double
17 Dim ms As Double
18
19 ’ row number for excel output
20 nRow = 1
21
22 ’ Add spheres to the modelspace
23 For i = 1 To List.Count
24 ’ get an item from list
25 Set MObj = List(i)
26
27 ’ R G B
28 If MObj.Create (255, 0, 0) Then
29 s.Range("output")(nRow , 1) = "S-" & i
30 s.Range("output")(nRow , 2) = MObj.M
31 For j = 0 To 2
32 s.Range("output")(nRow , 3 + j) = MObj.x(j)
33 Next
34 Else
35 s.Range("output")(nRow , 1) = "Mass sphere " & i & " is not created."
36 End If
37
38 ’ extrem values
39 ’ - initialisation
40 If i = 1 Then
41 For j = 0 To 2
42 xmin(j) = MObj.x(j)
43 xmax(j) = MObj.x(j)
44 Next
45 mmax = MObj.M
46 mmin = MObj.M
47
48 ’ - for the rest
49 Else
50 For j = 0 To 2
51 If MObj.x(j) < xmin(j) Then xmin(j) = MObj.x(j)
52 If MObj.x(j) > xmax(j) Then xmax(j) = MObj.x(j)
53 Next
54 If MObj.M > mmax Then mmax = MObj.M
10.6.2015
Page 60 CAD in Civil Engineering / 2015
55 If MObj.M < mmin Then mmin = MObj.M
56 End If
57 next
58
59 ’ calculation of the sum values
60 For j = 0 To 2
61 xs(j) = xs(j) + MObj.x(j)
62 Next
63 ms = ms + MObj.M
64
65 ’ next line
66 nRow = nRow + 1
67 Next
68
69 ’ calculation of the mean values
70 ms = ms / List.Count
71 For j = 0 To 2
72 xs(j) = xs(j) / List.Count
73 Next
74
75 ’ next line
76 nRow = nRow + 2
77
78 ’ output of maximum values
79 s.Range("output")(nRow , 1) = "Maximum"
80 s.Range("output")(nRow , 2) = mmax
81 For j = 0 To 2
82 s.Range("output")(nRow , 3 + j) = xmax(j)
83 Next
84
85 ’ output of minimum values
86 nRow = nRow + 1
87 s.Range("output")(nRow , 1) = "Minimum"
88 s.Range("output")(nRow , 2) = mmin
89 For j = 0 To 2
90 s.Range("output")(nRow , 3 + j) = xmin(j)
91 Next
92
93 ’ output of mean values
94 nRow = nRow + 1
95 s.Range("output")(nRow , 1) = "Mean value"
96 s.Range("output")(nRow , 2) = ms
97
98 For j = 0 To 2
99 s.Range("output")(nRow , 3 + j) = xs(j)
100 Next
101
102 ’ set -up center of mass object
103 CoM.M = ms * List.Count
104 code = CoM.setX(xs)
105
106 ’ create the sphere for the total mass
107 ’ R G B
108 code = CoM.Create(0, 0, 255)
109 End Sub
E. Baeck
6.3. FRAME APPLICATION Page 61
Figure 6.5: Effective Mass
Figure 6.5 shows the result, calling the new version of CreateSpheres.
10.6.2015
Part IV
.NET Linking with C#
62
7
Motivation to Use .NET
7.1 Scripting in AutoCAD
From the beginning of AutoCAD the script language AutoLisp was the main scriptin language
of AutoCAD. A lot of function of AutoCAD are available in AutoLisp. The disadvantage of
AutoLisp is, that the language is only available inside AutoCAD therefor it is not possible to
link other applications to AutoCAD to get a multi-application solution for a special problem.
On of the first programming interfaces of AutoCAD was the ARX interface. The ARX interface
can be used to extend the AutoCAD features with functions written in C or C++. This
interface was still available before VBA was released.
With the appearance of Microsoft’s COM technology Visual Basic for Application (VBA) came
into picture and was implemented in a lot of key application as scripting language. A very
important advantage of VBA is undisputed it’s unique IDE which is available in every COM
application. So, if you know programming in VBA in one application, you can use this knowl-
edge to get familiar in the next application with a VBA kernel.
Unfortunately Microsoft developed a new platform, the so called .NET framework as successor
of COM at the end of the last century without any further development which is related to the
common introduced VBA scripting kernel. That means that VBA now is like a fossil from
the last century still working within the modern time but without any new features. Therefor
it is not recommended to start a new development based on the technology of the last century.
So one problem already occurred, if 32bit code of VBA scripts are used in a 64bit VBA
AutoCAD environment. Scripts will crash with very bad understandable error messages, which
will come from the COM kernel. To solve this problem, you are recommended to implement
some strange work-arounds to avoid the problem. So I think this should be the point to say
goodby to the world of VBA and change to the new era of .NET 1.
We can use the .NET languages, because AutoCAD now is also able to support the .NET world
with a so called NETIMPORT function. The NETIMPORT function will load DLL-modules,
which are developed in one of the available .NET languages. Because there is no integrated
IDE available for .NET within the AutoCAD the handling is a little bit ugly. You have to
1... which may be already the era of yesterday, if you notice some information of the new strategy of Microsoft’s
Windows 8 world.
63
Page 64 CAD in Civil Engineering / 2015
develop the DLL modules offline in an IDE (for example the Visual Studio 2010) and then you
have import it into the AutoCAD application.
7.2 Hello World in C#
The following example HelloWorld is a C#-version of Martin Richards2 famous startup example
for all programmers which is called Hello World.
7.2.1 The Code
Hello
+ Main(string[]) : void
Figure 7.1: A UML Class
Diagram for the Hello
A UML class diagram consists of a rectangular box, which is divided
into three sections. The fist section contents the class’s name. This
name is written centered in bold letters. The second section contents
the attribute’s names of the class and the third section contents the
method’s names. The HelloWorld application only has one class,
which contents the starter method Main. This Method is like C ’s
main function. In a C#-application only one static method3 Main
is allowed, because more than one starter method will not make sense.
The application will print the hello line to the console window and then the number of command
line parameters are given. If parameters are available, the application will give a list of them.
Listing 7.1: The Hello World Application with a Command Line Analyzer
1 using System;
2
3 namespace HelloWorld
4 {
5 class Hello
6 {
7 static void Main(string [] args)
8 {
9 Console.WriteLine("Hello World!");
10
11 if (args.Length > 0)
12 {
13 Console.WriteLine(args.Length + " parameters given.");
14
15 // like in C++, but without the application ’s name
16 for (int i = 0; i < args.Length; i++)
17 {
18 Console.WriteLine("parameter " + (i+1) +" :" + args[i]);
19 }
20 }
21 else
22 {
2Martin Richards is the founder of the BCPL language, which can be seen as a predecessor of the famous C
language.3A static attribute or method in UML is marked as underlined.
E. Baeck
7.2. HELLO WORLD IN C# Page 65
23 Console.WriteLine("- No parameters given.");
24 }
25 }
26 }
27 }
7.2.2 Some Remarks
• Within the first two lines the used packages are set. With System we set the global C#-
package. This is the minimum we have to load. If we set it to comment, the compiler will
have problems to compile the Consol-statements.
• The fist environment (line 3, 4, 27) implements a so called name space. In this application
a name space is not needed, because we only have one class and one module, so no use is
needed.
• Because C# is fully object orientated, we can not develop programs without any class.
In C# like in Java everything is a class and nothing exists outside a class. Our little
program is embedded into the class hello (lines 5, 6, 26).
• Because in C# there is no main function like in C/C++, in C# we have to implement
ONE static method, which is called Main (lines 7, 8, 25). This Method is called from
the OS, when the program is started. We have to use a static method, because a static
method is a method of the class and NOT of the instance of a class. If it would be an
instance method, every created method would have there own Main method and therefore
we would get in general more than one.
• Like in C/C++ the OS passes the command-line parameters to the main function within
a string array (line 7). The only difference is, that we don’t get the application’s name
from the call as the first item of the string array.
• Within line 9 the famous hello is written. In C# we use the Console’s method WriteLine,
which only will get a string. This string then is printed into the console window.
• To check the command-line’s parameter we first check, whether the user has typed some.
This we can do by evaluating the string array’s length (line 11). If the string-array’s length
is greater than zero, we know, that there are some parameters. Otherwise we jump into
the else-branch (line 21).
• We see, that in C# the if/else is working like in C/C++. We see further, that
statements are packed into a code block by the usage of curly braces.
• The for loop too is working like in C/C++. A loop variable is introduced and initialized
within the first section. The second sections is working as a break condition and the third
section will execute something after a cycle is done. Here we find the useful ++ operator,
which increments a variable.
• Line 13 and 18 show, how simple we can build up strings from some different components
like in this case strings and integers. We simple have to use the add operator + and the
rest will be done by the refereed classes.
10.6.2015
Page 66 CAD in Civil Engineering / 2015
7.3 Our Hellos in C#
The following example OurHellos is a extended version of Martin Richards4 famous startup
example for all programmers which is called Hello World. The example code is coded in C#
and should show some key features of the .NET language.5
Greetings
+ DisplayEnglish() : void
+ DisplayGerman() : void
+ DisplaySpanish() : void
+ DisplayItalian() : void
OurHellos
+L : Log
+ sMsg : string
greetings[] : delGreeting
+ Init() : void
+ Main(string[]) : void
Figure 7.2: A UML Class Diagram of OurHellos
The application OurHellos
consists of two namespaces
(OurHellos and Logger) and
three classes and one delegate.
OurHellos contains the classes
OurHellos and Greetings.
This classes live inside one
module, the file OurHellos.cs.
Log
– FileName : string
+ Log()
+ Log(string)
+ AppendLog(string) : void
+ Reset() : void
Figure 7.3: A UML Class Dia-
gram of the Log
For dumping we introduce a new class which is called Log. This
class will have it’s own namespace, called Logger. This class
lives also in it’s own source file, which is called Logger.cs. This
is done, because logging is a very general feature, which we can
use in a lot of applications. The benefit of logging is, that the
program itself is writing, what goes on. If a problem would
occur and the program would crash, we may see - depending
on the log intensity - the location of the error. Important is,
that logging is closing the file after having written or flushing
the data to the disk, because in the case of crashing temporary
stored data (without closing or flushing) will be destroyed.
7.3.1 The Code
Listing 7.2: The Multi-multilingual Hello App
1 using System; // total namespace
2 using System.IO;
3
4 using System.Reflection; // to get access to the app -name
5 using Logger; // to use our own logger -class
6
7 namespace OurHellos // this is our namespace
8 {
9 // setup greetings for some languages
10 class Greetings
11 {
12 // ... this is english
13 public static void DisplayEnglish ()
4Martin Richards is the founder of the BCPL language, which can be seen as a predecessor of the famous C
language.5Within this script no entire description of the C# language is given. We only will discuss some basic features.
If you are interested in some further details of the C# language please look into the standard C# literature like
[2].
E. Baeck
7.3. OUR HELLOS IN C# Page 67
14 {
15 Console.WriteLine("Hello World!");
16 }
17
18 // ... this is german
19 public static void DisplayGerman ()
20 {
21 Console.WriteLine("Hello Welt!");
22 }
23
24 // ... this is spanish
25 public static void DisplaySpanish ()
26 {
27 Console.WriteLine("Hola mundo!");
28 }
29
30 // ... this is italian
31 public static void DisplayItalian ()
32 {
33 Console.WriteLine("Ciao mondo!");
34 }
35 }
36
37 // because we have no function pointers in C#,
38 // the dynamic call can be handled by a ’delegate ’
39 delegate void delGreeting ();
40
41 // the starter class is the container
42 // of the one and only Main routine
43 class HelloWorld
44 {
45 public static Log L = new Log ();
46 public static string sMsg;
47
48 // setup the delegate array
49 static delGreeting [] greetings = {
50 new delGreeting(Greetings.DisplayEnglish),
51 new delGreeting(Greetings.DisplayGerman),
52 new delGreeting(Greetings.DisplaySpanish),
53 new delGreeting(Greetings.DisplayItalian)
54 };
55
56 public static void Init()
57 {
58 L.Reset ();
59 L.AppendLog("Program started / Log reseted ...");
60
61 string path = Path.GetDirectoryName(
62 Assembly.GetAssembly(typeof(HelloWorld )). CodeBase );
63 Console.WriteLine("Program will be executed in ’{0}’",
64 path.Substring (6));
65 sMsg = string.Format("{0} greetings implemented.",greetings.Length );
66 L.AppendLog(sMsg);
67 }
68
69 // the one and only Main routine
10.6.2015
Page 68 CAD in Civil Engineering / 2015
70 // Main must be a static function
71 // we get the command line arguments in
72 // the args list
73 static void Main(string [] args)
74 {
75 Init ();
76
77 // let’s look into the command line
78 // if no argument is given , we print
79 // some usage infos
80 if (args.Length < 1)
81 {
82 Console.WriteLine("OurHellos [language number]");
83 Console.WriteLine(" Range: 1 to {0}", greetings.Length );
84 }
85
86 // one parameter
87 else
88 {
89 // we try to print the hello
90 try
91 {
92 // get the hello index
93 int iChoice = int.Parse(args [0]);
94
95 // and call the selected greeting
96 // greetings provides the pointer to teh function
97 greetings[iChoice - 1]();
98 }
99
100 // handle all possible errors
101 catch(Exception e)
102 {
103 // first we print our one message
104 Console.WriteLine("Oops , no language found!");
105 // then wie print the message of the exception
106 Console.WriteLine("Message: {0}",e.Message );
107 }
108 }
109 }
110 }
111 }
Listing 7.3: The Logger -Namespace, a Kind of Library
1 using System; // total namespace
2 using System.IO; // IO namespace
3
4 namespace Logger // the loggers namespace
5 {
6 class Log
7 {
8 // the one and only log file name (because it’s static)
9 private static string sFileName = "Logger.log";
10
11 // empty standard constructur
E. Baeck
7.3. OUR HELLOS IN C# Page 69
12 public Log()
13 {
14
15 }
16
17 // constructor to set a log file name
18 public Log(string sFile)
19 {
20 sFileName = sFile;
21 }
22
23 // appends a string to the log file starting with a time stamp
24 public void AppendLog(string sMessage)
25 {
26 StreamWriter f = new StreamWriter(sFileName , true);
27 f.WriteLine(DateTime.Now + "| " + sMessage );
28 f.Close ();
29 }
30
31 // removes an old log file
32 public void Reset()
33 {
34 File.Delete(sFileName );
35 }
36 }
37 }
7.3.2 Main Differences between C# and C++
From the code of OurHellos example given in section 7.3.1 we can see some of the main differences
between C++ and C# (see also the script of CLFE [4]).
1. First of all C# in contrast to C++ is an object orientated language without any possi-
bilities of writing traditional functional code. C++ on the other side is a language which
contents both worlds. You can see this for the little Hello World in C++ which is given
below. Like in other OOP-languages too (like Python) everything in C# is derived from
a class. The mother of all is therefor the class object. So every variable of every data
type is derived from this class.
Listing 7.4: A C++ Version of Hello World
1 // declare the iostream
2 #include <iostream >
3
4 // setup the namespace
5 using namespace std;
6 int main()
7 {
8 // stream the string to the screen
9 cout << "Hello world of C++!" << endl;
10 return 0;
11 }
You see, there is not only one class within this code. The code starts with a simple function
like in VBA or FORTRAN too. In contrast to that, the C# code looks like a set of
10.6.2015
Page 70 CAD in Civil Engineering / 2015
classes. We start the C# code also with a routine which is called Main, which lives in one
of this classes. Either you implement one class method with the name Main or you have
to select the one which should be called starting the program by a specific compiler flag.
2. To declare external items, in C and C++ we have to include so called function headers,
C or C++ files, which contents the declarations of the used items. Within our little
Hello World we see that the stream items obviously are declared by an included header
called iostream. In C# we have to embed our classes into so called name spaces. See
above the namespace OurHellos, which will content all classes of our program. Therefor
everything is now in our module. If you now wants to use items, which are not defined
in the considered module, you have to use the so called using statement. using System
will make available all names of the package System, which contents all classes of the
.NET library.
3. C# provides a garbage collector, which is a feature, which will free all not referenced
allocated memory automatically. So memory leaks are avoided by strategy. On the other
hand in C++ or FORTRAN90+ allocated memory has to be freed explicitly, which can
produce memory leaks. The disadvantage of an garbage collector however is, that we can
now, when the deallocation of the allocated memory will take place. To avoid this in C#
we will have a special class interface which will provide us the dispose method, which will
deallocate allocated memory immediately within the method call.
4. In contrast to C++ C# does not provide parameter passing by reference. We only can
pass a value or the pointer of an item. In C# the pointer is like in C++ the address of
the instance. Generally we cannot like in C++ perform a pointer arithmetic, that is, that
we can manipulate the address data of a pointer6.
7.3.3 Implementation of OurHellos
Because C# defacto is a Microsoft language, there are not so many possibilities to implement
our little C# example. On the other hand Microsoft seems to be interested, that the whole
world is changing from everywhere to their .NET language C# and this is supported by the
free of charge Visual Studio Community.7 So ether we can implement our example with this
version of the Visual Studio or we can use the commercial or educational version of this IDE.
Because we have the possibility to get the educational version of the IDE, we will discuss here
the usage of this software. Like many IDEs the Visual Studio also starts with a project. For this
project we use the name OurWorlds. Figure 7.4 shows the startup page of the Visual Studio.
Here we select the link New Project8.
After having clicked the link for a new project we will see the form to specify the type of project.
In the left window we select a C# - Windows application. Because there are a lot of Windows
6Because C# also provides like C++ hardware close programming, the pointer values can be manipulated
within the so called unsafe mode. Within this mode we also can call functions from not managed code, that
means unsafe code.7The examples in this book are developed using the Community Version 2013 of Visual Studio. Note that after
30 days you have to download a new license information. You simply have to login into your Microsoft account.8Neues Projekt in german
E. Baeck
7.3. OUR HELLOS IN C# Page 71
Figure 7.4: Startup page in Visual Studio
application, we have to select in the right Window a console type application9. At last we have
to specify the applications name, in this case OurWorlds and the applications folder. Then we
click ok and wait for the next input form. In this case, because a console application is the
most simple application there are no further input forms and we will see the startup frame of
our OurWorlds application with it’s code (see figure 7.6).
In the main window of the Visual Studio we see the startup code for our example. We see, that
apart from the namespace System there are created some other links to name spaces, which we
don’t need for our code. We can simple delete this links. On the left side we sie two windows.
The upper one contents the project tree with it’s title OurWorlds. We see two main nodes. The
first one contents the library links, which are apart of the link Microsoft.CSharp and mscorlib
the links which are referenced to the used name spaces.
The second node has the title of our project OurWorlds and contents the items of our software.
In this case there is only one class with the name Programm. If we now look into the lower left
window, we can see that we can found there the content of the selected item of the upper left
window. In this case our entry point and starter function Main with it’s argument list.
Now we can edit the startup code and implement our OurWorlds C# code. We cange the name
of the main class form Program to HelloWorld. Then we add a new class Greetings and put in
there the functions for the language depended greeting. After that we implement the delegate
which will be used as a function pointer’s array. And then we implement the code for our main
class HelloWorld. If we now select the class Greetings we will see all it’s methods in the lower
left window.
To run the program, we can start it from the IDE using F5 or using the typical run button from
9Konsolenanwendung in genman
10.6.2015
Page 72 CAD in Civil Engineering / 2015
Figure 7.5: Selecting the project type
Figure 7.6: Startup code for our OurWorlds application
E. Baeck
7.3. OUR HELLOS IN C# Page 73
Figure 7.7: Having completed the whole application code
the toolbar. So if we do so, we will see that there is no command line parameter given and the
application shows us it’s usage screen (see figure 7.8).
Figure 7.8: Having completed the whole application code
10.6.2015
Page 74 CAD in Civil Engineering / 2015
If we want to print the greeting with the number 4, we have to open the dialog to specify the
projects parameters. Then we select the form Debuggen where we can input the command line
parameters. We write 4.
Figure 7.9: Setup the command line parameters
If we now run the application (see figure 7.10), we get the Italian greeting Ciao Mondo.
Figure 7.10: Run the application with a command line parameter 4
E. Baeck
7.3. OUR HELLOS IN C# Page 75
If we run the application from the console window, we have to type in the applications name
and the desired command line parameter. In figure 7.11 we will try it with OurWorlds 10. The
number 10 is not supported and if we would not handle the situation, the program would crash.
In this case we print the message, that a not supported number is used and in the second line
the message of the exception is printed.
Figure 7.11: Run the application with a wrong command line parameter
7.3.4 Created Files and Folders
After the build is done, the folder bin will be created, if he’s not existing. In the bin folder the
builder will create a debug folder for the debug version, a release folder for the release version.
After the build process is done, we find the following files within this folders.
Type Comment Example
.exe normal executable HelloWorld.exe
.pdb program database for debugging HelloWorld.dbg
.vshost.exe a special version of the executable
to aid debugging
HelloWorld.vshost.exe
.vshost.exe.manifest a kind of configuration file contain-
ing mostly dependencies on libraries
HelloWorld.vshost.exe.manifest
Like Java, C# is compiled to an intermediary language (called MSIL10 or CIL11). But the
intermediate code is stored in EXE files, which have enough actual EXE code, to show a dialog
box asking users to install the .Net environment, it it is not found on the computer.
The intermediate code a kind of assembler is executed on the run time system and is compiled
in time to native machine code (Jit). The advantage of this approach is, that the compiled byte
code the CIL code is independent of the hardware, but on the other hand such an approach is
slower than a classical compilation from source code into native machine code.
10At the beginning of .NET the intermediate language was called MSIL, Microsoft Intermediate Language11Now the intermediate language simply is called CIL Microsoft Intermediate Language
10.6.2015
8
Basics in C#
Before we step into the object orientated kind of C# we study all classical features like dec-
laration and statements within the method Main, which can be seen as a Main program. The
method Main is part of class and the class is embedded into a namespace. This details are
discussed later in section 8.8.
8.1 The Preprocessor
C# is a byte code languages which is compiled into a byte code, which is executed with a so
called virtual machine. The virtual machine translates the byte code into the processors native
language. Before a source file is compiled into the byte code, a precompiling step is performed.
The preprocessor can be used like in C++ to perform conditional compiling, which depends for
example on the existence of the definition of some macros.
In C++ the precompile step is also needed to include the header files, which are used to declare
the used external resources like library functions. This in C# is different. C# don’t have include
files. External resources in C# are declared by the using statement. The using statement offers
the names which are defined in the related namespace. This is one of the most evident contrast
to C++. Note, that in C# defines are only allowed as first statements, it’s called before the
first token! Then in contrast to C++ in C# the #ifdef is called #if.
The following example shows the include and a conditional compiling in C++.
Listing 8.1: C’s Preprocessor is used in nearly every source file
1 #include <a_library_file.h>
2 #include "a_user_file.h"
3
4 #define MYMACRO
5 #ifdef MYMACRO
6 ... // code , which will be compiled if MYMCRO was defined
7 #else
8 ... // code , which will be compiled if MYMCRO was not defined
9 #endif
76
8.2. COMMENTS Page 77
In contrast to C++ the include will be substituted in C# by the using statement.
Listing 8.2: Like in C, we have a Preprocessor
1 #define MYMACRO
2
3 using a_library_namespace;
4 using a_user_nameespace;
5
6 #if MYMACRO
7 ... // code , which will be compiled if MYMCRO was defined
8 #else
9 ... // code , which will be compiled if MYMCRO was not defined
10 #endif
8.2 Comments
The C# language offers to different comment types. With the classical block comment, which
comes form the C language, we can bracket a part of a line or some lines and make them
comments. We start the comment with /* and close the comment with */. We can put an
arbitrary number of characters and lines in between this brackets.
The second type of comment, which was introduced by C++ is a line end comment. The
characters following the line end comment are thrown away by the compiler. The line end
comment is set with two slash characters //.
Listing 8.3: C++ like comments
1 /*
2 this is a block comment.
3 */
4
5 // and this is a line end comment.
10.6.2015
Page 78 CAD in Civil Engineering / 2015
8.3 Data Types
8.3.1 A List of Data Types
C# offers the following data types. Unlike C/C++ this data types are not only blocks of
memory, C# provides classes and a wide set of helper methodes.
Type Primitive Description Range
bool System.Boolean Boolean true or false
byte System.Byte 8-bit unsigned integer
ushort System.UInt16 16-bit unsigned integer
uint System.UInt32 32-bit unsigned integer
ulong System.UInt64 64-bit unsigned integer
sbyte System.SByte 8-bit signed integer
short System.Short 16-bit signed integer
int System.Int32 32-bit signed integer
long System.Int64 64-bit signed integer
float System.Float 32-bit floating point ±1.5 · 10−45to ± 3.4 · 1038
double System.Double 64-bit floating point −1.8 · 10−308to + 1.8 · 10+308
decimal System.Decimal 128-bit decimal
char System.Char 16-bit Unicode character /u0000-/uffff
string System.String variable length
With C# version 3.0 besides the mentioned explicit data types a new implicit data type is
available called var. An implicit data type, like in VBA or in Python is set by it’s assignment.
1 var i = 10; // implicitly typed
2 int i = 10; // explicitly typed
8.3.2 Little Example to Check some Data Types
DTChecker
+ Main(string[]) : void
Figure 8.1:
DTChecker’s Diagram
The application DTChecker analysis the C#-data types short, int,
long and double using the factorial function. The factorial will be
implemented in an iterative way. The factorials input is read from the
command line. The value of the factorial is calculated in every iteration
step. The bytes of the analyzed data types are printed in hexadecimal
digits, to show the overflow.
Listing 8.4: Implementation of a Data Type Checker
1 #define _RELEASE // this is a macro definition
2 // to handle optional compiling
3 // note: macro definition only
4 // are allowed in the header
E. Baeck
8.3. DATA TYPES Page 79
5 using System;
6 using System.Text;
7
8 // our application ’s namespace is setup here
9 namespace DataTypeChecker
10 {
11 class DTChecker
12 {
13 static void Main(string [] args)
14 {
15
16 // this is only compiled if the macro
17 // _RELEASE is set above
18 #if _RELEASE
19 try
20 {
21 #endif
22 int n = 25;
23 if (args.Length > 0) n = Convert.ToInt16(args [0]);
24 short sfact = 1; // factorial with a short
25 int ifact = 1; // factorial with an integer
26 long lfact = 1; // factorial with a long
27 double dfact = 1; // factorial with a double
28
29 string hex; // this string we use for
30 // hexadecimal printing
31 for (int i = 1; i <= n; i++)
32 {
33 // analyzing the short
34 sfact *= (short)i;
35 // hex representation of the result
36 hex = String.Format("{0: X20}", sfact);
37 System.Console.WriteLine("s> {0 ,3}!= {1 ,20} | {2}",
38 i, sfact , hex);
39 // this we would do in C: printf ("s> %3d ....
40
41 // analyzing the int
42 ifact *= (int)i;
43 hex = String.Format("{0: X20}", ifact);
44 System.Console.WriteLine("i> {0 ,3}!= {1 ,20} | {2}",
45 i, ifact , hex);
46
47 // analyzing the long
48 lfact *= (long)i;
49 hex = String.Format("{0: X20}", lfact);
50 System.Console.WriteLine("l> {0 ,3}!= {1 ,20} | {2}",
51 i, lfact , hex);
52
53 // analyzing the double
54 dfact *= (double)i;
55
56 // this we would do in C: byte bd [100];
57 // here we get the bytes of a double value
58 byte [] bd = BitConverter.GetBytes(dfact );
59 // then we create an instance of a string builder class
60 StringBuilder sbd = new StringBuilder ();
10.6.2015
Page 80 CAD in Civil Engineering / 2015
61 // and then we iterate all bytes from the array
62 foreach (byte by in bd)
63 {
64 // and append there hex represention to the output string
65 sbd.Append(by.ToString("X"));
66 }
67 System.Console.WriteLine("d> {0 ,3}!= {1 ,20} | {2:20}",
68 i, String.Format("{0 ,20:0}",dfact), sbd);
69
70 // let’s do some formating
71 System.Console.WriteLine(
72 " -----------------------------------------------");
73 }
74
75 // if the application is shipped to the ’client ’, then the program should
76 // not crash. Therefor we handle the case of exceptions. Because this would make
77 // error searching more difficult , we kick out this code for the development
78 // cycle. The code inside the _RELEASE brackets will be only compiled , if the
79 // macro is known (see above)
80 #if _RELEASE
81 }
82 // catch will handle all error situations. The instance e of the
83 // Exception class will content an error message , which should help
84 // to understand the error situation.
85 catch (Exception e)
86 {
87 System.Console.WriteLine("> Problem in program:");
88 System.Console.WriteLine(e.Message );
89 }
90 #endif
91 }
92 }
93 }
In the following item list, some remarks are given to some important lines of code.
• In line 1 a macro #release is defined, to enable error checking by exceptions. Exceptions
sometimes are not helpful testing an application, because they will hide helpful system
messages.
• In line 23 the input value for our factorial is read from the command line. If the command
line data is wrong, at this position an exception will be thrown and will crash the program,
if no catch block is found, to handle this exception.
• In line 24 to 27 the variables for our data types to analyze are introduced and initialized.
• For the byte printing we need a string, which is implemented in line 29.
• The loop is given in line 31 by a simple for loop.
• Every variable is multiplied by the for-loop counter after having casted it to the desired
type.
• To print the bytes of an integer type is very easy, because the String objects offers a
Format method which is able to print an integer in a hexadecimal format, like we know
E. Baeck
8.3. DATA TYPES Page 81
from the C language.
• The output into the console is done by the WriteLine method of the Console object.
• To print a double value byte wise, we cannot simply write it in hex format, so we have to
convert the byte pattern of a double into hexadecimal digits. This we can do by using the
object BitConverter (line 58) and it’s method GetBytes, which provides us all the bytes
of the pattern in a byte array. Having converted this, we have to use the StringBuilder
object and it’s method Append (line 65).
• Appending byte by byte to the output sting in line 65, we iterate the byte array by the
usage of a foreach loop.
The following output shows the result. At the beginning our three integer formats will show the
same byte pattern. Only the first to bits are used.
Listing 8.5: First 2 Steps, s:single/i:int/l:long/d:double
1 s> 1!= 1 | 00000000000000000001
2 i> 1!= 1 | 00000000000000000001
3 l> 1!= 1 | 00000000000000000001
4 d> 1!= 1 | 000000 F03F
5 -----------------------------------------------
6 s> 2!= 2 | 00000000000000000002
7 i> 2!= 2 | 00000000000000000002
8 l> 2!= 2 | 00000000000000000002
9 d> 2!= 2 | 000000040
10 -----------------------------------------------
Step 7 obvious is the last correct step for the short type. We know, that we only can handle
numbers with short up to 32767. It’s interesting, that with Step 8 we get the same bit pattern
but a negative short number. The number is negative because the highest bit in short, the
0x8000 is set, which can be considered as a sign bit.
Listing 8.6: Steps 7 and 8, s:single/i:int/l:long/d:double
1 s> 7!= 5040 | 000000000000000013 B0
2 i> 7!= 5040 | 000000000000000013 B0
3 l> 7!= 5040 | 000000000000000013 B0
4 d> 7!= 5040 | 00000 B0B340
5 -----------------------------------------------
6 s> 8!= -25216 | 00000000000000009 D80
7 i> 8!= 40320 | 00000000000000009 D80
8 l> 8!= 40320 | 00000000000000009 D80
9 d> 8!= 40320 | 00000 B0E340
10 -----------------------------------------------
In Step 12 we can see, that the short value totally is wrong and only uses it’s last two bytes,
which are the last four hexadecimal digits. On the other hand the int and long type shows the
same pattern. We know that a signed 4 byte number is limited by round about 2 · 109, i.e. 2G.
So it is not surprising, that in step 13 the int value obviously is wrong. Compared with the
long type we see that the highest bit in int is truncated, so the number is wrong and less then
the long number. Remarkable also is, that till now in all cases the double value was ok.
10.6.2015
Page 82 CAD in Civil Engineering / 2015
Listing 8.7: Steps 12 and 13, s:single/i:int/l:long/d:double
1 s> 12!= -1024 | 0000000000000000 FC00
2 i> 12!= 479001600 | 0000000000001 C8CFC00
3 l> 12!= 479001600 | 0000000000001 C8CFC00
4 d> 12!= 479001600 | 0000 FC8CBC41
5 -----------------------------------------------
6 s> 13!= -13312 | 0000000000000000 CC00
7 i> 13!= 1932053504 | 0000000000007328 CC00
8 l> 13!= 6227020800 | 0000000000017328 CC00
9 d> 13!= 6227020800 | 000 C08C32F741
10 -----------------------------------------------
In step 21 the long data type gives us the last correct value. We see that the 4 bytes now,
start to overflow. One step more and it’s different comparing the value with the double. On
the other hand we know from the Precision-Finder, that we only have 17 digits with the double
type, so that the last digits in the double also can not be correct in any time, because we count
20.
Listing 8.8: Steps 20 and 12, s:single/i:int/l:long/d:double
1 s> 20!= 0 | 00000000000000000000
2 i> 20!= -2102132736 | 00000000000082 B40000
3 l> 20!= 2432902008176640000 | 000021 C3677C82B40000
4 d> 20!= 2432902008176640000 | 05 A41BEB3E1C043
5 -----------------------------------------------
6 s> 21!= 0 | 00000000000000000000
7 i> 21!= -1195114496 | 000000000000 B8C40000
8 l> 21!= -4249290049419214848 | 0000 C5077D36B8C40000
9 d> 21!= 51090942171709400000 | 20 C6B5E93B28644
10 -----------------------------------------------
The last step which is calculable, is step 170. On more step and the double type reaches it’s
end. In this case the bit pattern does not make sense any more and therefore an infinite is
printed. For the double type the exponent will be the bottleneck and so it will get an overflow
above 170!.
Listing 8.9: Last Steps 171, s:single/i:int/l:long/d:double
1 s> 171!= 0 | 00000000000000000000
2 i> 171!= 0 | 00000000000000000000
3 l> 171!= 0 | 00000000000000000000
4 d> 171!= +infinite | 000000 F07F
5 -----------------------------------------------
E. Baeck
8.4. OPERATORS Page 83
8.4 Operators
C# offers the following operators, which came from the C/C++ language. With exception of
the address operators all operators known from C++ are available in C# too.
8.4.1 Assignment Operator
Operator Comment Example
= Assignment i = 5;
8.4.2 Arthmetic Operators
Operator Comment Example
+ addition i = 9 +5; ⇒ 14
- substraction i = 9 -5; ⇒ 4
* multiplication i = 9 *5; ⇒ 45
/ division i = 9 /5; ⇒ 1
% modulo i = 9 /5; ⇒ 4
8.4.3 Compound Arithmetic Assignment
Operator Comment Example
+= addition i = 2; i += 9; ⇒ 11
-= substraction i = 3; i -= 1; ⇒ 2
*= multiplication i = 2; i *= 4; ⇒ 8
/= division i = 6; i /= 2; ⇒ 3
%= modulo i = 9; i %= 2; ⇒ 1
8.4.4 Increment - Decrement Operators
Operator Comment Example
++ incrementation i = 2; i++; ⇒ 3
-- decrementation i = 3; i--; ⇒ 2
10.6.2015
Page 84 CAD in Civil Engineering / 2015
8.4.5 Relational and Equality Operators
Operator Comment Example
== equal to 3 == 2; ⇒ false
!= not equal to 3 != 2; ⇒ true
> greater 3 > 2; ⇒ true
< less than 3 < 2; ⇒ false
>= greater equal 3 >= 3; ⇒ true
<= less equal 3 <= 4; ⇒ false
8.4.6 Logical Operators
Operator Comment Example
! not !(3 == 2); ⇒ true
&& and (3 == 2) && (1==1); ⇒ false
|| or (3 == 2) || (1==1); ⇒ true
The following table shows the truth values of the && and the || operator.
Truth table of the && operator
a b a && b
true true true
true false false
false true false
false false false
Truth table of the || operator
a b a || b
true true true
true false true
false true true
false false false
8.4.7 Bitwise Operators
Operator Comment Example
& and 0x20 & 0xff; ⇒ 0x20
| or 0x20 | 0xff; ⇒ 0xff
^ exclusive or 0x20 ^ 0xff; ⇒ 0xdf
~ complement ~0x20; ⇒ 0xffffffdf
<< shift left 0x20<<1; ⇒ 0x40
>> shift right 0x20>>1; ⇒ 0x10
E. Baeck
8.4. OPERATORS Page 85
8.4.8 Compound Bitwise Assignment
Operator Comment Example
&= and i = 0x20; i &= 0xff; ⇒ 0x20
|= or i = 0x20; i = 0xff;— ⇒ 0xff
^= exclusive or i = 0x20; i ^= 0xff; ⇒ 0xdf
<<= shift left i = 0x20; i <<=1; ⇒ 0x40
>>= shift right i = 0x20; i >>=1; ⇒ 0x10
8.4.9 Explicit Type Casting Operator
The type casting operator converts one type into another type. The destination type is set
in between two round brackets. In the following example an short -1 is casted into an ushort
type, so the sign bit is no more interpreted as a sign and becomes part of a positive number
information. Every bit now is set in the two bytes variable and therefore we get the value 65535.
1 short i = -1; // value: -1
2 ushort j = (ushort)i; // value: 655
8.4.10 sizeof Operator
The sizeof operator determines the length of a variable in bytes. In the following example the
length is determined of an short, an int, a long, a float and a double. So we get the numbers
2, 4, 8, 4 and 8.
Listing 8.10: Evaluation of Data Type’s Size by the sizeof operator
1 System.Console.WriteLine(
2 "short: {0}, int: {1},long: {2}, float: {3}, double: {4}",
3 sizeof(short),sizeof(int),sizeof(long),sizeof(float),sizeof(double ));
4
5 ... and that is, what we get:
6 short: 2, int: 4, long: 8, float: 4, double: 8
8.4.11 Address and Value Operator
Address and value operator are only available in so called unsave mode. If you want to use
pointer, then you should remember, that the garbage controller will move memory blocks on
the heap to avoid memory fragmentation. If the memory block of a variable is now moved on
the heap, it’s address will change. To avoid this, you should use the environment fixed, which
is also shown in the next code snippet in the frame of an unsaved code block. An int pointer is
introduced an get the address of the member obj.intVar. Then we use the pointer within an
unsave code block within an fixed environment, to assign the value 9 and show the result with
a line print.
10.6.2015
Page 86 CAD in Civil Engineering / 2015
Listing 8.11: Pointer- and Address-Operator
1 unsafe {
2 // fixierter Code
3 fixed(int* pointer = &obj.intVar) {
4 *pointer = 9;
5 System.Console.WriteLine (* pointer );
6 }
The address operator & determines the address of a variable in memory. The value operator *
determines the value of data with a given address. In our example we determine the address of
a variable i and then the value of the second item of an integer array is determined. The address
of an array is given by the arrays name. The address of the second item of an array therefore is
given by the name of the array plus one.
Operator Comment Example
& address int* pointer = &obj.intVar
* value int s[2] = {1,2}; *(s+1); ⇒ 2
8.4.12 Verbatim Strings
If a string should be used without any escapes, we can prefix this string by the @-quote. This
is especially important, if path names are used or very long texts should be assigned. This is
shown within the following code snippet.
Listing 8.12: Using the Verbatim String
1 string cTemp1 = @"c:\temp";
2 string cTemp2 = "c:\\ temp"; // same result as in cTemp1
3 ...
4 string cTemp3 = @"This could be very large string something like a Select
5 query which you would want to be shown spanning across
6 multiple lines rather than scrolling to the right and
7 see what it all reads up";
E. Baeck
8.5. BRANCHES Page 87
8.5 Branches
Like in C/C++ in C# there are different possibilities to implement branching.
8.5.1 Filtering with an if Statement
A code block can be optional executed by the control of an if statement. If the condition1, a
boolean expression, is true the code block will be executed. If the value is false, the code block
will be skiped.
1 if ( condition )
2 {
3 ...
4 code block
5 ...
6 }
The conditional execution also can be extended optionally by an else block.
1 if ( condition )
2 {
3 ...
4 code block 1
5 ...
6 }
7 else
8 {
9 ...
10 code block 2
11 ...
12 }
The complex filter can be implemented by the use of muliple ifs. Here we introduce further ifs
with there conditions after the else statement.
1 if ( condition 1 )
2 {
3 ...
4 code block 1
5 ...
6 }
7 else if ( condition 2 )
8 {
9 ...
10 code block 2
11 ...
12 }
13 else
14 {
15 ...
16 code block 3
17 ...
18 }
1In C# a condition is implemented like in C/C++ too. We have the same operators and the same syntax.
10.6.2015
Page 88 CAD in Civil Engineering / 2015
8.6 Loops
8.6.1 for Loop
The most classical loop statement in C# is the for statement. The for statement executes a
statement or a code block. The execution of the loop is controlled by tree expressions. This
statement is working like in C/C++ too.
1 for ([ initialization ];[ break condition ];[ iterator condition ])
2 {
3 ... statement or code block
4
5 if (condition 1) continue;
6
7 if (condition 2) break;
8
9 ... further code blocks
10 }
• The initialization is executed before the loop is starting.
• The break condition is evaluated after each loop cycle. If the value of the expression is
vanishing the loop will be broken, if not a next cycle will be started.
• The iteration condition is a statement, which is executed after the execution of a cycle.
• The optional statement continue breaks a cycle and starts the next one.
• The optional statement break will break the this loop.
The next examples will add up all even numbers starting from 20 up to 40.
1 int sum = 0;
2 for (int i=20;i<41;i+=2) sum +=i;
The next implementation runs over all numbers starting from 0 up to 100 with a standard
increment of 1 and will add up all even numbers starting from 20 up to 40 too, using a continue
and a break statement.
1 int sum = 0;
2 for (int i=0;i<101;i++)
3 {
4 if ((i<20) || (i%2 != 0)) continue;
5 if (i>40) break;
6 sum +=i;
7 }
E. Baeck
8.6. LOOPS Page 89
8.6.2 do - while Loop
If an open loop with an unknown number of cycles should be implemented, we can do this very
general using an do - while loop. This loop is exactly like the do - while loop in C/C++. like
in C/C++ too. Unlike the for - loop, the do - while loop comes at least with one cycle if no
break statement is used.
1 do
2 {
3 ... statement or code block
4
5 if (condition 1) continue;
6
7 if (condition 2) break;
8
9 ... further code blocks
10 } while (condition)
• The initialization must be done explicitly.
• The optional statement continue breaks a cycle and starts with a new one.
• The optional statement break will break the this loop.
• Iteration increments must be done explicitly.
The next implementation runs over all numbers starting from 0 up to 100 with a standard
increment of 1 and will add up all even numbers starting from 20 up to 40 too, using a continue
and a break statement. An implementation with a for loop is given i the previous section.
1 int sum = 0;
2 int i = 0;
3 do
4 {
5 if ((i < 20) || (i % 2 != 0)) { i++; continue; }
6 if (i> 40) break;
7 sum += i++;
8 System.Console.WriteLine("i = {0,3}, sum = {1,4}",i,sum);
9 } while (i < 100);
8.6.3 while Loop
The while loop is like the do - while. The only difference is, that the break condition is evaluated
before a cycle is started and not like in the case of the do - while loop after the cycle has been
executed.
1 while (condition)
2 {
3 code block
4 }
10.6.2015
Page 90 CAD in Civil Engineering / 2015
8.6.4 foreach Loop
The foreach loop can be used to iterate iteratable objects. The loop will be performed on each
element of the interatable. In our little example (see listing 8.13) an array is initialized with
interger values. After the initialization is done the array values are printed using an foreach
loop.
Listing 8.13: Implementation of a foreach Loop printing array data
1 using System;
2 namespace ArrayApplication
3 {
4 class MyArray
5 {
6 static void Main(string [] args)
7 {
8 int [] a = new int [10]; /* a is an array of 10 integers */
9 int i;
10
11 // initialize elements of array a
12 for ( i = 0; i < 20; i++ )
13 {
14 a[i] = i + 100;
15 }
16
17 // output each array element ’s value
18 i = 0;
19 foreach (int j in a )
20 {
21 Console.WriteLine("Element [{0}] = {1}", ++i, j);
22 }
23 }
24 }
25 }
E. Baeck
8.7. ARRAYS Page 91
8.7 Arrays
Arrays are data container storing only objects of the same data type, i.e. for example only
integer values or only double values.
8.7.1 One Dimensional Arrays
A one dimensional array declaration looks like the following. The declaration starts with the
data type, here int. It should be an array, this is set by the square brackets, i.e. []. It follows
the array’s name, here a. On the right side of the assignment operator the new operator with
the size information finishes the declaration. An array is a referenced data type, i.e. an array
is passed by reference and therefore an array has to be declared using the new operator. That
means, if the array is no longer referenced, the garbage collector will delete it automatically. So
there is no need to delete it explicitly like we have to do it in C++.
1 int [] a = new int [10];
We also can initialize an array using the declaration statement as shown below. Here we can
see, that the size of the array is taken from the number of the initialization values.
1 int [] a = new int[] {1,2,3,4,5,6,7,8,9,10};
8.7.2 Multidimensional Arrays
A multidimensional is declared similar to the one dimensional one. The number of indices
are given by the comma as an separator. The initialization of the array is similar too, the
initialization values are grouped in rows. In our example below we see, that we have allocated
an array of the dimensions 3 by 2. Because the array in C# unlike in C++ is an object, we can
use the object’s method’s to get some array information. The method GetLength(dim) provides
the number of items in direction dim. So we can get the array’s dimensions to print the data,
like we see in the example below.
1 /* output each array element ’s value using a nested loop*/
2 int[,] b = new int[3, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 } };
3 for (int i = 0; i < b.GetLength (0); i++)
4 {
5 for (int j = 0; j < b.GetLength (1); j++)
6 {
7 Console.WriteLine("a[{0} ,{1}] = {2}", i, j, b[i, j]);
8 }
9 }
The console output of above’s example is the following.
1 a[0,0] = 1
2 a[0,1] = 2
3 a[1,0] = 3
4 a[1,1] = 4
5 a[2,0] = 5
6 a[2,1] = 6
10.6.2015
Page 92 CAD in Civil Engineering / 2015
8.8 OOP and Classes
Unlike C++ C# is a pure object orientated language2. That means that everything is a class
and everything is managed by classes. A class combines data, called attributes, with functions,
called methods. This can be described by so called UML3
There is no possibility to develop functional code like in C++. To run the program we need one
and only one class method called Main. This method is called by the operating system to run
the application. The command line parameters are passed to this method inside the args array.
1 static void Main(string [] args)
8.8.1 Namespaces
In C# everything is grouped in namespaces. A namespace can be assigned with the using
statement. Unlink in C++ we don’t need to include header files. In C++ have to link
libraries, if we want to use non standard resources. In C# we have to add a reference onto the
used library. How to do this we can see in section 10.2, see also figure 10.3.
From our Hello application we see, that we use the using of system (see listing 7.1). This
reference provides the core system, so that we can write some messages into the console window.
If we start with the development of an application, we have to introduce at least one namespace
which should content the classes of our application. If we use the project wizard of Visual Studio
a namespace and a starter class will be created. In the case of our Hello it is the namespace
HelloWorld and the starter class Hello.
8.8.2 Classes
A class in C# is declared like follows, where <data type> is a C# buildin data type or
a new data type introduced by the program itself or by a reference to a type library. The
<access specifier> controls the access to a variable (i.e. an attribute) or a function (i.e. a
method) of the class.
8.8.2.1 class Implementation
The following code shows, how to implement a class in C#.
1 <access specifier > class class_name <: base class >
2 {
3 // member variables
4 <access specifier > <data type > variable1;
5 <access specifier > <data type > variable2;
6 ...
7 <access specifier > <data type > variableN;
8 // member methods
2Object orientated Programming is often used with the abbreviation OOP.3The Unified Modeling Language includes a set of graphic notation techniques to create visual models of
software-intensive systems. The Unified Modeling Language is an international standard see [3], UML 2.3 was
formally released in May 2010.
E. Baeck
8.8. OOP AND CLASSES Page 93
9 <access specifier > <return type > method1(parameter_list)
10 {
11 // method body
12 }
13 <access specifier > <return type > method2(parameter_list)
14 {
15 // method body
16 }
17 ...
18 <access specifier > <return type > methodN(parameter_list)
19 {
20 // method body
21 }
22 }
An instance of a class, that is the realization of the class in memory, is created simply by
declaring a referenced variable type, i.e. a variable of the classes type assigning the memory by
the call of the classes constructor using the new operator.
8.8.2.2 Constructor and Destructor
The constructor in C# is a method which comes with the name of the class and is declaring
the parameters which should be used to initialize the instances. The constructor like in C++ is
declared without any return type.
In many cases a deconstructor is not needed, so we can renounce it. The deconstructor is called,
when the object is deleted. The deletion will be done by the garbage collector, if the object is
not referenced any more. The deconstructors name is like the classe’s name with a tilde prefix
(~) like in C++. Unlike in C++ a class can only have one base class to avoid the rhombus
problem.4
8.8.2.3 Access Specifiers
One important feature of OOP is the encapsulation of code, to make the code much more
reusable. To realize this OOP languages come in general with a wide set of access permissions.
C# has enhanced the number of permissions comparing it with C++ . The permissions available
are shown in the following table.
Permission Comment
public Fully accessible.
internal Accessible only within containing assembly or
friend assemblies
private Visible only within containing type
protected Visible only within containing type or subclasses
protected internal The union of protected and internal accessibility
4The rhombus problem comes up, if a class has two base classes and both of them have the same base class.
If now this classes have attributes or methods with the same name, the inheritance will become unclear. To avoid
this problem C# is not supporting multiple inheritance.
10.6.2015
Page 94 CAD in Civil Engineering / 2015
8.8.2.4 Rectangle class Example
Listing 8.14 shows a simple example class to implement a rectangle which is able to calculate
it’s area and print it’s data into the console window.
Listing 8.14: class Implementing an Rectangle Object
1 class Rectangle
2 {
3 // member variables
4 protected double length;
5 protected double width;
6
7 // constructor
8 public Rectangle(double l, double w)
9 {
10 Console.WriteLine("hello rectangle!");
11 length = l;
12 width = w;
13 }
14
15 // deconstructor
16 public ~Rectangle ()
17 {
18 Console.WriteLine("by rectangle ...");
19 }
20
21 // calculating rectangle ’s area
22 public double GetArea ()
23 {
24 return length*width;
25 }
26
27 // printing the rectangles data
28 public void List()
29 {
30 Console.WriteLine("Length: {0}", length );
31 Console.WriteLine("Width.: {0}", width);
32 Console.WriteLine("Area ..: {0}", GetArea ());
33 }
34 } //end class Rectangle
8.8.2.5 Inheritance Example
8.8.3 Some UML Diagrams
UML structure diagrams of the emphasize the things that must be present in the system being
modeled. Since structure diagrams represent the structure they are used extensively in docu-
menting the architecture of software systems. In our description of the examples we want to
implement we use the Class Diagram which describes the structure of a system by showing the
system’s classes, their attributes, and the relationships among the classes.
E. Baeck
8.8. OOP AND CLASSES Page 95
Class Name
Attributes
Methods
Additional infor-
mation within a
simple Note dia-
gram
Additional infor-
mation within a
simple Note dia-
gram
Figure 8.2: A UML Class and Note Diagram
A UML class diagram (see figure 8.2) consists of
a rectangular box, which is divided into three sec-
tions. The fist section contents the class’s name.
This name is written centered in bold letters.
The second section contents the attribute’s names
of the class and the third section contents the
method’s names.
10.6.2015
Page 96 CAD in Civil Engineering / 2015
A UML note diagram (see figure 8.2) consists of a stylized note sheet which is filled with some
information.
MyClass
Attribute1
Attribute2
Method1
Method2
this is my 1st classthis is my 1st class
Figure 8.3: A UML Note Diagram Assignment
A UML note diagram (see figure 8.3) will be as-
signed to an other component of the diagram scene
with a simple line.
Base Class
− attributeB1
− attributeB2
− methodB1
+ methodB2
Derived Class
+ attributeS1
− attributeS2
+ methodS1
+ methodS2
Figure 8.4: A UML Inheritance Diagram
Figure 8.4 shows how to draw diagrams for inheriting
classes. An arrow with a white filled arrowhead points
from the inheriting class, the special class, to the inher-
ited class, the base class. The attributes and the meth-
ods of the Base class are now available in the name space
of the inheriting class, i.e. the derived class now has the
attributes attributB1, attributB2, attributS1 and
attributS2.
The prefixes + and − describe the access permissions. + items are accessible from outside. In
C# they get the public attribute. − items are not accessible from outside, only methods of
their class are allowed to access. In C# they get the private attribute.
Base Class
− attributeB1
− attributeB2
− methodB1
+ methodB2
Figure 8.5: Item Types
There are to different class items, an item which is related only to
a class and an item which is related to an instance. An instance
related item needs an instance. So if an instance is created the item
is available with this instance pointer. Without an instance the item
is not available. So an instance related item can have an arbitrary
multiplicity, so every instance has it’s own item. This item is listed
without an underlining.
On the other hand there are items which are related to the class.
This item are accessed using the class name as a prefix and not the instance name. A class item
one once exists in the application. A class related item is listed in the UML class diagram with
an underlining.
E. Baeck
8.8. OOP AND CLASSES Page 97
sorted3..* random1
Class 1
List A
List B
Method 1
Class A
Attribute A1
Attribute A2
Method A
Class B
Attribute B1
Attribute B2
Method B
Figure 8.6: A UML Diagram for a Compo-
sition and an Aggregation
Figure 8.6 shows a aggregation and a composition.
An aggregation is drawn by a white filled rhombus.
An composition is drawn by a black filled rhombus.
Aggregation and compositions describe a container
or a list of several instances of an object, which are
members of a main class. If for example a profile
consists of several parts, the parts can be described
as an composition, if a part only exists within a pro-
file. If a part exists also without a profile, the parts
are described within the profile with an aggregation.
At the ends of the connecting lines the multiplicities
are noted. The multiplicity gives the range of refer-
enced instances in the form from..to. For the Class
A we have 2 up to infinite instances in an composi-
tion, therefor at the end of the line we can not have
a multiplicity of zero. In our example we have ex-
actly one instance of the class 1. On the other hand
Class B is referred to Class 1 within an aggregation. In our example on instance of Class B can
be reverenced by an undefined number of instances of Class 1. This is shown by the * icon. On
the other hand the class 1 references at least on instance of the Class B. Otherwise the number
of references is arbitrary. This is also shown by the * icon.
10.6.2015
Page 98 CAD in Civil Engineering / 2015
8.9 Exceptions
8.9.1 try and catch
In modern languages in general a powerful error handler strategy is available called exceptions.
In C# a so called try block contents the code which should be executed and whose errors, i.e.
exceptions, should be handled. An exception can be a division by zero or an access to a null
reference, i.e. a variable without any content. In those cases the program would crash without
any exception handlers.
In a traditional code like an old FORTRAN77 code for example all the error situations have to
be handled manually, i.e. by the usage of error codes and a chain of jumps back to the calling
routine. This in general is a very work intensive solution. In contrast if we simple introduce
a catch block, it is not necessary to implement a chain of jumps back. If inside the code of
the try block an error would ocurre, automatically the control of the program is passed to the
catch block. So the catch block should handle the error situation.
In the following code snippet we divide 5 by zero, which would throw an exception, i.e. produces
an error situation. If we put this division into a try block, the corresponding catch block will
be executed. So we will get the message, that we better should not do that. Optionally we can
pass the created exception object to the catch block. If we parse an Exception instance or if
we want to see the original exception message, we use the method ToString() to have access
to the exception’s message text.
1 try
2 {
3 int i = 5 / 0;
4 }
5 catch (Exception ex) // No args , so it will catch any exception
6 {
7 Console.WriteLine("Please don’t divide by zero!");
8 Console.WriteLine(ex.ToString ());
9 }
8.9.2 The finally Block
We can extend the try - catch construct by a finally block. The finally block will be
executed in every case, even if inside the try or the catch block will be return statement. So
the finally in every case is the ultimate code, which will be executed.
1 try
2 {
3 int i = 5 / 0;
4 }
5 catch // No args , so it will catch any exception
6 {
7 Console.WriteLine("Please don’t divide by zero!");
8 }
9 finally
10 {
11 Console.WriteLine("This is the last goodby!");
12 }
E. Baeck
8.10. FLOATINGPOINT PRECISION Page 99
8.10 Floatingpoint Precision
The Precision-Finder is a nice little program, which analysis the relative precision of a given
float format.
8.10.1 Description of the Application
Start
Initializing:
X1 = 1.; X2 = 1.; D = 2.;
Reductionstep:
X2 = X2/D;
Accumulationstep:
S = X1 +X2;
S > X 1yes
Resultstep:
Precision = X2 * D;
no
Stop
Figure 8.7: Flowchart for a Precision
Finder
As we know, the computer cannot handle an infinite
number of floating-point digits. Therefore it is im-
portant to know who many digits are available using
the small and the big floating-point format (float and
double). Figure 8.7 shows a flow chart of an algorithm
which continually reduces the value of a variable. Af-
ter each reduction the sum of the fixed and the reduced
variable is calculated. If now the contribution of the
reduced is vanishing, we have reached the total limit.
Beyond this limit the contributing information is totally
expunged. To get the relative precision, i.e. relating to
one, we have to take back the last reduction, if we have
reached the limit.
8.10.2 Exercise
Please implement the algorithm of the Precision-Finder
for the float and for the double format within a console
application like the famous Hello World example.
10.6.2015
9
Using
EXCEL from C#
9.1 First Steps
Microsofts EXCEL can be used as User-Interface to set up input data for any task. EXCEL as
already discussed in section 3 provides an embedded script IDE for Visual Basic. On the other
hand we easily can access the EXCEL type library using a .Net language like C#, VB.Net or
C++/CLI.
Linking to EXCEL’s type library from a .Net language we will see, that in this case we don’t
have an embedded IDE nor the possibility to implement embedded code into an EXCEL sheet.
What we can do, is to develop a software, which only uses the classes of EXCEL’s type library.1
To link the EXCEL object library we use the project’s menu function add reference. Figure 9.1
shows, that we find EXCEL’s object library within the COM interface. We select the library
and close the dialogue. After this step we can access the EXCEL’s object classes.
Figure 9.1: Link EXCEL’s Object Library
1Although Microsoft obvious no support the VBA development, there is no successor available since nearly
fifteen years. Astonishing also is, that using the type library of EXCEL we obvious use the old COM interface.
COM was introduced with Windows 3.1 in 1995.
100
9.2. MY HELLO WITHIN AN EXCEL-SHEET Page 101
9.2 My Hello within an EXCEL-Sheet
Figure 9.2: A Hello Sheet
The following code shows how to write a little Hello
into an EXCEL sheet. An EXCEL is executed and
a new EXCEL file is created with desired Hello
text.2
Listing 9.1: Implementation of a Little EXCEL Hello
1 using System; // the basics
2 using System.IO;
3 // using System.Collections.Generic; // not used
4 // using System.Linq; // database package
5 // using System.Text; // not used
6 // using System.Threading.Tasks; // not used
7
8 // link to excel
9 // alias -> reference to the type library
10 using Excel = Microsoft.Office.Interop.Excel;
11
12 namespace HelloExcel
13 {
14 class Program
15 {
16 static void Main(string [] args)
17 {
18 // standard hello
19 Console.WriteLine("Hello from the EXCEL Startup Example");
20
21 // variables
22 int i1 = 1;
23 float f1 = 1.2f;
24 double d1 = 3.4;
25
26 // 1. item {0}{1}{2}
27 Console.WriteLine("i1 = {0} -> {0}, f1={1}, d1={2}",i1,f1,d1);
28 // %d %5d
29 Console.WriteLine("i1 = {0} -> {0,5}", i1);
30
31 // setup the folder
32 string path = Directory.GetCurrentDirectory ();
33 Console.WriteLine("> current directory ...: ’{0}’", path);
34
35 // specify the excel file name
36 string file = "hello.xls";
37 Console.WriteLine("> create an EXCEL file: ’{0}’",file);
38
39 // specify the excel file name
40 file = path +"\\" + file;
41 Console.WriteLine("> total file name .....: ’{0}’", file);
2To implement this perfectly, we should not forget to release all allocated COM instances explicitly by calling
the garbage collector, sie below.
10.6.2015
Page 102 CAD in Civil Engineering / 2015
42
43 // some Excel instance variables (objects)
44 Excel.Application xlsApp; // application
45 Excel.Workbook xlsWorkbook; // xls file
46 Excel.Worksheet xlsSheet; // xls sheet to write hello
47
48 // start the Excel -App
49 xlsApp = new Excel.Application ();
50 xlsApp.Visible = true; // Excel should be visible
51 xlsApp.DisplayAlerts = false; // no alerts please!
52 Console.WriteLine("> EXCEL started!");
53
54 // create the work book
55 xlsWorkbook = xlsApp.Workbooks.Add();
56
57 // get the 1st sheet: 1 based !!!
58 xlsSheet = xlsWorkbook.Worksheets [1];
59
60 // write the hello: Cells is 1 based !!!
61 // | 1.st row
62 // | | 1st col that is A1
63 xlsSheet.Cells[1, 1] = "Hello Excel!";
64
65 // save the EXCEL file
66 xlsWorkbook.SaveAs(file);
67
68 // close the workbook (close the file)
69 xlsWorkbook.Close ();
70
71 // close the Excel -App
72 xlsApp.Quit ();
73 Console.WriteLine("> EXCEL closed!");
74
75 // clear up the com objects
76 releaseObject(xlsApp );
77 releaseObject(xlsWorkbook );
78 releaseObject(xlsSheet );
79 }
E. Baeck
9.3. SOME USEFUL EXCEL OBJECTS Page 103
9.3 Some Useful EXCEL Objects
If the COM type library of EXCEL is loaded, the objects of EXCEL can be used by inserting
the following using. To avoid the crazy long prefixes of an EXCEL object access according to
the structure of the type library, we introduce an alias, which in the following cases is called
Excel. This alias is introduced by the assignment of the desired branch of the library
1 using Excel = Microsoft.Office.Interop.Excel;
9.3.1 Excel’s Application Class
Excel ’s class Application is the container for everything, which is available from Excel. This
class is used to arrange the applications outfit and GUI. In our case we are only interested in a
collection, which handles and holds all the Excel files, called Workbooks.
An instance of EXCEL is created and started, if we create a new application instance. After all
the things are done, we should not forget to close our EXCEL instance. This is done with the
method Quit. If the instance is not closed, then the application still will life until the computer
is shut down or the instance is killed by a task manager. A typical code frame for an Excel
access is shown within the next code snippet.
1 using Excel = Microsoft.Office.Interop.Excel;
2 ...
3 Excel.Application xlApp;
4 xlApp = new Excel.Application ();
5 ... some work
6 xlApp.Quit ();
9.3.2 Excel’s Workbook
If we want to access to an Excel sheet, we have to open or create a so called Workbook object
of the Application class. This is controlled by the workbook’s container itself, which is called
Workbooks class. The class Workbooks especially provides us the following Methods.
• Open(filename), opens and load an existing Excel file into the Workbooks container.
• Because Workbooks is a container class, we can select one Workbook instance by a simple
array index call. So in the following code the first Workbook is selected and set to active
with it’s Activate method.
1 xlApp.Workbooks [1]. Activate ();
• Save() saves the active Excel Workbook instance.
• SaveCopyAs(filename), saves the active Workbook instance into a new file.
• Close(par1,par2,par3), closes the active Workbook instance.
If the first parameter in the Close method is set to true the changes will be saved to the
media. If it is set to false, the changes are ignored. The last two parameters are not
needed and can be set to Type.Missing.3
3 Type.Missing is used for not used or optional parameters using the COM interface from C#
10.6.2015
Page 104 CAD in Civil Engineering / 2015
9.3.3 Excel’s Worksheet
The Workbook instance has an attribute, which is called Worksheets. Worksheets in general is
the container for Worksheet instances and Chart instances. If we now want to select a Worksheet
instance, we have to call the getter function and cast the result to a Worksheet reference. The
following example shows, how to get the first Worksheet instance from a Workbook reference.
1 xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item (1);
We also can use an indexed access to the Worksheet.
1 xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets [1];
To have access to the cells of a Worksheet instance we can use its the indexer Cells with the
index of the row and the column.4
The following code shows how to set sheet values using the Cells indexer. The Cells indexer
selects a cell by it’s row and column number. Than we simply can assign the values. Important
to now is, that this index values are starting with one and not - like usual in C# - with h zero.
1 // print the root
2 int nRow = 2;
3 foreach (Root r in roots)
4 {
5 xlWorkSheet.Cells[nRow , 1] = r.dx;
6 xlWorkSheet.Cells[nRow , 2] = r.df;
7 xlWorkSheet.Cells[nRow , 3] = r.dfs;
8 xlWorkSheet.Cells[nRow , 4] = r.nCycles;
9 nRow ++;
10 }
A second kind of cell access is possible with the Range object. This object is an attribute of the
Worksheet. With the Range access we can access a cell using it’s name or it’s coordinate label
(for example ”A1” for the top left cell).
1 xlWorkSheet.Range["ROOTS"]. Value2 = string.Format("{0}",roots.Count)
2 xlWorkSheet.Range["ROOTS"].Cells [1 ,2]. Value2 = "... oh, just a little off!"
In the example above we see in line 1 the assignment of a string value to the cell value of
the cell called ROOTS. The second line shows how to use a named cell for a relative indexing.
The indexing is done with the indexer Cells. So you see that even with the simple standard
operators we have a lot of access methods to work an sheet cells.
9.3.4 The Garbage Collector’s Problem
We have seen, that C# uses a garbage collector and provides us the benefit of an automated
memory release for instances that run out of references, i.e. if no more reference are found in
the running app. Now, in many cases an advantage comes with it’s disadvantage. Here too. If
the garbage collector will do the memory release, we don’t know, when it will happen. On the
other side the instances are living within the COM space and we don’t really know, how the
4The Cells indexer is very slow. So if you want to get a better performance for a larger amount of data to
transfer, you should use a method to get the data directly into an object array.
E. Baeck
9.3. SOME USEFUL EXCEL OBJECTS Page 105
memory management will interact between .NET and COM . To be sure, that we will not get
memory problems related to this, we have to free the allocated instances manually.
After a typical EXCEL session therefore we would free our allocated instances in a way like that.
1 ...
2 releaseObject(xlApp);
3 releaseObject(xlWorkBook );
4 releaseObject(xlWorkSheet );
To do the memory release encapsulated within our application, we introduce the following
method called releaseObject, which should do the work for us.
1 // release explicitly a com object
2 private void releaseObject(object obj)
3 {
4 try
5 {
6 System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
7 obj = null;
8 }
9 catch (Exception ex)
10 {
11 obj = null;
12 Log.AppendLog("*** Error: Unable to release the Object "
13 + ex.ToString ());
14 }
15 finally
16 {
17 GC.Collect ();
18 }
19 }
In line 2 the instance pointer of the base class object is passed.5. In line 6 the instance is freed
by a ReleaseComObject call. This call tags the instances as instances to be freed. We put this
into a try environment to able to handle exceptions by our own. At the end of the try construct
in any case the finally block will be executed, which will do an explicit GC.Collect call, to
force the garbage collector to free now.
To be sure, that there are no errors related to memory problems with the COM components, we
should not forget to explicitly free this instance by an explicit release command to the garbage
collector.
5In C# everything is derived from object, so that we can say object is a kind of grandmother of us all.
10.6.2015
Page 106 CAD in Civil Engineering / 2015
9.3.5 The Folder Problem
If we are working with files, we should know where to access them. Sometimes it’s hard to solve
the problem, because one application uses it’s folder as work directory and some applications
like MS-EXCEL is using the document folder of the user. To get a little bit more clarity, we can
use a system helper function, which will show us the set work directory.
In the following code snippet we use the GetCurrentDirectory method of the Directory pack-
age, which is part of the system.IO package, to get the set work directory. To notify the user,
we print a little message in our log file. b
1 string cDir = Directory.GetCurrentDirectory ();
2 xlsfile = cDir + "\\" + file;
3 Log.AppendLog(string.Format("Starting XLS -export into {0}",xlsfile ));
E. Baeck
9.4. ROOTFINDER APPLICATION Page 107
9.4 RootFinder Application
The goal of the application RootFinder is, to find and list the roots of a given function inside a
given interval using the Newton’s method. Further it will show, how to write the roots data into
an EXCEL using COM automation sheet. This example will show and discuss the following
features.
• Implementation and usage of a logger class.
• Implementation of Newton’s root finder algorithm.
• Usage of delegates, to pass a function reference.
• Usage of an ArrayList instance.
• Encapsulation of data into an object.
• Usage of COM type libraries, in this case the library of EXCEL.
• Usage of an EXCEL-sheet as output media.
9.4.1 A Logger Class
Logging is very important to check the runtime behavior of a system. If logging should be save,
i.e. no information should be deleted by missing flush events after a crash, flushing has to be
done explicitly or the file we use for logging has to be opened for append writing and has to be
closed after writing immediately.
MyTools
Log
+ FileName : string
+ bCons : bool
+ Set(string): void
+ AppendLog(string) : void
+ Reset() : void
Figure 9.3: A Logger-Class
The Log class should be used from anywhere in the application
writing to the same file. Because we only have one attribute,
which should not be created multiple, we introduce a class,
which only comes with three static functions.
• Set should replace the default log-file name.
• AppendLog, the method to print into the log-file and
optionally into the console window.
• Reset, the method to delete an already existing log file.
The class is put into our Tools package MyTools with the
namespace statement.
In coding 9.2 (line 5) we see that the Log class is embedded into the namespace Logger, which
later will be used to access to the loggers features. We start with the standard log-file name
RootFinder.log and the set console flag, i.e. every string printed into the log-file also should be
printed into the console window. To replace this default values of the private attributes, which
are encapsulated attributes, we use the Set/Get property interface of C#. So from outsides
view, we have public attributes but this attributes are automatically converted to an Set/Get
10.6.2015
Page 108 CAD in Civil Engineering / 2015
interface.6 Please note too, that within the Set method the parsed value comes with the variable
value. In line 37 we see how to remove a file, this is done by the class File’s Delete Method.
In line 45 a instance of the StreamWriter class of System.IO is created. We write the line with
a leading time stamp using the DateTime class (line 46) and close the stream (line 47) to flush
the data to the disk. Optionally in line 49 the message is written into the console window too.
Listing 9.2: Implementation of a Logger Class
1 using System;
2 using System.IO; // like ’include <stdio.h>, <io.h>’
3
4 // the Log class is part of our library namespace
5 namespace MyTools
6 {
7 // logger calls
8 class Log
9 {
10 // log -filename
11 // static: object variable -> only one variable available inside the program
12 private static string sFileNameI = "RootFinder.log";
13
14 // flag to control the printing into the console window
15 // has to be a static , because it is used in a static
16 private static bool bConsI = true;
17
18 // set/get methodes for the private attributs
19 public static string sFileName
20 {
21 get { return sFileNameI; }
22 set { sFileNameI = value; }
23 }
24
25 // set/get methodes for the private attributs
26 public static string bCons
27 {
28 get { return bConsI; }
29 set { bConsI = value; }
30 }
31
32 // reset method to reset the logging system
33 // note: this methode should be usable inside a static methode
34 // therefor it is declared also as a static
35 public static void Reset()
36 {
37 File.Delete(sFileNameI );
38 }
39
40 // print a message into the log file
41 // note: this methode should be usable inside a static methode
42 // therefor it is declared also as a static
43 public static void AppendLog(string sMessage)
44 {
45 StreamWriter f = new StreamWriter(sFileNameI ,true);
6This property interface is not available in C++, in C++ we have to introduce normal methods, which will
pass the data.
E. Baeck
9.4. ROOTFINDER APPLICATION Page 109
46 f.WriteLine(DateTime.Now + "| " + sMessage );
47 f.Close ();
48
49 if (bConsI) System.Console.WriteLine(sMessage );
50 }
51 }
52 }
9.4.2 The Roots Data, the Class Root
RootFinder
Root
+ dx : double
+ df : double
+ dfs : double
+ nCycles : int
+ Root(double, double, double, int): void
Figure 9.4: A Root-Class
A root will be described by it’s position, by
the function value7, by the function’s slope
and the number of used cycles. The class
Root is part of the package / namespace
RootFinder. The number of used cycles will
also be used to mark not fully iterated re-
sults.
The RootFinder creates for every found root
an instance of the Root class. This instances
will be stored into an array container class.
Listing 9.3: Implementation of a Root Class
1 using System;
2
3 using Logger; // is used because we want to log something
4
5 // the root -class should be embedded inside the rootfinder
6 namespace RootFind
7 {
8 class Root
9 {
10 public double dx; // root’s position
11 public double df; // function ’s value
12 public double dfs; // slope at the position
13 public int nCycles; // number of cycles , if < 0: no root found
14
15 // contstructor to initialize the root ~A nstance with all
16 // attibute values
17 public Root(double x, double f, double fs , int cycles)
18 {
19 dx = x;
20 df = f;
21 dfs = fs;
22 nCycles = cycles;
23 }
24 }
25 }
7If it would be an mathematical exact root, the function value has to be zero.
10.6.2015
Page 110 CAD in Civil Engineering / 2015
9.4.3 The RootFinder Class and Newton’s Algorithm
RootFinder
Root
– dh : double
– dEpsZ : double
– dEpsS : double
– nMaxIt : int
– dStep : double
– roots : ArrayList
+ RootFunc(double) : delegate double
– GetF(RootFunc, double): double
– GetFs(RootFunc, double): double
+ GetRoot(RootFunc, double) : Root
+ run(RootFunc, double, double, double) : int
+ AddRoot(Root, double, double) : int
+ PrintRoots() : int
+ GetRoots() : ArrayList
Figure 9.5: A RootFinder-Class
The RootFinder class contents a set of control
parameters.
• dh, controls the numerical calcula-
tion of the slope.
• dEpsZ, root precision, a break con-
dition.
• dEpsS, minimum slope value.
• nMaxIt, maximum number of itera-
tions, a break condition.
• dStep, control parameter to handle
a vanishing slope
The found Root instances are stored into an
ArrayList instance. The ArrayList lives in the
System.Collections namespace. So we have to
load it. An instance is inserted with the method
Add into the ArrayList.
9.4.4 Newton’s Algorithm to calculate a Root
Figure 9.6: Newton Algorithm
The following example shows, how to pass a function
as a functions parameter. Within the Newton’s al-
gorithm a root of an equation should be calculated.
So we have to specify the function of interest. The
function can be considered as an input parameter.
The function’s name is passed to the derivative cal-
culator and to the newton main routine.
So, if we want to calculate the roots of an equation
f (x ) = 0, we can apply the iteration scheme ??. The
derivative in the denominator is calculated numeri-
cally in equation 9.1. We see that in both equations
we need the values of the function f . This problem
can be solved by passing the function as a parameter.
The derivative - it’s called fs in the code - is calculated numerical as follows.
f ′(x ) =df
dx≈
(f (x +
h
2)− f (x − h
2)
)/h (9.1)
E. Baeck
9.4. ROOTFINDER APPLICATION Page 111
The slope triangle in figure 9.6 is given by the following equation.
f ′(xn) =f (xn)
xn − xn−1(9.2)
xn+1 = xn −f (xn)
f ′(xn)(9.3)
Equation 9.3 now can be used to iterate, i.e. with xn we get xn+1, with xn+1 we get xn+2 and
so on. So, if we have a well behaved function like in figure 9.6 the iteration will reach it’s goal.
Start
Load Input:
x0; itmax ; ε; ...
Initializing:
x = x0; it = 0;
Function Data:
F = f (X ); FS = f ′(X );
|F | < ε Root foundyes
|FS | < ε
no
Error 1yes
it > itmax
no
Error 2yes
x = x − FFS
it++;
no
Figure 9.7: Newton’s Flowchart
The method GetRoot implements Newton’s
algorithm to calculate a root of a one dimen-
sional implicit given equation. First we load
the input data, i.e. the starting value and
all needed precision parameters. After hav-
ing loaded the data we do an initialization
step.
Then we enter the iteration loop by calcu-
lating the function value and the slope of
function at this position.
The first break condition is the function’s
check. If the function value is less than the
given precision, we have found a solution and
we can stop the loop. The actual x -value
now is the result value. Here it’s called root
found.
If no result value is found, we have to calcu-
late the next x -value dividing by the func-
tion’s derivative. So we have to check the
derivative to. This is done in a second
break condition. If the absolute value of the
derivative f ′(x ) is less than a bound value,
we can not go on the by standard. So in this
case we break the loop setting an error flag.
Here it’s called Error 1.
The third break condition should avoid, that
the loop will never stop, because there is no
root like in the case of f (x ) = x 2 +1. So we introduce a loop counter and increment this counter
with every cycle. If now the maximum number of cycles is reached we break the loop setting an
error flag. Here it’s called Error 2.
If now no break condition will be executed, we have to prepare the values for the next cycle.
We increment the cycle counter and calculate the next x according to Newton’s formula.
Later we will see, that within our RootFinder a vanishing derivative in general not will be a
problem, because if we not are interested in a constant function a vanishing derivative is a local
problem. So if we change the starting value, the probability to get the x -value for a vanishing
10.6.2015
Page 112 CAD in Civil Engineering / 2015
slope will be very small.
9.4.5 Sorting an ArrayList Class
RootFinder
<<interface>>
AscendingRootComparer
+ int Compare(object, object ): int
Figure 9.8: An Interface to Compare
To get a sorted order of the found roots, we can use
the sort method of the ArrayList class. Like with C ’s
qsort function, we need to specify a method for com-
paring the stored items. This is done by the inter-
face class AscendingRootComparer. Like C ’s compare
function of the qsort the method Compare gets two
parameters. There value should be compared. If the
first is less than the second we return -1, if the first is
greater than the second we return +1, if both are equal
we return a zero. The instance of this interface class will be passed to the sort method of the
ArrayList instance to sort.
Listing 9.4: Implementation of a RootFinder Class
1 using System;
2 using System.Collections; // this is used for the ArrayList class
3
4 using MyTools; // to use all tool -objects
5
6 // introduce the namespace for the rootfinder
7 namespace RootFind
8 {
9 class RootFinder
10 {
11 // interface to our function
12 public delegate double RootFunc(double x);
13
14 // parameter for the newton sceem
15 double dh = 1.0e-5; // slope preccision
16 double dEpsZ = 1.0e-8; // root preccision
17 double dEpsS = 1.0e-5; // minimum slope value
18 int nMaxIt = 20; // max. number of iterations
19 double dStep = 0.1d; // step for vanishing slope
20
21 // parameters for the scanner
22 ArrayList roots; // the found Root instances
23 // will be collected inside ArrayList
24
25 // calculate the function value
26 private double getF(RootFunc f, double x)
27 {
28 return f(x);
29 }
30
31 // calculation of the slope
32 private double getFs(RootFunc f, double x)
33 {
34 double dSlope = (f(x+dh/2d) - f(x-dh/2d))/dh;
35 return dSlope;
E. Baeck
9.4. ROOTFINDER APPLICATION Page 113
36 }
37
38 // calculate the next root
39 public Root GetRoot(RootFunc f, double x0)
40 {
41 double dx = x0; // starting x
42 double dF; // function value
43 double dFs; // slope value of the function
44 int nCycles = 0; // number of cycles used
45
46 // print the table header bar
47 Log.AppendLog("--i -----------x --------f(x) -------fs(x)");
48
49 // infinit loop
50 while(true)
51 {
52
53 dF = getF(f,dx); // calculate the function value
54 dFs = getFs(f,dx); // calculate the slope at the actual
55 // position
56 // log the aktual values to check the iteration loop
57 // |index x f(x) fs(x)
58 Log.AppendLog(string.Format(
59 "{0,3} {1 ,12:0.000e+00} {2 ,12:0.000e+00} {3 ,12:0.000e+00}",
60 nCycles , dx , dF , dFs));
61
62 // checking the function value
63 if (Math.Abs(dF) < dEpsZ) break;
64
65 // checking the slope. if the slop is to bad
66 // we step a little aside and try it once more
67 if (Math.Abs(dFs) < dEpsS)
68 {
69 do
70 {
71 dx += dStep;
72 dF = getF(f,dx);
73 dFs = getFs(f,dx);
74 nCycles ++;
75 } while(Math.Abs(dFs) >= dEpsS && (nCycles <= nMaxIt ));
76 }
77
78 // checking the loop counter. If no convergence is obtained
79 // the number of cycles is given by its negative value
80 if (nCycles > nMaxIt) { nCycles *= -1; break; }
81
82 // calcalating the step dx-value
83 dx -= dF/dFs;
84 // and count the cycle
85 nCycles ++;
86 }
87
88 // preparing the return data
89 Root r = new Root(dx,dF,dFs ,nCycles );
90
91 // return the Root instance
10.6.2015
Page 114 CAD in Civil Engineering / 2015
92 return r;
93 }
94
95 // the main function of the finder to scan for the roots
96 // we pass the range values and the function to be analyzed
97 public int run(RootFunc f, double dxFrom , double dxTo , double dxStep)
98 {
99 int nRet = 0; // return value
100 double dx = dxFrom;
101
102 roots = new ArrayList (); // allocate a new List
103
104 // over all staring values , we scan the range using
105 // the data of the specified interval and it’s step size
106 while (dx <= dxTo)
107 {
108 // calaculating the next root
109 Root r = GetRoot(f,dx);
110
111 // and add the root into the list , skipping all allready existing
112 // roots with same values
113 AddRoot(r,dxFrom ,dxTo);
114
115 // next step and a new analyzis
116 dx += dxStep;
117 }
118
119 // sort the roots
120 roots.Sort(new AscendingRootComparer ());
121
122 // ... what we want to return has allready be fixed
123 return nRet;
124 }
125
126 // add a root instance , if not already available
127 // range: dxFrom ... dxTo
128 public int AddRoot(Root r, double dxFrom , double dxTo)
129 {
130 // valid root information: cycles > 0
131 if (r.nCycles < 0) return -1;
132
133 // root inside the range?
134 if (r.dx < dxFrom || r.dx > dxTo) return -2;
135
136 // check for existing roots
137 foreach(Root rt in roots)
138 {
139 if (Math.Abs(rt.dx -r.dx) < 1.0e-8) return -3;
140 }
141
142 // add the instance to the container
143 roots.Add(r);
144
145 return roots.Count;
146 }
147
E. Baeck
9.4. ROOTFINDER APPLICATION Page 115
148 // print the root data
149 public int PrintRoots ()
150 {
151 // header
152 Log.AppendLog(string.Format("\n Results: {0} roots found.",roots.Count ));
153
154 // print the table header bar
155 Log.AppendLog("NoI -----------x --------f(x) -------fs(x)");
156
157 // iterate the container
158 foreach(Root r in roots)
159 {
160 Log.AppendLog(string.Format(
161 "{0,3} {1 ,12:0.000e+00} {2 ,12:0.000e+00} {3 ,12:0.000e+00}",
162 r.nCycles , r.dx , r.df , r.dfs));
163 }
164
165 return roots.Count;
166 }
167
168 // getter for the roots -address
169 public ArrayList GetRoots ()
170 {
171 return roots;
172 }
173
174 } // end of the RootFinder class
175
176 // class to compare 2 root instances (like C’s qsort)
177 public class AscendingRootComparer:IComparer
178 {
179 public int Compare(object objA , object objB)
180 {
181 Root rA = (Root)objA;
182 Root rB = (Root)objB;
183
184 if (rA.dx < rB.dx) return -1;
185 if (rA.dx > rB.dx) return +1;
186
187 return 0;
188 }
189 }
190 } // end of namespace
10.6.2015
Page 116 CAD in Civil Engineering / 2015
9.4.6 Applying the RootFinder Class
RootFinderApp
+ funcDel(double) : delegate double
+ Main(string[]) : void
+ print(funcDel, double) : void
Figure 9.9: RootFinderApp
The application class RootFinderApp contents the static
Main method and some helper items. So we introduce a
intern helper class function which implements our testing
functions (here the sin and parabolic function).
To check the Newton module we introduce a delegate to
pass a function. The Newton is call with the GetRoot
method.
The roots will be scanned inside a given interval with the method run. We pass a function
to analyze using the delegate of the RootFinder class (line 48). Then the RootFinder instance
is created (line 51). In line 57 the run method is executed, we pass a function pointer (the
delegate), the starting and the end value of the interval and the scan step.
In line 60 the print method of the RootFinder is executed. After that an EXCEL-Sheet auto-
matically is filled with the roots data using the COM type library.
Listing 9.5: Implementation of a RootFinderApp Class
1 using System;
2
3 using Logger; // import to use the Log object
4 using RootFind; // import to use the RootFinder -Class
5
6 namespace RootScannerApp
7 {
8 class RootScannerApp
9 {
10
11 // use a "delegate" to pass a function as a parameter
12 // it’s a double function with one double argument
13 public delegate double funcDel(double y);
14
15 // class with some functions to analyze
16 class function
17 {
18 // parabolic
19 public static double parabolic(double x)
20 {
21 return Math.Pow(x,2) -1d;
22 }
23
24 // sin -function
25 public static double sin(double x)
26 {
27 return Math.Sin(x);
28 }
29 }
30
31 // smale delegate test function , which prints a function value
32 public static void print(funcDel f, double x)
33 {
34 System.Console.WriteLine("f({0}) = {1}",x,f(x));
E. Baeck
9.4. ROOTFINDER APPLICATION Page 117
35 }
36
37 // the one and only starter methode
38 static void Main(string [] args)
39 {
40 Log.Reset (); // delete the existing Log
41 Log.AppendLog("> program Main executing ....");
42
43 // this code is used to check the delegate
44 // funcDel fx = new funcDel(function.parabolic );
45 // print(fx , 2d);
46
47 // create a delegate
48 RootFinder.RootFunc fx = new RootFinder.RootFunc(function.sin);
49
50 // create a RootFinder -Instance to analyze a function
51 RootFinder rF = new RootFinder ();
52
53 // check the newton
54 // Root r = rF.GetRoot(fx ,100d);
55
56 // scan the range
57 rF.run(fx ,-10d,+10d,1d);
58
59 // print the found roots
60 rF.PrintRoots ();
61
62 // print to an xls file
63 XLSWriter xW = new XLSWriter ();
64 xW.Write(rF.GetRoots ());
65 }
66 }
67 }
10.6.2015
Page 118 CAD in Civil Engineering / 2015
9.4.7 The RootFinder’s XLSWriter Class
RootFinder
XLSWriter
– xlsfile : string
+ XLSWriter(string) : void
+ Write(ArrayList) : int
+ Update(ArrayList) : int
– releaseObject(object) : void
Figure 9.10: XLSWriter
If we want to use the EXCEL type library we have to
load the Excel namespace, which lives in the package
Microsoft.Office.Interop. In line 6 we introduce an
alias called Excel, to make it a little bit more readable.
The constructor (line 16) is working with an optional ar-
gument, the file name of the EXCEL file to write. The
method Directory.GetCurrentDirectory() in line 18
returns the current directory, which should be used for
the file’s position.
The method Write gets the ArrayList with the found roots
(line 25). First an old result file is deleted by the Delete
method of the File class (line 30). First of all we create some instance reference variables to get
a better handling, an EXCEL application reference (line 32), Workbook reference (Line 33) and
a Worksheet reference in line 34. To handle optional arguments in COM we need a reference to
an object which is called Missing.Value, this is created in line 35.
Starting from line 37 we create the XLS data in memory, so we start an EXCEL-instance by
creating it’s instance in line 37. The application contents a container which is called Workbooks
and holds all opened EXCEL files, i.e. all workbooks. So in the next line (line 38) we create a
new workbook by calling the Add method of Workbooks with an missing value. So our Workbooks
container contents only one item.
With the Workbooks method get_Item we get an instance pointer to a desired Worksheet in-
stance. We have created only one Worksheet therefore we use the index one, which is the first.8
To access the cells of a Worksheet we use it’s method Cells which gets the row and the column
index of the desired cell. The top left cell is addressed with row one and column 1. In our
example we write first the header line of a table into the row one (line 44-47). We can simply
assign the values to the Cell instance. A cast is not needed. On the other hand we can also
access the cells with the Worksheet ’s Range method, which expects a symbolic address like in
our case in line 50 "A1:D1", which should be used to underline the header line.
After the setting of header font and alignment - both items are attributes of the Cell class (line
54-59) - the roots data are printed into the table in line 61 to 70. We iterate the used container
with a foreach loop.
After this we save the Workbook (line 72) to the disc with Workbook ’s SaveAs method. Doing this
we have to careful with the applied EXCEL version. The number of arguments of the SaveAs
method in general can differ from version to version. If a parameter is not used - and here
nearly all parameter are not used - we have to pass the System.Reflection.Missing.Value
flag therefore this call looks a little bit confusing.
After having closed the Workbook with it’s method Close (line 76) we quit the EXCEL appli-
cation.
8Please note, that accessing COM containers we always start with one as the first index in contrast to C#’s
access starting from zero.
E. Baeck
9.4. ROOTFINDER APPLICATION Page 119
The next section (line 79-81) is an adaption of the garbage collector to COM instances. If we are
working with COM instances, we don’t know, when this instances will be freed by the garbage
collector, if we don’t use them any more. So if we want to free them a a given source position,
we have to use a special release method of the InteropServices. Because to do this we have
more than one statement, we introduce a special method called releaseObject (line 148). To
be sure, that we don’t crash the program, we pack the commands into a try parenthesis. First
we release the COM instance, than we set it to zero. After this we call explicitly the garbage
collector to do his job in line 163.
Listing 9.6: Implementation of a XLSWriter Class
1 using System;
2 using System.Collections; // this is used for the ArrayList class
3
4 using MyTools; // is used because we want to log something
5
6 using Excel = Microsoft.Office.Interop.Excel;
7 using System.IO;
8
9 // introduce the namespace for the rootfinder
10 namespace RootFind
11 {
12 class XLSWriter
13 {
14 private string xlsfile;
15
16 public XLSWriter(string file = "RootScanner.xls")
17 {
18 string cDir = Directory.GetCurrentDirectory ();
19 xlsfile = cDir + "\\" + file;
20 Log.AppendLog(string.Format("Starting XLS -export into {0}",xlsfile ));
21 }
22
23 // create a xls -file and
24 // write roots into xls file
25 public int Write(ArrayList roots)
26 {
27 try
28 {
29 // first delete the xlsfile
30 File.Delete(xlsfile );
31
32 Excel.Application xlApp;
33 Excel.Workbook xlWorkBook;
34 Excel.Worksheet xlWorkSheet;
35 object misValue = System.Reflection.Missing.Value;
36
37 xlApp = new Excel.Application ();
38 xlWorkBook = xlApp.Workbooks.Add(misValue );
39
40 // get the first sheet
41 xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item (1);
42
43 // add a headerline
44 xlWorkSheet.Cells[1, 1] = "x";
10.6.2015
Page 120 CAD in Civil Engineering / 2015
45 xlWorkSheet.Cells[1, 2] = "f(x)";
46 xlWorkSheet.Cells[1, 3] = "f ’(x)";
47 xlWorkSheet.Cells[1, 4] = "Cycles";
48
49 // and underline them
50 xlWorkSheet.Range["A1:D1"]. Borders.
51 get_Item(Excel.XlBordersIndex.xlEdgeBottom ). Weight
52 = Excel.XlBorderWeight.xlThin;
53
54 for (int i=1;i<=4;i++)
55 {
56 xlWorkSheet.Cells[1, i].Font.Bold = true;
57 xlWorkSheet.Cells[1, i]. HorizontalAlignment
58 = Excel.XlHAlign.xlHAlignCenter;
59 }
60
61 // print the root
62 int nRow = 2;
63 foreach (Root r in roots)
64 {
65 xlWorkSheet.Cells[nRow , 1] = r.dx;
66 xlWorkSheet.Cells[nRow , 2] = r.df;
67 xlWorkSheet.Cells[nRow , 3] = r.dfs;
68 xlWorkSheet.Cells[nRow , 4] = r.nCycles;
69 nRow ++;
70 }
71
72 xlWorkBook.SaveAs(xlsfile , Excel.XlFileFormat.xlWorkbookNormal ,
73 misValue , misValue , misValue , misValue ,
74 Excel.XlSaveAsAccessMode.xlExclusive ,
75 misValue , misValue , misValue , misValue , misValue );
76 xlWorkBook.Close(true , misValue , misValue );
77 xlApp.Quit ();
78
79 releaseObject(xlApp);
80 releaseObject(xlWorkBook );
81 releaseObject(xlWorkSheet );
82
83 Log.AppendLog(string.Format("XLS -File ’{0}’ export completed.",
84 xlsfile ));
85 }
86 catch (Exception ex)
87 {
88 Log.AppendLog(string.Format(
89 "*** Error to export file ’{0}’",xlsfile ));
90 Log.AppendLog(ex.ToString ());
91 }
92 return 0;
93 }
94
95 // open the xls -file and
96 // write roots into xls file
97 public int Update(ArrayList roots)
98 {
99 try
100 {
E. Baeck
9.4. ROOTFINDER APPLICATION Page 121
101 Excel.Application xlApp;
102 Excel.Workbook xlWorkBook;
103 Excel.Worksheet xlWorkSheet;
104 object misValue = System.Reflection.Missing.Value;
105
106 xlApp = new Excel.Application ();
107 xlWorkBook = xlApp.Workbooks.Open(xlsfile );
108
109 // get the first sheet
110 xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item (1);
111
112 // print the root
113 int nRow = 2;
114 foreach (Root r in roots)
115 {
116 xlWorkSheet.Cells[nRow , 1] = r.dx;
117 xlWorkSheet.Cells[nRow , 2] = r.df;
118 xlWorkSheet.Cells[nRow , 3] = r.dfs;
119 xlWorkSheet.Cells[nRow , 4] = r.nCycles;
120 nRow ++;
121 }
122
123 xlWorkSheet.Range["ROOTS"]. Value2
124 = string.Format("{0}",roots.Count);
125 xlWorkSheet.Range["ROOTS"].Cells [1 ,2]. Value2 = "bisserl daneben";
126
127 xlWorkBook.Save ();
128 xlWorkBook.Close(true , misValue , misValue );
129 xlApp.Quit ();
130
131 releaseObject(xlApp);
132 releaseObject(xlWorkBook );
133 releaseObject(xlWorkSheet );
134
135 Log.AppendLog(string.Format("XLS -File ’{0}’ export completed.",
136 xlsfile ));
137 }
138 catch (Exception ex)
139 {
140 Log.AppendLog(string.Format("*** Error to export file ’{0}’",
141 xlsfile ));
142 Log.AppendLog(ex.ToString ());
143 }
144 return 0;
145 }
146
147 // release explicitly a com object
148 private void releaseObject(object obj)
149 {
150 try
151 {
152 System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
153 obj = null;
154 }
155 catch (Exception ex)
156 {
10.6.2015
Page 122 CAD in Civil Engineering / 2015
157 obj = null;
158 Log.AppendLog(
159 "*** Error: Unable to release the Object " + ex.ToString ());
160 }
161 finally
162 {
163 GC.Collect ();
164 }
165 }
166 }
167 }
E. Baeck
10
AutoCAD Extensions written in C#
10.1 First Steps
Within the following chapter, we will discuss the usage of C# as a scripting language to extend
and automate AutoCAD drawings. Like in EXCEL too, C# is not an embedded scripting
language like VBA or AutoLisp. The disadvantages of VBA we already have discussed in
reference to EXCEL. The disadvantage of AutoDesk’s own language AutoLisp is, that we only
can use it within the AutoCAD application. If we want to link EXCEL and AutoCAD to
develop an automated processing chain, we better use a language, which is available in both
applications.
To use an extension written in a .Net language like C# we first should check, whether the SDK,
the software development kit called ObjectARX is already installed on our computer. If not,
we have to download the package from the AutoDesk site. To use the ObjectARX we should be
very careful with the package version. If the package version not absolutely fits to the version of
the installed AutoCAD CAD package, our developed extensions in general can not be loaded.
The ObjectARX package contents both interfaces to AutoCAD, the classical ARX interface
which supports classical C++ extensions and on the other hand the .Net interface, which sup-
ports the .Net languages. In our case we select the .Net interface, because like we have already
have discussed the .Net languages provides us an easy possibility to implement MS-Office com-
ponents.
The .Net interface is the most modern interface. This interface however comes with a tremendous
disadvantage for the development cycle. Every .Net extension once loaded into AutoCAD can
not be unloaded again. That means, if we have an error within our developed software, we have
to restart the AutoCAD environment with every new test. This also applies to every debugging
session.
The educational version of AutoCAD comes with the following splash window. So we can not
automate with an EXE module. A simple example is given in the next section.
123
Page 124 CAD in Civil Engineering / 2015
Figure 10.1: Splash of the Educational Version
10.2 A little Hello
We start with a new project within the Visual Studio. We again select the project type like in
figure 7.5. In this case we select the class library template (see figure 10.2, which will create a
DLL1 Module. We select the DLL template, because the AutoCAD Software should be master
and our module should only work like an extension, as a little plugin.
Figure 10.2: Start with a DLL-Project
The first step to get in contact with the AutoCAD objects is, to add a reference to the following
DLL modules.2 This we can do, if we start the command Project/Add Reference. This command
will start the dialog we see in figure 10.3. If the references are not loaded, we first have to browse
them with the Browse button. If they are loaded into the dialog, we have to check them and
close with ok.
1A DLL module in contrast to an EXE module is not a program, which can be started, it is a library which
will be linked to an EXE module at runtime dynamically. Therefore Dnymical Link Library.2Please note, that the dialog can change with a new version of Visual-Studio.
E. Baeck
10.2. A LITTLE HELLO Page 125
Figure 10.3: Add the References to the ObjectARX Libraries
The following DLLs we need working with AutoCAD 2013.
• AcMgd.DLL
Library of managed code for general classes.
• AcDbMgd.DLL
Library of managed code for database access classes.
• AcCoreMgd.dll
From AutoCAD version 2013 we have link to this library too. If not we will get open
references both to the DocumentManager class and to the CommandMethod attribute.
10.6.2015
Page 126 CAD in Civil Engineering / 2015
The following code shows the extension code which is implemented for the new command hi.
Because it’s not an EXE module, the static void Main is not used.
Listing 10.1: Implementation of a Hi Command in AutoCad ’s Command Set
1 using Autodesk.AutoCAD.DatabaseServices; // not used here
2 using Autodesk.AutoCAD.EditorInput; // command line access
3 using Autodesk.AutoCAD.Runtime; // used for CommandMethod
4 using Autodesk.AutoCAD.ApplicationServices; // used for application
5 using System; // .Net system
6
7 // everything lifes inside this name space
8 namespace AutoCAD_Hello_World
9 {
10 // implementation of a little hello in AutoCAD command line
11 public class Hello
12 {
13 // here we introduce the new AutoCAD command ’hi’
14 [CommandMethod("hi")]
15 public void HelloWorld ()
16 {
17 // get the document ’s reference
18 Document doc = Application.DocumentManager.MdiActiveDocument;
19 // ... and it’s editor
20 Editor ed = doc.Editor;
21
22 // ... and then we write our hello to the AutoCad World
23 ed.WriteMessage("Hello AutoCad World");
24 }
25 }
26 }
• In line 1 to 4 we see the link to the AutoCAD classes/libraries we want to use.
• In line 14 the method HelloWorld is decorated with an attribute3 called
1 [CommandMethod ("hi")]
which will install a new command in AutoCad, which can be called from the command
line window. The command hi will call the decorated method HelloWorld.
• In line 18 we get the pointer to the active document, which is provided by the
DocumentManager.
• In line 20 we get the pointer to the command line window, the so called editor.
• In line 23 we will do the rest, i.e. writing our Hello into the command line window.
3An attribute in C# is set into square brackets. The compiler copies this attribute into the DLL file, from
where AutoCAD can get it.
E. Baeck
10.2. A LITTLE HELLO Page 127
To run the new command within the AutoCad environment, we have to load the developed DLL
with the AutoCad command NETLOAD first (see figure 10.4).
Figure 10.4: Load the DLL with the NETLOAD Command
Figure 10.5 shows the HI command in the command line and the output of our DLL module.4
Figure 10.5: Applying the new HI command
4Please note too, that with a new AutoCAD version a new interface layout may come.
10.6.2015
Page 128 CAD in Civil Engineering / 2015
10.3 A little MText Hello
In section 10.2 we have discussed how to create a DLL-Module for an AutoCAD .Net extension.
The content of the module was very minimalistic, so we only want to say hello within the
command window. In this section we again want to say a hello but, in this case with a more
sophisticated approach. So we want to implement a code which will extend the drawing by a
MText object. That means we want to discuss the access to a documents database and the
possibility to extend this database.
To create the module we will do the same steps as in section 10.2. To load the module within
AutoCAD we also use the same commands. The only difference will the access to the database.
To get access to the documents database objects, we have to insert a using
Autodesk.AutoCAD.Geometry and a using Autodesk.AutoCAD.DatabaseServices. With this
two using statements we can create AutoCAD drawing items and we can insert these items into
the database.
Because debugging within this development is very ugly5, we also insert the using Logger code.
With this code we can use our already developed logging code.
At first we introduce a new method within our class Hello. With the attribute CommandMethode
we will implement a new AutoCAD command called hiAgain. The first command within our
new method will print a start up info into the log file. Then we implement the access to the
MdiActiveDocument, which is our drawing file and the access to the drawing file’s database.
Interacting with the documents database will work like a database access, will probably now
from working with SQL databases. We start a transaction from the database’s transaction
manager. If we put this into a using statement, at the end of the transaction automatically the
used resources are freed. So before we step into the next part, we write a little information into
the log file, that the creation of our MText drawing object will be performed. This will be done
with simple C# creation of a MText6 instance. If we have created an instance of MText, we
assign the following MText attributes.
• Contents, i.e. the text of MText.
• TextHeight, this is the height of the text, we want to draw.
• Location, this is the position of the MText object within our modelling space. The Location
will be specified by the AutoCAD point instance Point3d, which is specified by it’s three
coordinate values.
After this we want to insert our MText instance into the database. To avoid crashing, we put the
next steps into a try..catch..finally structure. So if we will have some problems accessing
the database, an exception will be thrown and we will jump into the catch block. If no problems
will occur, the catch block will not be executed. At the end in both cases the finally block
5It is very hard, to debug an extension module for AutoCAD, because .Net modules cannot be unloaded. That
means you have to restart AutoCAD, if you want to run a new debugging session. So if you write a logging file,
executing at least the debug version of your software, you can safe a lot of time, because you will see within the
log file, what’s going on inside your extension module.6You see that for every AutoCAD drawing object, we will have a respective class inside the AutoCAD type
library.
E. Baeck
10.3. A LITTLE MTEXT HELLO Page 129
will be executed. So inserting our instance into the database the following steps have to be
performed.
• Get access to the so called BlockTableRecord. The BlockTableRecord is a record
of the database, which should get the MText data. This record we get from the
TransactionManager. We use the actual record ID and open this record ForWrite, because
we want to write the data into the database.
• Having received, the BlockTabelRecord we append the MText data to the record. Now
the content of the record has changed.
• Then we add the instance with the TransactionManager’s method AddNewlyCreated-
DBObject. The first argument will be our MText’s reference, the second argument, will
tell the method if the instance should be added, in this case we set the value true or if the
the instance should be removed from the database.
• To write the chances physically into the database, we have to close the transaction with a
Commit command.
If something would go wrong, the catch block will be executed and this code will terminate the
transaction with an Abort command.
At the end we should not forget to free all created AutoCAD instances. This we should do
explicitly with a Dispose call. If we would not do this, the garbage controller will do this for us,
but we don’t now when. Therefore it’s better to do the clearing explicitly with an appropriate
Dispose call for every created instance.
Listing 10.2: Implementation of a MText-Hello in the AutoCad - Modelspace
1 using Autodesk.AutoCAD.EditorInput; // command line access
2 using Autodesk.AutoCAD.Runtime; // used for CommandMethod
3 using Autodesk.AutoCAD.ApplicationServices; // used for application
4
5 using Autodesk.AutoCAD.Geometry; // to use the geometry package
6 using Autodesk.AutoCAD.DatabaseServices; // to access the Database
7
8 using System; // .Net system
9 using Logger;
10
11 // everything lifes inside this name space
12 namespace SomeAcCommands
13 {
14 // implementation of a little hello in AutoCAD command line
15 public class Hello
16 {
17 // now we want to extend the document database by a new ACad object ,
18 // the MText object , which will write a new ’Hello ’ into the screen.
19 [CommandMethod("hiAgain")]
20 public void HelloMText ()
21 {
22 Log.AppendLog("> Starting ’hiAgain ’...");
23
24 // the document is taken
10.6.2015
Page 130 CAD in Civil Engineering / 2015
25 Document doc = Application.DocumentManager.MdiActiveDocument;
26 // get the database ’s reference
27 Database db = doc.Database;
28
29 // start the transaction
30 using(Transaction acTrans = db.TransactionManager.StartTransaction ())
31 {
32 Log.AppendLog("> Creating MText instance ...");
33
34 // that’s it we are intrested in: create new objects
35 MText acMText = new MText ();
36 acMText.Contents = "Hello Word from ’hiAgain ’!";
37 acMText.TextHeight = 5.0;
38
39 // the location is given by y an ACad point object
40 acMText.Location = new Point3d (10.0 ,20.0 ,0.0);
41
42 // we try to create the ACad object and transfer it into the
43 // database of the document.
44 try
45 {
46 Log.AppendLog(" Start transaction ...");
47
48 // get the actual record of the database
49 BlockTableRecord acBTR = (BlockTableRecord)acTrans.GetObject(
50 db.CurrentSpaceId ,OpenMode.ForWrite );
51
52 // then append the MText entitiy
53 acBTR.AppendEntity(acMText );
54 acTrans.AddNewlyCreatedDBObject(acMText ,true);
55 acTrans.Commit ();
56
57 Log.AppendLog(" Transaction commited.");
58 }
59
60 // if something is going wrong , abort the transaction
61 catch
62 {
63 acTrans.Abort ();
64 Log.AppendLog(" *** Error: Transaction aborted.");
65 }
66
67 // at the end delete the no more used instance of MText
68 finally
69 {
70 if (acMText != null) acMText.Dispose ();
71 }
72 Log.AppendLog(" Command ’hiAgain ’ completed.");
73 }
74 }
75
76 } // end of class
77 } // end of namespace
E. Baeck
10.3. A LITTLE MTEXT HELLO Page 131
What’s the essence of the discussed example?
• The example shows us, how to handle the access to a documents database, if we want to
insert automatically new drawing items into a drawing.
• The details of the interaction with a database are given, so that we can use this scheme
for new tasks.
• The example also shows, how to create the instances of AutoCAD drawing entities.
Figure 10.6 shows us the result within the AutoCAD GUI, if we run the new command hiAgain.
After executing this command, we should run the command zoom and specify the zoom by the
extends of the drawing, that is zoom/e.
Figure 10.6: Creating a MText drawing entity
10.6.2015
Page 132 CAD in Civil Engineering / 2015
10.4 Project Plate with Hole
Within this section we discuss the automated creation of an AutoCAD two drawings of a rect-
angular plate with a cylindric hole.
1. The first version of this drawing should be a drawing with three system views, a top view,
a front view and a side view. Every view should content dimensions showing the systems
geometric data.
With this implementation we discuss how to use AutoCAD’s basic 2d features, i.e creating
points and lines, using line colors and line types, as well as using some dimension objects.
2. The second version of the drawing should be a 3d drawing using a volume representation.
With the second drawing we discuss how to create a volume model starting from a simple
2d drawing. Further we will discuss how to use boolean operators to create more complex
volume systems starting from some simple
10.4.1 Project Parameters
Figure 10.7: Plate’s Parameters
The plate’s parameters should be read from an EXCEL
input data sheet. In the first data block we see the
length, the width and the thickness of the rectangular
plate. Further we have to set the diameter of the cylin-
drical hole, which should be in the center of the plate.
The second block of input data will specify the dimen-
sions in the case of the two dimensional drawing.
10.4.2 Helper Classes
10.4.2.1 The Logger Class
In section 9.4.1 we have seen, that it is good to have a logger class to check the things going on.
So we take over this class into our new project (see figure 9.3). The code is given there. The
only change is, that we put the Logger class into the AcTools namespace, to make it a little bit
more compact.
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 133
10.4.2.2 The AcLogger Class
AcTools
AcLogger
+ Print(string): void
Figure 10.8: AutoCAD Logger
Because it is sometimes important too, to get some informa-
tion inside the AutoCAD command window, we introduce a
second helper class, which prints the log into this window.
This class is called AcLogger and has only one static method,
which is called Print. The string we pass to this method is
printed in AutoCAD ’s command window.
Listing 10.3: Implementation of a AutoCAD - Command-Line-Logger
1 using Autodesk.AutoCAD.EditorInput; // command line access
2 using Autodesk.AutoCAD.ApplicationServices; // used for application
3
4 namespace AcTools
5 {
6 // command window logger for AutoCAD
7 public class AcLogger
8 {
9 // print into the command window
10 public static void print(string cMsg)
11 {
12 // the document is taken
13 Document doc = Application.DocumentManager.MdiActiveDocument;
14 // ... and it’s editor
15 Editor ed = doc.Editor;
16
17 // ... and then we write the message
18 ed.WriteMessage(cMsg);
19 }
20 }
21 }
You see, that our AcLogger simply is a version of the previous Hello World application. We call
the AutoCAD document instance and access it’s Editor item. Then we simply call the editors
WriteMessage method to print into the command line window.
10.4.2.3 The AcTrans Class
AcTools
AcTrans
+ Add(Entity): void
+ LoadLineType(string): void
Figure 10.9: The Transaction
The second thing we have seen in section 10.3 is, that it’s in-
credible complicated to add a simple object into an AutoCAD
drawing. We have to handle the take over with all this cryp-
tically data base commands, which are not really helpful for
clarity. So we will introduce a further helper class which is
called AcTrans and should do this ugly work for us.
10.6.2015
Page 134 CAD in Civil Engineering / 2015
Listing 10.4: Implementation of a AutoCAD - Transmitter Class
1 using Autodesk.AutoCAD.ApplicationServices; // used to get the Document
2 using Autodesk.AutoCAD.DatabaseServices; // used to get the Database
3
4 using System; // is used for garbage collector access
5
6 namespace AcTools // this is our namespace for helper classes
7 {
8 // a class to perform the transaction to the
9 // document database
10 class AcTrans
11 {
12 // add an arbitray AcEntity into the database
13 // (everything inherits the Entity)
14 public static void Add(Entity entity)
15 {
16 // reference the document
17 Document doc = Application.DocumentManager.MdiActiveDocument;
18
19 // ... and it’s database
20 Database db = doc.Database;
21
22 // perform a transaction to pass an autocad entity to the database
23 // after the closed bracket everything inside the brackets will
24 // be freed
25 using (Transaction acTrans
26 = db.TransactionManager.StartTransaction ())
27 {
28 // first we will try it
29 try
30 {
31
32 // get the actual record of the database
33 BlockTableRecord acBTR = (BlockTableRecord)acTrans
34 .GetObject(db.CurrentSpaceId , OpenMode.ForWrite );
35
36 // then append the entity to the record
37 acBTR.AppendEntity(entity );
38 // and add the created database object to the transaction
39 acTrans.AddNewlyCreatedDBObject(entity , true);
40 // with the Commit everything inside the transaction
41 // will be performed on the database file , so don’t forget
42 // to commit at the end!
43 acTrans.Commit ();
44
45 }
46
47 // if not possible , execute to following
48 catch
49 {
50 // if something goes wrong , we should roll back , what is
51 // already executed and abort the transaction
52 acTrans.Abort ();
53
54 // let us know , if something goes wrong
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 135
55 string msg = "*** Error: Tansaction aborted due to errors";
56 Log.AppendLog(msg);
57 AcLogger.print(msg + "\n");
58 }
59
60 // executed in every case: free all unused items
61 finally
62 {
63 GC.Collect ();
64 }
65 }
66 } // end of Add
67
68
69 // load a line type form the linetype library into the database
70 public static void LoadLineType(string sLineTypeName)
71 {
72 Log.AppendLog(string.Format(" load linetype ’{0}’",sLineTypeName ));
73
74 // reference the document
75 Document doc = Application.DocumentManager.MdiActiveDocument;
76
77 // ... and it’s database
78 Database db = doc.Database;
79
80 // perform a transaction to pass an autocad entity to the database
81 // after the closed bracket everything inside the brackets will
82 // be freed
83 using (Transaction acTrans = db.TransactionManager
84 .StartTransaction ())
85 {
86 // open line type table for read
87 LinetypeTable acLineTypeTbl;
88
89 // get the reference
90 acLineTypeTbl = acTrans.GetObject(db.LinetypeTableId ,
91 OpenMode.ForRead) as LinetypeTable;
92 // check if linetype is available
93 if (acLineTypeTbl.Has(sLineTypeName) == false)
94 {
95 // line type name / line type file
96 db.LoadLineTypeFile(sLineTypeName ,"acad.lin");
97 }
98
99 // save into database
100 acTrans.Commit ();
101 }
102 } // end of LoadLineType
103 }
104 }
The previous code shows with it’s method Add, how to insert a new entity into the AutoCAD
database by a transaction. On the other hand the code will show, how to get information from
the AutoCAD database. This is presented with the example to add a new line type.
10.6.2015
Page 136 CAD in Civil Engineering / 2015
The method Add
To add an created instance to the AutoCAD database, we first have to have access to the actual
document (line 17), which is called MdiActiveDocument. From this document we get the pointer
of the database (line 20). The data transfer now is put in-between a try...catch error handler
to avoid crashing. So we have to do the following steps.
1. Get a BlockTableRecord pointer.
This pointer we get from AutoCAD ’s Transactionmanger class. We start the transaction
with a StartTransaction call in line 25-26. With the Transaction instance acTrans
we now get the BlockTableRecord with the next free id and with the flag ForWrite.
Objects of the BlockTableRecord class are used as containers for entities within drawing
file databases.
2. Add the item
Every AutoCAD class of the package Autodesk.AutoCAD.DatabaseServices is derived from
the Entity class, so we can simple add an arbitrary AutoCAD entity to the received
BlockTableRecord by using it’s method AppendEntity. This is done in line 37. With
this method entities are added to the database and the block table record.
3. Add items to the transaction with AddNewlyCreatedDBObject.
The created object will be added to the transaction, if the flag is set to true. If we set
the flag to false the object is removed from whatever transaction it’s within. If a class is
not derived from Entitiy it’s objects can not be stored in the database.
4. Commit everything to the database.
This function commits the changes made in all the database objects opened during the
Transaction, and then closes them. To enhance the performance of database interaction,
it is recommended first to prepare a transaction, i.e. all the changes are done temporary
in memory, then with the closing commit step everything new is stored into the database
physically. This is done in line 43.7
7If the performance of this step would be forgotten, the changes are not saved to the document file.
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 137
10.4.3 Plate Class
PlateSpace
Plate
+ dL: double
+ dW: double
+ dt: double
+ dD: double
+ dScale: double
+ dLinespc: double
+ dViewspc: double
+ sXLS: string
+ color[4]: int
+ Plate(String): void
+ Load(): void
+ releaseObject(object): void
Figure 10.10: The Plate
The plate is described by the following parameters.
• dL, the plate’s length
• dW, the plate’s width
• dt, the plate’s thickness
• dD, the hole diameter in the plate’s center
• dScale, a scaling factor for the dimension’s label
• dLinespc, the distance of the dimension objects
• dViewspc, the distance of the views
• sXLS, the name of the EXCEL file to load
• color, some color index values to plot the entities
The plate’s parameters should be loaded from an EXCEL
file (see figure 10.7). This is done by the method Load.
Reading data form a COM instance, we have to release the
used COM instances manually. This is done by the method
releaseObject.
The class Plate will be used, implementing the drawing routine for our plate with the hole. It
is used as a parameter container.
Listing 10.5: Implementation of the Plate class
1 using System; // .Net library
2 using System.IO;
3 using Excel = Microsoft.Office.Interop.Excel; // to use EXCEL
4
5 using Logger; // for logging
6
7 namespace PlateSpace
8 {
9 class Plate
10 { // plate’s..
11 public double dL; // length
12 public double dW; // width
13 public double dt; // thickness
14 public double dD; // Diameter
15
16 public double dScale; // scaling factor for dimensions and texts
17 public double dLinespc; // line spacing for use creating dimensions
18 public double dViewspc; // distance between views
19
20 public string sXLS; // name of the xls -file
21
22 public int [] color = new int [4]; // color index values
10.6.2015
Page 138 CAD in Civil Engineering / 2015
23
24 // constructor (xls - filename)
25 public Plate(string sFile)
26 {
27 string sDir = Directory.GetCurrentDirectory ();
28 sXLS = sDir + "\\" + sFile;
29 Log.AppendLog(string.Format("> Inputfile ’{0}’",sXLS ));
30
31 dL = 0.0; // this we should do in C++
32
33 // specify the color index values
34 color [0] = 1; // outline
35 color [1] = 2; // hidden lines
36 color [2] = 3; // center lines
37 color [3] = 4; // dimension color
38 }
39
40 // load data from an excel -sheet
41 public void Load()
42 {
43 Log.AppendLog(string.Format(" Load data from ’{0}’...",sXLS ));
44
45 try
46 {
47 Excel.Application xlApp;
48 Excel.Workbook xlWorkbook;
49 Excel.Worksheet xlWorkSheet;
50
51 // start excel
52 xlApp = new Excel.Application ();
53 // open the xls -file
54 xlWorkbook = xlApp.Workbooks.Open(sXLS);
55 // select the sheet
56 xlWorkSheet = (Excel.Worksheet)xlWorkbook.Worksheets.get_Item (1);
57
58 // read the data form the excel sheet
59 dL = xlWorkSheet.Range["LENGTH"]. Value2;
60 dW = xlWorkSheet.Range["WIDTH"]. Value2;
61 dt = xlWorkSheet.Range["THICKNESS"]. Value2;
62 dD = xlWorkSheet.Range["DIAMETER"]. Value2;
63 dScale = xlWorkSheet.Range["SCALE"]. Value2;
64 dLinespc= xlWorkSheet.Range["Linespacing"]. Value2;
65 dViewspc= xlWorkSheet.Range["Viewspacing"]. Value2;
66
67 Log.AppendLog(" Plate data");
68 Log.AppendLog(string.Format(" Length .....: {0 ,10:0.00}",
69 dL));
70 Log.AppendLog(string.Format(" Width ......: {0 ,10:0.00}",
71 dW));
72 Log.AppendLog(string.Format(" Thickness ..: {0 ,10:0.00}",
73 dt));
74 Log.AppendLog(string.Format(" Diameter ...: {0 ,10:0.00}",
75 dD));
76 Log.AppendLog(string.Format(" Scaling ....: {0 ,10:0.00}",
77 dScale ));
78 Log.AppendLog(string.Format(" Linespacing: {0 ,10:0.00}",
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 139
79 dLinespc ));
80 Log.AppendLog(string.Format(" Viewspacing: {0 ,10:0.00}",
81 dViewspc ));
82
83 // close the file
84 xlWorkbook.Close ();
85
86 // quit the application
87 xlApp.Quit ();
88
89 // realse the com objects
90 releaseObject(xlApp);
91 releaseObject(xlWorkbook );
92 releaseObject(xlWorkSheet );
93 }
94
95 catch(Exception ex)
96 {
97 Log.AppendLog(string
98 .Format("xls -input ’{0}’ file can not be loaded.",sXLS ));
99 // print the error message
100 Log.AppendLog(ex.ToString ());
101 }
102 }
103
104 // release com objects
105 private void releaseObject(object obj)
106 {
107 try
108 {
109 System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
110 obj = null; // object address is invalid after release
111 }
112
113 // if we problems , then tell it
114 catch (Exception ex)
115 {
116 Log.AppendLog("Error: unable to release COM object");
117 obj = null;
118 }
119
120 // at the end free all unreferenced C# instances
121 finally
122 {
123 GC.Collect ();
124 }
125 }
126
127 } // end of class
128 } // end of namespace
10.6.2015
Page 140 CAD in Civil Engineering / 2015
10.4.4 OpenFileDialog
Sometimes it is necessary that user of our program has the possibility to browse the files system
for a special file. In such cases we should implement standard access tools like the OpenFileDialog
which is today implemented on all platforms in a similar kind. To call this dialog we have to
add the reference to System.Windows.Forms. After this we can add the corresponding using
into our class module as follows.
1 using System.Windows.Forms;
If we have added the using of the Windows Forms we can run the OpenFileDialog as shown in
listing 10.6.
Listing 10.6: Running an OpenFileDialog Instance
1 ...
2 OpenFileDialog ofDlg = new OpenFileDialog ();
3 ofDlg.Filter = "EXCEL 2007|*. xls|EXCEL 2010|*. xlsx|All Files |*.*";
4 ofDlg.InitialDirectory = Directory.GetCurrentDirectory ();
5
6 if (DialogResult.OK == ofDlg.ShowDialog ())
7 {
8 MessageBox.Show("You Selected " + ofDlg.FileName , "Good Choise!",
9 MessageBoxButtons.OK,MessageBoxIcon.Information );
10 }
11 else
12 {
13 MessageBox.Show("Go ahead , select a file!", "No Selection!",
14 MessageBoxButtons.OK, MessageBoxIcon.Stop);
15 }
16 ...
• In line 3 we see, how to assemble the file filtering. One filter is given by two strings. The
strings are separated by vertical lines. The first string will show the comment, the second
the wildcard filtering. In our figure 10.11 we have selected the first filter, which is the filter
for old xls files. Filters can be added using | separators.
• In line 4 the initial directory is set. In our case the current directory is set, i.e. the
directory of the loaded DLL-module.
• Line 6 shows how to handle the ok and cancel event of the dialog. We can get the infor-
mation from the returned function value. In our case we check against DialogResult.OK.
• Line 8 and 13 show how to run a standard Windows MessageBox. The first parameter is
the text to show, the second the caption followed by the dialog buttons and the message
icon.
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 141
Figure 10.11: Open File Dialog
The code in 10.6 can be used to
specify the input file to read the
plate values. This dialog should be
called, if the standard input file is
not found.
10.4.5 AutoCAD Object Types
If we want to store objects like lines, arcs or texts into the database of a document, i.e. to
put them into to drawing, we should know that there are two kinds of geometric objects in
AutoCAD.
10.4.5.1 Geometry - Objects
The objects from the package Autodesk.AutoCAD.Geometry can be used to create geometric
systems. This objects we can not insert into the database. In our example we use the class
Point3d to create the coordinates of our entities. Especially we use the point constructor which
is working with 3 double values.
10.4.5.2 DatabaseService - Objects
If we want to write geometric objects into the database of a drawing, i.e. inserting them into
the drawing, we have to use the objects of the package Autodesk.AutoCAD.DatabaseServices.
Only this objects, derived from the base class Entity we can put into the database of a drawing.
In our example we create instances of the class Line which is living in the DatabaseService
package.
10.6.2015
Page 142 CAD in Civil Engineering / 2015
10.4.6 Plate Commands
To create a drawing from our plate in 2 and 3 dimensions, we introduce the following two
AutoCAD commands.
• createPlate
This command will read the Plate data from the EXCEL file and will create a two dimen-
sional dimensioned drawing with three views.
• createSolidPlate
This command will read the Plate data from the EXCEL file and will create a three
dimensional drawing in one view.
Listing 10.7: Implementation of the new Plate Commands
1 using Autodesk.AutoCAD.EditorInput; // command line access
2 using Autodesk.AutoCAD.Runtime; // used for CommandMethod
3 using Autodesk.AutoCAD.ApplicationServices; // used for application
4
5 using Autodesk.AutoCAD.Geometry; // to use the geometry package
6 using Autodesk.AutoCAD.DatabaseServices; // to access the Database
7
8 using System; // .Net system
9 using MyTools; // to use the Log class
10 using AcTools; // to use our AC - tools
11 using PlateSpace; // to use the plate class
12
13 // everything lifes inside this name space
14 namespace SomeAcCommands
15 {
16 // implementation of a little hello in AutoCAD command line
17 public class NewCommands
18 {
19
20 // command to create a 2d dimensioned plate drawing
21 [CommandMethod("createPlate")]
22 public void CreatePlate ()
23 {
24 Log.AppendLog("> createPlate started ....");
25 AcLogger.print("createPlate started ...\n");
26
27 // Load linetypes
28 AcLogger.print("load line types ...\n");
29 //> AcTrans.LoadLineType (" DASHDOT ");
30 //> AcTrans.LoadLineType (" HIDDEN ");
31
32 // create the plate instance and specify the parameter file
33 // file should be in the bin/debug folder
34 AcLogger.print("load plate data ...\n");
35 Plate pl = new Plate("PlateData.xls");
36
37 // load data from xls file
38 pl.Load ();
39
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 143
40 // check the read values
41 pl.List ();
42
43 // drawing the rectangles
44 // - top view
45 AcLogger.print("draw top view ...\n");
46 Point3d pO = new Point3d(0, 0, 0);
47 PlateCommands.DrawRectangle(pl , pO , pl.dL , pl.dW);
48
49 // - side view
50 AcLogger.print("draw side view ...\n");
51 double dShift = pl.dViewspc * pl.dScale;
52 Point3d p1 = new Point3d(pl.dL +dShift , 0, 0);
53 PlateCommands.DrawRectangle(pl , p1 , pl.dt , pl.dW);
54
55 // - front view
56 AcLogger.print("draw front view ...\n");
57 Point3d p2 = new Point3d(0, -pl.dt - dShift , 0);
58 PlateCommands.DrawRectangle(pl , p2 , pl.dL , pl.dt);
59
60 // hole in top view
61 AcLogger.print("draw hole ...\n");
62 Point3d p3 = new Point3d(pO.X + pl.dL/2.0, pO.Y + pl.dW/2.0, 0.0);
63 PlateCommands.DrawHoleFromTop(pl ,p3 ,pl.dD);
64
65 AcLogger.print("createPlate closed .\n");
66 }
67
68 // create a solid plate with our plate data from excel
69 [CommandMethod("createSolidPlate")]
70 public void CreateSolidPlate ()
71 {
72 Region Reg1 = null;
73 DBObjectCollection Curves = null;
74 DBObjectCollection RegionP = null;
75 DBObjectCollection RegionH = null;
76
77 // reference the document
78 Document doc = Application.DocumentManager.MdiActiveDocument;
79
80 // ... and it’s database
81 Database db = doc.Database;
82
83 try
84 {
85 Curves = new DBObjectCollection ();
86 RegionP = new DBObjectCollection ();
87 RegionH = new DBObjectCollection ();
88
89 Solid3d PlateSolid = new Solid3d ();
90 Solid3d HoleSolid = new Solid3d ();
91
92 // create the plate instance and specify the parameter file
93 // file should be in the bin/debug folder
94 AcLogger.print("load plate data ...\n");
95 Plate pl = new Plate("PlateData.xls");
10.6.2015
Page 144 CAD in Civil Engineering / 2015
96
97 // load data from xls file
98 pl.Load ();
99
100 AcLogger.print("create rectangle ...");
101 // some variables
102 Point3d [] pt = new Point3d [4]; // we have 4 points
103 Line[] ln = new Line [4]; // and 4 lines
104
105 // create the points
106 pt[0] = new Point3d ();
107 pt[1] = new Point3d(pl.dL , 0.0 ,0.0);
108 pt[2] = new Point3d(pl.dL , pl.dW , 0.0);
109 pt[3] = new Point3d (0.0,pl.dW ,0.0);
110
111 // create all lines and specify the color index
112 // (old pen number)
113 for (int i = 0; i < 4; i++)
114 {
115 ln[i] = new Line(pt[i], pt[(i + 1) % 4]);
116 ln[i]. ColorIndex = pl.color [0];
117 Curves.Add(ln[i]);
118 }
119
120 // ceate the region
121 AcLogger.print("create plate region ...");
122 RegionP = Region.CreateFromCurves(Curves );
123
124 // create the plate volumn
125 AcLogger.print("create plate solid ...");
126 Reg1 = (Region)RegionP [0];
127 PlateSolid.Extrude(Reg1 ,pl.dt ,0.0);
128 PlateSolid.ColorIndex = 1;
129
130 // create hole volumn
131 // - clear the container
132 Curves.Clear ();
133
134 Circle acCirc = new Circle ();
135 acCirc.Center = new Point3d(pl.dL/2.0, pl.dW/2.0, 0.0);
136 acCirc.Radius = pl.dD/2.0;
137 Curves.Add(acCirc );
138
139 RegionH = Region.CreateFromCurves(Curves );
140
141 HoleSolid.Extrude (( Region)RegionH [0],pl.dt *2.0 ,0.0);
142 HoleSolid.ColorIndex = 2;
143
144 // move the cylinder down
145 Point3d pDisp = new Point3d (0.0,0.0,-pl.dt /2.0);
146 Matrix3d mat = new Matrix3d ();
147 mat = Matrix3d.Displacement(pDisp.GetAsVector ());
148
149 // execute the translation
150 HoleSolid.TransformBy(mat);
151
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 145
152 // cut the hole
153 PlateSolid.BooleanOperation(BooleanOperationType.BoolSubtract ,
154 HoleSolid );
155 // Add it to the Database
156 AcTrans.Add(PlateSolid );
157
158 } // end of try
159
160 catch(System.Exception ex)
161 {
162 AcLogger.print(ex.ToString ());
163 }
164 }
165 } // end of class
166 } // end of namespace
Within the command implementation (see listing 10.7) some additional helper functions are
used.
• DrawRectangle
This method will draw a rectangle, which has a vertical and a horizontal dimension. The
functions parameters are a reference to the Plate instance, the reference point (lower-left)
and as well the length and the height of the rectangle. All other parameters are read from
the Plate instance. Note, that we can not use the AutoCAD class Rectangle3d because
this class is not derived from the class Entity. It is only a geometric class.
• DrawHoleFromTop
This method will draw a circle in the middle of the plate. We pass the a reference to the
Plate instance, the center point of the circle and it’s diameter. The details like colors are
read from the Plate instance.
Listing 10.8: Implementation of the Plate Helper Methods
1 using Autodesk.AutoCAD.EditorInput; // command line access
2 using Autodesk.AutoCAD.Runtime; // used for CommandMethod
3 using Autodesk.AutoCAD.ApplicationServices; // used for application
4
5 using Autodesk.AutoCAD.Geometry; // to use the geometry package
6 using Autodesk.AutoCAD.DatabaseServices; // to access the Database
7
8 using System; // .Net system
9 using Logger; // to use the Log class
10 using PlateSpace; // to use the plate class
11
12 namespace SomeAcCommands
13 {
14 // implement the new methods to create a plate drawing
15 class PlateCommands
16 {
17
18 // draw a rectangle with it’s dimensions using plate data
19 public static void DrawRectangle(Plate pl , Point3d pO ,
20 double dL , double dW)
21 {
10.6.2015
Page 146 CAD in Civil Engineering / 2015
22 // reference the document
23 Document doc = Application.DocumentManager.MdiActiveDocument;
24
25 // ... and it’s database
26 Database acCurDB = doc.Database;
27
28 // some variables
29 Point3d [] pt = new Point3d [4]; // we have 4 points
30 Line[] ln = new Line [4]; // and 4 lines
31
32 // create the points
33 pt[0] = pO;
34 pt[1] = new Point3d(pO.X + dL , pO.Y + 0, pO.Z);
35 pt[2] = new Point3d(pO.X + dL , pO.Y + dW , pO.Z);
36 pt[3] = new Point3d(pO.X + 0, pO.Y + dW , pO.Z);
37
38 // create all lines and specify the color index (old pen number)
39 for (int i = 0; i < 4; i++)
40 {
41 ln[i] = new Line(pt[i], pt[(i + 1) % 4]);
42 ln[i]. ColorIndex = pl.color [0];
43 AcTrans.Add(ln[i]);
44 }
45
46 // create the dimension using the ’RotatedDimension ’
47 // linespacing * scaling
48 double dShift = pl.dLinespc * pl.dScale;
49
50 // horzontal dimension
51 RotatedDimension acRotDim = new RotatedDimension ();
52 acRotDim.XLine1Point = pt[0];
53 acRotDim.XLine2Point = pt[1];
54 acRotDim.DimLinePoint = new Point3d(pO.X, pO.Y - dShift , pO.Z);
55 acRotDim.ColorIndex = pl.color [3];
56
57 // set the dimension style to standard
58 acRotDim.DimensionStyle = acCurDB.Dimstyle;
59 acRotDim.Dimscale = pl.dScale;
60 AcTrans.Add(acRotDim );
61
62 // vertical dimension
63 acRotDim = new RotatedDimension ();
64 acRotDim.XLine1Point = pt[1];
65 acRotDim.XLine2Point = pt[2];
66 acRotDim.DimLinePoint = new Point3d(pO.X + dL + dShift , pO.Y, pO.Z);
67 acRotDim.ColorIndex = pl.color [3];
68 acRotDim.Rotation = Math.PI / 2.0;
69
70 // set the dimension style to standard
71 acRotDim.DimensionStyle = acCurDB.Dimstyle;
72 acRotDim.Dimscale = pl.dScale;
73 AcTrans.Add(acRotDim );
74
75 } // end of function
76
77
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 147
78 // draw a hole from the top
79 public static void DrawHoleFromTop(Plate pl, Point3d pO, double dD)
80 {
81 // reference the document
82 Document doc = Application.DocumentManager.MdiActiveDocument;
83
84 // ... and it’s database
85 Database acCurDB = doc.Database;
86
87 // draw a circle
88 Circle acCirc = new Circle ();
89 acCirc.Center = pO;
90 acCirc.Radius = dD/2.0;
91 acCirc.ColorIndex = pl.color [0];
92 AcTrans.Add(acCirc );
93
94 // insert the radial dimension for the circle
95 RadialDimension radDim = new RadialDimension ();
96 radDim.Center = acCirc.Center;
97 radDim.ChordPoint = new Point3d(acCirc.Center.X + pl.dD/2.0,
98 acCirc.Center.Y, 0.0);
99
100 radDim.LeaderLength = 10.0;
101 radDim.DimensionStyle = acCurDB.Dimstyle;
102 radDim.Dimscale = pl.dScale;
103 radDim.ColorIndex = pl.color [3];
104 AcTrans.Add(radDim );
105
106 // draw center lines
107 // - horizontal
108 Line cCenLin = new Line(
109 new Point3d(acCirc.Center.X -pl.dD/2.0*1.1 ,
110 acCirc.Center.Y, 0.0),
111 new Point3d(acCirc.Center.X +pl.dD/2.0*1.1 ,
112 acCirc.Center.Y, 0.0));
113 //> cCenLin.Linetype = "DASHDOT ";
114 //> cCenLin.LinetypeScale = 10.0;
115 cCenLin.ColorIndex = pl.color [2];
116 AcTrans.Add(cCenLin );
117
118 // - vertical
119 cCenLin = new Line(new Point3d(acCirc.Center.X,
120 acCirc.Center.Y - pl.dD / 2.0 * 1.1,
121 0.0),
122 new Point3d(acCirc.Center.X,
123 acCirc.Center.Y + pl.dD / 2.0 * 1.1,
124 0.0));
125 //> cCenLin.Linetype = "DASHDOT ";
126 //> cCenLin.LinetypeScale = 10.0;
127 cCenLin.ColorIndex = pl.color [2];
128 AcTrans.Add(cCenLin );
129 }
130 } // end of class
131 }
10.6.2015
Page 148 CAD in Civil Engineering / 2015
10.4.7 Results
Figure 10.12 shows one result created with the implemented command createPlate. To get a
better drawing in this case the color selection was fitted to a paper print.
Figure 10.12: Result of createPlate
Figure 10.13 shows a wire-frame plot of the result created with the implemented command
createSolidPlate.
Figure 10.13: Result of createSolidPlate
E. Baeck
10.4. PROJECT PLATE WITH HOLE Page 149
Figure 10.14 and 10.15 show a realistic view of the the result created with the implemented
command createSolidPlate using the 3dOrbit mode.
Figure 10.14: Result of createSolidPlate, solid view
Figure 10.15: Zooming the Plate’s Hole
10.6.2015
Part V
Solutions
150
11
C#-Applications
11.1 Precision-Finder
11.1.1 The Frame Application
PrecisionFinder
+ Main : void
Figure 11.1:
An Testing Class
The implementation of the PrecisionFinder App should be done in
terms of re-usability. That means, that we first will implement an
environment application like our Hello World, which only handles the
command line input an will call the desired methods of a class, which
itself should handle the calculation of the relative precision. Figure 11.1
shows a typical class for testing.
If no command line parameter is given, the App should give us a little help screen. If the
parameter float is given, the relative float precision should be printed. In the case of the
parameter double the relative double precision should be printed.
Listing 11.1: The Precision-Finder-Application
1 using System; // system features
2 using MyTools; // access to our Library which
3 // includes the Precision class
4
5 namespace MyPrecisionFinder
6 {
7 class PrecisionFinder
8 {
9 static void Main(string [] args)
10 {
11 Console.WriteLine(
12 "Precision -Finder Version 1.0\n... CM -CAD - SS13 ...\n");
13
14 // help screen
15 if (args.Length < 1)
16 {
17 Console.WriteLine("PrecisionFinder typ");
18 Console.WriteLine(" typ: [float/double ]\n");
19 Console.WriteLine("Example: PrecisionFinder double\n");
20 }
21
151
Page 152 CAD in Civil Engineering / 2015
22 else
23 {
24 if (args [0] == "float")
25 {
26 Console.WriteLine("float precsion: {0}\n",
27 Precision.Float ());
28 }
29
30 else if (args [0] == "double")
31 {
32 Console.WriteLine("double precsion: {0}\n",
33 Precision.Double ());
34 }
35 else
36 {
37 Console.WriteLine(
38 "*** Error: parameter ’{0}’ not supported\n", args [0]);
39 }
40 }
41 }
42 }
43 }
11.1.2 The Precision Class
MyTools
Precision
+ Float() : float
+ Double() : double
Figure 11.2:
Precision Class
The class Precision only has two static methods, one to calculate the
relative precision for the float data type and one to calculate the
relative precision for the double data type. We don’t have a constructor
or a destructor, because it does not make sense to create an instance
of this class. All methods are public, because we want to call them
from outside the class, i.e. form the PrecisionFinder Main method. For
further usage we put the class into our standard package MyTools, in
C# called namespace.
The Code of this class is given below.
Listing 11.2: The Precision Class
1 using System; // not used , if we don’t use
2 // system features
3 namespace MyTools // this is our library namespace
4 {
5 class Precision
6 {
7 // static method to caculate the relative
8 // precision for float data type
9 public static float Float ()
10 {
11 float x1 = 1.0f;
12 float x2 = 1.0f;
13 float d = 1.1f;
14 float s;
15
16 do
E. Baeck
11.1. PRECISION-FINDER Page 153
17 {
18 x2 = x2 / d;
19 s = x1 + x2;
20 }
21 while (s > x1);
22 return x2*d;
23 }
24
25 // static method to caculate the relative
26 // precision for double data type
27 public static double Double ()
28 {
29 double x1 = 1.0;
30 double x2 = 1.0;
31 double d = 2.0;
32 double s;
33
34 do
35 {
36 x2 = x2 / d;
37 s = x1 + x2;
38 }
39 while (s > x1);
40 return x2 * d;
41 }
42 }
43 }
11.1.3 Running the PrecisionFinder
If we start the created exe File of the PrecisionFinder without any argument, we will see the
following console output.
1 c:\cm-cad -SS13 >PrecisionFinder
2 Precision -Finder Version 1.0
3 ... CM -CAD - SS13 ...
4
5 PrecisionFinder typ
6
7 typ: [float/double]
8
9
10 Example: PrecisionFinder double
If we use the command line parameter float, we will get the relative precision for the float
data type, which shows nearly 7 digits.
1 c:\cm-cad -SS13 >PrecisionFinder float
2 Precision -Finder Version 1.0
3 ... CM -CAD - SS13 ...
4
5 float precsion: 6 ,275832E-08
10.6.2015
Page 154 CAD in Civil Engineering / 2015
If we use the command line parameter double, we will get the relative precision for the double
data type, which shows nearly 16 digits.
1 c:\cm-cad -SS13 >PrecisionFinder double
2 Precision -Finder Version 1.0
3 ... CM -CAD - SS13 ...
4
5 double precsion: 2 ,22044604925031E-16
If a not supported parameter is given, an error message is printed.
1 c:\cm-cad -SS13 >PrecisionFinder wrong
2 Precision -Finder Version 1.0
3 ... CM -CAD - SS13 ...
4
5 *** Error: parameter ’wrong ’ not supported
Remark:
The quality of the calculation will be influenced by the step-width, which in our case is 2. A
better value we get if we use a d value much more closer to 1.
E. Baeck
Appendix A
Used Software
The software which is used in this lecture is available for free.
A.1 The Visual-Studio IDE
The Visual-Studio IDE of Microsoft is available in an Express version for free. The pro-
gram can be installed with an installer, which is downloading and installing the software.
For the lecture one ISO-image file of the application is also available from the Info.Server,
http:\\info.baustatik.uni-due.de.
On one hand we can copy the ISO-image with a DVD writer to a DVD. Then we can after this
install the software from the CD. With additional utilities like the DAMON Tools Lite, which
is also available for free, we can install the application without any DVD copy directly from the
image.
Figure A.1: DAEMON-Interface
If the DAEMON Tools Lite is installed,
you’ll see the interface shown in figure
A.1. To run the setup we first add an
ISO image with the most left button on
the toolbar. Then we will see the image
in the upper window. Then we add a
virtual drive with the DT+ button. To
run the setup we have to open the vir-
tual drive with the green triangle run
button after having selected the desired
image.
155
Page 156 CAD in Civil Engineering / 2015
Figure A.2: DAEMON-Drive
If the explorer has opened the directory
of the virtual drive, we can look inside
the ISO image. Here we see one file
and one directory. If we click the file
wdexpress full we start the Visual-
Studio-Installer of the desired express
package. Now we can follow the next
given installation steps.
E. Baeck
Bibliography
[1] Wikipedia, The Free Encyclopedia
[2] D. Marshall
Programming, Microsoft Visual C# 2005, The Language
Microsoft Press, 2006
[3] ISO/IEC 19501:2005
Information technology - Open Distributed Processing - Unified Modeling Language
(UML) Version 1.4.2
[4] E. Baeck
Computer Languages for Engineers, Book of Examples
pdf-Script, 2011
157
Index
.NET, 63, 100, 105
line, 42
sphere, 44
3dOrbit, 149
Acad3DSolid, 44, 49
AcadAcCmColor, 44, 49
SetRGB, 45, 51
AcadLine, 42
color, 42
TrueColor, 45
Update, 42
AcadSphere, 44
AcCoreMgd.dll, 125
AcDbMgd.DLL, 125
AcMgd.DLL, 125
Activate, 103
AddLine, 42
AddNewlyCreatedDBObject, 136
AddSphere, 44
alias, 103
alignment, 118
and, 9
AppendEntity, 136
Application, 103
ARX, 63
Assigning, 10
AutoCAD 2013, 125
AutoCAD Database, 133
AutoLISP, 63
AutoLisp, 123
bit, 81
BlockTableRecord, 136
C, 81
catch, 98
Cells, 104, 118
Chart, 104
class, 92
Class Module, 27
Class Initialize, 28
Close, 103
Collection, 29, 32, 38, 49
Add, 29, 53
Remove, 38
COM, 63, 103, 105, 116, 119
Command Button, 18
command window, 133
commit, 136
Common Intermediate Language, 75
Const, 39
constant, 39
Constructor, 50
Database, 136
Debug object, 10
declaration
option explicit, 7
declarations
explicit, 7
implicit, 7
delegate, 66, 110, 116
Delete, 43, 118
derivative, 110
Destructor, 50
dispose, 70
DLL, 124
Do...Loop, 13, 15
Double, 8 Byte float, 14
else, 65
End Function, 15
Error handler, 35–37
EXCEL, 31, 100, 132
Application, 32, 56
Cells, 32
GetOpenFileName, 32, 56
Quit, 32
Range, 32, 56
158
INDEX Page 159
Worksheets, 32, 56
EXCEL-Sheet, 18
exception, 35–37, 98
Faculty and Overflow, 12
False, 9, 51
File, 26, 118
Close, 26, 39
Line Input, 26
Open, 26
Append, 26, 39
Input, 26
Output, 26, 39
Print, 26
finally, 98, 105
font, 118
for, 65
For Each ... next, 43
For...Next, 11
foreach, 118
Function, 15
garbage collector, 29, 70, 104, 119
GC.Collect, 105
Get Functions, 38
GetCurrentDirectory, 118
GetInteger, 35, 38
GetPoint, 37, 38
GetReal, 36, 38
global variable, 39
IACadLine, 43
if, 65
Info.Server, 155
InputBox function, 13
interface, 112
InteropServices, 119
ISO-Image, 155
LBound, 28
line dialog, 38
MdiActiveDocument, 136
memory leaks, 29
MessageBox, 140
module, 39
MsgBox function, 13
MSIL, 75
namespace, 70, 92, 107, 152
NETLOAD, 127
New Operator, 27, 29
Newton Algorithm, 15, 18
not, 9
Nothing, 27
object, 69, 105
ObjectARX, 123
OOP, 69, 92, 93
Open, 103
OpenFileDialog, 140
or, 9
Point3d, 141
polar coordinates, 45
Private, 27
Prompt, 35
Public, 27, 28
Python, 69, 78
Randomize, 53
Range, 104, 118
relative indexing, 104
Relative Precision, 13
RGB, 45
Rnd, 53
Save, 103
SaveCopyAs, 103
Set Operator, 27, 29
Sheet, 118
Single, 4 Byte Float, 14
static, 64
step, 11
system, 92
Taskmanager, 32
ThisDrawing, 35, 42
ThisDrawing.ModelSpace, 42–44
timestamp, 39
now, 39
transaction, 133
True, 9, 51
try, 98, 105, 119
Type.Missing, 103
10.6.2015
Page 160 CAD in Civil Engineering / 2015
TypeName, 43
UBound, 28
UML, 92
aggregation, 97
class diagram, 64, 95
composition, 97
inheritance diagram, 96
note diagram, 96
note diagram assignment, 96
package diagram, 107, 152
using, 70, 92, 103
Utility object, 35
var, 78
VBA, 78, 123
Windows.Forms, 140
Workbook, 103, 104, 118
Workbooks, 103, 118
Worksheet, 104
xor, 9
E. Baeck