Geosoft GX Developer 8.5
Working with GX Developer
Object-Oriented Programming
The OASIS data processing system consists of a graphical user interface, a database system for very large data sets, an integrated mapping and visualization system, and a processing systems that processes data and creates maps. There are also many layers of functionality that enable you to interact with the databases, maps, the processing engine and the outside world. In order to simplify this world, Oasis montaj was designed and written using object-oriented programming techniques.
The object structure of the system is also apparent to the GX Developer . For application developers experiencing object-oriented programming for the first time this can be confusing since there are significant differences from purely procedure-based programming. This section is intended to acquaint you with the object-oriented structure of the OASIS database environment and introduce you to some of the key concepts that will influence your GX programming.
A fundamental component of an object-oriented system is a Class. A Class encapsulates the information, features and functions (also called methods) that are used to manipulate the contents of the Class. A good analogy to a Class is a House. When you think of a House, you think of a building that houses a single family, contains a kitchen, bedrooms, family members, front door, etc., and when you knock on the door (execute a method), someone answers. This is a Class called House. Note that a Class does not exist; it is just the set of characteristics that make up what you think of as a House and the methods that you can use to interact with a House.
A class instance does exist – it is a specific house, say 2128 Langtry Drive in Oakville, Ontario, Canada. There can be many instances of the class House, each with its own unique contents and characteristics. According to our definition, all instances of a House will have a front door, and when you knock on it someone will answer. For a class instance to exist, it must be created, at which time any resources required to create the class are consumed (bricks, wood, etc for a House; memory, disk space, etc for a GX class).
In GX Developer, a variable must be declared to hold an instance of a class. The variable type will be the class name, and the variable name will be used to reference that instance of the class. The variable is often called a class handle. Note that declaring a class variable does not create the class – it just creates a name that can be used for an instance of that class. All classes will have a “Create_ “ method to create an instance of a class, and a “Destroy_” method to destroy an instance of a class and return its resources to the system. Other class methods will only work on classes that have been created and not yet destroyed.
A GX programming example is a Class named VV. This class is used to hold a single array of any type of data. One of its key characteristics is that it can hold and efficiently manipulate extremely large data arrays of data. It also comes with a rich set of methods that can be used to manipulate the data in the array (such as filter it, enlarge it, get and set values in it, etc). The VV class and the methods that manipulate the class are described in the prototype file vv.gxh in the Gx/gxh directory. There are also many other classes that can accept a VV instance as an argument to one of their class methods. For example, the DB class (the database class) has a method (PutChanVV_DB) that stores a VV instance in a channel of a database.
In summary, a Class has a name and describes a set of information (data) and what you can do with it. A Class instance is a specific unique instance of a class, and methods are the things you can do to manipulate an instance of a class.
Differences between Procedural and Object-Oriented Programming
In an object-oriented world, you will notice many differences between procedural languages, such as FORTRAN, and object-oriented languages, such as the GX Programming Language. While a full discussion of these differences is beyond the scope of this manual, there are a few basic concepts that you should remember:
· Data hiding
· Instantiation
· Objects versus OASIS symbols
Data hiding is a fundamental characteristic of objects. This means that you cannot directly access or view the data within an object except through the methods (functions) of the class object. For example, the VV class deals with 1-dimensional data arrays, and it can efficiently store and manipulate very large array data sets. The VV class hides how it does this from you, and it hides how it stores the data in the computer memory because this is really of no concern to you. To access data in a VV array, you will use VV methods such as iLength_VV, which tells you the length of the VV, and rGetReal_VV or SetReal_VV to get and set a real value in a VV array efficiently. Such as with virtual vectors (which replace arrays in the GX environment). To see all of the data in the vector, you require two methods — one for determining the length of the vector (iLength_VV) and one for extracting the data (rGetReal_VV). You also require a loop to extract each data point until the end of the vector (i.e. length) is reached.
Instantiation is the process of creating instances and returning handles to objects. To understand this concept, consider the dialog box – an interface component that lets you accept or display information to users. In GX programming, we provide a method for creating a dialog box (Create_DGW). When you use this method, the system assigns memory to a database object (i.e. creates an instance of the object) and returns a handle to the dialog box.
You can continue creating instances of other dialog boxes until you run out of memory. The key point to remember is that each instance has its own handle — the connection that enables you to access the dialog box and perform various actions with it. Handles are discussed in the next section.
Another key element of the object-oriented programming component in the OASIS environment is the treatment of objects and symbols. As we learned above, objects are unique components of the OASIS system and interface that we can manipulate. Symbols, on the other hand, are the named parts of the database consisting of lines and channels. Each line and channel has its own identifier.
When working with symbols, keep in mind that they are defined in the database. When you use a symbol (line, channel), the system returns a keyword (e.g. a line or channel id). You don't work with the symbol directly. Symbols are permanent
In contrast, objects can be any part of database or system (database itself or a part of the Graphical User Interface). When you use an object you must associate a handle with it. When you destroy an object, the instance disappears. In other words, objects are not permanent – they are tools that exist only as long as you require them.
Working with Class Libraries
When you are starting to program GXs, one key point our application developers stress is to know the libraries (classes) and functions (methods) in each library. These provide you with
all of the functionality you require to use the OASIS interface, get data and perform actions (i.e. processing) on data.
Although it is a good idea to be familiar with all libraries, there are certain ones you will use more than the others. These are shown in the following table:
Tasks | GXH Library |
---|---|
Database (lines, channels and database) | DB, DU |
File handling | RA, WA, BF |
Strings | STR |
System | SYS |
Maps, Views | MAP, MVIEW |
Vectors (arrays) | VV |
GX Program Structure
It is rare that a new GX is created completely from scratch. Instead, a new GX is created by modifying an existing GX, even if only for the general outline. All Geosoft GXs are provided as source code that can be used as the basis for a new GX. By copying and using an existing GX, you will adopt a the basic structure for a fully functioning GX. You will find all Geosoft GX source code in folder .../gx/src
.
We will use the COPY GX (.../gx/src/copy/) to walk through a basic functioning GX tool. The COPY GX copies one database channel to a new channel - if the new channel does not exist, it will be created, and the channel data can be decimated during the copy.
The walk-through is intended to show the general outline of a GX, and establish some general principals for writing a GX; a fuller description of individual processes found within the GX may be found later in this section.
Step 1: Set the header information: NAME, VERSION and DESCRIPTION.
- In addition to being useful for source control, these parameters are recognized by the VIEWGX program.
- Note that multi-line text is allowed (see the DESCRIPTION statement.)
- Parameters residing in the system parameter block, used and/or modified by this GX, are explained.
- As in normal C, “//” indicates the start of a comment, which is ignored during compilation.
//==================================================================== NAME = "Copy one channel to another" VERSION = "v1.01.00 Copyright Geosoft Inc. 1999" DESCRIPTION = " Copies one channel to another. If the new channel does not exist, it will be created with the same definition as the original channel. The channel data can be decimated during the copy. Parameters: COPY.FROM - Original channel .TO - Destination channel .DECIMATE - Decimation factor, default 1 .FIDSTART - New fiducial start, default is current start. .FIDINCR - New fiducial increment, default is current increment. "
Step 2: Include the GX resources
- The compiled resource is contained in a Geosoft Resource “GR” file, while resource identifiers are contained in the Geosoft Resource Header “GRH” file. These files are created from the resource source file (GRC file) by compiling the resource file using the gxc.exe compiler.
//==================================================================== // RESOURCES //==================================================================== RESOURCE = "copy.gr" #include "copy.grh"
Step 3: Included GX Function Header files. These contain the necessary library function prototypes.
- GX library functions may not be used unless their prototypes are included.
- The “catch-all” header
all.gxh
includes all the regular, non-mapping Geosoft function prototypes. - Constants defined by the #define pragma may also be located here.
//==================================================================== // INCLUDE //==================================================================== #include <all.gxh> // system
Step 4: Declare variables.
- These include all object handles, as well as the int, real and string types.
- Though not required, it is common practice to declare variables in the following order: handles, integers, reals, strings.
//==================================================================== // VARIABLES //==================================================================== EDB EData; // Database handle DB Data; // Database handle DB_SYMB InCh; // Channel Handle DB_SYMB OutCh; // Channel Handle DB_SYMB Line; // Line Handle DGW Diag; // Dialogue handle LST List; // List handle int i; // Utility int iN; // Decimation factor int iLines; // Number of Lines Processed int iTotLines; // Total Number of Lines to Process real rFidStart; // Fid start real rFidIncr; // Fid increment real rNewStart; // New fid start real rNewIncr; // New fid increment string(50) sInCh; // Channel Names string(50) sOutCh; // Channel Names string(32) sTemp; // Temp string string(60) sLabel; // Label for progress bar
Step 5: Enclose the main code block.
- This includes the remainder of the source file.
- The code is enclosed in a pair of curly brackets.
//==================================================================== // CODE //==================================================================== {
Step 6: Do the initial setup.
- This usually involves getting the current database or map, and setting up information required later for user dialogs.
- Some GXs may also recover parameters from a control or initialization file here, and set various default values.
// --- Get database --- EData = Current_EDB(); Data = Lock_EDB(EData);
Step 7: Perform interactive processes.
- Interactive processes should be enclosed by the if(iInteractive_SYS()){} control block.
- These processes generally involve creating, loading, displaying, then interrogating a dialog object for information modifiable by a user.
- Variables are usually obtained from, and loaded back into, the workspace parameter block, using the SetInfoSYS_DGW and GetInfoSYS_DGW functions.
// --- Are we running interactively ? --- if (iInteractive_SYS()) { // --- Create the Dialogue --- Diag = Create_DGW("COPYForm"); // --- Set up lists --- List = GetList_DGW(Diag,_COPYFORM_0); SymbLST_DB(Data,List,DB_SYMB_CHAN); Sort_LST(List,0,0); List = GetList_DGW(Diag,_COPYFORM_1); SymbLST_DB(Data,List,DB_SYMB_CHAN); Sort_LST(List,0,0); // --- Set any Defaults --- SetInfoSYS_DGW(Diag,_COPYFORM_0,DGW_TEXT,"COPY","FROM"); SetInfoSYS_DGW(Diag,_COPYFORM_1,DGW_TEXT,"COPY","TO"); SetInfoSYS_DGW(Diag,_COPYFORM_2,DGW_TEXT,"COPY","DECIMATE"); SetInfoSYS_DGW(Diag,_COPYFORM_3,DGW_TEXT,"COPY","FIDSTART"); SetInfoSYS_DGW(Diag,_COPYFORM_4,DGW_TEXT,"COPY","FIDINCR"); // --- Run the Dialogue --- ÃÂ i = iRunDialogue_DGW(Diag); if (i != 0) Cancel_SYS(); // The user hit cancel // --- Get the Strings --- GetInfoSYS_DGW(Diag,_COPYFORM_0,DGW_TEXT,"COPY","FROM"); GetInfoSYS_DGW(Diag,_COPYFORM_1,DGW_TEXT,"COPY","TO"); GetInfoSYS_DGW(Diag,_COPYFORM_2,DGW_TEXT,"COPY","DECIMATE"); GetInfoSYS_DGW(Diag,_COPYFORM_3,DGW_TEXT,"COPY","FIDSTART"); GetInfoSYS_DGW(Diag,_COPYFORM_4,DGW_TEXT,"COPY","FIDINCR"); // --- Destroy the Dialogue --- Destroy_DGW(Diag); }
Step 8: Retrieve information from the workspace parameter block and verify it.
- Verification means ensuring that the data exists, and that it falls within acceptable limits for the process that must be performed.
// --- Get Parameters --- GetString_SYS("COPY","FROM",sInCh); GetString_SYS("COPY","TO",sOutCh); iN = GetInt_SYS("COPY","DECIMATE"); rNewStart = GetReal_SYS("COPY","FIDSTART"); rNewIncr = GetReal_SYS("COPY","FIDINCR"); // --- Verify parameters --- if (iN==iDUMMY) iN = 1; if (iN<= 0) Abort_SYS("Decimation factor must be > 0."); if ((rNewIncr!=rDUMMY)&&(rNewIncr<=0.0)) Abort_SYS("Fid increment must be > 0.");
Step 9: Do setup for processing.
- Create handles, retrieve and verify symbols needed for processing.
- Initialize the progress indicator, as well as variables necessary to track progress.
// --- Does the Input Channel Exist ? --- if (!iExistChan_DB(Data,sInCh)) Abort_SYS(_("channel does not exist.")); InCh = FindChan_DB(Data,sInCh); // --- Does the Output Channel Exist ? --- if (!iExistChan_DB(Data,sOutCh)) { OutCh = DupSymb_DB(Data,InCh,sOutCh); // Create it UnLockSymb_DB(Data,OutCh); } else OutCh = FindChan_DB(Data,sOutCh); // --- Lock the channel symbols --- if (InCh != OutCh) LockSymb_DB(Data,InCh,DB_LOCK_READONLY,DB_WAIT_INFINITY); LockSymb_DB(Data,OutCh,DB_LOCK_READWRITE,DB_WAIT_INFINITY); // --- Prepare to do the work --- iLines = 0; iTotLines = iCountSelLines_DB(Data); Progress_SYS(1);
Step 10: Process the data or map.
- Processes often loop through selected database lines, or call functions which do so.
// --- Go through all selected Lines --- ProgName_SYS("",1); Line = FirstSelLine_DB(Data); while (iIsLineValid_DB(Data,Line)) { // --- Update the Progress Bar --- LockSymb_DB(Data,Line,DB_LOCK_READONLY,DB_WAIT_INFINITY); GetSymbName_DB(Data,Line,sLine); UnLockSymb_DB(Data,Line); Printf_STR(sProg1, sizeof(sProg1), _("Copying %s to %s: Line %s"), sInCh, sOutCh, sLine); ProgName_SYS(sProg1,0); ProgUpdateL_SYS(iLines,iTotLines); // --- Copy/Decimate --- Decimate_DU(Data,Line,InCh,OutCh,iN); // --- Correct the Fiducial Start --- if ((rNewIncr!=rDUMMY)||(rNewStart!=rDUMMY)) { if (rNewStart==rDUMMY) rFidStart = rGetFidStart_DB(Data,Line,InCh); else rFidStart = rNewStart; if (rNewIncr==rDUMMY) rFidIncr = rGetFidIncr_DB(Data,Line,InCh); else rFidIncr = rNewIncr; SetFid_DB(Data,Line,OutCh,rFidStart,rFidIncr); } // --- Advance to Next Line --- Line = NextSelLine_DB(Data, Line ); iLines++; } // --- Add maker --- EasyMakerSymb_DB(Data,OutCh, _("Copy channel"),"COPY;"); // --- Unlock the Channel Symbol --- if (InCh != OutCh) UnLockSymb_DB(Data,InCh); UnLockSymb_DB(Data,OutCh);
Step 11: Clean up.
- Destroy any created objects which should not exist once the GX terminates.
- Unlock databases and maps.
- Turn off the progress indicator.
// --- done --- Progress_SYS(0); UnLock_EDB(EData); // --- Release the database --- // --- display the new channel --- LoadChan_EDB( EData, sOutCh ); }
Geosoft GX Developer 8.5