Rescue C++ Class Library

This documentation is maintained by Rod Hanks, rhanks@benchbuilt.com. Comments and corrections are appreciated.

Table of contents

Changes in June 1998

Changes in April 1998

Changes in November 1997

Changes in October 1997

Changes in June 1997

Class naming conventions

Reading the header files

Programmer notes

Error Handling

Archiving to Oracle

Binary Formats

Interconnectedness

The wireframe model

Sample programs

cSet classes

cBag classes

RCH2DArray

RCH3DArray

RCHString

RescueArray

RescueArrayByte

RescueArrayDouble

RescueArrayFloat

RescueArrayShort

RescueBlock

RescueBlockUnit

RescueBlockUnitHorizonSurface

RescueBlockUnitPropertyGroup

RescueBlockUnitSide

RescueBlockUnitSide

RescueCoordinateLine

RescueCoordinatePolyLine

RescueCoordinateSystem

RescueCoordinateSystemAxis

RescueEdgeSet

RescueGeometry

RescueGeometryObject

RescueGrid

RescueGridAxis

RescueHorizon

RescueLookup

RescueLookupItem

RescueLookupString

RescueLookupTable

RescueMacroVolume

RescueModel

RescueObject

RescuePolyLine

RescuePolyLineNode

RescuePolyLineNodeUV

RescueProgressReporter

RescueProperty

RescueReferenceSurface

RescueSection

RescueSplitLine

RescueSurface

RescueSurfaceCell

RescueTrimEdge

RescueTrimLoop

RescueTrimVertex

RescueTripletArray

RescueUnit

RescueVertex

RescueWellbore

RescueWellboreCell

RescueWellboreProperty

RescueWellboreSampling

RescueWellboreSurface

cNameValuePair

Changes for June 1998

The RESCUE library has been enhanced so that binary files are compatible between Windows environments and most Unix environments. See Binary Formats.

A cNameValuePair object has been added to RescueModel to assist vendors in keeping track of key information as a model passes from one vendor to another.

A RescueEdgeSet object has been added to RescueSurface (where it is inherited by RescueSection, RescueReferenceSurface, and RescueBlockUnitHorizonSurface). If used, the outer boundary of this edge set defines the edge of the surface. The inner group of trim loops may be used to define the exact position of intervening features.

Changes for April 1998

The RESCUE library has been enhanced to include an archive method which archives the library to an Epicentre database, and an unarchive method which gets it back out. This involves quite a bit of code, but it is almost all transparent to the user. There are six methods of interest, all in RescueModel. One to archive a model, one to unarchive it, two to delete it (identified in one of two ways) from the database, one to list available models, and one to influence the commit behaviour.

The test program ArchiveDB illustrates the usage of all methods.

This was a difficult project and careful adherance to a set of goals were necessary in order to succeed. Our goals were…

Before you try linking your application with this version, please look thru Archiving to Oracle.

Changes for November 1997

At the ILAB in Houston during the week of November 17th it was decided that the Rescue code is "ready for prime time". Only a few polishing changes, designed to cause minimal impact to existing application code, were needed.

The RescueSurface::GetVertexConnectionAt method was removed, along with its supporting private method RescueSurface::AddVertexToArray. This method did not perform a useful task and was not used by anyone.

The ProgressReport function call was replaced by a pure virtual function RescueProgressReporter. A static function was added to RescueModel to register an instance of RescueProgressReporter. To add progress reporting to your program, create a subclass of RescueProgressReporter, instantiate it, and pass a pointer to it to the RescueModel::RegisterProgressReporter function. The readModel example program illustrates how to do this.

In order to support extremely thin sections, double values were returned to RescuePolyLineNode (and thus to RescueTrimVertex). Both float and double interfaces to this object are available. This requires a change to the file structure, but existing files (files from the November ILAB) are fully supported by this version of the library.

Two new methods were added to assist readers and writers. RescueGeometry::GeometryType() determines if the geometry of the block unit grid is x/y orthogonal, conformable, or squashed x/y orthoganal. RescueTrimLoop::IsLoop() returns true if the RescueTrimEdges which are contained in the loop do form a closed loop which proceeds in a consistent direction.

Changes for October 1997

The October 1997 version of the library will read model files from the later half of the April 1997 ILAB (after the property type was added) and from the September 1997 ILAB.

RescueReferenceSurfaces assumed horizontal

The public constructors for RescueReferenceSurface which formerly required an i and j axis have had those arguments deleted. Because RescueReferenceSurfaces are primarily horizontal the constructor now automatically assigns the first coordinate system axis to i and the second coordinate system axis to j. This will require a minor change to existing code which creates reference surfaces for proportional and referential block unit grids.

RescueMacroVolume handles disjoint volumes in RescueBlockUnit

In order to handle situations where a block unit contains two or more disjoint volumes a new object, RescueMacroVolume, has been added. The object is so named because it holds the macro model description of a single contiguous volume. The K layer RescueEdgeSets have been moved from RescueBlockUnit to this object, along with the RescueBlockUnitSides and interior RescueSections. The RescueEdgeSet which formerly resided in RescueBlockUnitHorizonSurface has been moved to RescueMacroVolume as well.

For situations where a block unit contains a single contiguous volume this change is easily accomodated. RescueBlockUnit automatically creates one RescueMacroVolume. Programs simply perform the same operations against this RescueMacroVolume (retrieved by blockUnit->NthMacroVolume(0)) that they formerly performed against RescueBlockUnit (AddBlockUnitSide, DropBlockUnitSide, etc.). The blockUnit->NthMacroVolume(0) operation is safe, because a RescueBlockUnit is guaranteed to always have at least one RescueMacroVolume (therefore, don't attempt to delete macro volumes from a block unit while the count is > 0). However, the library cannot guarantee that the RescueMacroVolume has been filled out.

The meaning is slightly different for trims of RescueBlockUnitHorizonSurfaces even in the single-volume case. The old RescueBlockUnitHorizonSurface object had a single RescueEdgeSet. If the horizon surface defined a top of one unit and the bottom of another, this single RescueEdgeSet served as trim loop for both top and bottom surfaces. The RescueMacroVolume contains two RescueEdgeSet pointers, one for trimming the top of the volume and one for the bottom. Potentially, therefore, the bottom of one unit can be trimmed differently from the top of the unit immediately beneath it. If one RescueEdgeSet can serve both purposes then the user may install the same object in two different RescueMacroVolumes.

For situations where a RescueBlockUnit does contain more than one volume, the writer may create new volumes by using RescueBlockUnit->AddMacroVolume(). The new volume is then populated with block unit sides, interior sections, top and bottom trims, and k layer trims which apply to that volume only.

RescueTrimEdges grouped into RescueTrimLoops

A RescueEdgeSet formerly had one cSetRescueTrimEdge for boundary edges and one cSetRescueTrimEdge for interior edges. However, in some situations this is confusing. Trim edges are ordinarily grouped into one or more loops. It is difficult for a reader to know exactly which trim edges go together. This is especially noticable where a surface touches a contiguous volume in two disjoint places. Ideally the writer should trim each of these intersections with a set of RescueTrimEdges.

In this version a RescueEdgeSet contains one cSetRescueTrimLoop for boundary edges and one cSetRescueTrimLoop for interior edges. Each cSetRescueTrimLoop contains one or more RescueTrimLoop objects, each of which contains a cSetRescueTrimEdge…a set of edges which are known to be connected to each other. With this change, the trim loops for each intersection are grouped together, leaving an unambiguous situation.

Doubles changed to floats

In order to conserve space in files and in memory, all doubles in the program have been changed to float, except those in RescueVertex. The assumption is that models will be built in some local coordinate system, and being only a few square miles in areal extent single-precision will be big enough to precisely place all points. The model will be placed precisely in some better known coordinate system by a RescueVertex point, which, being double-precision, can be placed precisely in some coordinate system.

It is also assumed that single-precision is precise enough for properties that we probably don't know that well anyway.

RescueSection boolean changed to enumeration

The former RescueSection constructor argument isFault has been replaced by a four-value enumeration RescueSection::SectionType, having values of auxilliary, fault, unconformity, lease boundary. When older files are read in, boolean false is equated to lease boundary, true becomes fault. The IsFault() method has been replaced by Type().

Arrays changed to Fortran ordering

External arrays (those which are passed to and from the library user) have been changed from C ordering to Fortran ordering. That is, for a doubly subscripted array, the individual elements are arranged in memory in the order (0,0),(1,0),(0,1),(1,1) instead of (0,0),(0,1),(1,0),(1,1). Actually, most models have been built this way historically, so there is no conversion facility for this change.

RCH2DArray, RCH3DArray, and RescueArray::XYZAt methods have been changed, making these methods compatible with the "i fastest" arrays which Rescue users have traditionally built.

Coordinate systems are projectable

Twelve variables have been added to RescueCoordinateSystem. If passed, these should provide all of the information needed to project these coordinate systems or to transform coordinates from from one coordinate system to another.

Library can be stored in a persistent object database

Although this aspect has not been tested, objects are no longer declared statically inside other classes. This makes the code less elegant and requires almost every object to have a destructor, but should allow Rescue objects to be declared as sub-classes of the persistent object class used by persistent object databases.

There are at least a couple of abstract classes in the library. You may need to make them instantiable in order to use the library with a persistent object database. They remain abstract in the library because it is self-documenting for most users.

Changes for June 1997

The June 1997 version of the library will read model files from the later half of the April 1997 ILAB (after the property type was added). New model files are version 5. Old model files are version 4. Because the property type change was made hastily during the ILAB, the file version number was not changed. Therefore, older version 4 files will not read properly.

Programs from the April 1997 ILAB should compile and run without a great deal of difficulty. However, some constructors have changed and this will necessitate minor code changes in many programs.

Properties of block unit grids are now cell-centered. The practical result of this is that there is one less value index in each dimension than there used to be. However, when version 4 files are read in, their property arrays are still node-centered, and they are not converted by the library.

A RescueVertex has been added to grids which are capable of being rotated to define the point about which the rotation occurs. In every case this value can be passed as NULL (0) when the grid is not rotated. Many of the constructors default it to 0.

Each K layer of a block unit grid may be assigned a user-determined 32-bit global id. Readers can retrieve the id for each K layer. There is an understanding that layers having the same ID within the same unit have "layer equivalence". The default id of zero means no equivalence is defined. Methods for defining and reading layer ids have been added to RescueGeometry.

Two alternate forms of block unit grid constructor are available. Proportional block unit grid geometries are defined by two surfaces and two offsets. The k layers of the grid are layed out proportionally between these two top and bottom surfaces. Referential block unit grid geoemetries are defined by a single surface, an offset, a thickness and a flag (onlap/offlap). All k layers are the same thickness, but the grid follows the contours of the referenced surface. See descriptions of the constructors in RescueBlockUnit and descriptions of the grid in RescueGeometry.

Properties can be assigned from a lookup table. The lookup table may define integer values, either bytes or shorts, as strings or two-column floating point tables. The floating point tables are intended to define the result of some function. See the RescueLookup and its associated objects, as well as the constructors for RescueProperty and RescueWellboreProperty.

RescueBlockUnitSide once again has only 1 side. When reading version 4 files with multiple sides the last side defined is chosen and previous ones are discarded.

Class naming conventions.

Classes which begin with "Rescue" were created to hold objects of the Rescue model, as created by the Rescue working group.

Classes which begin with cSet and cBag were created to hold lists of other Rescue model objects. Originally these classes were a single template class.

Classes which begin with RCH were contributed from my personal "bag of tricks". I use these classes in many of my projects for various customers.

Reading the header files (for the C++ novice)…

The best way to find out about the C++ class library is to read the header files (source files ending in .h). This document includes the header files, hyperlinked to make it easy to follow the relationships.

Not everyone interested in the library is an experienced C++, or even C programmer. This short primer will help you get started, and try to relate the C++ to something you may be more familiar with, such as EXPRESS.

A class in C++ corresponds roughly to an Entity in EXPRESS. The Rescue class library consists of one .h file and one .cpp file for each class. The only .h file which does not follow this pattern is "myHeaders.h" which contains housekeeping information which would only be of interest to a programmer. A representative .h file is shown below. This file may be out of date.

The heading of each .h file gives a general description of the class. Some are more helpful than others.


/********************************************************************

  RescueBlockUnit.h

  block unit for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
The next section is housekeeping for C++, but by examining it you can get a quick look at the other classes within the library to which this class has relationships. Careful though, some classes may be listed when they do not have a relationship. The best listing of relationships is shown below under class members.

#ifndef RESCUEBLOCKUNIT_H
#define RESCUEBLOCKUNIT_H

#include "myHeaders.h"
#include "RescueGrid.h"
#include "RescueBlockUnitSide.h"
#include "cSetRescueBlockUnitSide.h"
#include "cBagInt.h"
#include "cBagRescueBlockUnitPropertyGroup.h"
#include "cBagRescueSection.h"
#include "cSetRescueEdgeSet.h"
#include "RescueCoordinateSystem.h"
#include "RescueGeometry.h"
#include "cSetRescueMacroVolume.h"

class RescueUnit;
class RescueBlock;
class RescueSection;
class RescueBlockUnitHorizonSurface;
class RescueBlockUnitPropertyGroup;
class RescueReferenceSurface;
class RescueMacroVolume;

The next section is important. It declares the class, and most importantly for the reader, it declares the superclass of the class. Superclasses work exactly like they do in Express. The subclass has all of the members and methods of the superclass, plus any members or methods declared in its own class. Sometimes a subclass will have a method which is declared to be exactly the same as a method in the superclass. In that case, the subclass method overrides the superclass method for instances of the subclass. Almost all objects in the Rescue class library have a superclass, although more often than not it is an abstract, housekeeping object such as RescueObject or RescueGeometryObject. This is analogous to a superclass of something like e_and_p_data in Epicentre.

class RescueBlockUnit:public RescueObject
{
public:

The public methods of the class come next. These are the tools which the programmer uses to build or interrogate the model. "Constructors" are usually placed first. Constructor methods have the same name as the class they construct, and do not have return types. There will generally be at least one public constructor, and sometimes several with different arguments. In this case the user chooses the argument list which best suits her needs. If there is no public constructor, then there will generally be a private one (under private methods, discussed below). In that case, instead of creating the object directly the user creates the object via a method of some other object.

  RescueBlockUnit(RescueCoordinateSystem::Orientation orientation,
                  RescueBlock *parentBlock,
                  RescueUnit *parentUnit,
                  float i_origin, float i_step,
                  int i_lowbound, int i_count,
                  float j_origin, float j_step,
                  int j_lowbound, int j_count,
                  int k_lowbound, int k_count,
                  float missingValue,
                  float rotation, RescueVertex *vertex = 0);
  RescueBlockUnit(RescueCoordinateSystem::Orientation orientation,
                  RescueBlock *parentBlock,
                  RescueUnit *parentUnit,
                  float i_origin, float i_step,
                  int i_lowbound, int i_count,
                  float j_origin, float j_step,
                  int j_lowbound, int j_count,
                  int k_lowbound, int k_count,
                  float missingValue,
                  RescueReferenceSurface *topSurfaceIn, float topOffsetIn,
                  RescueReferenceSurface *bottomSurfaceIn, float  bottomOffsetIn,
                  float rotation, RescueVertex *vertex = 0);
                                            // Constructor for a grid whose z values are 
                                            // determined by the reference surfaces and offsets.
                                            // Each k-layer is proportional to the distance between
                                            // the top and bottom reference surfaces, after the
                                            // offsets are applied. This applies only to vertexes
                                            // of type R_EQUAL_AXIS.
  RescueBlockUnit(RescueCoordinateSystem::Orientation orientation,
                  RescueBlock *parentBlock,
                  RescueUnit *parentUnit,
                  float i_origin, float i_step,
                  int i_lowbound, int i_count,
                  float j_origin, float j_step,
                  int j_lowbound, int j_count,
                  int k_lowbound, int k_count,
                  float missingValue,
                  RescueReferenceSurface *referenceSurfaceIn, float referenceOffsetIn, 
                  float thicknessIn, RescueGeometry::RescueLapType onOffLapIn,
                  float rotation, RescueVertex *vertex = 0);
                                            // Constructor for a grid whose z values are 
                                            // determined by the reference surface and offset.
                                            // Each k-layer is of the same thickness, determined
                                            // by the thickness argument. This applies only to vertexes
                                            // of type R_EQUAL_AXIS.

Each argument to the constructor consists of a type followed by an argument name. The name is a C++ housekeeping requirement, but names are chosen to provide some illumination on the purpose of the argument. Most arguments in the Rescue library are required. If the argument is optional the argument name is followed by an equals sign and then the default value. An asterisk (*) between the data type and the argument name should be read "pointer to". Generally Rescue classes are referred to by pointers when they are used as arguments. When you see scalar types, such as double or int, referred to as pointers, it means an array of values is passed, rather than a single value. If an array of Rescue objects where passed, it would be declared with a double asterisk (**).

In a few instances it is permissible to pass 0 (NULL) in place of pointers to Rescue classes, but not very often. Where it is permissible there is usually a comment to the effect.

When a data type is declared with a Rescue class name followed by a double colon it means the type is an enumeration (the same concept as in EXPRESS) and that the enumeration is declared in the class whose name preceeds the double colon. The other style of enumeration in Rescue is to begin the enumeration name with "_Rescue".

Mixed in with constructors you will often see a destructor, which looks like this…

  ~RescueBlockUnit();
Destructors are c++ housekeeping of no interest to the non-programmer.

After the constructors come public methods. These are the tools the programmer uses to manipulate or interrogate the object. Public methods in the Rescue library correspond to both methods and attributes in EXPRESS. "Action" methods, designed to perform some operation upon the model, have names that begin with a verb. These correspond best to methods in EXPRESS.

"Informational" methods, designed to return information about the object to outsiders, correspond to attributes in EXPRESS. By convention, direct access to class members, discussed below, is not allowed. The discussion of asterisks as it applies to classes and arrays applies also to return codes. However, a second form of return for arrays is also used. The methods named "Unit" and "Block" below, are examples of methods that return a single value (in this case a related RescueUnit or RescueBlock). A method like NthInteriorSection, shown below, returns a single value from an array of possible values. This naming convention is used throughout the Rescue library for returning an indexed value from an array.

Reading these methods gives you an idea of the other objects which relate to this object, and of the sort of information this object can contain.

 
  RescueUnit *Unit() {return unit;}
  RescueBlock *Block() {return block;}
  RescueBlockUnitHorizonSurface *SurfaceAboveMe() {return surfaceAboveMe;}
  RescueBlockUnitHorizonSurface *SurfaceBelowMe() {return surfaceBelowMe;}

  void SetSurfaceAboveMe(RescueBlockUnitHorizonSurface *existingSurface)
                                      {surfaceAboveMe = existingSurface;}
  void SetSurfaceBelowMe(RescueBlockUnitHorizonSurface *existingSurface)
                                      {surfaceBelowMe = existingSurface;}

  RescueMacroVolume *AddMacroVolume();
  void DropMacroVolume(RescueMacroVolume *existingVolume);
  RescueMacroVolume *NthMacroVolume(int zeroBasedOrdinal)
                        {return (*macroVolumes).NthObject(zeroBasedOrdinal);}

  void AddBlockUnitPropertyGroup(RescueBlockUnitPropertyGroup *existingBlockUnitPropertyGroup)
              {(*blockUnitPropertyGroups) += existingBlockUnitPropertyGroup;} 
  bool DeleteBlockUnitPropertyGroup(RescueBlockUnitPropertyGroup *existingBlockUnitPropertyGroup)
      {return ((*blockUnitPropertyGroups) -= existingBlockUnitPropertyGroup);}
  RescueBlockUnitPropertyGroup *NthBlockUnitPropertyGroup(int zeroBasedOrdinal)
  {return (RescueBlockUnitPropertyGroup *) (*blockUnitPropertyGroups).NthObject(zeroBasedOrdinal);}
                  // RescueBlockUnit does not "own" RescueBlockUnitPropertyGroups,
                  // so it does not create or delete them, merely
                  // catalogs relationships to them.

  RescueGrid *BlockUnitGrid() {return blockUnitGrid;}
  RescueGeometry *GridGeometry() {return gridGeometry;}
  
  int  CountOfBlockUnitPropertyGroup() {return (*blockUnitPropertyGroups).Count();}
  int  CountOfVolumes() { return  (*macroVolumes).Count(); }

Often methods are followed by comments which give additional information. A declaration method has a return type, followed by a name, followed by an argument list in parentheses. If the method also contains a section in curly brackets {}, then this is the declaration of the procedure of the method in the C++ language. This part will generally not be very interesting to the non-programmer.

A method whose return type is "void" doesn't return anything. These methods are provided solely to perform some operation on the model. Sometimes methods which have a non-void return type are provided mostly to perform an action also. In this case the method name usually begins with a verb, often "Add", "Drop", or "Delete".

  virtual bool IsOfType(_RescueObjectType thisType);
                                        // Returns true if the object is a
                                        // member of the specified class.
  virtual bool IsValid();               // Returns true if object appears
                                        // to be currently valid.

Most Rescue classes declare the methods above. They are of interest only to the programmer.

Private methods come next. These are methods used by the class itself or by some friend class, to manipulate the object. To the non-programmer these can be considered C++ housekeeping of little interest.

private:
  RescueBlockUnit(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);

The next items are the members of the class. These correspond to attributes in Express, although they cannot be accessed directly by a programmer. Programmers must use informational methods discussed above.

  RescueBlock *block;
  RescueUnit *unit;
  RescueBlockUnitHorizonSurface *surfaceAboveMe;
  RescueBlockUnitHorizonSurface *surfaceBelowMe;
  cSetRescueMacroVolume *macroVolumes;
  cBagRescueBlockUnitPropertyGroup *blockUnitPropertyGroups;
  RescueGrid *blockUnitGrid;     // shared by the geometry and all properties.
  RescueGeometry *gridGeometry;

This section is the meat of the header file for relationship-seekers. When another rescue class is declared with an asterisk, it means this class has a relationship to a single instance of that other class.

The cSet<Rescue Class> and cBag<Rescue Class> notation indicates that this class has a relationship to an array of instances of the other class.

The cSet notation indicates that a one-to-many relationship exists. The class on the other end of the relationship will have either no relationship to this class or a relationship to a single member of this class. If the later case, the two ends of the relationship must point to each other. The notation also implies one other thing, that deletion of the parent object is cascaded to all of the children.

The cBag notation is generally used for many to many relationships. It doesn't indicate many to many exactly. It indicates that there is no constraint upon relationships which the child instance may have. Deletions are not cascaded to members of these relationships.

Our example doesn't contain any, but classes also often have members which are integers, double floating points, and strings. Arrays of these types will be noted with an asterisk between type and name. Strings are nearly always declared "RCHString *name", meaning the RCHString class is used. This class is very similar to the EXPRESS STRING data type, with no upper limit on length.

The bottom of the header file is not very interesting. Sometimes ID's are declared here. These are used for housekeeping when a model is being reconstructed from an archival source. They are not used at other times. They, along with any friend class declarations, are C++ housekeeping of little interest to non-programmers.

  int blockID;
  int unitID;
  int surfaceAboveMeID;
  int surfaceBelowMeID;
  cBagInt *blockUnitPropertyGroupsID;

  friend class cSetRescueBlockUnit;
};

#endif

Programmer notes

Generally, Rescue objects should be instantiated on the heap, not the stack. This is because the model assumes that all of the objects within it belong to it, and it attempts to clean these objects up where appropriate, which might mean it would attempt to delete the object…with catastrophic results if the object is on the stack. If the object has an overloaded operator you would like to use, this can still be done, as in this example…

*(line->PolyLineNodes()) += new RescuePolyLineNode(subloop * 300.0 + 100.0, 
                                                      loop * 300.0,
                                                      subloop2 * 300.0);

All objects in the Rescue model have a parent object, except RescueModel, which is the ancestor of all. Generally the parent object is declared in the constructor of the object. If it is not, then the parent object has a public method for registering the child you have just created. Objects which are not registered in one of these two ways are not considered part of the model. They won't be archived or deleted with the model.

When a method returns a pointer, you must carefully read the comments that are placed with that method in the .h file (or sometimes just the inline code), in order to know whether or not you should free or change the object or array to which the returned pointer refers. Generally the Rescue library will return a pointer to the actual object rather than a copy, in order to avoid the overhead of duplication. Therefore, generally you will not delete objects and arrays which are returned to you.

By the same token, when you provide a pointer to an object or array as an argument to a method, you must again read the comments placed with that method in the .h file. Again to save on overhead, many methods in the Rescue library copy the pointer rather than copying the entire object or array, so objects and arrays which you pass to Rescue often become Rescue's responsibility for freeing.

As a matter of style, in the Rescue library comments generally follow the code to which they refer.

The primary difference between cSet<RescueClass> and cBag<RescueClass> is that cSet classes delete the object when the object is dropped from the list or when the cSet object is destructed. In every case where a Rescue class has a member variable which is a pointer to a cSet<RescueClass> or cBag<RescueClass> these classes are created in the constructor and deleted in the destructor.

These classes where originally all defined by a pair of template classes. Templates were found to be a challenge for some of the compilers and linkers the RESCUE community wanted to use, so individual classes where created. However, these individual classes were not customized, so if you've seen one you've seen them all. The only exception to this is the generally uninteresting cBagInt.

Other than the RescueModel object, which has no parent, objects within the Rescue library should not be deleted directly. Each object has a parent object. This is an object which contains a reference to the object of interest within a "cSet" class. This parent object will contain a "Drop" method which is used to delete the object of interest.

Error Handling

The only errors which are likely to be encountered in the Rescue library code are those which are global in nature and unrecoverable. These include running out of virtual memory and encountering floating point errors, bus errors and segmentation faults. The best way to handle these problems is to install global error handling in your application.

Floating point errors, Bus errors and Segmentation Faults

Floating point errors result from overflow, underflow, and division by zero. Different programming environments handle them differently. Some may signal them, and others not. Bus errors and Segmentation Faults occur from attempts to access data with an invalid pointer. They should not occur in production code, but we all know that they sometimes do. They may result from programming errors in your application or in the Rescue library. The position of the program counter often does not pinpoint the culprit, i.e. a seg fault in the Rescue library code does not indicate that the code error is in the library, and the opposite is also true.

These errors are handled by establishing signal handlers. Signal handlers are established on a global basis using the standard library function signal. Information on this function is available in many places, including a general overview in the man pages of your favorite OS.

Running out of virtual memory

Running out of virtual memory is a real possibility, even in completely debugged production code. There is no satisfactory way for an application to know how big a model is before it begins to read it, nor is there any truly satisfactory way for an application to know how much virtual memory is still available to it. Biting off more than you can chew is a constant danger.

Since memory problems may occur at any point in the execution of your application, the best solution to this problem is to establish global error handling for memory allocation. The normal way to do this is to create your own malloc and realloc. Your custom malloc may well call the system malloc, but it will check the result to see if the allocation failed and will perform some cleanup action if it did.

The next task is to get the Rescue library to use your malloc instead of the system malloc. To do this, you will need to make a one-line change to myHeaders.h. At the top of this file, insert the following line

#include "mySpecialHeader.h"

The special header will contain something like the following…

#include "myAllocationStuff.h"
#define malloc mySpecialMalloc
#define realloc mySpecialRealloc 

The define line causes the Rescue library to make a reference to your malloc instead of to the system one. The include file includes any prototypes needed to make this reference compile correctly. Your new malloc must have the same arguments and return type as the system malloc.

Once you have made this change, recompile the entire library.

Of course, the Rescue library doesn't do all of its memory allocation using malloc. It also uses the C++ new operator. There are two ways to handle this. You can decide to overload the new operator, or you can use set_new_handler to provide an error handling routine to the system new operator.

Overriding the new operator

You will need to overload this operator globally, since it is used in the Rescue library code not just to allocate Rescue classes but to allocate arrays as well. Many sources of information will tell you how to do this. Basically you will override the C++ new and new[] operators, as shown below.

void *operator new(size_t size)
{
	return mySpecialMalloc(size);
}

void *operator new[](size_t size)
{
	return mySpecialMalloc(size);	
	// Curiously there is only one argument, so we can't use calloc!
}  

Providing a new handler

Your operating system should have a function named set_new_handler() or _set_new_handler() (some have both!). When you establish a handler by passing the address of your procedure to this function the system new operator will call back to your function when an error occurs.

On some operating systems there may be a return code (in case you manage to fix the problem, an unlikely event). In other cases the function is void. Thanks to Jonathon Morris for sample set_new_handler() code.

#ifdef PCBUILD

int  NewHandler(size_t sz )
{
   longjmp( mark, 55 );
   return  0;     // should never get here
}

#else

void  NewHandler()
{
   longjmp( mark, 55 );
}

#endif

Special malloc and realloc

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
jmp_buf mark;              /* Global address for long jump to jump to */

void *mySpecialMalloc( size_t size )
{
	void *myReturn = malloc(size);
	if (myReturn == 0)
	{
		longjmp(mark, 1);
	}
	return myReturn;
}

void *mySpecialRealloc( void *pointer, size_t size )
{
	void *myReturn = realloc(pointer, size);
	if (myReturn == 0)
	{
		longjmp(mark, 1);
	}
	return myReturn;
}

Handling the error

Now that you can detect when you run out of memory, the next problem is to do the right thing when it happens. Typically, if you run out of memory while reading a model you will want to stop reading and let the user know that not enough memory was available. You will then want to clean-up any memory used so far and go on to some other task. This requires a bit of work on your part. If you are providing a new handler you will need to remember to establish it one time in your application. Each time you begin a section of code which may run out of memory you must establish an error handling point. Your code will look something like this…

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include "RescueModel.h"
extern jmp_buf mark;              /* Global address for long jump to jump to */

#ifdef USING_NEW_HANDLER
#ifdef PCBUILD
   int (*oldHandler)(size_t) = _set_new_handler( NewHandler );
#else
   void (*oldHandler)() = set_new_handler( NewHandler );
#endif
#endif

  int jmpret = setjmp( mark );
  if (jmpret == 0)
  {
	RescueModel *myModel = RescueModel::UnarchiveModel(argv[1]);
	// perform successful post-read actions here.
  }
  else
  {
    RescueModel::CleanFromUnarchive();    // Special function is required because the UnarchiveModel 
                                          // function never returned the pointer to the model.	
	// notify user of failure here.
  }

When building a model, the process is very similar, except that the pointer to the model is known, so no special function is needed. The code will look like this…

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include "RescueModel.h"
extern jmp_buf mark;              /* Global address for long jump to jump to */

  RescueCoordinateSystem *ultimateCs = new 
    RescueCoordinateSystem("ultimate cs", RescueCoordinateSystem::LDF, 0, 
                                     "latitude", "degA", 
                                     "longitude", "degA", 
                                     "elevation", "ft");
  RescueVertex *modelVertex = new RescueVertex("model vertex",
                           ultimateCs, 96.5, 27.2, 1000);
  RescueCoordinateSystem *penUltimateCs = new
    RescueCoordinateSystem("penultimate cs", RescueCoordinateSystem::LDF, modelVertex,
                                     "northing", "m",
                                     "easting", "m",
                                     "elevation", "m");
  RescueModel *model = new RescueModel("test model 1", penUltimateCs);
  int jmpret = setjmp( mark );
  if (jmpret == 0)
  {
	// build model here.
  }
  else
  {
	delete model;	  // Delete unfinished model. 
	// notify user of failure here.
  }

Archiving to Oracle

Compiling and linking

In order to make the use of Oracle optional, a precompiler symbol, DB_HOOK, was used to isolate any Oracle-involved code. To compile the Rescue library for use with the Oracle enhancement, make sure the DB_HOOK symbol is defined, and include the myOracle.c file (which contains low-level interface routines). When compiling your own code you must also define the DB_HOOK symbol, so that header files you reference will be expanded correctly by the pre-compiler.

To compile the Rescue library for use without the Oracle enhancement, do not define the DB_HOOK symbol, not in your code and not in the library. Do not include myOracle.c.

If some of the header files in your project or libraries you link to were compiled with DB_HOOK and some were compiled without, the most probable symptom will be a flurry of difficult to explain bus errors and seg faults.

Rescue uses the OCI (Oracle Call Interface) feature of Oracle, not Pro*C (which is an embedded SQL language). For those new to Oracle programming, linking the appropriate libraries into your program can be a bit of a trial especially on Unix. The Oracle 8.0 version that I used on NT for most of my development required me to include a single LIB file, which was simple and easy. The Oracle 7.0.* versions I have used on the SunOS and Solaris over the past five or so years required a bewildering array of linker commands and libraries, and each little version required a completely different set, so that Makefiles typically could not be transported from one machine to another. The SGI version I used at POSC seemed to follow this model.

If you find yourself in this situation, here is a little survival guide…The Oracle distribution contains some sample Pro*C code, and perhaps some OCI code as well. It also includes a procedure for linking Pro*C and OCI programs. You will not be able to use this procedure because it assumes that your program consists of only a few simple modules, and commercial software is never like this.

What I always do is find the sample Makefile. I look at the targets at the bottom to find out what symbols are being included. Usually it is only two or three symbols, but these symbols are created from the bewildering 200 lines that come before. I take this Makefile, and cut the targets off the bottom. I take the few symbols that are used in the target line and define them as a single symbol, usually something like OCILIB. Then I include this symbol with my own modules and libraries on the linker line of my own target. This also makes the Makefile more transportable, since I can use a different include file on each machine, while the rest of the Makefile stays the same.

An environment variable ORACLE_INCLUDE is used to point to the directory where Oracle-supplied header files reside. myOracle.c uses the header "ociapr.h". archiveDB also uses this header, so the ORACLE_INCLUDE variable is used in that Makefile as well.

Creating an Oracle Instance

Due mostly to the high number of tables and the large number of constraints, Epicentre is a challenging model for Oracle to handle. Consequently you must be careful when you create your Oracle instance to allocate enough space for all the activities which will occur. Below is the "init.ora" I used for testing.

db_name = orc2
db_files = 1020
control_files = (F:\ORANT\database\ctl1orc2.ora, F:\ORANT\database\ctl2orc2.ora)
db_file_multiblock_read_count = 32
db_block_buffers = 3200
shared_pool_size = 24000000
log_checkpoint_interval = 8000
processes = 200
dml_locks = 1200
log_buffer = 163840
sequence_cache_entries = 100
sequence_cache_hash_buckets = 89
#audit_trail = true
#timed_statistics = true
background_dump_dest = F:\ORANT\rdbms80\trace
user_dump_dest = F:\ORANT\rdbms80\trace
db_block_size =2048
compatible = 8.0.3.0.0
sort_area_size = 65536
log_checkpoint_timeout = 0
remote_login_passwordfile = shared
max_dump_file_size = 10240
open_cursors = 5000
It is basically a "large" database, as created by the Database Wizard, with some changes. The dml_locks, open_cursors, and shared_pool_size variables were all increased to avoid problems which seem to occur mostly when deleting models from the archive.

Creating an Epicentre Account

An instance of Epicentre is defined by a user account in an Oracle instance. The user account contains a set of tables, indexes, and constraints which form a PDS (POSC Data Store). Create the account using normal Oracle administration tools, and give it the ability to create tables. The command files for creating the PDS reference a tablespace named POSC_MODEL_TAB. This tablespace should be setup with a storage clause that has a relatively small initial extent (because we will create many tables, and a large proportion of those will be almost empty) but an ability to create large tables (through extents of increasing size).

When the tablespace has been created, execute the following command files inside SQL*Plus. The command files are found in the sql directory of the distribution.

Most, if not all, of these command files will produce some errors. Try to be sanguine about this, but take note if nearly all of the statements are resulting in some error, especially problems due to space. It may mean that you have a problem at your site.

You may want to customize the rescue_blob.sql file. This file creates the tables where the blobs are stored. If you have many large models this table may become very large indeed, so you may want to create it with a very large initial extent.

An alternate way to create a database is to import the Oracle Export file empty.dmp into your empty Oracle account.

o2% imp rescue/rescue

Import: Release 7.3.2.3.0 - Production on Wed Mar 25 18:32:40 1998

Copyright (c) Oracle Corporation 1979, 1994.  All rights reserved.


Connected to: Oracle7 Server Release 7.3.2.3.0 - Production Release
With the distributed, replication, parallel query and Spatial Data options
PL/SQL Release 2.3.2.3.0 - Production

Import file: expdat.dmp > empty.dmp

Enter insert buffer size (minimum is 4096) 30720>

Export file created by EXPORT:V07.03.02 via conventional path
List contents of import file only (yes/no): no >

Ignore create error due to object existence (yes/no): no >

Import grants (yes/no): yes >

Import table data (yes/no): yes >

Import entire export file (yes/no): no > yes

If you want to get rid of your PDS without dropping the Oracle account (perhaps in order to start over without bothering your Oracle administrator) you can execute the following two command files in order

Portability Issues

Blobs which are written into the Oracle database have binary numbers in them, and these numbers are not converted by either Oracle or Rescue on being read and written. Models in the Oracle archive are therefore like models in a binary flat file…they can be read only on a machine with the same binary number formats as the machine on which they were written.

When using Rescue with Sql*Net, remember that it is the Sql client machine that is important, not the machine where the Oracle server resides.

Naming issues

Rescue models in the database are identified by model name, which must be 40 bytes or less in length. This name must be unique. If a program attempts to store a model whose name already exists in the database, the existing model is automatically deleted before the archive process begins.

It is therefore a good idea to check the database before you archive to find out if the name already exists. This is similar to checking for an existing file before overwriting when using a conventional file archive.

When creating models for storage in Oracle, care should be taken to keep names short. In Rescue usage here-to-fore names could be any length. Names in Epicentre are generally 40 bytes long, but Rescue has to use some of these bytes for internal purposes, so names should be 30 bytes or less. There are some exceptions to this however, depending upon the mapping of individual names, and no model from ILAB4 failed to load due to names that were too long.

Committing Rescue Models

Ideally, a Rescue model should be written to Oracle as a single transaction, and the entire transaction then committed at one go. This is both faster and more robust, since a partially archived model will almost surely not be instantiable. However, for most commercial models this requires a truely humongous rollback segment, far beyond what you will find on most Oracle instances.

If you find yourself in the happy situation of unlimited rollback space, use this construction to set Rescue to do a single commit…

    RescueModel.SetAtomicCommit(true);
The default behaviour is to do many small commits, which creates a problem if an error is encountered during the archiving process. A partially archived model should be immediately deleted.

Error Handling

Error handling is an issue in every Oracle program. The program may fail for a variety of reasons, from running out of one of several kinds of spaces to some failure of the network. The default behaviour of the library is to print an error message to stderr and continue running, but this is never satisfactory. A model which was stored with an error may not be instantiable, and will certianly be wrong.

Oracle error handling can dovetail with the global error handling you are probably already doing. Create an error handling routine such as this one (from archiveDB.cpp)

int OracleErrorCallBack(int whichError, void *cursor, char *currentStatement)
{
  char msg[80];

  cda_def *cur = (cda_def *) cursor;
  if (currentStatement != 0)
  {
    fprintf(stderr, "%s\n", currentStatement);
    if (cur->peo >= 0 && cur->peo < strlen(currentStatement))
    {
      fprintf(stderr, "\nnear…\n%s\n", ¤tStatement[cur->peo]); 
    }
  }
  fprintf(stderr,"Oracle error: code is %d, op is %d\n",
           (int) cur->rc, (int) cur->ft);
  oermsg(cur->rc, (unsigned char *) msg);
  fprintf(stderr,"%s\n", msg);
  if (strcmp(msg, "orol") != 0)
  {
    _daeRollbackTransaction();
  }
  longjmp(mark, 1);
  return 0;
}
Register it in your mainline, like this…
  _daeSetErrorCallBack(OracleErrorCallBack);
then your existing archiving code, which already checks for memory errors, etc., will check for Oracle errors also…
      int jmpret = setjmp( mark );
      if (jmpret == 0)
      {
        myModel->ArchiveModel(argv[3], argv[4], argv[5], argv[6]);
        delete myModel;
      }
      else
      {
        printf("Failed to archive to Oracle\n");
        exit(-1);
      }

Binary Formats

When archiving to flat files, RESCUE has two modes, text and binary. The text format writes all data using stdio printf functions. These files will generally be transportable to any other computer system. Binary produces a more compact file by writing shorts, ints, floats, and doubles directly into the file, but introduces concerns where files are transported between computers of different types.

Generally, RESCUE reads and writes these files without regard to the actual format of these data types in memory. As a result, the file can only be used on a machine whose memory representation of these data types is consistent with the one on which it was produced.

This is not as much of a problem as it might appear, since virtually all computers use two's complement notation for integers and almost all (the notable exception being older Digital and IBM machines) use the IEEE standard for floats and doubles.

The place where these difficulties is most noticable is between most Unix boxes (including Sun and SGI) and Intel-based PCs. Although shorts and ints have the same format, and both groups of machines adhere to the IEEE standard, PC's generally arrange the bytes of their data types in internet order, while most Unix boxes use the opposite ordering.

The RESCUE library provides explicit help in moving between these two groups of machines. If the compile-time variable _WINDOWS is defined, Extra.cpp (the module which performs all reading and writing for the Rescue library) will swap the byte order of shorts, ints, floats and doubles when reading from or writing to a binary file. The result is that binary files are compatible between these groups of machines.

There is generally a problem in moving between 32 and 64-bit computers in binary, since in virtually all 32 bit computers shorts will be 2 bytes, ints and floats 4 bytes, and doubles 8 bytes, while on 64 bit computers ints will generally be 8 bytes and shorts, floats and doubles generally have different lengths as well. RESCUE provides no support for this situation in binary mode.

Interconnectedness

The Rescue model is characterized by a high degree of interconnectedness. In a well-constructed model you can locate a node on the wireframe model and travel in various directions through the data all through the model. From the wireframe model you can step off at any point to a horizon or section surface. From there you can journey into the micro model of the RescueGeometry grid or to a connected wellbore. Each item is described as being connected to a large number of other items. To produce a useful model for others to use you must instantiate these relationships, so that the user of your model will be able to take advantage of the rich environment which Rescue provides.

The wireframe model

The Rescue modeling library contains a complete wireframe description of the whole model. The wireframe description is defined by some number of points in space, and the relationships between the points. These points are anchored spatially to an xyz location in the RescueModel's overall RescueCoordinateSystem.

The anchor points of this description are made of RescueTrimVertex objects. These objects have a relationship to some number of RescuePolyLines of which they form the end points. They also have a relationship to some number of RescueSurfaces (which are either RescueBlockUnitHorizonSurfaces or RescueSections) as well as a spatial index against the grids of these surfaces.

A RescuePolyLine runs between two RescueTrimVertexes. The poly line may have an additional set of RescuePolyLineNodes which further refine its shape if it is not straight in the area between the vertexes. RescuePolyLineNodes have the same relationships to surfaces that RescueTrimVertexes do (in fact, RescuePolyLineNode is the superclass of RescueTrimVertex) but they are guaranteed to lie on only one RescuePolyLine.

Because each point on the poly line has a separate list of surfaces it is related to, by traveling along a poly line you may encounter different surfaces as you go. This is handy when using a poly line to describe a boundary in a complex area, for example a poly line used as part of the trim loop for both a section and a surface.

In practice, RescuePolyLines are incorporated into RescueTrimEdge objects for use in the wireframe model. RescueTrimEdge objects have one additional piece of information, the direction of traversal. When the traversal direction is R_LEFT_TO_RIGHT, the RescuePolyLine should be traversed from its left vertex, to its zeroth poly line node, first poly line node, … nth poly line node, right vertex. When the traversal direction is R_RIGHT_TO_LEFT the line is traversed beginning with the right vertex, moving to the highest indexed poly line node down to the zeroth indexed poly line node, then the left vertex.

Groups of RescueTrimEdges which form a single loop are placed together into RescueTrimLoops. RescueTrimLoops which describe the same thing are placed into RescueEdgeSets, whose position in the model (as children of RescueMacroVolume and RescueBlockUnitSide) determines their meaning.

Sample programs

There are ten programs in the test suite. These programs instantiate all of the objects in Rescue and exercise most of the major options. Beyond that, none of the programs provides a truly useful consistent model. It is simply too time consuming to create models without tools, and I have none at my disposal (please don't volunteer any!).

There are some programs which create models…

There are some programs which read models…

archiveDB writes models from files to Oracle and back again. It also lists models currently in an Epicentre archive, and deletes models from an archive.

When studying the sample code, remember this adage…do as I say, not as I do.

cSet<Rescue Class>

The cSet classes are used to instantiate "owner" relationships from parent to child. All of the classes are the same. We avoid using templates because some compilers don't handle them well. These classes are never instantiated by the user, but they are often used to read items in an array.

/****************************************************************************

Copyright 1995 Petrotechnical Open Software Corporation

POSC grants permission to copy or reproduce this material in its original
form for internal use only.

This software is subject to the provision of the "POSC Software License
Agreement" which states in part:

1) Licensee accepts a non-exclusive, non-transferable, license  to use,
display, modify and distribute works derived from the licensed documentation
and Software Product.

2) Licensee shall have no right to distribute in its original form any
Software Product or documentation licensed under this agreement.

****************************************************************************/
/*************************************************************************

        cSetRescuePolyLine.h

  Keeps a list of pointers to some RescuePolyLine.

        Rod Hanks               January 18th, 1995   /  August 1996

****************************************************************************/

#ifndef cSetRescuePolyLine_H
#define cSetRescuePolyLine_H

#ifdef NO_BOOL
#ifndef bool
#define bool short
#define true 1
#define false 0
#endif
#endif
#include <stdlib.h>

class RescuePolyLine;

class cSetRescuePolyLine
{
protected:
  RescuePolyLine **objects;
  int allocated;
  int count;

public:
  cSetRescuePolyLine();
  ~cSetRescuePolyLine();
  void operator+=(RescuePolyLine *newObject);
  bool operator-=(RescuePolyLine *existingObject);
  bool operator-=(int ndx);
  RescuePolyLine *NthObject(int ordinal);
  RescuePolyLine *ObjectNamed(char *nameIn);
  RescuePolyLine *ObjectIdentifiedBy(int identifier);
  int Count(void);
  void EmptySelf(void);
  void Archive(FILE *archiveFile);
  void UnArchive(FILE *archiveFile);
  void Relink(RescueObject *parent);

  RescuePolyLine *PolyLineBetween(RescueTrimVertex *end1, RescueTrimVertex *end2);
#ifdef DB_HOOK
  void Archive(RescueModel *parentModel,
               char *earth_model_s, char *geoscience_ntrp_s,
               char *data_collection_s);
  void UnArchive(RescueModel *parentModel, char *earth_model_s, char *data_collection_s);
#endif
};

#endif

cBag<Rescue Class>

The cBag classes are used to instantiate "casual" relationships from parent to child. All of the classes are the same. We avoid using templates because some compilers don't handle them well. These classes are never instantiated by the user, but they are often used to read items in an array.

/****************************************************************************

Copyright 1995 Petrotechnical Open Software Corporation

POSC grants permission to copy or reproduce this material in its original
form for internal use only.

This software is subject to the provision of the "POSC Software License
Agreement" which states in part:

1) Licensee accepts a non-exclusive, non-transferable, license  to use,
display, modify and distribute works derived from the licensed documentation
and Software Product.

2) Licensee shall have no right to distribute in its original form any
Software Product or documentation licensed under this agreement.

****************************************************************************/
/*************************************************************************

        cBagRescuePolyLine.h

  Keeps a list of pointers to RescuePolyLine.

        Rod Hanks               December 15th, 1995   / August 1996

****************************************************************************/

#ifndef cBagRescuePolyLine_H
#define cBagRescuePolyLine_H

#ifdef NO_BOOL
#ifndef bool
#define bool short
#define true 1
#define false 0
#endif
#endif
class RescuePolyLine;

class cBagRescuePolyLine
{
protected:
  RescuePolyLine **objects;
  int allocated;
  int count;

public:
  cBagRescuePolyLine();
  ~cBagRescuePolyLine();
  void operator+=(RescuePolyLine *newObject);
  bool operator-=(RescuePolyLine *existingObject);
  RescuePolyLine *NthObject(int ordinal);
  int Count(void) {return count;}
};

#endif


RCH2DArray

An array with two dimensions used as a convienience to handle two dimensional arrays passed to and from Rescue objects. It is handy for RescueWellbore grids, coordinate poly lines in RescueGeometry, and other places.

This object has been customized for Rescue in two ways. First, it uses floats instead of doubles. Second, it keeps the array in Fortran order, i.e. i changes faster than j.

If you pass the array pointer to these objects in a constructor or AcceptValue method which copies the pointer to the array make sure you allocate the array for these objects yourself and pass them in the constructor. Otherwise both the RescueArray object and the RCH2DArray object will think they own the array, and both may attempt to free it.

/************************************************************************

  RCH2DArray.h

  A float array that can be allocated as a single array, but accessed via
  2 dimensions. Frees the array only if it created it.

  For RESCUE, the array has been switched from C to Fortran ordering.

  Rod Hanks   January, 1997

***********************************************************************/
#include "myHeaders.h"

class RCH2DArray
{
public:
  RCH2DArray(int maxI, int maxJ, float *values = 0);
  float &Ndx(int i, int j);
  float Value(int i, int j);
  float *Array() {return values;}
  ~RCH2DArray() {if (freeValues) delete values;}
private:
  int maxI;
  int maxJ;
  float *values;
  bool freeValues;
};



RCH3DArray

An array with 3 dimensions, used to handle three dimensional grids passed to and from the Rescue model. It is handy for coordinates of surfaces.

This object has been customized for Rescue in two ways. First, it uses floats instead of doubles. Second, it keeps the array in Fortran order, i.e. i changes faster than j which changes faster than k.

/************************************************************************

  RCH3DArray.h

  A float array that can be allocated as a single array, but accessed via
  3 dimensions. Frees the array only if it created it.

  For RESCUE, the array has been switched from C to Fortran ordering.

  Rod Hanks   January, 1997

***********************************************************************/
#include "myHeaders.h"

class RCH3DArray
{
public:
  RCH3DArray(int maxI, int maxJ, int maxK, float *values = 0);
  float &Ndx(int i, int j, int k);
  float Value(int i, int j, int k);
  float *Array() {return values;}
  ~RCH3DArray() {if (freeValues) delete values;}
private:
  int maxI;
  int maxJ;
  int maxK;
  float *values;
  bool freeValues;
};




RCHString

A simple string class. It is used for most alpha information in the library, including the individual objects in a cSetString.

/**************************************************************************

	RCHString.h

	A simple string class.

	Rod Hanks,	April 1996

**************************************************************************/

#ifndef RCHSTRING_H
#define RCHSTRING_H
#include <malloc.h<
#include <stdio.h>

#ifdef NO_BOOL
#define bool short
#define true 1
#define false 0
#endif

class istream;

class RCHString
{
  char *stringValue;
  unsigned int allocated;
  char *delimiters;
  char *pos;
  bool each;
  bool respectQuotes;

public:
  RCHString();
  RCHString(int length);
  RCHString(char *begin);
  ~RCHString();
  char *String() {return stringValue;}
  void Accept(char *value);
  void AddTo(RCHString &more);
  void AddTo(char *more);
  void AddTo(int more);
  void AddTo(double more);
  void Replace(RCHString &more);
  void Replace(char *replace);
  void Replace(int replace);
  void Replace(double more);
  RCHString &operator+=(char *more);
  RCHString &operator=(char *replace);
  RCHString &operator+=(RCHString &more);
  RCHString &operator=(RCHString &more);
  RCHString &operator+=(int more);
  RCHString &operator=(int replace);
  RCHString &operator+=(double more);
  RCHString &operator=(double replace);
  bool operator==(char *other);
  bool operator!=(char *other);
  bool operator==(RCHString &other);
  bool operator!=(RCHString &other);
  bool StartsWith(RCHString &other);
  bool StartsWith(char *other);
  bool EndsWith(RCHString &other);
  bool EndsWith(char *other);
  RCHString &operator<<(RCHString &more);
  RCHString &operator<<(char *more);
  RCHString &operator<<(int more);
  RCHString &operator<<(char more);
  RCHString &operator<<(double more);
  void tokenize(char *delimiters=0, bool eachIn=false, 
                                    bool respectQuotes=false);
  bool operator>>(char *buffer);
  bool operator>>(RCHString &buffer);
  int length();
  void doubleApostrophe();
};

#endif

RescueArray

An abstract superclass array object, used by RescueProperty and RescueWellboreProperty for property values. These objects construct one of the three subclasses of RescueArray, RescueArrayByte, RescueArrayShort, RescueArrayFloat, based upon the constructor used.

/********************************************************************

  RescueArray.h

  A dynamically sized array handler for N dimensional grids of
  floating points for RESCUE's data model. The related grid gives
  the dimensionality.

  This abstract superclass can be instantiated as one of it's subclasses.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEARRAY_H
#define RESCUEARRAY_H

#include "myHeaders.h"
#include "RCHString.h"
#include "RescueGrid.h"

class RescueArray:public RescueObject
{
public:
  RescueArray(char *propertyNameIn, 
              char *propertyTypeIn,
              char *unitOfMeasureIn,
              RescueGrid *existingGrid, 
              bool cellCenteredIn = false);
  ~RescueArray();
  RCHString *PropertyName() {return propertyName;}
  void SetPropertyName(char *newPropertyName) {(*propertyName) = newPropertyName;}
  RCHString *PropertyType() {return propertyType;}
                                    // Do NOT drop the objects returned.
  void SetPropertyType(char *newPropertyType) {(*propertyType) = newPropertyType;}
  RCHString *UnitOfMeasure() {return unitOfMeasure;}
                                    // Do NOT drop the object returned.
  void SetUnitOfMeasure(char *newUnitOfMeasure) {(*unitOfMeasure) = newUnitOfMeasure;}
  RescueGrid *Grid() {return grid;}
  bool CellCentered() {return cellCentered;}

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid()=0;          // Returns true if object appears
                                    // to be currently valid.
protected:
  RescueArray(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
private:
  void SetGrid(RescueGrid *newGrid) {grid = newGrid;}
protected:
  RCHString *propertyName;
  RCHString *propertyType;
  RCHString *unitOfMeasure;
  RescueGrid *grid;
  bool cellCentered;

  friend class RescueProperty;
  friend class RescueWellboreProperty;
};

#endif



RescueArrayByte

An array of 8 bit unsigned integers, used by RescueProperty and RescueWellboreProperty for property values. This class is used when the missing value argument to the constructor is of type unsigned char. You should use these constructors when the properties are defined by a RescueLookup which has 255 or fewer entries.

/********************************************************************

  RescueArrayByte.h

  A dynamically sized array handler for N dimensional grids of
  floating points for RESCUE's data model. The related grid gives
  the dimensionality.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RescueArrayByte_H
#define RescueArrayByte_H

#include "myHeaders.h"
#include "RescueArray.h"

class RescueLookup;

class RescueArrayByte:public RescueArray
{
public:
  ~RescueArrayByte() {free(value);}
  int NullValue() {return nullValue;}
  RescueLookup *LookupTable() {return lookupTable;}
  unsigned char *Value() {return value;}
                                    // Return copies of the contents.  
                                    // Do NOT delete returned objects.
  void SetValue(unsigned char nullValue, unsigned char *valueArray);
                                    // The array has the number of dimensions in
                                    // the grid.
                                    // The instance makes a copy of the array.
  void AcceptValue(unsigned char nullValue, unsigned char *valueArray);
                                    // Same as SetValue, except that the pointer
                                    // must have been created with new.  Instead
                                    // of copying the array the method copies the
                                    // pointer.  Do NOT delete the pointer after
                                    // passing it to the array.

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueArrayByte(char *propertyNameIn, 
              char *propertyTypeIn,
              char *unitOfMeasureIn,
              RescueGrid *existingGrid, 
              unsigned char nullValueIn,
              RescueLookup *lookupIn,
              bool cellCenteredIn = false, unsigned char *valueArray = 0)
              :RescueArray(propertyNameIn, propertyTypeIn, unitOfMeasureIn, existingGrid, cellCenteredIn)
              ,nullValue(nullValueIn)
              ,lookupTable(lookupIn)
              ,value(valueArray) {isA = R_RescueArrayByte;}
                                    // Create the array with or without the values.
                                    // The pointer must have been created with new.
                                    // The pointer is copied, not the data it
                                    // points to, so it becomes the property of this
                                    // object.
  RescueArrayByte(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
#ifdef DB_HOOK
  RescueArrayByte(char *propertyNameIn, 
              char *propertyTypeIn,
              char *unitOfMeasureIn,
              unsigned char nullValueIn,
              int lookupIdIn,
              bool cellCenteredIn = false, unsigned char *valueArray = 0)
              :RescueArray(propertyNameIn, propertyTypeIn, unitOfMeasureIn, 0, cellCenteredIn)
              ,nullValue(nullValueIn)
              ,lookupTable(0)
              ,lookupId(lookupIdIn)
              ,value(valueArray) {isA = R_RescueArrayByte;}
#endif
  unsigned char nullValue;
  unsigned char *value;
  RescueLookup *lookupTable;

  int lookupId;   // used only during relinking.

  friend class RescueProperty;
  friend class RescueWellboreProperty;
};

#endif



RescueArrayDouble

An array of doubles, formerly used by RescueProperty and RescueWellboreProperty for property values.

RescueArrayFloat is now used instead.

/********************************************************************

  RescueArrayDouble.h

  A dynamically sized array handler for N dimensional grids of
  floating points for RESCUE's data model. The related grid gives
  the dimensionality.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RescueArrayDouble_H
#define RescueArrayDouble_H

#include "myHeaders.h"
#include "RCHString.h"
#include "RescueGrid.h"
#include "RescueArray.h"

class RescueArrayDouble:public RescueArray
{
public:
  ~RescueArrayDouble() {free(value);}

  double NullValue() {return nullValue;}
  double *Value() {return value;}
                                    // Return copies of the contents.  
                                    // Do NOT delete returned objects.
  void SetValue(double nullValue, double *valueArray);
                                    // The array has the number of dimensions in
                                    // the grid.
                                    // The instance makes a copy of the array.
  void AcceptValue(double nullValue, double *valueArray);
                                    // Same as SetValue, except that the pointer
                                    // must have been created with new.  Instead
                                    // of copying the array the method copies the
                                    // pointer.  Do NOT delete the pointer after
                                    // passing it to the array.

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueArrayDouble(char *propertyNameIn, 
              char *propertyTypeIn,
              char *unitOfMeasureIn,
              RescueGrid *existingGrid, double nullValueIn, 
              bool cellCenteredIn = false, double *valueArray = 0)
              :RescueArray(propertyNameIn, propertyTypeIn, unitOfMeasureIn, existingGrid, cellCenteredIn)
              ,nullValue(nullValueIn)
              ,value(valueArray) {isA = R_RescueArrayDouble;}
                                    // Create the array with or without the values.
                                    // The pointer must have been created with new.
                                    // The pointer is copied, not the data it
                                    // points to, so it becomes the property of this
                                    // object.
  RescueArrayDouble(FILE *archiveFile);
  void Archive(FILE *archiveFile);

  double nullValue;
  double *value;

  friend class RescueProperty;
  friend class RescueWellboreProperty;
};

#endif



RescueArrayFloat

An array of floats, used by RescueProperty and RescueWellboreProperty for property values.

/********************************************************************

  RescueArrayFloat.h

  A dynamically sized array handler for N dimensional grids of
  floating points for RESCUE's data model. The related grid gives
  the dimensionality.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RescueArrayFloat_H
#define RescueArrayFloat_H

#include "myHeaders.h"
#include "RCHString.h"
#include "RescueGrid.h"
#include "RescueArray.h"

class RescueArrayFloat:public RescueArray
{
public:
  ~RescueArrayFloat() {free(value);}

  float NullValue() {return nullValue;}
  float *Value() {return value;}
                                    // Return copies of the contents.  
                                    // Do NOT delete returned objects.
  void SetValue(float nullValue, float *valueArray);
                                    // The array has the number of dimensions in
                                    // the grid.
                                    // The instance makes a copy of the array.
  void AcceptValue(float nullValue, float *valueArray);
                                    // Same as SetValue, except that the pointer
                                    // must have been created with new.  Instead
                                    // of copying the array the method copies the
                                    // pointer.  Do NOT delete the pointer after
                                    // passing it to the array.

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueArrayFloat(char *propertyNameIn, 
              char *propertyTypeIn,
              char *unitOfMeasureIn,
              RescueGrid *existingGrid, float nullValueIn, 
              bool cellCenteredIn = false, float *valueArray = 0)
              :RescueArray(propertyNameIn, propertyTypeIn, unitOfMeasureIn, existingGrid, cellCenteredIn)
              ,nullValue(nullValueIn)
              ,value(valueArray) {isA = R_RescueArrayFloat;}
                                    // Create the array with or without the values.
                                    // The pointer must have been created with new.
                                    // The pointer is copied, not the data it
                                    // points to, so it becomes the property of this
                                    // object.
  RescueArrayFloat(FILE *archiveFile);
  void Archive(FILE *archiveFile);

  float nullValue;
  float *value;

  friend class RescueProperty;
  friend class RescueWellboreProperty;
};

#endif



RescueArrayShort

An array of unsigned short integers, used by RescueProperty and RescueWellboreProperty for property values. This class is used when the missing value argument to the constructor is of type unsigned short. You should use these constructors when the properties are defined by a RescueLookup which has more than 255 entries.

/********************************************************************

  RescueArrayShort.h

  A dynamically sized array handler for N dimensional grids of
  floating points for RESCUE's data model. The related grid gives
  the dimensionality.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RescueArrayShort_H
#define RescueArrayShort_H

#include "myHeaders.h"
#include "RescueArray.h"
#include "RescueLookup.h"

class RescueArrayShort:public RescueArray
{
public:
  ~RescueArrayShort() {free(value);}
  int NullValue() {return nullValue;}
  RescueLookup *LookupTable() {return lookupTable;}
  unsigned short *Value() {return value;}
                                    // Return copies of the contents.  
                                    // Do NOT delete returned objects.
  void SetValue(unsigned short nullValue, unsigned short *valueArray);
                                    // The array has the number of dimensions in
                                    // the grid.
                                    // The instance makes a copy of the array.
  void AcceptValue(unsigned short nullValue, unsigned short *valueArray);
                                    // Same as SetValue, except that the pointer
                                    // must have been created with new.  Instead
                                    // of copying the array the method copies the
                                    // pointer.  Do NOT delete the pointer after
                                    // passing it to the array.

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueArrayShort(char *propertyNameIn, 
                    char *propertyTypeIn,
                    char *unitOfMeasureIn,
                    RescueGrid *existingGrid, 
                    unsigned short nullValueIn,
                    RescueLookup *lookupIn,
                    bool cellCenteredIn = false, unsigned short *valueArray = 0)
                    :RescueArray(propertyNameIn, propertyTypeIn, unitOfMeasureIn, existingGrid, cellCenteredIn)
                    ,nullValue(nullValueIn)
                    ,lookupTable(lookupIn)
                    ,value(valueArray) {isA = R_RescueArrayShort;}
                                    // Create the array with or without the values.
                                    // The pointer must have been created with new.
                                    // The pointer is copied, not the data it
                                    // points to, so it becomes the property of this
                                    // object.
  RescueArrayShort(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
#ifdef DB_HOOK
  RescueArrayShort(char *propertyNameIn, 
              char *propertyTypeIn,
              char *unitOfMeasureIn,
              unsigned short nullValueIn,
              int lookupIdIn,
              bool cellCenteredIn = false, unsigned short *valueArray = 0)
              :RescueArray(propertyNameIn, propertyTypeIn, unitOfMeasureIn, 0, cellCenteredIn)
              ,nullValue(nullValueIn)
              ,lookupTable(0)
              ,lookupId(lookupIdIn)
              ,value(valueArray) {isA = R_RescueArrayShort;}
#endif
  unsigned short nullValue;
  unsigned short *value;
  RescueLookup *lookupTable;

  int lookupId;   // used only during relinking.

  friend class RescueProperty;
  friend class RescueWellboreProperty;
};

#endif



RescueBlock

A block is a business object. It consists of an area which extends from the top to the bottom of the model. It is bounded either by faults or by artificial surfaces such as lease boundaries. Each model must have at least one block.

 RescueBlock *block1 = new RescueBlock("Block 1", model);

A block has a relationship to one or more RescueBlockUnits.

/********************************************************************

  RescueBlock.h

  The block object for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEBLOCK_H
#define RESCUEBLOCK_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
#include "RCHString.h"
#include "RescueBlockUnit.h"
#include "cSetRescueBlockUnit.h"
class RescueModel;
class RescueUnit;

class RescueBlock:public RescueObject
{
public:
  RescueBlock(char *newBlockName, RescueModel *newBlockParent);
                              // Create a new block.
                              // To dispose a block, use
                              // block->ParentModel()->DropRescueBlock(block);
  ~RescueBlock();
  RCHString *BlockName() {return blockName;}
                              // Do NOT delete the returned object.
  void SetBlockName(char *newBlockName) {(*blockName) = newBlockName;}
  RescueModel *ParentModel() {return parentModel;}

  int BlockUnitCount() {return blockUnits->Count();}

  RescueBlockUnit *NthRescueBlockUnit(int zeroBasedOrdinal) 
                              {return blockUnits->NthObject(zeroBasedOrdinal);}
  RescueBlockUnit *BlockUnitIdentifiedBy(int identifier) 
                           {return blockUnits->ObjectIdentifiedBy(identifier);}
  RescueBlockUnit *BlockUnitForUnit(RescueUnit *unitToFind);
                                    // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.
  bool DropBlockUnit(RescueBlockUnit *blockUnitToDrop) 
                         {return  ((*blockUnits) -= blockUnitToDrop);}
                                    // Mustn't drop an owned object directly.
                                    // Use the owner's drop method instead.
                                    // These return false if the object passed
                                    // is not a member of the set (and in that
                                    // case the object IS NOT dropped.
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();      // Returns true if object appears
          // to be currently valid.
private:
  RescueBlock(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
#ifdef DB_HOOK
  void Archive(RescueModel *parentModel, char *earth_model_s, 
                           char *data_collection_s, char *local_data_collection_s,
                           RescueBlock *previousBlock, char *geoscience_ntrp_s);
  void ArchiveGroups(char *data_collection_s, char *geoscience_ntrp_s);
  RescueBlock(RescueModel *parentModel, char *unit_s, char *data_collection_s,
              char *parent_model_s, char *coordinate_sys_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
  int PreviousId() {return previousId;}
#endif

  RCHString *blockName;
  RescueModel *parentModel;
  cSetRescueBlockUnit *blockUnits;

#ifdef DB_HOOK
  char surrogateKey[20];
  int previousId;
#endif

  friend class RescueBlockUnit;
  friend class cSetRescueBlock;
};

#endif



RescueBlockUnit

A rescue block unit is the part of a RescueBlock which is contained between the RescueHorizons of some RescueUnit. Each model must have at least one block unit. In many ways, the block unit is the central object of the model.

Block units may represent very complicated volumes. The representation should be kept as simple as possible to make it easier for readers. For complex geometries such as toroids, the preferred solution is to pinch out horizons.

A block unit contains a single block unit grid, termed the micro model, which devides the volume within the block unit into cells. The macro model description of this volume includes the RescueBlockUnitHorizonSurfaces which form the top and bottom of the volume and one or more RescueMacroVolume descriptions, which include RescueSections which form the sides of the volume as well as various elements of the wire frame model to tie the sections and surfaces together.

For situations where a RescueBlockUnit contains more than one volume (as in the drawing above), the writer may create new volumes by using RescueBlockUnit->AddMacroVolume(). The new volume is then populated with block unit sides, interior sections, top and bottom trims, and k layer trims which apply to that volume only.

A RescueBlockUnit is guaranteed to have at least one RescueMacroVolume. Therefore a statement in the form

rescueBlockUnit->NthMacroVolume(0)
will always be valid if rescueBlockUnit is a pointer to a valid RescueBlockUnit.

  RescueBlockUnit*blockUnit = new RescueBlockUnit(RescueCoordinateSystem::LDF, 
                                              block1, unit1, 
                                             0.0, 9.0, 0, 3, 
                                             0.0, 8.5, 0, 3, 
                                             0, 6, -9999.00, 
                                             0.0); 

A block unit has an integral three-dimensional grid which is the heart of the micro-model. This special RescueGeometry grid is discussed in detail elsewhere. The constructor above is for normal grids. Two other forms of grids are available.

Proportional grids, shown being constructed below, have two RescueReferenceSurfaces and two offsets. These reference surfaces may be the same as the RescueBlockUnitHorizonSurfaces which form the top and bottom of the block unit. If so, the offset will generally be 0. The reference surfaces may be RescueReferenceSurface objects constructed especially for this purpose or a RescueBlockUnitHorizonSurface constructed for use with another unit. These surfaces are more likely to have an offset. In parts of the grid where no further information is given the k layer boundaries will be constructed so that the top layer boundary follows the top surface at a distance of the top offset, the bottom layer boundary follows the bottom surface at a distance of the bottom offset, and other k layers are sized to fit between these two surfaces. Offsets are always positive values. All k layers will be the same thickness at any given point.

Reference surfaces used must have at least as many nodes in the i and j boundaries as the block unit grid, and also should have the same rotation degrees about the same point in space.

  RescueBlockUnit* blockUnit = new RescueBlockUnit(RescueCoordinateSystem::LDF, block1, unit1,
                                               0.0, 9.0, 0, 3,
                                               0.0, 8.5, 0, 3,
                                               0, 6, -9999.00,
                                               topSurface, 4.0, bottomSurface, 0.0,
                                               0.0);

Referential grids, shown being constructed below, have a single reference surface, an offset, a thickness, and an onlap/offlap flag. The shape of the grid follows the surface at the distance given by the offset. The reference surface may be one of the RescueBlockUnitHorizonSurfaces which form the top and bottom of the grid, but need not be. Offset and thickness are always zero or a positive value.

  RescueBlockUnit* blockUnit = new RescueBlockUnit(RescueCoordinateSystem::LDF, block1, unit1,
                                               0.0, 9.0, 0, 3,
                                               0.0, 8.5, 0, 3,
                                               0, 6, -9999.00,
                                               topSurface, 5.0, 1.2, RescueGeometry::R_ONLAP,
                                               0.0);

In order to allow the grid to be at least partly a regular orthogonal grid, each block unit may have its own coordinate system. This coordinate system is created by applying a rotation to the global coordinate system defined for the model as a whole. This rotation is given in degrees, from positive x toward positive y. When grids are rotated, a RescueVertex is used to define the point about which rotation occurs.

There is an explicit relationship between ijk in the grid's indexing system and xyz in the coordinate system's axes, i.e. the first axis of the grid relates to the first axis of the coordinate system, etc.

The counts in the constructor are for nodes, not cells.

Besides housekeeping relationships to RescueBlock and RescueUnit, a block unit has a relationship to the RescueBlockUnitHorizonSurface which lies above it and the one which lies below it. The RescueBlockUnitHorizonSurface defined above the block unit must have a relationship to the RescueHorizon defined above the RescueUnit, and the one which lies below the block unit must be related to the RescueHorizon which lies below the RescueUnit.

The RescueBlockUnit is a major player in the property model through its relationship to RescueBlockUnitPropertyGroup.

/********************************************************************

  RescueBlockUnit.h

  block unit for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEBLOCKUNIT_H
#define RESCUEBLOCKUNIT_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
#include "RescueGrid.h"
#include "RescueBlockUnitSide.h"
#include "cSetRescueBlockUnitSide.h"
#include "cBagInt.h"
#include "cBagRescueBlockUnitPropertyGroup.h"
#include "cBagRescueSection.h"
#include "cSetRescueEdgeSet.h"
#include "RescueCoordinateSystem.h"
#include "RescueGeometry.h"
#include "cSetRescueMacroVolume.h"

class RescueUnit;
class RescueBlock;
class RescueSection;
class RescueBlockUnitHorizonSurface;
class RescueBlockUnitPropertyGroup;
class RescueReferenceSurface;
class RescueMacroVolume;

class RescueBlockUnit:public RescueObject
{
public:
  RescueBlockUnit(RescueCoordinateSystem::Orientation orientation,
                  RescueBlock *parentBlock,
                  RescueUnit *parentUnit,
                  float i_origin, float i_step,
                  int i_lowbound, int i_count,
                  float j_origin, float j_step,
                  int j_lowbound, int j_count,
                  int k_lowbound, int k_count,
                  float missingValue,
                  float rotation, RescueVertex *vertex = 0);
  RescueBlockUnit(RescueCoordinateSystem::Orientation orientation,
                  RescueBlock *parentBlock,
                  RescueUnit *parentUnit,
                  float i_origin, float i_step,
                  int i_lowbound, int i_count,
                  float j_origin, float j_step,
                  int j_lowbound, int j_count,
                  int k_lowbound, int k_count,
                  float missingValue,
                  RescueReferenceSurface *topSurfaceIn, float topOffsetIn,
                  RescueReferenceSurface *bottomSurfaceIn, float  bottomOffsetIn,
                  float rotation, RescueVertex *vertex = 0);
                                            // Constructor for a grid whose z values are 
                                            // determined by the reference surfaces and offsets.
                                            // Each k-layer is proportional to the distance between
                                            // the top and bottom reference surfaces, after the
                                            // offsets are applied. This applies only to vertexes
                                            // of type R_EQUAL_AXIS.
  RescueBlockUnit(RescueCoordinateSystem::Orientation orientation,
                  RescueBlock *parentBlock,
                  RescueUnit *parentUnit,
                  float i_origin, float i_step,
                  int i_lowbound, int i_count,
                  float j_origin, float j_step,
                  int j_lowbound, int j_count,
                  int k_lowbound, int k_count,
                  float missingValue,
                  RescueReferenceSurface *referenceSurfaceIn, float referenceOffsetIn, 
                  float thicknessIn, RescueGeometry::RescueLapType onOffLapIn,
                  float rotation, RescueVertex *vertex = 0);
                                            // Constructor for a grid whose z values are 
                                            // determined by the reference surface and offset.
                                            // Each k-layer is of the same thickness, determined
                                            // by the thickness argument. This applies only to vertexes
                                            // of type R_EQUAL_AXIS.
  ~RescueBlockUnit();

  RescueUnit *Unit() {return unit;}
  RescueBlock *Block() {return block;}
  RescueBlockUnitHorizonSurface *SurfaceAboveMe() {return surfaceAboveMe;}
  RescueBlockUnitHorizonSurface *SurfaceBelowMe() {return surfaceBelowMe;}

  void SetSurfaceAboveMe(RescueBlockUnitHorizonSurface *existingSurface)
                                      {surfaceAboveMe = existingSurface;}
  void SetSurfaceBelowMe(RescueBlockUnitHorizonSurface *existingSurface)
                                      {surfaceBelowMe = existingSurface;}

  RescueMacroVolume *AddMacroVolume();
  void DropMacroVolume(RescueMacroVolume *existingVolume);
  RescueMacroVolume *NthMacroVolume(int zeroBasedOrdinal)
                        {return (*macroVolumes).NthObject(zeroBasedOrdinal);}

  void AddBlockUnitPropertyGroup(RescueBlockUnitPropertyGroup *existingBlockUnitPropertyGroup)
              {(*blockUnitPropertyGroups) += existingBlockUnitPropertyGroup;} 
  bool DeleteBlockUnitPropertyGroup(RescueBlockUnitPropertyGroup *existingBlockUnitPropertyGroup)
      {return ((*blockUnitPropertyGroups) -= existingBlockUnitPropertyGroup);}
  RescueBlockUnitPropertyGroup *NthBlockUnitPropertyGroup(int zeroBasedOrdinal)
  {return (RescueBlockUnitPropertyGroup *) (*blockUnitPropertyGroups).NthObject(zeroBasedOrdinal);}
                  // RescueBlockUnit does not "own" RescueBlockUnitPropertyGroups,
                  // so it does not create or delete them, merely
                  // catalogs relationships to them.

  RescueGrid *BlockUnitGrid() {return blockUnitGrid;}
  RescueGeometry *GridGeometry() {return gridGeometry;}
  
  int  CountOfBlockUnitPropertyGroup() {return (*blockUnitPropertyGroups).Count();}
  int  CountOfVolumes() { return  (*macroVolumes).Count(); }

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueBlockUnit(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
#ifdef DB_HOOK
  void Archive(char *parent_model_s, char *data_collection_s, char *geoscience_ntrp_s);
  void ArchiveGroups(char *data_collection_s, char *geoscience_ntrp_s);
  RescueBlockUnit(RescueModel *parentModel, char *blockUnit_s, int blockIDIn,
                  char *data_collection_s, char *parent_model_s, char *coordinate_sys_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
  int PreviousId() {return previousId;}
#endif

  RescueBlock *block;
  RescueUnit *unit;
  RescueBlockUnitHorizonSurface *surfaceAboveMe;
  RescueBlockUnitHorizonSurface *surfaceBelowMe;
  cSetRescueMacroVolume *macroVolumes;
  cBagRescueBlockUnitPropertyGroup *blockUnitPropertyGroups;
  RescueGrid *blockUnitGrid;     // shared by the geometry and all properties.
  RescueGeometry *gridGeometry;
  int blockID;
  int unitID;
  int surfaceAboveMeID;
  int surfaceBelowMeID;
  cBagInt *blockUnitPropertyGroupsID;
#ifdef DB_HOOK
  char surrogateKey[20];
  int previousId;
#endif
  friend class cSetRescueBlockUnit;
  friend class RescueBlock;
  friend class RescueGrid;
  friend class RescueBlockUnitHorizonSurface;
};

#endif



RescueBlockUnitHorizonSurface

A subclass of RescueReferenceSurface, this object is a surface description for the bounding surface (top or bottom) of a block unit. If two block units share the surface (one being above and the other below it) the surface is described only once and referenced by each block unit. The object has a relationship to the RescueHorizon of which it is a member and to the RescueBlockUnit above and below it.

  RescueBlockUnitHorizonSurface *top = new
           RescueBlockUnitHorizonSurface(RescueCoordinateSystem::LDF,
                                                horizon2,                                         
                                                0.0 + (300.0* blockLoop),                                                
                                                100.0, 0, 4,                                         
                                                0.0,
                                                100.0, 0, 4,                                         
                                                0.0, -9999.99);
  top->Geometry()->SetZValue((double *) horizonGeometry);top->SetBlockUnitBelowMe(topU);

The constructors are setup to create orthogonal grids whose x and y values are determined by the origin and step of the zeroth and first axes. You can choose to pass 0 for origin and step and supply x and y coordinates using RescueTripletArray SetXValue and SetYValue methods.

Like a block RescueBlockUnit, the class contains a rotation, meaning it has its own coordinate system.

The surface description is trimmed against the block unit volumes which may exist above and/or below the surface by the top and bottom RescueEdgeSet in the RescueMacroVolumes which belong to the RescueBlockUnits above and below the surface.

Because horizon surfaces may be extended beyond the block units to which they belong, readers should find horizons associated with block units only by using the RescueBlockUnit SurfaceAboveMe and SurfaceBelowMe methods.

The proximity of block unit grid cells to this surface is recorded via RescueSurfaceCell instances, which are maintained via the RescueGeometry interface.

/********************************************************************

  RescueBlockUnitHorizonSurface.h

  Holds the horizon which bounds a particular block unit
  for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEBLOCKUNITHORIZONSURFACE_H
#define RESCUEBLOCKUNITHORIZONSURFACE_H

#include "myHeaders.h"
#include "RescueReferenceSurface.h"
#include "RescueEdgeSet.h"
class RescueHorizon;
class RescueBlockUnit;

class RescueBlockUnitHorizonSurface:public RescueReferenceSurface
{
public:
  RescueBlockUnitHorizonSurface(RescueCoordinateSystem::Orientation orientation,
                                RescueHorizon *parentHorizon,
                                float i_origin, float i_step,
                                int i_lowbound, int i_count,
                                float j_origin, float j_step,
                                int j_lowbound, int j_count,
                                float missingValue,
                                float rotation, RescueVertex *vertex = 0);
  RescueBlockUnitHorizonSurface(RescueCoordinateSystem::Orientation orientation,
                                RescueHorizon *parentHorizon,
                                float i_origin, float i_step,
                                int i_lowbound, int i_count,
                                float j_origin, float j_step,
                                int j_lowbound, int j_count,
                                float missingValue,
                                float rotation, RescueVertex *vertex,
                                float *valueTriplets);
  RescueHorizon *ParentHorizon() {return parentHorizon;}
  RescueBlockUnit *BlockUnitAboveMe() {return unitAboveMe;}
  RescueBlockUnit *BlockUnitBelowMe() {return unitBelowMe;}

  void SetBlockUnitAboveMe(RescueBlockUnit *existingUnit)
                                      {unitAboveMe = existingUnit;}
  void SetBlockUnitBelowMe(RescueBlockUnit *existingUnit)
                                      {unitBelowMe = existingUnit;}
  
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueBlockUnitHorizonSurface(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  void Relink(RescueObject *parentObject);

#ifdef DB_HOOK
  void Archive(RescueModel *parentModel,
               char *parent_model_s,
               char *geoscience_ntrp_s,
               char *data_collection_s);
  RescueBlockUnitHorizonSurface(char *earth_pos_face_s,
                                RescueCoordinateSystem *coordinateSystemIn,
                                char *parent_model_s, 
                                char *data_collection_s, 
                                char *coordinate_sys_s);
#endif

  RescueHorizon *parentHorizon;
  RescueBlockUnit *unitAboveMe;
  RescueBlockUnit *unitBelowMe;


  int unitAboveID;  // Used only during relinking.
  int unitBelowID;
  RescueEdgeSet *edges;  // Used only when reading a version 4 or 5 file.

  friend class cSetRescueBlockUnitHorizonSurface;
  friend class RescueHorizon;
  friend class RescueBlockUnit;
};

#endif


RescueBlockUnitPropertyGroup

Properties attached to a RescueBlockUnit grid are gathered into named groups. This class has a pointer to the RescueUnit and RescueBlockUnit objects for which it holds properties, and a set of RescueProperty objects to hold the actual values.

  RescueBlockUnitPropertyGroup *group          
               = new RescueBlockUnitPropertyGroup(groupName[groupLoop],
                                                        blockUnit); 

/********************************************************************

  RescueBlockUnitPropertyGroup.h

  block unit for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEBLOCKUNITPROPERTYGROUP_H
#define RESCUEBLOCKUNITPROPERTYGROUP_H

#include "myHeaders.h"
#include "RescueProperty.h"
#include "RCHString.h"
class RescueUnit;
class RescueBlockUnit;
#include "cSetRescueProperty.h"

class RescueBlockUnitPropertyGroup:public RescueObject
{
public:
  RescueBlockUnitPropertyGroup(char *groupNameIn,
                               RescueBlockUnit *blockUnitIn);
  ~RescueBlockUnitPropertyGroup();
  RCHString *GroupName() {return groupName;}
                              // Do NOT delete the returned object.
  void SetGroupName(char *newGroupName);
  RescueUnit *ParentUnit() {return unit;}
  RescueBlockUnit *ParentBlockUnit() {return blockUnit;}

  int RescuePropertyCount() {return properties->Count();}
  RescueProperty *NthRescueProperty(int zeroBasedOrdinal) 
                  {return properties->NthObject(zeroBasedOrdinal);}
                                    // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.
  bool DropRescueProperty(RescueProperty *unitToDrop) 
                          {return ((*properties) -= unitToDrop);}

  virtual bool IsOfType(_RescueObjectType thisType);
					// Returns true if the object is a
					// member of the specified class.
  virtual bool IsValid();  		    // Returns true if object appears
					                        // to be currently valid.
private:
  virtual void Archive(FILE *archiveFile);
  RescueBlockUnitPropertyGroup(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);

  RCHString *groupName;
  RescueUnit *unit;
  RescueBlockUnit *blockUnit;
  cSetRescueProperty *properties;

  int blockUnitID;   // used only during relinking.

  friend class RescueProperty;
  friend class cSetRescueBlockUnitPropertyGroup;
};

#endif

RescueBlockUnitSide

A block unit side describes a particular side of one particular RescueMacroVolume of one particular block unit. It contains a reference to one RescueSection which defines its boundaries. If two block units are coincident along a particular surface, each block unit has its own block unit side, although those block unit sides probably reference the same section. The block unit side's RescueEdgeSet boundary edges are used to trim the surface of the boundary section against the surface of the macro volume, with counter-clockwise trim loops, as seen from outside the volume which they enclose. The block unit side's RescueEdgeSet interior edges may also be used to provide additional information about any faults which may touch or break the surface in the area of the block unit side.

        RescueBlockUnitSide *blockUnitSide = new RescueBlockUnitSide(section);
        blockUnit->NthMacroVolume(0)->AddBlockUnitSide(blockUnitSide);

The RescueSection which is named in the RescueBlockUnitSide should also be indexed to the RescueGeometry of the RescueBlockUnit via RescueSurfaceCell intersections.

/********************************************************************

  RescueBlockUnitSide.h

  The side of a block unit, described by a relationship to a section
  and a set of trim edges on that section.

  Rod Hanks,  July 1996

*********************************************************************/
#ifndef RESCUEBLOCKUNITSIDE_H
#define RESCUEBLOCKUNITSIDE_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
#include "RescueEdgeSet.h"
#include "RescueSection.h"

class RescueBlockUnitSide:public RescueObject
{
public:
  RescueBlockUnitSide(RescueSection *existingSection);
  ~RescueBlockUnitSide();

  RescueSection *Section() {return section;}
  RescueEdgeSet *Edges() {return edges;}

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
protected:
  virtual void Archive(FILE *archiveFile);
  RescueBlockUnitSide(FILE *archiveFile);
  virtual void Relink(RescueObject *object); // Pass RescueModel.
#ifdef DB_HOOK
  void Archive(char *data_collection_s, char *geoscience_ntrp_s);
  RescueBlockUnitSide(char *blockUnitSide_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
  int PreviousId() {return previousId;}
#endif

private:
  RescueSection *section;   
  RescueEdgeSet *edges;           //Interior edges are used to define the
                                  //intersection of the sections.
#ifdef DB_HOOK
  char surrogateKey[20];
  int previousId;
#endif

  int sectionID;           // Used only during relinking.
  friend class RescueBlock;
  friend class cSetRescueBlockUnitSide;
};

#endif


RescueCoordinateLine

This class is used by RescueGeometry to store vertex geometries defined by a straight line from top to bottom and a set of points on that line. The class is not directly instantiated or accessed by the user.

RescueCoordinatePolyLine

This class is used by RescueGeometry to store vertex geometries defined by a polyline, a set of points running from top to bottom in the grid, with an xyz triplet at each k layer. The class is not directly instantiated or accessed by the user.

RescueCoordinateSystem

A three dimensional coordinate system. It contains three RescueCoordinateSystemAxis objects and defines their orientation. This class is used to define the orientation enumeration used for both coordinate systems and grids.

  RescueCoordinateSystem *penUltimateCs = new
    RescueCoordinateSystem("penultimate cs", RescueCoordinateSystem::LDF, modelVertex,
                                     "northing", "m",
                                     "easting", "m",
                                     "elevation", "m");

A RescueModel has a single over-all coordinate system, in which the wireframe model and most other objects are defined. Gridded objects may have a defined rotation. If so, coordinates within those objects are based upon a coordinate system which is transformed from the RescueModel one. The rotation is given as degrees from positive x toward positive y.

Most often, the over-all coordinate system will be a local coordinate system. It will be defined by a vertex which is given in some well-known coordinate system (such as a UTM or state plane coordinate system as defined by POSC)

A RescueCoordinateSystem may have a relationship to a RescueVertex, which is a point defined in another RescueCoordinateSystem, used as the origin for this system. The intent is to allow a fuller description of coordinate systems when a local coordinate system is used, for example by defining the origin of a local coordinate system as a point defined in some lat/long system.

The last twelve variables in the constructor are all optional. They would ordinarily be used for the well-known coordinate system, but not for the local coordinate system. They are used to provide enough information about the coordinate system to allow it to be projected or converted to another coordinate system by a reader. The style and content of these twelve variables have been modeled after the USGS General Cartographic Transformation Package (GCTP).

insys Input projection system as follows
  • 0 - Geographic
  • 1 - Universal Transverse Mercator
  • 2 - State Plane Coordinates
  • 3 - Albers Conical Equal-area
  • 4 - Lambert Conformal Conic
  • 5 - Mercator
  • 6 - Polar Stereographic
  • 7 - Polyconic
  • 8 - Equidistant Conic
  • 9 - Transverse Mercator
  • 10 - Stereographic
  • 11 - Lambert Azimuthal Equal-area
  • 12 - Azimuthal Equidistant
  • 13 - Gnomonic
  • 14 - Orthographic
  • 15 - General Vertical
  • 16 - Sinusoidal
  • 17 - Equirectangular
  • 18 - Miller Cylindrical
  • 19 - Van der Grinten
  • 20 - Oblique Mercator
  • 21 - Robinson
  • 22 - Space Oblique Mercator
  • 23 - Modified Stereographic Conformal (Alaska)
inzone Zone code number for UTM (insys==1), and state plane (insys==2), otherwise 0.
inunit
  • 0 - radians
  • 1 - U.S. feet
  • 2 - meters
  • 3 - seconds of arc
  • 4 - degrees of arc
  • 5 - International feet
  • 6 - Unit legislated for selected state zone
insph
  • 0 - Clarke 1866
  • 1 - Clarke 1880
  • 2 - Bessel
  • 3 - New International 1967
  • 4 - International 1909
  • 5 - WGS 72
  • 6 - Everest
  • 7 - WGS 66
  • 8 - GRS 1960
  • 9 - Airy
  • 10 - Modified Everest
  • 11 - Modified Airy
  • 12 - WGS 84
  • 13 - Southeast Asia
  • 14 - Australian National
  • 15 - Krassovsky
  • 16 - Hough
  • 17 - Mercury 1960
  • 18 - Modified Mercury 1968
  • 19 - Normal Sphere
semiMajorAxis Semi-major axis of spheroid
eccentricity Eccentricity squared or semi-minor axis of spheroid
standardLat Latitude of standard parallel or latitude of first parallel
secondLat Latitude of second parallel or unused
centralLong Longitude at central meridian
latOrigin Latitude projection origin
falseEasting False easting applied to all coordinates, always in meters
falseNorthing False northing applied to all coordinates, always in meters

/********************************************************************

  RescueCoordinateSystem.h

  Coordinate system for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUECOORDINATESYSTEM_H
#define RESCUECOORDINATESYSTEM_H

#include "myHeaders.h"
#include "RescueCoordinateSystemAxis.h"
class RescueVertex;
class RescueUnit;

class RescueCoordinateSystem:public RescueObject
{
public:
  typedef enum {LUF, LUB, LDF, LDB, RUF, RUB, RDF, RDB} Orientation;

/*
  The displayOrientation shows which corner the origin is located on: 

    Key:  Left/Right
          Up/Down
          Front/Back
*/
  RescueCoordinateSystem(char *name,
                         Orientation displayOrientationIn,
                         RescueVertex *vertexIn,
                         char *Xproperty, char *Xuom,
                         char *Yproperty, char *Yuom,
                         char *Zproperty, char *Zuom,
                         int insysIn = 0,
                         int inzoneIn = 0,
                         int inUnitIn = 0,
                         int insphIn = 0,
                         double semiMajorAxisIn = 0.0,
                         double eccentricityIn = 0.0,
                         double standardLatIn = 0.0,
                         double secondLatIn = 0.0,
                         double centralLongIn = 0.0,
                         double latOriginIn = 0.0,
                         double falseEastingIn = 0.0,
                         double falseNorthingIn = 0.0);
  int Dimensions() {return 3;}
  RescueCoordinateSystemAxis *Axis(int zeroBasedOrdinal);
  RescueCoordinateSystemAxis *AxisIdentifiedBy(int identifier);
  RescueVertex *Vertex() {return vertex;}
                                  // Do NOT free the object passed.
  void SetVertex(RescueVertex *newVertex);

  RCHString *Name() {return coordinateSystemName;}
                              // Do NOT delete the returned object.
  Orientation OrientationIs() {return displayOrientation;}
  int InSys() {return insys;}
  int InZone() {return inzone;}
  int InUnit() {return inUnit;}
  int InSpheroid() {return insph;}
  double SemiMajorAxis() {return semiMajorAxis;}
  double EccentricityOrSemiMinorAxis() {return eccentricity;}
  double StandardLat() {return standardLat;}
  double SecondLat() {return secondLat;}
  double CentralLong() {return centralLong;}
  double LatOrigin() {return latOrigin;}
  double FalseEasting() {return falseEasting;}
  double FalseNorthing() {return falseNorthing;}

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
  ~RescueCoordinateSystem();
                                  // The Coordinate system "owns" the
                                  // the vertex.  Since a vertex also
                                  // "owns" its coordinate system, you
                                  // can make the whole thing go away
                                  // by deleting the coordinate system
                                  // at the top of the chain.
private:
  RescueCoordinateSystem(FILE *archiveFile);
  void Archive(FILE *archiveFile);
#ifdef DB_HOOK
  void Archive(bool mainCsFlag,
               RescueUnit *unit, char *parent_model_s, char *geoscience_ntrp_s,
               char *data_collection_s);
  RescueCoordinateSystem(char *data_collection_s, RCHString *csBuf);  // used by RescueModel
  RescueCoordinateSystem(char *data_collection_s, char *coordinate_sys_s);
  void UnArchive(char *coordinate_sys_s, char *data_collection_s);
  bool PreAssignSK();
  char *SurrogateKey() {return surrogateKey;}
  char *StorageID() {return storageID;}
#endif

  RCHString *coordinateSystemName;
  Orientation displayOrientation;
  RescueVertex *vertex;            // May be NULL (otherwise this could go on forever).
  RescueCoordinateSystemAxis *axes[3];
  int insys;
  int inzone;
  int inUnit;
  int insph;
  double semiMajorAxis;
  double eccentricity;
  double standardLat;
  double secondLat;
  double centralLong;
  double latOrigin;
  double falseEasting;
  double falseNorthing;
#ifdef DB_HOOK
  char surrogateKey[20];
  char storageID[41];
#endif
  friend class RescueModel;
  friend class RescueVertex;
  friend class RescueTrimVertex;
  friend class RescuePolyLine;
  friend class RescueTripletArray;
  friend class RescueWellbore;
  friend class RescueGrid;
};

#endif


RescueCoordinateSystemAxis

This class holds the axis name and unit of measure for a coordinate system axis. It is not instantiated directly by the user. It has a relationship to a single RescueCoordinateSystem. As in Epicentre, coordinate system axes cannot be shared among coordinate systems.

/********************************************************************

  RescueCoordinateSystemAxis.h

  CoordinateSystem axis for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUECoordinateSystemAXIS_H
#define RESCUECoordinateSystemAXIS_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
#include "RCHString.h"
class RescueCoordinateSystem;

class RescueCoordinateSystemAxis:public RescueObject
{
public:
  RescueCoordinateSystem *ParentCoordinateSystem() {return parentCoordinateSystem;}
  ~RescueCoordinateSystemAxis();
  RCHString *AxisName() {return axisName;}
                                  // Do NOT delete the returned object.
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                     // Do NOT delete the returned object.
  RCHString *UnitOfMeasure() {return unitOfMeasure;}
                               // to be currently valid.
private:
  RescueCoordinateSystemAxis(RescueCoordinateSystem *parentIn, char *nameIn, char *uomIn);
  void Archive(FILE *archiveFile);
  RescueCoordinateSystemAxis(FILE *archiveFile);
  void Relink(RescueObject *parentObject);

#ifdef DB_HOOK
  void Archive(char *data_collection_s, char *coordinateSystem_s, int axisNo);
  RescueCoordinateSystemAxis(char *r_property_type_nm, char *description);
  char *SurrogateKey() {return surrogateKey;}
  bool PreAssignSK();

  char surrogateKey[20];
#endif

  RescueCoordinateSystem *parentCoordinateSystem;
  RCHString *axisName;
  RCHString *unitOfMeasure;

  friend class RescueCoordinateSystem;
  friend class RescueGridAxis;
  friend class RescuePolyLine;
  friend class RescueTripletArray;
};

#endif


RescueEdgeSet

An edge set defines the boundaries of some surface against some other object. It is used by RescueBlockUnitSide, and RescueMacroVolume. It contains two sets of RescueTrimLoops, the boundary set and the interior set. The exact usage of each is given with each of the user objects.

/********************************************************************

  RescueEdgeSet.h

  A set of edges which describe the relationship of a top, bottom, or
  side of a block unit to a set of surfaces.

  Rod Hanks,  July 1996

*********************************************************************/
#ifndef RESCUEEDGESET_H
#define RESCUEEDGESET_H

#include "myHeaders.h"
#include "RescueTrimLoop.h"
#include "cSetRescueTrimLoop.h"
#ifdef DB_HOOK
#include "RDBMS.h"
#include <string.h>
#endif

class RescueEdgeSet:public RescueObject
{
public:
  RescueEdgeSet();
  ~RescueEdgeSet();

  void AddBoundaryLoop(RescueTrimLoop *existingLoop)
                        {(*boundaryLoops) += existingLoop;}
  void DropBoundaryLoop(RescueTrimLoop *existingLoop)
                        {(*boundaryLoops) -= existingLoop;}
  RescueTrimLoop *NthBoundaryLoop(int zeroBasedOrdinal)
                        {return (*boundaryLoops).NthObject(zeroBasedOrdinal);}
  void AddInteriorLoop(RescueTrimLoop *existingLoop)
                        {(*interiorLoops) += existingLoop;}
  void DropInteriorLoop(RescueTrimLoop *existingLoop)
                        {(*interiorLoops) -= existingLoop;}
  RescueTrimLoop *NthInteriorLoop(int zeroBasedOrdinal) 
                        {return (*interiorLoops).NthObject(zeroBasedOrdinal);}
  
  int  CountOfBoundaryLoop() { return  (*boundaryLoops).Count(); }
  
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
protected:
  virtual void Archive(FILE *archiveFile);
  RescueEdgeSet(FILE *archiveFile);
  virtual void Relink(RescueObject *object); // Pass RescueModel.

private:
  void RegisterUser() {usageCount++;}
  void UnregisterUser();
#ifdef DB_HOOK
  void Archive(char *data_collection_s, char *geoscience_ntrp_s);
  RescueEdgeSet(char *topological_rel_s);
  char *SurrogateKey() {return surrogateKey;}
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
#endif
  int usageCount;
  cSetRescueTrimLoop *boundaryLoops;   
  cSetRescueTrimLoop *interiorLoops;
#ifdef DB_HOOK
  char surrogateKey[20];
#endif
  friend class RescueMacroVolume;
  friend class RescueBlockUnitHorizonSurface;
  friend class RescueBlockUnitSide;
  friend class cSetRescueEdgeSet;
  friend class RescueSurface;
};

#endif


RescueGeometry

The RescueGeometry object, along with its closely related RescueGrid object, forms the core of the micro model at the block unit level. The indexing system for the geometry is described by the related RescueGrid, which is always a three dimensional grid defined by a lowbound and count in a three-dimensional logical indexing space ijk. Relationships between this indexing space and a three dimensional coordinate system are discussed with RescueBlockUnit.

This grid is often equal axis in the ix and jy direction, meaning the x coordinate may be obtained from the formula x = origin + (I * step), etc. The grid may be equal axis in any one, or none, of its dimensions. In any case, the grid defines a low bound and a count which define the logical indexing scheme for grid nodes in each direction.

  RescueGeometry *geom = blockUnit->GridGeometry();

RescueGeometry objects are not created explicitly. RescueBlockUnit creates the grid and geometry objects automatically during its construction. The object can then be retrieved from the block unit.

At root, the grid is a corner point grid, capable of storing eight xyz triplets for each grid cell, so that any cell corner may be split in any direction. In practice, the grid provides a variety of methods, discussed below, for storing and retrieving node coordinates. It is best, both from the standpoint of storage and utility, to use the simplest method which will serve for any section of the grid. It is not only permissible, but encouraged to use all methods within a single grid.

A combination of grid-centered and cell-centered indexing is used within the grid, depending upon the purpose of the indexing. The ijk index of a cell matches the ijk index of its corner 0 node. If the highest node index along a dimension is n, the highest cell index along that dimension is n - 1.

Numbering in corner point grids within Epicentre is based upon a LUB (as described in RescueCoordinateSystem) orientation. The following numbering schemes match the Epicentre method when the orientation is LUB. If we want to use other orientations, we need to get POSC to add orientation to grids (which they currently do not have) and then revise their numbering specification to our more general form.

Cell Corner Numbering

Corner ordering begins at the origin, proceeds in the direction of increasing I, and continues on around the k layer. It then jumps to the k + 1 layer and proceeds again in the same fashion.

CornerCell to Node I Cell to Node JCell to Node k
0Ij k
1I + 1j k
2I + 1j + 1 k
3Ij + 1 k
4Ij k + 1
5I + 1j k + 1
6I + 1j + 1 k + 1
7Ij + 1 k + 1

Cell Face Numbering

Cell face numbering begins at the origin, and proceeds around the cell in the same fashion as with corner numbering. The top face (defined as the one with the lowest k index) is next, followed by the bottom face.

FaceFromTo
0I,JI+1,J
1I+1,JI+1,J+1
2I+1,J+1I,J+1
3I,J+1I,J
4k layer
5k + 1 layer

Cell Face Corner Numbering

Face corner numbering is used to describe the UV's of cell faces against the a surface. Faces have four corners, numbered 0 through 3. Each face is described logically by four ijk node indexes. In each face, one of these index values is unchanging when indexing all four corners. Face corner numbering depends upon the values of the first index (which is the first ijk index which is not unchanging) and the second index (which is the second ijk index which is not unchanging). The unchanging index is not involved in face corner numbering.

Face Cornerfirst index second index
0lowestlowest
1lowesthighest
2highesthighest
3highestlowest

RescueGeometry grids contain a two dimensional array of relationships to a RescueGeometryObject. For each ij vertex in the grid, the array contains either

  1. No object. Xyz coordinates are derived solely from the grid. x and y are obtained solely from the i and j axes. These axes should be defined with an origin and step.

    There are three types of grids, with three different algorithms for determining z from grid information. Proportional grids are defined with a top and bottom reference surface and a top and bottom offset. The position of each k layer boundary is calculated by placing the k layers proportionally between the top and bottom surfaces. The thickness of each layer is the same, but thickness varies according to the space available between the surfaces.

    Referential grids are defined with a single surface, an offset, a thickness, and an onlap/offlap flag. The thickness of each layer is the same, and it does not vary within the grid. The position of each k layer boundary is calculated to keep the boundary a constant distance from the referenced surface.

    Equal axis grids are defined by information in the RescueGrid related to the RescueGeometry object. The Z value is calculated from the origin and step information for the third axis.

  2. RescueZStack. This object contains an array of doubles, one for each k layer of the grid. X and y coordinates are derived from the ij grid axes, which hopefully have been declared with origin and step. The z coordinate is read from the stack.
  3. RescueCoordinateLine. The object contains an xyz triplet for the top of the line (defined as the location where the line coincides with the k=0 layer of the grid), an xyz triplet for the bottom of the line (which coincides with the highest indexed k layer in the grid), and an array of Z values for each k layer in between. The x and y coordinates are straight-line extrapolated from the top and bottom coordinates, the z value is read from the array.
  4. RescueCoordinatePolyLine. The object contains an xyz triplet for each k layer in the grid.
  5. RescueSplitLine. The object contains eight xyz triplets for each k layer in the grid, one for each node corner which could theoretically be located at the node. This allows each node to be split in every possible direction.

Where arrays are defined for k layers, the indexes of the array are always congruent to the k layer indexes, so that the first array element would correspond to the zeroth k layer etc, except for RescueCoordinateLine, which, although it proceeds in the same direction, contains values only for the 1 through n-1 k layers, rather than for the whole stack (since the top and bottom coordinates take care of the zeroth and highest k layers).

The individual RescueGeometryObjects are never accessed directly by the programmer. RescueGeometry contains different methods to write and read vertex coordinates from the grid. The class automatically assigns the proper RescueGeometryObject, based on the lowest numbered object which will hold the information it has been given (the class doesn't examine the coordinates it has been given, only the methods by which they were given).

Model builders should use the lowest numbered technique which will hold the necessary information at a given vertex. This both reduces storage and increases the utility of the information. Readers of grid geometry have two options. For simplicity they can choose to treat the grid as a corner point grid having 8 triplets for each cell. If they wish to take advantage of assumptions that can be made with more regular grids they can discover which storage technique is in use in the area of the grid they are reading and use reading techniques which are peculiar to that technique.

In addition to grid geometry, the RescueGeometry object contains a set of RescueSurfaceCell objects which record the proximity of surfaces (horizons or sections) with cells and a set of RescueWellboreCell objects which record the intersection of wellbores with cells.

Each K layer of a block unit grid may be assigned a user-determined 32-bit global id. Readers can retrieve the id for each K layer. There is an understanding that layers having the same ID within the same unit have "layer equivalence". The default id of zero means no equivalence is defined.

/********************************************************************

  RescueGeometry.h

  A geometry handler for RESCUE style corner point grids.

  Rod Hanks,  January, 1997

*********************************************************************/
#ifndef RESCUEGEOMETRY_H
#define RESCUEGEOMETRY_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
class RescueGrid;
class RescueGeometryObject;
class RescueSurface;
#include "RescueSurfaceCell.h"
#include "cSetRescueSurfaceCell.h"
#include "cSetRescueWellboreCell.h"
class RescueModel;
class RescueWellbore;
class RescueReferenceSurface;
#if DB_HOOK
class RescueBlockUnit;
#endif

class RescueGeometry:public RescueObject
{
public:
  typedef enum {R_EQUAL_AXIS,              // x, y, z derived from grid origin and step or from reference surfaces.
                R_UNEQUAL_AXIS,             // x and y from origin and step, z is given.
                R_COORDINATE_LINE,         // straight coordinate line.
                R_COORDINATE_POLYLINE,     // piece wise coordinate line.
                R_SPLIT_LINE}               // split nodes (corner point or multiple coordinate line).
                     RescueVertexType;

  typedef enum {R_ONLAP,                   // Reference surface is ABOVE the grid.
                R_OFFLAP}                  // Reference surface is BELOW the grid.
                      RescueLapType;

  typedef enum {R_XY_ORTHOGONAL,           // If VertexIs() == R_UNEQUAL_AXIS  or VertexIs() == R_EQUAL_AXIS
                R_SQUASHED_ORTHOGONAL,     // If all interior vertexes are R_EQUAL_AXIS or R_UNEQUAL_AXIS but
                                           // at least some exterior vertexes are R_COORDINATE_LINE or
                                           // R_COORDINATE_POLYLINE.
                R_CONFORMABLE}             // If neither of the above is true.
                      RescueGridType;

  RescueGeometry(RescueModel *parentModelIn, RescueGrid *existingGrid, float missingValueIn);
                                            // Normal constructor for most block unit grids.
                                            // x,y,z of vertexes of type R_EQUAL_AXIS are 
                                            // determined by the grid.
  RescueGeometry(RescueModel *parentModelIn, RescueGrid *existingGrid, float missingValueIn,
                 RescueReferenceSurface *topSurfaceIn, float topOffsetIn,
                 RescueReferenceSurface *bottomSurfaceIn, float  bottomOffsetIn);
                                            // Constructor for a grid whose z values are 
                                            // determined by the reference surfaces and offsets.
                                            // Each k-layer is proportional to the distance between
                                            // the top and bottom reference surfaces, after the
                                            // offsets are applied. This applies only to vertexes
                                            // of type R_EQUAL_AXIS.
  RescueGeometry(RescueModel *parentModelIn, RescueGrid *existingGrid, float missingValueIn,
                 RescueReferenceSurface *referenceSurfaceIn, float referenceOffsetIn, 
                 float thicknessIn, RescueLapType onOffLapIn);
                                            // Constructor for a grid whose z values are 
                                            // determined by the reference surface and offset.
                                            // Each k-layer is of the same thickness, determined
                                            // by the thickness argument. This applies only to vertexes
                                            // of type R_EQUAL_AXIS.
  ~RescueGeometry();
  RescueGrid *Grid() {return grid;}
  RescueModel *ParentModel() {return parentModel;}
  float MissingValue() {return missingValue;}
  void SetZValue(float *valueArray);
                                    // Sets Z values for all nodes.
                                    // The array has three dimensions (i,j,k) each             
                                    // sized to the number of nodes  in the grid.  No
                                    // nodes will be split in the z direction after this.
                                    // Promotes to R_UNEQUAL_AXIS.
                                    // Copies the array.
  void SetZValue(int i, int j, float *valueArray);
                                    // Sets the z values for a particular ij vertex.
                                    // The array is the length of the number of
                                    // k layers. i and j are vertex indexes.
                                    // Promotes to R_UNEQUAL_AXIS.
                                    // The array must have been created with new float []
                                    // and becomes the property of the grid.
  void SetZValue(int i, int j, int k, float value);
                                    // Sets the z value of a particular k layer.  i and j
                                    // are vertex indexes.
                                    // Promotes to R_UNEQUAL_AXIS.
  void SetCoordinateLine(int i, int j, float xTop, float yTop, float zTop,
                                       float xBottom, float yBottom, float zBottom,
                                       float *middleZvalues = 0);
                                    // Sets a vertex to a coordinate line.  i and j are vertex
                                    // indexes.  If middleZvalues  is given there are two less
                                    // than the number of k layers (since top and bottom are
                                    // defined by zTop and zBottom).
                                    // Vertex will promote or collapse to R_COORDINATE_LINE.
                                    // If middleValues is given, it must have been created
                                    // with new float[] and becomes the property of the grid.
  void SetCoordinatePolyLine(int i, int j, float *values);
                                    // The array contains 2 dimensions.  The first is the k layer,
                                    // the second is x = 0, y = 1, z = 2.  i and j are vertex
                                    // indexes.  Will promote or collapse to R_COORDINATE_POLYLINE.
                                    // The array must have been created with new float[].  It becomes
                                    // the property of the grid.  Do NOT free it.
  void SetCornerNode(int i, int j, int k, int corner, float x, float y, float z);
                                    // i, j, k define a cell, corner is a corner of that cell (0-8).
                                    // x, y, and z is the geometry of that corner. Promotes to
                                    // R_SPLIT_LINE.
  void SetXValue(int i, int j, int k, int corner, float value);
  void SetYValue(int i, int j, int k, int corner, float value);
  void SetZValue(int i, int j, int k, int corner, float value);
                                    // Sets a split x,y, or z value for a particular node corner.
                                    // i,j,k identify the cell, corner the node.
                                    // Will promote vertex to R_SPLIT_LINE.
  RescueVertexType VertexIs() {return vertexIs;}      
                                    // Returns the highest RescueVertexType present in the grid.
  RescueVertexType VertexIs(int i, int j);
                                    // Returns the storage regime in use at the given vertex index.
  RescueGridType GeometryType();    // Characterizes the grid as a whole.
  void Values(int i, int j, int k, int corner, float &x, float &y, float &z);
                                    // Returns, in x, y, and z, the geometry of the given cell
                                    // (identified by i, j, k) and corner.
  bool Values(int i, int j, int k, float &x, float &y, float &z);
                                    // For all unsplit nodes, returns, true, and in x, y, and z, 
                                    // the values of the unsplit node identified by i, j, and k.  
                                    // This is by node, not cell. If the node is split, returns
                                    // false, and x, y, and z are zero.
  bool Values(int i, int j, int k, float &z);
                                    // For all unsplit nodes, returns true and the z value of the
                                    // unsplit node identified by i, j, and k.  If the node is split,
                                    // returns false and z is zero.
  void CellToNode(int i, int j, int k, int corner, int &iPrime, int &jPrime, int &kPrime);
                                    // Returns node based ijk for cell ijk and corner.

  void SetSurfaceIntersection(RescueSurface *surface,
                              RescueSurfaceCell::SurfaceSide side,
                              int i, int j, int k,
                              int cellFaceNumber,
                              float *uvs=0);
                                      // Declare a new relationship between a cell
                                      // in this grid and a surface.
                                      // array is 2 x 4 in which the first index is u=0, v=1,
                                      // and the second index is the face corner number (see
                                      // document). The array must have been allocated with new float[]
                                      // and becomes the property of the grid.
  bool DropRescueSurfaceCell(RescueSurfaceCell *cellToDrop) 
                          {return ((*surfaceCell) -= cellToDrop);}
                                      // Destructor will drop it from the surface side.
  RescueSurfaceCell *NthSurfaceCell(int zeroBasedOrdinal) {return surfaceCell->NthObject(zeroBasedOrdinal);}


  void SetWellboreIntersection(RescueWellbore *wellbore,
                              int i, int j, int k);
                                      // Declare a new relationship between a cell
                                      // in this grid and a wellbore.
  bool DropRescueWellboreCell(RescueWellboreCell *cellToDrop) 
                          {return ((*wellboreCell) -= cellToDrop);}
                                      // Destructor will drop it from the surface side.
  RescueWellboreCell *NthWellboreCell(int zeroBasedOrdinal) {return wellboreCell->NthObject(zeroBasedOrdinal);}

  void SetKLayerID(int zeroBasedNdx, int globalID) {kLayerIDs[zeroBasedNdx] = globalID;}
  int KLayerID(int zeroBasedNdx) {return kLayerIDs[zeroBasedNdx];}

  bool IsProportional() {return (referenceSurface1 != 0 && referenceSurface2 != 0);}
                                      // Returns TRUE if the RescueGeometry grid is proportional
                                      // (determined by top and bottom surfaces).
  RescueReferenceSurface *TopReferenceSurface() {return referenceSurface1;}
  RescueReferenceSurface *BottomReferenceSurface() {return referenceSurface2;}
  float TopOffset() {return offset1;}
  float BottomOffset() {return offset2;}
                                      // Routines to return information about proportional
                                      // grid definitions.
  bool IsReferenced() {return (referenceSurface1 != 0 && referenceSurface2 == 0);}
                                      // Returns TRUE if the RescueGeometry grid is of fixed
                                      // thickness, referenced from some surface.
  RescueReferenceSurface *ReferenceSurface() {return referenceSurface1;}
  float SurfaceOffset() {return offset1;}
  float KLayerThickness() {return thickness;}
  RescueLapType LapType() {return onOffLap;}
                                       // Routines to return information about constant
                                       // thickness grids.
  
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  void CommonInitialization();
  RescueGeometry(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
  void SetGrid(RescueGrid *newGrid) {grid = newGrid;}

  RescueGeometryObject **VertexAddress(int i, int j) {return &vertices[i * jNodes + j];}
                                  // Returns address of array element for a particular vertex.
  RescueGeometryObject **VertexAddress(int i, int j, int corner);
                                  // Returns address for particular corner of a stack of cells.
  RescueGeometryObject **PromoteToSplitLine(int i, int j, int k, int corner);
  float ProportionalValueAt(int i, int j, int k);
  float ReferencedValueAt(int i, int j, int k);
#ifdef DB_HOOK
  void Archive(RescueBlockUnit *bu, char *data_collection_s, char *geoscience_ntrp_s);
  RescueGeometry(char *macro_volume_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
#endif
  RescueGrid *grid;
  int jNodes;
  float missingValue;
  RescueGeometryObject **vertices;  // One of these for each ij vertex on the grid.
  RescueVertexType vertexIs;
  RescueModel *parentModel;

  int *kLayerIDs;
  RescueReferenceSurface *referenceSurface1;
  RescueReferenceSurface *referenceSurface2;
  float offset1;
  float offset2;
  float thickness;
  RescueLapType onOffLap;

  int referenceSurface1Id;
  int referenceSurface2Id;

  cSetRescueSurfaceCell *surfaceCell;
  cSetRescueWellboreCell *wellboreCell;
#ifdef DB_HOOK
  char surrogateKey[20];
#endif

  friend class RescueBlockUnit;
  friend class RescueSurface;
  friend class RescueWellbore;
  friend class RescueProperty;
};

#endif


RescueGeometryObject

An abstract superclass of objects which contain vertex coordinates in RescueGeometry grids. Instantiated as one of RescueZStack, RescueBlockUnitSide, RescueCoordinatePolyLine, or RescueSplitLine. RescueGeometryObjects are never accessed directly by programmers using the library. RescueGeometry methods are used to retrieve and store vertex coordinates.

RescueGrid

The grid object corresponds very closely to the Epicentre Grid entity, except that it includes a low bound for each axis and an orientation. It contains a rotation, which in Epicentre terms defines (along with the RescueModel coordinate system) the coordinate system of the grid, and one to three RescueGridAxis objects.

When a rotation is specified, a RescueVertex should also be given to define the point about which rotation occurs.

The orientation of a grid applies to the i, j, k grid axes only. All coordinate systems in a model use the same orientation as does the RescueCoordinateSystem defined within the RescueModel.

Grids are not instantiated directly by the user.

/********************************************************************

  RescueGrid.h

  Grid for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEGRID_H
#define RESCUEGRID_H

#include "myHeaders.h"
#include "RescueGridAxis.h"
#include "RescueCoordinateSystem.h"
class RescueCoordinateSystemAxis;
class RescueBlockUnit;
#include "cSetRescueGridAxis.h"
#include "RCHString.h"

/*
  The displayOrientation shows which corner the origin is located on: 
  LUF, LUB, LDF, LDB, RUF, RUB, RDF, and RDB.

    Key:  Left/Right
          Up/Down
          Front/Back
*/
class RescueGrid:public RescueObject
{
public:
  ~RescueGrid();
  RescueGrid(RescueCoordinateSystem::Orientation displayOrientationIn, int i_lowbound, int i_count);
  RescueGrid(RescueCoordinateSystem::Orientation displayOrientationIn, 
             float i_origin, float i_step, int i_lowbound, int i_count);
  RescueGrid(RescueCoordinateSystem::Orientation displayOrientationIn, int i_lowbound, int i_count, 
                                                                       int j_lowbound, int j_count);
  RescueGrid(RescueCoordinateSystem::Orientation displayOrientationIn, RescueCoordinateSystemAxis *i_axis,
             float i_origin, float i_step, int i_lowbound, int i_count, 
             RescueCoordinateSystemAxis *j_axis,
             float j_origin, float j_step, int j_lowbound, int j_count, 
             float zRotation = 0.0, RescueVertex *vertexIn = 0);
  RescueGrid(RescueCoordinateSystem::Orientation displayOrientationIn, int i_lowbound, int i_count, int j_lowbound, int j_count, 
             int k_lowbound, int k_count);
  RescueGrid(RescueCoordinateSystem::Orientation displayOrientationIn, RescueCoordinateSystemAxis *i_axis,
             float i_origin, float i_step, int i_lowbound, int i_count, 
             RescueCoordinateSystemAxis *j_axis,
             float j_origin, float j_step, int j_lowbound, int j_count, 
             int k_lowbound, int k_count, 
             float zRotation = 0.0, RescueVertex *vertexIn = 0);
                              // Create 1d, 2d, 3d grids.
  int Dimensions() {return axes->Count();}
  int NodeCount(bool cellCentered = false);            // Return number of nodes in the grid.
  int Vertices();              // Number of ij vertexes in the grid.
  float ZRotation() {return zRotation;}
  RescueGridAxis *Axis(int zeroBasedOrdinal) {return axes->NthObject(zeroBasedOrdinal);}

  RescueVertex *Vertex() {return vertex;}
                                  // Do NOT free the object passed.
  void SetVertex(RescueVertex *newVertex);

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
  bool IsRegular(int which);      // Where i = 0, j = 1, k = 2.
private:
  RescueGrid(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
  virtual void Relink(RescueObject *parentModel);
#ifdef DB_HOOK
  void Archive(char *owner_s, char *owner_t,
               RescueUnit *unitMayBeNull,
               RescueCoordinateSystem *coordinateSystem,
               char *parent_model_s, 
               char *geoscience_ntrp_s,
               char *data_collection_s);
  RescueGrid(RescueCoordinateSystem *coordinateSystemIn,
                       char *owner_s, 
                       char *parent_model_s, 
                       char *data_collection_s, 
                       char *coordinate_sys_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
#endif

  RescueCoordinateSystem::Orientation displayOrientation;
  float zRotation;
  cSetRescueGridAxis *axes;

  RescueVertex *vertex;            
#ifdef DB_HOOK
  char surrogateKey[20];
#endif

  friend class RescueBlockUnit;
  friend class RescueSurface;
  friend class RescueWellbore;
  friend class RescueWellboreSampling;
  friend class RescueProperty;
  friend class RescueGeometry;
  friend class RescueWellboreProperty;
  friend class cSetRescueWellboreCell;
};

#endif


RescueGridAxis

The grid axis object contains a reference to the parent grid, a low bound, and a count. It may contain a reference to a coordinate system axis, an origin and a step. If these are present then the real-world coordinate of a node on the axis can be derived by x = origin + (step * I). If the parent grid contains a non-zero rotation, then the related axis is not actually the referenced coordinate system axis, but the corresponding axis in the derived coordinate system.

Grid axes are instantiated by the constructor of RescueGrid.

/********************************************************************

  RescueGridAxis.h

  Grid axis for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEGRIDAXIS_H
#define RESCUEGRIDAXIS_H

#include "myHeaders.h"
class RescueGrid;
class RescueCoordinateSystem;
class RescueCoordinateSystemAxis;

class RescueGridAxis:public RescueObject
{
public:
  RescueGrid *ParentGrid() {return parentGrid;}
  int LowBound() {return lowBound;}
  int Count() {return count;}
  bool IsRegular() {return (step == 0.0) ? false : true;}
  RescueCoordinateSystemAxis *RelatedCoordinateSystemAxis() 
                                             {return relatedAxis;}
  float ValueAt(int ndx) {return origin + ((float) (ndx - lowBound) * step);}
  float Origin() {return origin;}
  float Step() {return step;}
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();      // Returns true if object appears
          // to be currently valid.
private:
  RescueGridAxis(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
  virtual void Relink(RescueGrid *parent, RescueCoordinateSystem *cs);
  virtual void Relink(RescueObject *object) {} 

  RescueGridAxis(RescueGrid *parentIn, int lowBoundIn, int countIn)
    :parentGrid(parentIn)
    ,relatedAxis(0)
    ,lowBound(lowBoundIn)
    ,count(countIn)
    ,origin((float) 0.0)
    ,step((float) 0.0) {isA = R_RescueGridAxis;}
  RescueGridAxis(RescueGrid *parentIn, 
                 RescueCoordinateSystemAxis *axis, 
                 float originIn, float stepIn,
                 int lowBoundIn, int countIn)
    :parentGrid(parentIn)
    ,relatedAxis(axis)
    ,lowBound(lowBoundIn)
    ,count(countIn)
    ,origin(originIn)
    ,step(stepIn) {isA = R_RescueGridAxis;}
#ifdef DB_HOOK
  void Archive(char *sk, char *identifier, char *data_collection_s);
#endif
  
  RescueGrid *parentGrid;
  RescueCoordinateSystemAxis *relatedAxis;
  int lowBound;
  int count;
  float origin;
  float step;

  int relatedAxisID;    // Used only during relink.

  friend class RescueGrid;
  friend class cSetRescueGridAxis;
};

#endif


RescueHorizon

The horizon is a business object which defines the upper or lower boundary of a RescueUnit. The horizon contains a reference to the unit above, the unit below, and a set of RescueBlockUnitHorizonSurface objects which together define the actual geological surface.

   RescueHorizon *horizon1 = new 
                   RescueHorizon("Horizon 1", model);
                   horizon1->SetUnitBelowMe(unit1);
                   
/********************************************************************

  RescueHorizon.h

  The horizon object for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEHORIZON_H
#define RESCUEHORIZON_H

#include "myHeaders.h"
#include "RCHString.h"
#include "RescueBlockUnitHorizonSurface.h"
#include "cSetRescueBlockUnitHorizonSurface.h"
class RescueModel;
class RescueUnit;

class RescueHorizon:public RescueObject
{
public:
  RescueHorizon(char *horizonNameIn, RescueModel *parentModelIn);
  ~RescueHorizon();
  RCHString *HorizonName() {return horizonName;}
                              // Do NOT delete the returned object.
  void SetHorizonName(char *newHorizonName) {(*horizonName) = newHorizonName;}
  RescueModel *ParentModel() {return parentModel;}

  RescueUnit *UnitAboveMe() {return unitAboveMe;}
  RescueUnit *UnitBelowMe() {return unitBelowMe;}

  RescueHorizon *HorizonAboveMe();
  RescueHorizon *HorizonBelowMe();
                                    // Do NOT delete the object returned.
  void SetUnitAboveMe(RescueUnit *existingUnit)
                                      {unitAboveMe = existingUnit;}
  void SetUnitBelowMe(RescueUnit *existingUnit)
                                      {unitBelowMe = existingUnit;}
  
  int BlockUnitHorizonSurfaceCount() {return (*surfaces).Count();}
  RescueBlockUnitHorizonSurface *NthRescueBlockUnitHorizonSurface(int zeroBasedOrdinal) 
                  {return (*surfaces).NthObject(zeroBasedOrdinal);}
  RescueBlockUnitHorizonSurface *HorizonSurfaceIdentifiedBy(int identifier)
            {return (*surfaces).ObjectIdentifiedBy(identifier);}
                                    // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.
  bool DropRescueBlockUnitHorizonSurface(RescueBlockUnitHorizonSurface *unitToDrop) 
                          {return ((*surfaces) -= unitToDrop);}
  virtual bool IsOfType(_RescueObjectType thisType);
					// Returns true if the object is a
					// member of the specified class.
  virtual bool IsValid();  		    // Returns true if object appears
					                        // to be currently valid.
  bool IsNamed(char *possibleName);
private:
  RescueHorizon(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  void Relink(RescueObject *parentObject);

  RCHString *horizonName;
  RescueModel *parentModel;
  RescueUnit *unitAboveMe;
  RescueUnit *unitBelowMe;
  cSetRescueBlockUnitHorizonSurface *surfaces;

  int unitAboveID;  // These are used only for relinking.
  int unitBelowID;

  friend class RescueBlockUnitHorizonSurface;
  friend class cSetRescueHorizon;
};

#endif

RescueLookup

A RescueLookup is a table of lookup values which may be associated with RescueProperty and RescueWellboreProperty arrays. The object is automatically added to a list of such objects kept by the RescueModel object.

  RescueLookup *stringLookup = new RescueLookup("Colors", 7, model);
You must declare the number of lookup items in the constructor and this cannot change during the life of the object. Objects may be deleted from the model using RescueModel's DropRescueLookup method. Once the lookup object is instantiated, it should be completely filled with RescueLookupItem objects. Missing items in property arrays should be handled via the RescueArray nullValue member, not by missing objects in a RescueLookup.
  char propertyString[7][10] = {"red", "orange", "yellow", "green", "blue", "indigo", "violet"};
  int tLoop;
  for (tLoop = 0; tLoop < 7; tLoop++)
  {
    stringLookup->SetNthItem(tLoop, new RescueLookupString(propertyString[tLoop]));
  }
By convention, all of the objects in a RescueLookup should be of the same type (either RescueLookupString or RescueLookupTable).
/********************************************************************

  RescueLookup.h

  A table of lookups for properties. Individual lookup items are
  accessed by their index in the array.

  Rod Hanks,  May 1997

*********************************************************************/
#ifndef RescueLookup_H
#define RescueLookup_H

#include "myHeaders.h"
#include "RCHString.h"
class RescueLookupItem;
class RescueModel;

#ifdef DB_HOOK
#include "RDBMS.h"
#include <string.h>
#endif

class RescueLookup:public RescueObject
{
public:
  RescueLookup(char *newName, int size, RescueModel *newParentModel);
  ~RescueLookup();
  // Create a new unit.
  // To dispose a unit, use unit->ParentModel()->DropRescueLookup(unit);
  RCHString *LookupName() {return name;}
                              // Do NOT delete the returned object.
  void SetName(char *newName) {(*name) = newName;}
  RescueModel *ParentModel() {return parentModel;}

  bool IsNamed(char *possibleName) {return ((*name) == possibleName);}
  int Count() {return count;}
  RescueLookupItem *NthItem(int zeroBasedIndex);
  void SetNthItem(int zeroBasedIndex, RescueLookupItem *newItem);

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  virtual void Archive(FILE *archiveFile);
  RescueLookup(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
#ifdef DB_HOOK
  void Archive(char *data_collection_s, char *earth_model_s);
  RescueLookup(char *rescue_lookup_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
#endif

  RCHString *name;
  RescueModel *parentModel;
  int count;
  RescueLookupItem **lookups;
#ifdef DB_HOOK
  char surrogateKey[20];
#endif

  friend class cSetRescueLookup;
  friend class RescueModel;
  friend class RescueProperty;
  friend class RescueWellboreProperty;
};

#endif


RescueLookupItem

A RescueLookupItem is a member of a RescueLookup, giving the value of a particular index. It is an abstract superclass which is instantiated either as RescueLookupString or RescueLookupTable.

/********************************************************************

  RescueLookupItem.h

  An item in a table of lookups for properties. 

  Rod Hanks,  May 1997

*********************************************************************/
#ifndef RescueLookupItem_H
#define RescueLookupItem_H

#include "myHeaders.h"
#ifdef DB_HOOK
class ChunkBuffer;
#endif

class RescueLookupItem:public RescueObject
{
public:
  RescueLookupItem() {}

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid()=0;          // Returns true if object appears
                                    // to be currently valid.
private:
  virtual void Archive(FILE *archiveFile)=0;
#ifdef DB_HOOK
  virtual void Archive(ChunkBuffer *cBuf)=0;
#endif
  friend class RescueLookup;
};

#endif


RescueLookupString

A RescueLookupString is an item in a RescueLookup which defines the value of a particular index as a string.

/********************************************************************

  RescueLookupString.h

  An item in a table of lookups for properties which translates to
  a string. 

  Rod Hanks,  May 1997

*********************************************************************/
#ifndef RescueLookupString_H
#define RescueLookupString_H

#include "myHeaders.h"
#include "RescueLookupItem.h"
#include "RCHString.h"

class ChunkBuffer;

class RescueLookupString:public RescueLookupItem
{
public:
  ~RescueLookupString();
  RescueLookupString(char *translationString);
  RCHString *Translation() {return translation;}
                              // Do NOT delete the returned object.

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  virtual void Archive(FILE *archiveFile);
  RescueLookupString(FILE *archiveFile);
#ifdef DB_HOOK
void RescueLookupString::Archive(ChunkBuffer *cBuf);
RescueLookupString(ChunkBuffer *cBuf);
#endif
  RCHString *translation;

  friend class RescueLookup;
};

#endif


RescueLookupTable

A RescueLookupTable is an item in a RescueLookup which defines the value of a particular index as a table of doubles having two columns and a user defined number of rows. It is generally used to define the result of some function.
/********************************************************************

  RescueLookupTable.h

  An item in a table of lookups for properties which translates to
  a two column table of floats. 

  Rod Hanks,  May 1997

*********************************************************************/
#ifndef RescueLookupTable_H
#define RescueLookupTable_H

#include "myHeaders.h"
#include "RescueLookupItem.h"
#include "RCHString.h"

class RescueLookupTable:public RescueLookupItem
{
public:
  RescueLookupTable(int rowsIn, float *tableIn)
    :rows(rowsIn)
    ,table(tableIn)
  {isA = R_RescueLookupTable;}
          // The array must be allocated on the heap and must be
          // rowsIn * 2 floats long.  It becomes the property of
          // the object.  Do not free it.
  ~RescueLookupTable() {free(table);}
  float *Translation() {return table;}
          // Do not free or change the array returned.
  int Rows() {return rows;}
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  virtual void Archive(FILE *archiveFile);
  RescueLookupTable(FILE *archiveFile);
#ifdef DB_HOOK
void Archive(ChunkBuffer *cBuf);
RescueLookupTable(ChunkBuffer *cBuf);
#endif
  float *table;
  int rows;

  friend class RescueLookup;
};

#endif


RescueMacroVolume

The RescueMacroVolume object contains the macro model elements which pertain to a particular contiguous volume of a particular block unit. Each RescueBlockUnit must have at least one RescueMacroVolume. Many, perhaps most, will have only one. When a block unit contains two or more disjoint volumes, then the RescueBlockUnit object will contain one RescueMacroVolume for each such volume.

The RescueMacroVolume contains a relationship to a set of RescueBlockUnitSides which provides descriptions of the surfaces which bound the volume as well as a set of trim loops which further define the intersection of the volume and those surfaces. The set of RescueBlockUnitSide objects are not in any meaningful order. The edges of the surfaces are stitched together, wherever they coincide, by shared RescuePolyLines in the wireframe model. A volume will have a minimum of 3 sides.

The RescueMacroVolume contains a set of interior RescueSections used to reference any sections which exist either wholly or partially inside the volume but which do not form a boundary of the unit. A set of RescueEdgeSets is kept for each k layer in the grid. The boundary edges of each RescueEdgeSet gives the boundary of the k layer against the surrounding RescueBlockUnitSides. The interior edges of the edge set gives the intersections of the layer with any interior RescueSections. Wherever they touch, these edges share RescueTrimVertexes or entire RescuePolyLines with other items in the wireframe model.

The RescueMacroVolume may contain a top RescueEdgeSet and a bottom RescueEdgeSet. These serve to describe the intersection of the RescueBlockUnitHorizonSurface above or below the RescueBlockUnit with the volume.

/********************************************************************

  RescueMacroVolume.h

  The macro model description for a volume in a block unit.

  Rod Hanks,  September 1997

*********************************************************************/
#ifndef RescueMacroVolume_H
#define RescueMacroVolume_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
#include "RescueBlockUnitSide.h"
#include "cSetRescueBlockUnitSide.h"
#include "cBagInt.h"
#include "cBagRescueSection.h"
#include "cSetRescueEdgeSet.h"
#include "RescueCoordinateSystem.h"

class RescueSection;

class RescueMacroVolume:public RescueObject
{
public:
  void AddBlockUnitSide(RescueBlockUnitSide *existingSide)
                        {(*blockUnitSides) += existingSide;}
  void DropBlockUnitSide(RescueBlockUnitSide *existingSide)
                        {(*blockUnitSides) -= existingSide;}
  RescueBlockUnitSide *NthBlockUnitSide(int zeroBasedOrdinal)
                        {return blockUnitSides->NthObject(zeroBasedOrdinal);}
  void AddInteriorSection(RescueSection *existingSection)
                        {(*interiorSections) += existingSection;}
  void DropInteriorSection(RescueSection *existingSection)
                        {(*interiorSections) -= existingSection;}
  RescueSection *NthInteriorSection(int zeroBasedOrdinal) 
                        {return interiorSections->NthObject(zeroBasedOrdinal);}
                  // RescueMacroVolume does not "own" RescueSections,
                  // so it does not create or delete them, merely
                  // catalogs relationships to them. However, it does
                  // own block unit sides (but not the sections which
                  // they refer to).

  void AddKLayerEdge(RescueEdgeSet *existingEdgeSet)
              {(*kLayerEdges) += existingEdgeSet;} 
  bool DeleteKLayerEdge(RescueEdgeSet *existingEdgeSet)
      {return ((*kLayerEdges) -= existingEdgeSet);}
  RescueEdgeSet *NthKLayerEdge(int zeroBasedOrdinal)
      {return kLayerEdges->NthObject(zeroBasedOrdinal);}

  void SetTopEdge(RescueEdgeSet *topEdge);
  void SetBottomEdge(RescueEdgeSet *bottomEdge);
  /*
    RescueMacroVolume has a curious relationship with its top and bottom RescueEdgeSets.
    It isn't sure whether it owns them or not.  RescueEdgeSet keeps a usage count.  RescueMacroVolume
    increments and decrements this count via RescueEdgeSet's RegisterUser and UnregisterUser
    methods.  UnregisterUser deletes the edge set when the usage falls to zero.

    Do not delete RescueEdgeSets.  If you don't want one anymore, simply replace it everyplace
    it is used with a new one.  It will delete itself.
  */
  RescueEdgeSet *TopEdges() {return topEdges;}
  RescueEdgeSet *BottomEdges() {return bottomEdges;}

  int  CountOfSides() { return  blockUnitSides->Count(); }

  ~RescueMacroVolume();
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueMacroVolume();
  RescueMacroVolume(FILE *archiveFile);
  void PartialRead(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
#ifdef DB_HOOK
  void Archive(RescueBlockUnit *bu,
               char *data_collection_s, 
               char *geoscience_ntrp_s);
  RescueMacroVolume(char *earth_pos_rgn_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
  int PreviousId() {return previousId;}
#endif

  cSetRescueBlockUnitSide *blockUnitSides;
  cBagRescueSection *interiorSections;
  /*
    boundary sections are arranged as nearly as possible counter-clockwise
    around the volume they enclose.

    Note that section surfaces are ordinarily described with counter-clockwise
    trim loops, as seen from outside the volume which they enclose.  However,
    if a section surface is used as the boundary of two adjacent volumes it
    can only be correctly described in relation to one of them.  Of course, the
    problem is worse for interior sections, since there is not even a convention
    for how they are constructed.
    
    Therefore, software must examine the trim loops to determine which way round 
    the description of the surface is built with respect to any particular boundary.

    If this is insufficient, we could include a "normal" point with respect to
    each surface in RescueSurface.
  */
  RescueEdgeSet *topEdges;
  RescueEdgeSet *bottomEdges;
  /*
    Trims the intersection between this volume and it's top and bottom RescueBlockUnitHorizonSurface.
    If the two intersections are trimmed the same, these may point to the same object.  Also, the
    objects pointed to here may also be pointed to by some other RescueMacroVolume.

    Readers should not compare topEdges/bottomEdges pointers to decide if they are the same object
    however.  Since there is no global list of RescueEdgeSets, each RescueEdgeSet is written out 
    each time it is used and instantiated as a new object each time it is read in.  However, you
    can compare the Id() of two RescueEdgeSets you read.  If they are the same, then the creator
    of the model re-used a RescueEdgeSet.
  */
  cSetRescueEdgeSet *kLayerEdges;
  /*
  The kLayerEdges is a set of trim edge sets, one for each k layer of the 3 dimensional
  block unit grid.  The edges are arranged in order by increasing k index.  That is,
  the first RescueEdgeSet in kLayerEdges relates to the edge having the lowest k
  index.

  Note that pinched out layers can share RescuePolyLines, but they cannot share
  RescueEdgeSets - because we own the edge set we will try to delete it when
  we are deleted, and if we try twice we will meet with disaster.
*/

  cBagInt *interiorSectionIDs;
#ifdef DB_HOOK
  char surrogateKey[20];
  int previousId;
#endif

  friend class cSetRescueMacroVolume;
  friend class RescueBlockUnit;
  friend class RescueGeometry;
};

#endif




RescueModel

The model is a convenient handle by which the entire set of available information is manipulated. Using RescueModel methods, an entire model can be archived, unarchived, or deleted with a single statement.

    RescueModel* myModel = RescueModel::UnarchiveModel(argv[1]);
    RescueModel* myModel = new RescueModel("test model b", cs);
    myModel->ArchiveModel("tmodel2.txt");
    delete myModel;

The model contains a RescueCoordinateSystem. This coordinate system is the grandfather of all coordinate systems used throughout the model. All other coordinate systems can be derived from this one by rotating this coordinate system a given number of degrees about a given RescueVertex.

Not only the coordinate systems in the model, but the various grids in the model are closely related to this coordinate system. For all three dimensional grids in the model, i is related to the x axis, j to the y axis, and k to the z axis. For two dimensional grids used to represent horizontal surfaces, i is related to x and j is related to y. For other grids, which grid axis relates to which coordinate system axis is generally given in the constructor.

The model contains a number of methods to allow retrieval of lists of other objects. The order of these objects in the list is generally not meaningful.

/********************************************************************

  RescueModel.h

  The main object for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEMODEL_H
#define RESCUEMODEL_H

#include "myHeaders.h"

#include "RCHString.h"
#include "RescueUnit.h"
#include "RescueBlock.h"
#include "RescueHorizon.h"
#include "RescueWellbore.h"
#include "RescueSection.h"
#include "cSetRescueUnit.h"
#include "cSetRescueBlock.h"
#include "cSetRescueHorizon.h"
#include "cSetRescueWellbore.h"
#include "cSetRescueSection.h"
#include "cSetRescuePolyLine.h"
#include "cSetRescueTrimVertex.h"
#include "cSetRescueReferenceSurface.h"
#include "cSetRescueLookup.h"
#include "RescueProgressReporter.h"
#include "cSetString.h"

class RescueCoordinateSystem;
class cNameValuePair;

class RescueModel:public RescueObject
{
public:
  static RescueProgressReporter *RegisterProgressReporter(RescueProgressReporter *newProgressObject);

  static RescueModel *UnarchiveModel(char *pathName, bool binary = false);        
                                      // Create an instance from an  
                                      // exchange file.
  static void CleanFromUnarchive();   // Deletes a model which was half-created
                                      // due to an interrupted UnarchiveModel
                                      // command.  Do not call this function at
                                      // any other time.
  bool ArchiveModel(char *pathName, bool binary = false);  
                                      // Write an exchange file from 
                                      // an instance.
#ifdef DB_HOOK
  static RescueModel *UnarchiveModel(char *userName, char *password,
                                     char *modelName);
                                      // Create an instance from an Epicentre database.
  bool ArchiveModel(char *userName, char *password,
                    char *existenceKind, char *description);
                                      // Write an exchange instance to an Epicentre database.
                                      // Not necessary to delete it if it already exists.
  bool DeleteFromArchive(char *userName, char *password);
                                      // Delete this model from the archive.  Does not
                                      // affect the state of the model in memory.
  static bool DeleteFromArchive(char *userName, char *password, char *modelName);
                                      // Delete a model with a particular name from
                                      // the archive.
  static RCHString *ListArchivedModels(char *userName, char *password);
                                      // Returns an RCHString with
                                      // "Model:" modelName \t description \n
                                      // User application can parse this to present a list
                                      // of potential models to a user or to determine which
                                      // model to Unarchive.  The RCHString object becomes
                                      // the responsibility of the caller.
  static void ListArchivedModels(char *userName, char *password, 
                          "cSetString *modelNames, 
                          "cSetString *descriptiopns);
                                      // Pass two (preferably empty) cSetStrings, Rescue will
                                      // fill the first with model names, the second with
                                      // descriptions.
                                      // The cSetString and RCHString objects becomes
                                      // the responsibility of the caller.
  static void SetAtomicCommit(bool commitState = true) {atomicCommit = commitState;}
                                      // If set to true, the routines do one big commit at the
                                      // end.  You begger have a REALLY big rollback area.
  static bool IsAtomicCommit() {return  atomicCommit;}
#endif

  RescueModel(char *modelNameIn);     // Create an empty model.
  RescueModel(char *modelNameIn, RescueCoordinateSystem *coordinateSystemIn);     
  ~RescueModel();                     // Drop existing model (will drop all
                                      // associated class instances).

  RCHString *ModelName() {return modelMoniker;}
                                    // Do NOT drop the object returned.
  void SetModelName(char *newName);

  int UnitCount() {return units->Count();}
  int BlockCount() {return blocks->Count();}
  int HorizonCount() {return horizons->Count();}
  int WellboreCount() {return wellbores->Count();}
  int SectionCount() {return sections->Count();}
  int PolyLineCount() {return polyLines->Count();}
  int VertexCount() {return trimVertexes->Count();}

  RescueUnit *NthRescueUnit(int zeroBasedOrdinal) {return units->NthObject(zeroBasedOrdinal);}
  RescueBlock *NthRescueBlock(int zeroBasedOrdinal) {return blocks->NthObject(zeroBasedOrdinal);}
  RescueHorizon *NthRescueHorizon(int zeroBasedOrdinal) {return horizons->NthObject(zeroBasedOrdinal);}
  RescueWellbore *NthRescueWellbore(int zeroBasedOrdinal) {return wellbores->NthObject(zeroBasedOrdinal);}
  RescueSection *NthRescueSection(int zeroBasedOrdinal) {return sections->NthObject(zeroBasedOrdinal);}
  RescuePolyLine *NthRescuePolyLine(int zeroBasedOrdinal) {return polyLines->NthObject(zeroBasedOrdinal);}
  RescueTrimVertex *NthRescueTrimVertex(int zeroBasedOrdinal) {return trimVertexes->NthObject(zeroBasedOrdinal);}
                                    // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.

  bool DropRescueUnit(RescueUnit *unitToDrop) {return ((*units) -= unitToDrop);}
  bool DropRescueBlock(RescueBlock *blockToDrop) {return ((*blocks) -= blockToDrop);}
  bool DropRescueHorizon(RescueHorizon *horizonToDrop) {return ((*horizons) -= horizonToDrop);}
  bool DropRescueWellbore(RescueWellbore *wellboreToDrop) {return ((*wellbores) -= wellboreToDrop);}
  bool DropRescueSection(RescueSection *sectionToDrop) {return ((*sections) -= sectionToDrop);}
  bool DropRescuePolyLine(RescuePolyLine *polyLineToDrop) {return ((*polyLines) -= polyLineToDrop);}
  bool DropRescueTrimVertex(RescueTrimVertex *trimVertexToDrop) {return ((*trimVertexes) -= trimVertexToDrop);}
  bool DropRescueReferenceSurface(RescueReferenceSurface *surfaceToDrop) {return ((*referenceSurfaces) -= surfaceToDrop);}
  bool DropRescueLookup(RescueLookup *lookupToDrop) {return ((*lookups) -= lookupToDrop);}
                                    // Mustn't drop an owned object directly.
                                    // Use the owner's drop method instead.
                                    // These return false if the object passed is
                                    // not a member of the set (and in that case the
                                    // object IS NOT dropped.
  RescueHorizon *HorizonNamed(char *horizonName) {return horizons->ObjectNamed(horizonName);}
  RescueSection *SectionNamed(char *sectionName) {return sections->ObjectNamed(sectionName);}
  
  RescueUnit *UnitIdentifiedBy(int identifier) {return units->ObjectIdentifiedBy(identifier);}
  RescueBlock *BlockIdentifiedBy(int identifier) {return blocks->ObjectIdentifiedBy(identifier);}
  RescueHorizon *HorizonIdentifiedBy(int identifier) {return horizons->ObjectIdentifiedBy(identifier);}
  RescueWellbore *WellboreIdentifiedBy(int identifier) {return wellbores->ObjectIdentifiedBy(identifier);}
  RescueSection *SectionIdentifiedBy(int identifier) {return sections->ObjectIdentifiedBy(identifier);}
  RescueBlockUnitHorizonSurface *HorizonSurfaceIdentifiedBy(int identifier);
  RescueBlockUnitPropertyGroup *BlockUnitPropertyGroupIdentifiedBy(int identifier);
  RescueBlockUnit *BlockUnitIdentifiedBy(int identifier);
  RescueReferenceSurface *ReferenceSurfaceIdentifiedBy(int identifier);
  RescueLookup *LookupIdentifiedBy(int identifier) {return lookups->ObjectIdentifiedBy(identifier);}
  
  RescueSurface *SurfaceIdentifiedBy(int identifier);
  RescuePolyLine *PolyLineIdentifiedBy(int identifier) {return polyLines->ObjectIdentifiedBy(identifier);}
  RescueTrimVertex *TrimVertexIdentifiedBy(int identifier) {return trimVertexes->ObjectIdentifiedBy(identifier);}
  RescueTrimVertex *TrimVertexLocatedBy(float x, float y, float z) {return trimVertexes->TrimVertexLocatedBy(x, y, z);}
  RescuePolyLine *PolyLineBetween(RescueTrimVertex *end1, RescueTrimVertex *end2) {return polyLines->PolyLineBetween(end1, end2);}
  RescueLookup *LookupNamed(char *name) {return lookups->ObjectNamed(name);}
                                    // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.
  RescueHorizon *TopHorizon();
  RescueHorizon *BottomHorizon();
                                    // These horizon and unit functions depend upon the
  RescueUnit *TopUnit();            // objects being setup right with respect to the
  RescueUnit *BottomUnit();         // HorizonAboveMe/HorizonBelowMe, UnitAboveMe/UnitBelowMe.

  RescueCoordinateSystem *CoordinateSystem() {return coordinateSystem;}
                                    // Do NOT delete the returned object.
  void SetCoordinateSystem(RescueCoordinateSystem *newCoordinateSystem)
                            {coordinateSystem = newCoordinateSystem;}
                                    // Coordinate systems are not considered owned objects.
  cNameValuePair *NameValuePairs() {return nameValuePair;}
                                    // Interrogate the object returned to manipulate name/value pairs
                                    // belonging to this model.  DO NOT delete the object, it belongs
                                    // permanently to the model.
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
  static int fileVersion;
private:
#ifdef DB_HOOK
  void Archive(char *existenceKind, char *description);
  static void DeleteFromArchivePrimitive(char *modelName);
  RescueModel(char *earth_model_s, char *data_collection_s);
  void UnArchive(char *earth_model_s, char *data_collection_s);
#endif
  RescueModel(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  void UnArchive(FILE *archiveFile);
  void CommonInitialization(char *nameIn);
  static void RescueProgress(char *progressDescription);

  RCHString *modelMoniker;
  RescueCoordinateSystem *coordinateSystem;
  cSetRescueUnit *units;
  cSetRescueBlock *blocks;
  cSetRescueHorizon *horizons;
  cSetRescueWellbore *wellbores;
  cSetRescueSection *sections;
  cSetRescuePolyLine *polyLines;
  cSetRescueTrimVertex *trimVertexes;
  cSetRescueReferenceSurface *referenceSurfaces;
  cSetRescueLookup *lookups;
  cNameValuePair *nameValuePairs;

  static RescueProgressReporter *progressReportObject;
#ifdef DB_HOOK
  static char second_after_rank_s[20];
  static char after_rank_s[20];
  static char above_rank_s[20];
  static char below_rank_s[20];

  static char *SecondAfterRankSK() {return second_after_rank_s;}
  static char *AfterRankSK() {return after_rank_s;}
  static char *AboveRankSK() {return above_rank_s;}
  static char *BelowRankSK() {return below_rank_s;}

  static bool atomicCommit;
#endif

#ifdef EPI_LAYER
  static daeSession session;
  static daeScope dataStore;
#endif

  friend class RescueBlock;
  friend class RescueHorizon;
  friend class RescueUnit;
  friend class RescueWellbore;
  friend class RescueSection;
  friend class RescuePolyLine;
  friend class RescueTrimVertex;
  friend class RescueReferenceSurface;
  friend class RescueLookup;
  friend class RescueBlockUnit;
  friend class RescueBlockUnitPropertyGroup;
  friend class cSetRescueReferenceSurface;
  friend class cSetRescueSection;
  friend class RescueBlockUnitHorizonSurface;
  friend class cSetRescueTrimEdge;
  friend class cSetRescueTrimLoop;
  friend class cSetRescueEdgeSet;
  friend class cSetRescueLookup;
  friend class cSetRescueBlockUnitHorizonSurface;
  friend class cSetRescueHorizon;
  friend class cSetRescueWellboreSurface;
  friend class cSetRescueWellboreProperty;
  friend class cSetRescueWellboreSampling;
  friend class cSetRescueWellbore;
  friend class cSetRescueBlockUnitSide;
  friend class RescueMacroVolume;
  friend class cSetRescuePolyLine;
};

#endif



RescueObject

This is an abstract supertype which is the base class of most of the objects in the Rescue library. It provides a method for uniquely identifying each object.

#ifndef RESCUEOBJECT_H
#define RESCUEOBJECT_H

#include <stdio.h>


typedef enum {R_TOMBSTONE, 
	          R_RescueObject,
              R_RescueModel,
              R_RescueBlock,
              R_RescueUnit,
              R_RescueHorizon,
              R_RescueSection,
              R_RescueBlockUnit,
              R_RescueBlockUnitSide,
              R_RescueProperty,
              R_RescueBlockUnitPropertyGroup,
              R_RescueBlockUnitHorizonSurface,
              R_RescueWellbore,
              R_RescueWellboreProperty,
              R_RescueGrid,
              R_RescueGridAxis,
              R_RescueArray,
              R_RescueTripletArray,
              R_RescueCoordinateSystemAxis,
              R_RescueVertex,
              R_RescueCoordinateSystem,
              R_RescueSurface,
              R_RescueDoubletArray,
              R_RescueTrimVertex,
              R_RescueEdgeSet,
              R_RescueTrimEdge,
              R_RescuePolyLine,
              R_RescuePolyLineNode,
              R_RescuePolyLineNodeUV,
      	      R_RescueGeometry,
			  R_RescueSurfaceCell,
              R_RescueWellboreSampling,
              R_RescueWellboreSurface,
              R_RescueWellboreCell,
              R_RescueReferenceSurface,
              R_RescueLookup,
              R_RescueLookupItem,
              R_RescueLookupString,
              R_RescueLookupTable,
              R_RescueArrayDouble,
              R_RescueArrayByte,
              R_RescueArrayShort,
              R_RescueTrimLoop,
              R_RescueArrayFloat,
              R_RescueMacroVolume} _RescueObjectType;

/************************* R e s c u e O b j e c t *************************/
/*
	An abstract class for all of the objects in the application view,
	the main purpose being initialization, run-time typing of objects, 
	and tombstones.
*/
class RescueObject
{
public:
/************************* I n i t i a l i z a t i o n ********************/
/******************** F u l l y   C o m p a t i b l e **********************/
#if 0
  static bool Initialize(char *username, char *password, char *facility);
                                        // This static method is used to log
                                        // on to the database.
                                        // The initialization applies to all
                                        // classes in this header.
  static void Commit();			// Commit database changes.
  static void Rollback();		// Rollback database changes.
  static void LogOff();			// Log off of the database.
					// Note these operations can be done
					// on any object (or none) but they
					// always apply to ALL objects.
#endif
/*************************** R e a d i n g *********************************/
/******************** F u l l y   C o m p a t i b l e **********************/
  bool IsIdentifiedBy(int possibleID) {return (uniqueID == possibleID);}
  int Identifier() {return uniqueID;}
  bool IsNamed(char *mayBeName) {return false;}
  _RescueObjectType IsA() {return isA;}
  virtual bool IsOfType(_RescueObjectType thisType)
				{return (thisType == R_RescueObject);}
					// Returns true if the object is a
					// member of the specified class.
  virtual bool IsValid() = 0;  		// Returns true if object appears
					                        // to be currently valid.
/************************** H o u s e k e e p i n g **********************/
/******************** F u l l y   C o m p a t i b l e **********************/
  ~RescueObject() {isA == R_TOMBSTONE;}
  RescueObject() {uniqueID = uniqueIDCounter++;}
/************************** P r i v a t e *********************************/
protected:
  void ReadId(FILE *archiveFile); 
  virtual void Relink(RescueObject *object) {} 

  volatile _RescueObjectType isA;
  int uniqueID;
  static int uniqueIDCounter;
};

#endif

RescuePolyLine

The poly line is an important member of the wireframe model. It defines a multi-segmented line in three dimensional space, and through its relationships to RescueTrimVertex and RescuePolyLineNode, the relationships between that line and other lines and surfaces.

A RescuePolyLine is a line defined as an ordered sequence of points. It has at least two end points, which are RescueTrimVertexs. It may also have interior points, which are RescuePolyLineNodes. RescuePolyLineNodes may be members of only one RescuePolyLine, but RescueTrimVertexs may be members of any number of RescuePolyLines. When RescuePolyLines share RescueTrimVertexs they are considered to be connected.

          RescuePolyLine *line = new RescuePolyLine(model, 
                             model->NthRescueTrimVertex((loop * 12) + (subloop * 3) + subloop2),
                             model->NthRescueTrimVertex((loop * 12) + ((subloop + 1) * 3) + subloop2));

/********************************************************************

  RescuePolyLine.h

  An edge on a wireframe drawing.

  Rod Hanks,  July 1996

*********************************************************************/
#ifndef RESCUEPOLYLINE_H
#define RESCUEPOLYLINE_H

#include "myHeaders.h"
#include "RescuePolyLineNode.h"
class RescueTrimVertex;
class RescueModel;
#include "cSetRescuePolyLineNode.h"

class RescuePolyLine:public RescueObject
{
public:
  ~RescuePolyLine();
  RescuePolyLine(RescueModel *parentModelIn, 
                 RescueTrimVertex *leftVertexIn, 
                 RescueTrimVertex *rightVertexIn);

  cSetRescuePolyLineNode *PolyLineNodes() {return polyLineNodes;}
  RescueTrimVertex *LeftVertex() {return leftVertex;}
  RescueTrimVertex *RightVertex() {return rightVertex;}

  virtual bool IsOfType(_RescueObjectType thisType);
					// Returns true if the object is a
					// member of the specified class.
  virtual bool IsValid();  		    // Returns true if object appears
					                        // to be currently valid.
protected:
  virtual void Archive(FILE *archiveFile);
  RescuePolyLine(FILE *archiveFile);
  virtual void Relink(RescueObject *object); // Pass RescueModel.

private:
  cSetRescuePolyLineNode *polyLineNodes;
  RescueTrimVertex *leftVertex;
  RescueTrimVertex *rightVertex; 

  int leftVertexID;
  int rightVertexID;  // Used only during relinking.

  friend class cSetRescuePolyLine;
};

#endif

RescuePolyLineNode

The polyline node is a member of the wireframe model. It defines a node on a RescuePolyLine which exists on that line and no other (shared nodes are defined with RescueTrimVertex). Through a set of RescuePolyLineNodeUV, it also defines the relationship of that node to some number of surfaces.

*(line->PolyLineNodes()) += new RescuePolyLineNode(subloop * 300.0 + 100.0, 
                                                      loop * 300.0,
                                                      subloop2 * 300.0);

As in the example, the poly line node is created separately, then added to the RescuePolyLine. Unlike most lists, order is important. The node closest to the left vertex of the RescuePolyLine occupies the zeroth position in the list. Other nodes are then placed in the list in order from left to right.

/********************************************************************

  RescuePolyLineNode.h

  A point on a polyline.

  The point is described by two kinds of values.  A u,v pair gives the
  address of the point in terms of the i,j values of the some face's
  two dimensional grid.

  The x,y,z triplet gives the address of the point within the model's
  3 dimensional coordinate system.  It is calculated from the u,v pair.

  Rod Hanks,  June 1996

*********************************************************************/
#ifndef RESCUEPOLYLINENODE_H
#define RESCUEPOLYLINENODE_H

#include "myHeaders.h"
#include "RescuePolyLineNodeUV.h"
#include "cSetRescuePolyLineNodeUV.h"
class RescueSurface;

class RescuePolyLineNode:public RescueObject
{
public:
  ~RescuePolyLineNode();
  RescuePolyLineNode(double x, double y, double z);
  RescuePolyLineNode(float x, float y, float z);
  void SetUVValue(RescueSurface *face, float u, float v);
              // If face is already listed, uv is changed.
              // If not, face is added to the list.
  void SetXYZValue(double x, double y, double z)
                          {xValue = x; yValue = y; zValue = z;}
  void SetXYZValue(float x, float y, float z)
                          {xValue = (double) x; yValue = (double) y; zValue = (double) z;}

  int FaceCount() {return surfaceUVs->Count();}
  RescueSurface *NthFace(int zeroBasedOrdinal) 
            {return surfaceUVs->NthObject(zeroBasedOrdinal)->Face();}
  float U(RescueSurface *face) {return UVForFace(face)->U();}  
  float V(RescueSurface *face) {return UVForFace(face)->V();}  
                  // Return u and v for a particular
                  // face (0.0 if face not present).

  double X() {return xValue;}     
  double Y() {return yValue;}     
  double Z() {return zValue;}     
  
  bool  SurfaceOnNode( RescueSurface&  surf );
                                          // If the node has UV coords on the
                                          // given surface return TRUE
  
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
protected:
  virtual void Archive(FILE *archiveFile);
  RescuePolyLineNode(FILE *archiveFile);
  virtual void Relink(RescueObject *object); // Pass RescueModel.
  RescuePolyLineNodeUV *UVForFace(RescueSurface *face);
  double xValue;
  double yValue;
  double zValue;

private:
  cSetRescuePolyLineNodeUV *surfaceUVs;

  friend class cSetRescuePolyLineNode;
  friend class RescuePolyLine;
};

#endif


RescuePolyLineNodeUV

The Node UV records the relationship between a RescuePolyLineNode and a RescueSurface (either a RescueBlockUnitHorizonSurface or a RescueSection). The exact surfaces related to each point are recorded, along with a UV (which is a floating point description of the point within the surface's two dimensional logical indexing space).

  line->PolyLineNodes()->NthObject(0)->SetUVValue(surface,
                                                          (double) ((blockLoop * 3) + 1), 
                                                           0.0);

RescuePolyLineNodeUV objects are not instantiated directly. They are created by the RescuePolyLineNode SetUVValue method (which RescueTrimVertex also inherits).

/********************************************************************

  RescuePolyLineNodeUV.h

  The description of a point in terms of it's position on some face's
  two dimensional grid.

  Rod Hanks,  July 1996

*********************************************************************/
#ifndef RescuePolyLineNodeUV_H
#define RescuePolyLineNodeUV_H

#include "myHeaders.h"

class RescueSurface;

class RescuePolyLineNodeUV:public RescueObject
{
public:
  RescuePolyLineNodeUV(RescueSurface *faceIn, float u, float v)
                            :uValue(u)
                            ,vValue(v)
                            ,face(faceIn) {isA = R_RescuePolyLineNodeUV;}
  void SetUVValue(float u, float v) {uValue = u; vValue = v;}
  float U() {return uValue;} 
  float V() {return vValue;} 
  RescueSurface *Face() {return face;}
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
protected:
  virtual void Archive(FILE *archiveFile);
  RescuePolyLineNodeUV(FILE *archiveFile);
#ifdef DB_HOOK
  RescuePolyLineNodeUV(float uValueIn, float vValueIn, int faceIDin)
    :uValue(uValueIn), vValue(vValueIn), faceID(faceIDin) {}
#endif

private:
  virtual void Relink(RescueObject *object);
 
  float uValue;
  float vValue;
  RescueSurface *face;

  int faceID;     // Used only for relinking.

  friend class cSetRescuePolyLineNodeUV;
  friend class RescuePolyLine;
};

#endif


RescueProgressReporter

This is an abstract object whose purpose is to allow reporting of progress during model archiving and retrieval. To use this feature, create a subclass of this class with a definition of the function ReportProgress. Instantiate your class and pass the instance to the RescueModel::RegisterProgressReporter method. Turn off previously registered objects by passing 0. The registration method returns the currently registered object. If no object is currently registered the return will be 0. This mechanism allows individual routines to establish their own progress reporting objects at the top, then replace any pre-existing progress reporter as they exit.

  {
    MyProgressReporter localProgressReporter;
  
    RescueProgressReporter *callersReporter = RescueModel::RegisterProgressReporter(&localProgressReporter);
    // routine tasks here. 
    RescueModel::RegisterProgressReporter(callersReporter);
  }

/**************************************************************************

  RescueProgressReporter.h

  An abstract class which may be subclassed to report progress during
  RESCUE operations.  Create an instance of the subclass and pass it to
  RescueModel::RegisterProgressReporter.

  Rod Hanks,  November 1997

**************************************************************************/

#ifndef RescueProgressReporter_H
#define RescueProgressReporter_H
#include "myHeaders.h"

class RescueProgressReporter

{
public:
  virtual void ReportProgress(char *phaseDescription)=0;
};

#endif


RescueProperty

This object contains properties which are attached to a block unit's grid. The properties are held by the parent RescueBlockUnitPropertyGroup.

  RescueProperty *property = new RescueProperty(group,                
                                                propertyName[propertyLoop],        
                                                unitOfMeasure[propertyLoop],
                                                -999.9, 
                                                (float *) propertyArray);
The example above creates a property using RescueArrayFloat. These types of property arrays are used for floating point measurements. A name, unit of measure, missing value example, and array of properties are given.
        prop = new RescueProperty(group, "Property B", "Type B", "Colors", 
                                                    model->LookupNamed("Colors"),
                                                    (unsigned char) 255);
This next example creates a lookup-based array of properties which will use RescueArrayByte. These types of property arrays are used when there are no more than 255 discrete measurements. Using the associated RescueLookup object, each measurement can be defined by a string or by a table of floating points. In the example above, the array of indexes into the RescueLookup is given in a later step.
        prop = new RescueProperty(group, "Property C", "Type C", "Waveforms", 
                                                    model->LookupNamed("Waveforms"),
                                                    (unsigned short) 9999);
The final example creates a lookup-based array of properties which will use RescueArrayShort. These types of property arrays are used when there are no more than 2^16-1 discrete measurements. Again using the associated RescueLookup object, each measurement can be defined by a string or by a table of floating points. The data type of the nullValue argument is used to determine how much space to allocate for each item in the array. The following code fragment shows how a reader would determine which type of array was used.
        data = prop->Data();
        switch (data->IsA())
        {
        case R_RescueArrayFloat:
          break;
        case R_RescueArrayByte:
          break;
        case R_RescueArrayShort:
          break;
        }
Properties are cell-centered. This means that in each of the three dimensions the arrays of properties have one less node than the block unit grid.
/********************************************************************

  RescueProperty.h

  Property for RESCUE's data model.  Attach to 

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEPROPERTY_H
#define RESCUEPROPERTY_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
#include "RCHString.h"
#include "RescueArray.h"
class RescueBlockUnitPropertyGroup;

class RescueLookup;

class RescueProperty:public RescueObject
{
public:
  RescueProperty(RescueBlockUnitPropertyGroup *parentGroupIn,
                 char *propertyNameIn, 
                 char *propertyTypeIn, char *unitOfMeasureIn,
                 float nullValue, float *valueArray = 0);
                            // Constructs a property array for floats,
  RescueProperty(RescueBlockUnitPropertyGroup *parentGroupIn,
                 char *propertyNameIn, 
                 char *propertyTypeIn, char *unitOfMeasureIn,
                 RescueLookup *lookupTableIn,
                 unsigned char nullValue, unsigned char *valueArray = 0);
                            // Constructs a property array for a lookup table
                            // with 255 or fewer entries,
  RescueProperty(RescueBlockUnitPropertyGroup *parentGroupIn,
                 char *propertyNameIn, 
                 char *propertyTypeIn, char *unitOfMeasureIn,
                 RescueLookup *lookupTableIn,
                 unsigned short nullValue, unsigned short *valueArray = 0);
                            // Constructs a property array for a lookup table
                            // with 2^16-1 or fewer entries,
  ~RescueProperty() {delete data;}

  RescueBlockUnitPropertyGroup *ParentGroup() {return parentGroup;}
  RescueArray *Data() {return data;}
                            // Use data->IsOfType() to discover if the
                            // object is one of RescueArrayFloat, 
                            // RescueArrayByte, or RescueArrayShort.
                            // Then cast the returned pointer and access
                            // accordingly.
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  virtual void Archive(FILE *archiveFile);
  RescueProperty(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
#ifdef DB_HOOK
  void Archive(RescueBlockUnit *bUnit, char *data_collection_s, char *geoscience_ntrp_s);
  RescueProperty(RescueBlockUnitPropertyGroup *parentGroupIn,
                 char *p_element_value_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
  char *UnarchivedSK() {return surrogateKey;}
#endif
  RescueBlockUnitPropertyGroup *parentGroup;
  RescueArray *data; // grid is parentGroup->blockUnit->blockUnitGrid
#ifdef DB_HOOK
  char surrogateKey[20];
#endif
  friend class cSetRescueProperty;
  friend class RescueBlockUnitPropertyGroup;
};

#endif


RescueReferenceSurface

A RescueReferenceSurface is a horizontal RescueSurface, either a RescueBlockUnitHorizonSurface or an independent surface which is used to define proportional or referential RescueGeometry grids.

When a surface which is already being used in the model as a RescueBlockUnitHorizonSurface is used as a reference surface it is instantiated via constructors described with that class. RescueReferenceSurfaces may be instantiated directly however, when they will be used only for constructing a RescueGeometry grid and are not used as a horizon surface.

/********************************************************************

  RescueReferenceSurface.h

  Holds a horizontal surface which may be used to reference z values
  on a RescueGeometry (block unit grid).

  This is mostly necessary because some children of RescueSurface,
  notably RescueSection, would NOT be good candidates for reference
  surfaces.

  Rod Hanks,  June 1997

*********************************************************************/
#ifndef RescueReferenceSurface_H
#define RescueReferenceSurface_H

#include "myHeaders.h"
#include "RescueSurface.h"
#include "RescueEdgeSet.h"
class RescueHorizon;
class RescueBlockUnit;

class RescueReferenceSurface:public RescueSurface
{
public:
  RescueReferenceSurface(RescueModel *model,
                         RescueCoordinateSystem::Orientation orientation,
                         float i_origin, float i_step,
                         int i_lowbound, int i_count,
                         float j_origin, float j_step,
                         int j_lowbound, int j_count,
                         float missingValue, float rotation, RescueVertex *vertex);
  RescueReferenceSurface(RescueModel *model,
                         RescueCoordinateSystem::Orientation orientation,
                         float i_origin, float i_step,
                         int i_lowbound, int i_count,
                         float j_origin, float j_step,
                         int j_lowbound, int j_count,
                         float missingValue, float rotation, RescueVertex *vertex, 
                         float *values);
         // Creates a new surface with regular x/y geometry.
          // If passed, the values are applied to the Z axis.
  RescueReferenceSurface(RescueModel *model,
                         RescueCoordinateSystem::Orientation orientation,
                          int i_lowbound, int i_count,
                          int j_lowbound, int j_count,
                          float missingValue)
                :RescueSurface(orientation, i_lowbound, i_count, j_lowbound, j_count, missingValue)
                                    {CommonInitialization(model);}
  RescueReferenceSurface(RescueModel *model,
                         RescueCoordinateSystem::Orientation orientation,
                         int i_lowbound, int i_count,
                         int j_lowbound, int j_count,
                         float missingValue, 
                         float *tripletArray)
               :RescueSurface(orientation, i_lowbound, i_count, j_lowbound, 
                              j_count, missingValue, tripletArray)
                                    {CommonInitialization(model);}
          // Creates a new parametric surface.
  
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
protected:
  RescueReferenceSurface(RescueCoordinateSystem::Orientation orientation,
                         RescueCoordinateSystemAxis *i_axis,
                         float i_origin, float i_step,
                         int i_lowbound, int i_count,
                         RescueCoordinateSystemAxis *j_axis,
                         float j_origin, float j_step,
                         int j_lowbound, int j_count,
                         float missingValue, float rotation, RescueVertex *vertex)
                :RescueSurface(orientation, i_axis, i_origin, i_step,
                               i_lowbound, i_count, j_axis, j_origin, j_step,
                               j_lowbound, j_count, missingValue, rotation, vertex) 
                                    {}
  RescueReferenceSurface(RescueCoordinateSystem::Orientation orientation,
                         RescueCoordinateSystemAxis *i_axis,
                         float i_origin, float i_step,
                         int i_lowbound, int i_count,
                         RescueCoordinateSystemAxis *j_axis,
                         float j_origin, float j_step,
                         int j_lowbound, int j_count,
                         float missingValue, float rotation, RescueVertex *vertex, 
                         float *values)
                 :RescueSurface(orientation, i_axis, i_origin, i_step, i_lowbound, 
                                i_count, j_axis, j_origin, j_step, j_lowbound, j_count,
                                missingValue, rotation, vertex, values) 
                                     {}
  RescueReferenceSurface(FILE *archiveFile);
  void Archive(FILE *archiveFile);
#ifdef DB_HOOK
  void Archive(RescueModel *parentModel,
               char *parent_model_s,
               char *geoscience_ntrp_s,
               char *data_collection_s);
  RescueReferenceSurface(char *earth_pos_face_s,
                        RescueCoordinateSystem *coordinateSystemIn,
                        char *parent_model_s, 
                        char *data_collection_s, 
                        char *coordinate_sys_s);
  RescueReferenceSurface(char *earth_pos_face_s,
                        RescueCoordinateSystem *coordinateSystemIn,
                        char *parent_model_s, 
                        char *data_collection_s, 
                        char *coordinate_sys_s,
                        bool skipFlag):RescueSurface(earth_pos_face_s, coordinateSystemIn,
                                                     parent_model_s, data_collection_s,
                                                     coordinate_sys_s) {};
#endif
private:
  void CommonInitialization(RescueModel *model);
  RescueReferenceSurface(FILE *archiveFile, int flag):RescueSurface(archiveFile) {}        
/*  
  Used by RescueBlockUnitHorizonSurface when unarchiving.  We don't want to go thru the
  RescueReferenceSurface initialization, since it is skipped on writing.
*/
  friend class cSetRescueReferenceSurface;
  friend class RescueBlockUnitHorizonSurface;
};

#endif


RescueSection

A section is a surface which is not a horizon. It may be a fault or an artificial surface such as a lease boundary. It may be horizontal, but even if so it cannot be used as the top or bottom surface of a RescueBlockUnit (a RescueBlockUnitHorizonSurface is used for that), nor can it be used referentially for a grid geometry (A RescueReferenceSurface is used for that). It may form part of the boundary of a RescueBlockUnitSide or it may be used as interior detail in a RescueMacroVolume. It is a subclass of RescueSurface and most of its behavior within the model is described there.

  RescueSection *section1 = new RescueSection(RescueCoordinateSystem::RDF, 
                                              "main fault",                                          
                                              model,
                                              true, 
                                              0, 6,            
                                              0, 6,                       
                                              -9999.99, 
                                              section1Face->Array());
Surfaces are similar to Epicentre's regular 2d parametric grids.
/********************************************************************

  RescueSection.h

  The sections for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUESECTION_H
#define RESCUESECTION_H

#include "myHeaders.h"
#include "RescueSurface.h"
#include "RCHString.h"
class RescueModel;
class RescueCoordinateSystemAxis;

class RescueSection:public RescueSurface
{
public:
  typedef enum {AUXILLIARY, FAULT, UNCONFORMITY, LEASE_BOUNDARY} SectionType;
  ~RescueSection();
  RescueSection(RescueCoordinateSystem::Orientation orientation,
                char *newSectionName,
                RescueModel *parentModel,
                SectionType typeIn,
                int i_lowbound, int i_count,
                int j_lowbound, int j_count,
                float missingValue);
  RescueSection(RescueCoordinateSystem::Orientation orientation,
                char *newSectionName,
                RescueModel *parentModel,
                SectionType typeIn,
                int i_lowbound, int i_count, 
                int j_lowbound, int j_count,
                float missingValue, float *tripletArray);
          // Create an empty section.
           // Drop with section->ParentModel()->DropRescueSection(section);
  RCHString *SectionName() {return sectionName;}
                              // Do NOT delete the returned object.
  void SetSectionName(char *newSectionName) {(*sectionName) = newSectionName;}
  SectionType Type() {return type;}
  RescueModel *ParentModel() {return parentModel;}
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
  bool IsNamed(char *possibleName);
#ifdef DB_HOOK
  void Archive(RescueModel *parentModel,
               char *parent_model_s,
               char *geoscience_ntrp_s,
               char *data_collection_s);
  RescueSection(char *earth_pos_face_s,
                RescueCoordinateSystem *coordinateSystemIn,
                char *parent_model_s, 
                char *data_collection_s, 
                char *coordinate_sys_s);
#endif
private:
  RescueSection(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  void Relink(RescueObject *parentObject);

  RCHString *sectionName;
  RescueModel *parentModel;
  SectionType type;

  friend class cSetRescueSection;
  friend class RescueBlockUnitSide;
};

#endif


RescueSplitLine

A subclass of RescueGeometryObject, this class is never instantiated or accessed directly by the user. It is used by RescueGeometry to store node coordinates in parts of the grid where a true corner-point capability (eight xyz triplets per node corner) is needed.

RescueSurface

Although not declared abstract, this object is never instantiated in the model. One of its two subclasses, RescueSection or RescueBlockUnitHorizonSurface, is used instead.

A surface contains a two dimensional grid, either axis of which may be regular (i.e. having a regular relationship to a coordinate system axis via origin and step). Generally when used as sections the axes will not be regular, but are likely to be regular when used for RescueBlockUnitHorizonSurface.

xyz triplets for each node are stored in a RescueTripletArray.

In addition, a surface contains a bag of RescueSurfaceCell and a bag of RescueWellboreSurface objects to record its interactions with RescueGeometry grid cells and RescueWellbore wellbore paths.

/********************************************************************

  RescueSurface.h

  A surface in RESCUE terms is a parametric 2d grid (i,j), with the
  geometry described by an (x,y,z) triplet for each node of the grid.
  The coordinate system of the triplet is the global coordinate system 
  of the model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUESURFACE_H
#define RESCUESURFACE_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
#include "RescueGrid.h"
#include "RescueTripletArray.h"
#include "RescueTrimEdge.h"
#include "cBagRescueSurfaceCell.h"
#include "cBagRescueWellboreSurface.h"
#include "RescueCoordinateSystem.h"
class RescueCoordinateSystemAxis;
class RescueSurfaceCell;
class RescueGeometry;
class RescueEdgeSet;

class RescueSurface:public RescueObject
{
public:
  RescueSurface(RescueCoordinateSystem::Orientation orientation,
                RescueCoordinateSystemAxis *i_axis,
                float i_origin, float i_step,
                int i_lowbound, int i_count,
                RescueCoordinateSystemAxis *j_axis,
                float j_origin, float j_step,
                int j_lowbound, int j_count,
                float missingValue, float rotation, RescueVertex *vertex);
  RescueSurface(RescueCoordinateSystem::Orientation orientation,
                RescueCoordinateSystemAxis *i_axis,
                float i_origin, float i_step,
                int i_lowbound, int i_count,
                RescueCoordinateSystemAxis *j_axis,
                float j_origin, float j_step,
                int j_lowbound, int j_count,
                float missingValue, float rotation, RescueVertex *vertex, 
                float *values);
          // Creates a new surface with regular x/y geometry.
          // If passed, the values are applied to the Z axis.
  RescueSurface(RescueCoordinateSystem::Orientation orientation,
                int i_lowbound, int i_count,
                int j_lowbound, int j_count,
                float missingValue);
  RescueSurface(RescueCoordinateSystem::Orientation orientation,
                int i_lowbound, int i_count,
                int j_lowbound, int j_count,
                float missingValue, 
                float *tripletArray);
          // Creates a new parametric surface.
  RescueGrid *Grid() {return surfaceGrid;}
  RescueTripletArray *Geometry() {return surfaceGeometry;}
  RescueSurfaceCell *NthSurfaceCell(int zeroBasedOrdinal) 
                        {return surfaceCell->NthObject(zeroBasedOrdinal);}
                  // RescueBlockUnit does not "own" RescueSurfaceCells,
                  // so it does not create or delete them, merely
                  // catalogs relationships to them.  These intersections are
                  // managed from RescueGeometry.
  RescueEdgeSet *Edges() {return edges;}
  int *VertexConnectionsAt(RescueGeometry *geometry, int kLayer, int &arrayLength);
                  // Returns a doublely subscripted array in which 0=i, 1=j,
  float ZValueAt(int i, int j);
                  //  Returns z value at an i,j point.

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
  ~RescueSurface();
protected:
  RescueSurface(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  void Relink(RescueObject *parentModel);
private:
  int *AddVertexToArray(int *arrayIn, int i, int j, 
                        int &allocated, int &arrayLength);
  void AddWellboreSurface(RescueWellboreSurface *existingIntersect)
                        {(*surfaceWellbore) += existingIntersect;}
  void DropWellboreSurface(RescueWellboreSurface *existingIntersect)
                        {(*surfaceWellbore) -= existingIntersect;}
                                     // Constructor for RescueWellboreSurface will connect
                                     // both ends.
  void AddSurfaceCell(RescueSurfaceCell *existingCell)
                        {(*surfaceCell) += existingCell;}
  void DropSurfaceCell(RescueSurfaceCell *existingCell)
                        {(*surfaceCell) -= existingCell;}
                                     // Surface cell intersections are managed from
                                     // the geometry side. See RescueGeometry.
#ifdef DB_HOOK
protected:
  void Archive(RescueModel *parentModel,
               char *parent_model_s,
               char *geoscience_ntrp_s,
               char *data_collection_s);
  RescueSurface(char *earth_pos_face_s,
                RescueCoordinateSystem *coordinateSystemIn,
                char *parent_model_s, 
                char *data_collection_s, 
                char *coordinate_sys_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
  int PreviousId() {return previousId;}
private:
#endif

  RescueGrid *surfaceGrid;            // 2d grid.
  RescueTripletArray *surfaceGeometry;
  cBagRescueSurfaceCell *surfaceCell;
  cBagRescueWellboreSurface *surfaceWellbore;
  RescueEdgeSet *edges;          
#ifdef DB_HOOK
  char surrogateKey[20];
  int previousId;
#endif

  friend class RescueBlockUnitHorizonSurface;
  friend class RescueSection;
  friend class RescueSurfaceCell;
  friend class RescueWellboreSurface;
  friend class RescueModel;
  friend class RescuePolyLine;
  friend class RescueGrid;
  friend class cSetRescueWellboreSurface;
  friend class RescueMacroVolume;
};

#endif



RescueSurfaceCell

This class records the proximity of a RescueSurface to a cell of the grid of a RescueGeometry. The class is not directly instantiated. It is created by RescueGeometry:: SetSurfaceIntersection and deleted by RescueGeometry:: DropRescueSurfaceCell. It can be accessed from the related RescueGeometry or the related RescueSurface.

/********************************************************************

  RescueSurfaceCell.h

  The record of an intersect between a grid cell and a surface.

  Rod Hanks,  January 1997

*********************************************************************/
#ifndef RESCUESURFACECELL_H
#define RESCUESURFACECELL_H

#include "myHeaders.h"
#include <stdlib.h>
#ifdef DB_HOOK
class ChunkBuffer;
#endif
class RescueGeometry;
class RescueSurface;

class RescueSurfaceCell:public RescueObject
{
public:
  typedef enum {FRONT,BACK} SurfaceSide;

  RescueGeometry *Geometry() {return geometry;}
  RescueSurface *Surface() {return surface;}
  SurfaceSide Side() {return side;}
  int CellFaceNumber() {return cellFaceNumber;}
  float *UVArray() {return uvs;} // DO NOT free the array that is returned.
  void CellIndex(RescueGeometry *geometry, int &i, int &j, int &k);

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
  ~RescueSurfaceCell();
private:
  RescueSurfaceCell(RescueGeometry *geometryIn, 
                    RescueSurface *surfaceIn,
                    int cellNumber,
                    int cellFaceNumberIn, SurfaceSide sideIn,
                    float *uvsIn = 0);
                  // use RescueGeometry::SetSurfaceIntersection.
  virtual void Archive(FILE *archiveFile);
  RescueSurfaceCell(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
#ifdef DB_HOOK
  virtual void Archive(ChunkBuffer *cBuf);
  RescueSurfaceCell(ChunkBuffer *cBuf);
#endif
  RescueGeometry *geometry;
  RescueSurface *surface;
  int cellNumber;
  int cellFaceNumber;
  SurfaceSide side;
  float *uvs;    // array is 2 x 4 in which the first index is u=0, v=1,
                  // and the second index is the face corner number (see
                  // document).

  int surfaceID;   // used only during relinking.

  friend class RescueGeometry;
  friend class cSetRescueSurfaceCell;
};

#endif


RescueTrimEdge

The trim edge is used to record a relationship between the wireframe model and a RescueBlockUnitSide, RescueBlockUnitHorizonSurface, or RescueMacroVolume, via the RescueEdgeSet member of those classes.

  surface->Edges()->AddBoundaryEdge(new RescueTrimEdge(line, R_LEFT_TO_RIGHT));

The edge is created, then added to the appropriate RescueTrimLoop. A RescueTrimEdge may belong to one and only one RescueTrimLoop.

/********************************************************************

  RescueTrimEdge.h

  An edge of a trim loop.  It contains a pointer to a PolyLine and
  a direction.

  Rod Hanks,  July 1996

*********************************************************************/
#ifndef RESCUETRIMEDGE_H
#define RESCUETRIMEDGE_H

#include "myHeaders.h"
#include "RescuePolyLine.h"
#include "RescueTrimVertex.h"
#ifdef DB_HOOK
#include "RDBMS.h"
#include <string.h>
#endif

typedef enum {R_RIGHT_TO_LEFT, R_LEFT_TO_RIGHT} _RescueLineDirection;
                                  // As seen from outside the object.

class RescueTrimEdge:public RescueObject
{
public:
  RescueTrimEdge(RescuePolyLine *polyLineIn, _RescueLineDirection directionIn)
                                  :polyLine(polyLineIn)
                                  ,direction(directionIn)
                                {isA == R_RescueTrimEdge;}
  _RescueLineDirection Direction() {return direction;}
  RescueTrimVertex *StartingPoint() 
    {return (direction == R_LEFT_TO_RIGHT) ? polyLine->LeftVertex() 
                                           : polyLine->RightVertex();}
  RescueTrimVertex *EndingPoint()
  {return (direction == R_LEFT_TO_RIGHT) ? polyLine->RightVertex()
                                         : polyLine->LeftVertex();}
  int NodeCount() {return polyLine->PolyLineNodes()->gt;Count();}
  RescuePolyLineNode *NthNode(int zeroBasedOrdinal) 
  {return polyLine->PolyLineNodes()->NthObject((direction == R_LEFT_TO_RIGHT) 
            ? zeroBasedOrdinal 
            : (polyLine->PolyLineNodes()->Count() - zeroBasedOrdinal) - 1);}
                                // These do not include vertexes at the end.
  
  bool  SurfaceOnEdge( RescueSurface&  surf );
                                          // If this edge lies on the given
                                          // surface return TRUE
  
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
protected:
  virtual void Archive(FILE *archiveFile);
  RescueTrimEdge(FILE *archiveFile);
  virtual void Relink(RescueObject *object); // Pass RescueModel.
#ifdef DB_HOOK
  void Archive(char *data_collection_s);
  RescueTrimEdge(char *earth_pos_edg_s);
  char *SurrogateKey() {return surrogateKey;}
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
#endif
private:
  RescuePolyLine *polyLine;
  _RescueLineDirection direction;

  int polyLineID;   // Used only during relinking.
#ifdef DB_HOOK
  char surrogateKey[20];
#endif
  friend class cSetRescueTrimEdge;
};

#endif


RescueTrimLoop

A RescueTrimLoop contains a group of RescueTrimEdges which describe the intersection of a surface with a surface or a surface with a volume.

The loop is created, then added to the appropriate RescueEdgeSet. A RescueTrimLoop must belong to one and only one RescueEdgeSet.

/********************************************************************

  RescueTrimLoop.h

  A set of edges which form a loop which may describe the relationship of a top, 
  bottom, or side of a block unit to a set of surfaces.

  Rod Hanks,  September 1997

*********************************************************************/
#ifndef RescueTrimLoop_H
#define RescueTrimLoop_H

#include "myHeaders.h"
#include "RescueTrimEdge.h"
#include "cSetRescueTrimEdge.h"

class RescueTrimLoop:public RescueObject
{
public:
  RescueTrimLoop();
  ~RescueTrimLoop();

  void AddLoopEdge(RescueTrimEdge *existingEdge)
                        {(*loopEdges) += existingEdge;}
  void DropLoopEdge(RescueTrimEdge *existingEdge)
                        {(*loopEdges) -= existingEdge;}
  RescueTrimEdge *NthLoopEdge(int zeroBasedOrdinal)
                        {return loopEdges->NthObject(zeroBasedOrdinal);}
  
  int  CountOfLoopEdge() { return  loopEdges->Count(); }
  bool IsLoop();    // Returns true if the edges are closed and
                    // do progress in a consistent direction.
  
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
protected:
  virtual void Archive(FILE *archiveFile);
  RescueTrimLoop(FILE *archiveFile);
  virtual void Relink(RescueObject *object); // Pass RescueModel.
#ifdef DB_HOOK
  void Archive(char *data_collection_s);
  RescueTrimLoop(char *earth_pos_edg_s);
  char *SurrogateKey() {return loopEdges->SurrogateKey();}
#endif

private:
  RescueTrimLoop(cSetRescueTrimEdge *loopEdgesIn);

  cSetRescueTrimEdge *loopEdges;   

  friend class cSetRescueTrimLoop;
  friend class RescueEdgeSet;
};

#endif

RescueTrimVertex

The trim vertex is the cornerstone of the wireframe model . It records a point in space which is the end point of one or more RescuePolyLine objects. The coordinates are given in the primary RescueCoordinateSystem of the RescueModel, with no rotation. The vertex contains a bag of RescuePolyLine objects to which it is related, and via its superclass RescuePolyLineNode a bag of RescueSurface objects to which it is also related.

  new RescueTrimVertex(model, subloop * 300.0, 
                              loop * 300.0, 
                              subloop2 * 300.0);

/********************************************************************

  RescueTrimVertex.h

  The TrimVertex anchors an end of a polyline.  It is just like a
  regular PolyLineNode, except that it keeps a list of the PolyLines
  of which it is a member.  This list can be used to navigate along
  wireframes.

  Rod Hanks,  July 1996

*********************************************************************/
#ifndef RESCUETRIMVERTEX_H
#define RESCUETRIMVERTEX_H

#include "myHeaders.h"
#include "RescuePolyLineNode.h"
#include "cBagRescuePolyLine.h"
#include "cBagInt.h"

class RescuePolyLine;
class RescueModel;

class RescueTrimVertex:public RescuePolyLineNode
{
public:
  RescueTrimVertex(RescueModel *parentModel,
                   double x, double y, double z);
  RescueTrimVertex(RescueModel *parentModel,
                   float x, float y, float z);
  ~RescueTrimVertex();
  RescuePolyLine *NthPolyLine(int zeroBasedOrdinal)
  {return (*lines).NthObject(zeroBasedOrdinal);}
  virtual bool IsOfType(_RescueObjectType thisType);
					// Returns true if the object is a
					// member of the specified class.
  virtual bool IsValid();  		    // Returns true if object appears
					                        // to be currently valid.
protected:
  virtual void Archive(FILE *archiveFile);
  RescueTrimVertex(FILE *archiveFile);
  virtual void Relink(RescueObject *object); // Pass RescueModel.

private:
  cBagRescuePolyLine *lines;

  cBagInt *lineIDs; // Used only during relinking.

  friend class cSetRescueTrimVertex;
  friend class RescuePolyLine;
};

#endif

RescueTripletArray

The triplet array records xyz coordinates of points on a RescueGrid. It knows how to deal with grids of 1, 2 or 3 dimensions, and avoids storing coordinates which are defined by equal axis grids. It is used by RescueSurface and RescueWellbore to store geometries. The object is never instantiated directly. RescueSurface and RescueWellbore constructors create these objects as needed.

Like other arrays in Rescue, these are in Fortran order, meaning that the first index changes fastest.

/********************************************************************

  RescueTripletArray.h

  A dynamically sized array handler for n dimensional grids of
  floating point triplets for RESCUE's data model.

  The dimensionality of the underlying grid is available from
  the associated grid.

  The RescueTripletArray knows how to deal with these situations,
  (1) n-dimensional arrays in which all axes are parametric
  (2) 2 and 3 dimensional arrays in which the i and j axis are
  regular and thus determine the values of the x and y members of
  the triplet.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUETRIPLETARRAY_H
#define RESCUETRIPLETARRAY_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include "RDBMS.h"
#include <string.h>
class RescueCoordinateSystem;
#endif
class RescueGrid;

class RescueTripletArray:public RescueObject
{
public:
  RescueTripletArray(RescueGrid *existingGrid, float missingValueIn)
                                              :grid(existingGrid)
                                              ,missingValue(missingValueIn)
                                              ,xValue(0)
                                              ,yValue(0)
                                              ,zValue(0)
                                  {isA = R_RescueTripletArray;}
  RescueTripletArray(RescueGrid *existingGrid, float missingValueIn, 
                     float *valueArray);
                                    // Create the array with or without the triplets.
  RescueGrid *Grid() {return grid;}
  float MissingValue() {return missingValue;}
  void SetValue(float nullValueIn, float *valueArray);
                                    // The array has the number of dimensions in
                                    // the grid, plus an extra dimension with count
                                    // of 3, corresponding to x, y, and z.
                                    // The instance makes a copy of the array.
                                    // if the grid has regular axes, then values
                                    // corresponding to the regular axis dimensions
                                    // are ignored.
  void AssignXValue(float *valueArray);
  void AssignYValue(float *valueArray);
  void AssignZValue(float *valueArray);
                                    // The array has the number of dimensions in
                                    // the grid. The pointer is copied, meaning the
                                    // array must have been created with new float [].
                                    // The pointer becomes the property of the object.
  void SetXValue(float *valueArray);
  void SetYValue(float *valueArray);
  void SetZValue(float *valueArray);
                                    // The array has the number of dimensions in
                                    // the grid.  
  float *XValue() {return xValue;}  // Returns a pointer to an array for the
  float *YValue() {return yValue;}  // coordinate system axis desired.  Do NOT
  float *ZValue() {return zValue;}  // delete the array when you are done with it.
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
  bool IsRegular(int which);      // Where i = 0, j = 1, k = 2
  void XYZAt(int i, float &x, float &y, float &z);
                                  // For 1d grids, For an i grid address, return
                                  // x, y, z.
  void XYZAt(int i, int j, float &x, float &y, float &z);
                                  // For 2d grids, For an i,j grid address, return
                                  // x, y, z.
  void XYZAt(int i, int j, int k, float &x, float &y, float &z);
                                  // For 3d grids, For an i,j,k grid address, return
                                  // x, y, z.
private:
  RescueTripletArray(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);
  void SetGrid(RescueGrid *newGrid) {grid = newGrid;}
#ifdef DB_HOOK
  void Archive(char *owner_s, char *owner_t,
               char *grid_s, char *grid_t,
               char *data_collection_s,
               RescueCoordinateSystem *cs);
  RescueTripletArray(char *owner_s, char *owner_t);
  char *SurrogateKey() {return surrogateKey;}
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
#endif
  RescueGrid *grid;
  float missingValue;            
  float *xValue;                 // I am aware that rendering packages ordinarily need
  float *yValue;                 // triplets.  I was reluctantly forced into storing the
  float *zValue;                 // data as separate arrays because of equal axis grids.
#ifdef DB_HOOK
  char surrogateKey[20];
#endif
  friend class RescueBlockUnit;
  friend class RescueSurface;
  friend class RescueWellbore;
};

#endif


RescueUnit

A unit is a business object which is contained between a pair of RescueHorizon objects. Theoretically a unit extends from one side of the model to another. A unit has a relationship to the RescueHorizon above it and below it. It also contains a bag of RescueBlockUnits (RescueBlock having been chosen, more or less arbitrarily, to have the honor of "owning" RescueBlockUnit objects) and a bag of RescueBlockUnitPropertyGroup.

  RescueUnit *unit1 = new RescueUnit("Unit 1", model);

A model must have at least one unit.

/********************************************************************

  RescueUnit.h

  The unit object for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEUNIT_H
#define RESCUEUNIT_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include <string.h>
#include "RDBMS.h"
#endif
#include "RCHString.h"
#include "RescueBlockUnitPropertyGroup.h"
class RescueModel;
class RescueHorizon;
#include "cSetRescueBlockUnitPropertyGroup.h"
#include "cBagRescueBlockUnit.h"

class RescueUnit:public RescueObject
{
public:
  RescueUnit(char *newUnitName, RescueModel *newParentModel);
  ~RescueUnit();
  // Create a new unit.
  // To dispose a unit, use unit->ParentModel()->DropRescueUnit(unit);
  RCHString *UnitName() {return unitName;}
                              // Do NOT delete the returned object.
  void SetUnitName(char *newUnitName) {(*unitName) = newUnitName;}
  RescueModel *ParentModel() {return parentModel;}

  RescueHorizon *HorizonAboveMe() {return horizonAboveMe;}
  RescueHorizon *HorizonBelowMe() {return horizonBelowMe;}

  RescueUnit *UnitAboveMe();
  RescueUnit *UnitBelowMe();

  void SetHorizonAboveMe(RescueHorizon *existingHorizon)
                                      {horizonAboveMe = existingHorizon;}
  void SetHorizonBelowMe(RescueHorizon *existingHorizon)
                                      {horizonBelowMe = existingHorizon;}
  
  int BlockUnitPropertyGroupCount() {return groups->Count();}
  RescueBlockUnitPropertyGroup *NthRescueBlockUnitPropertyGroup(int zeroBasedOrdinal) 
                  {return groups->NthObject(zeroBasedOrdinal);}
  RescueBlockUnitPropertyGroup *BlockUnitPropertyGroupIdentifiedBy(int identifier) 
                  {return groups->ObjectIdentifiedBy(identifier);}
                                   // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.
  bool DropRescueBlockUnitPropertyGroup(RescueBlockUnitPropertyGroup *unitToDrop) 
                          {return ((*groups) -= unitToDrop);}

  void AddBlockUnit(RescueBlockUnit *existingBlockUnit) 
                            {(*blockUnits) += existingBlockUnit;}
  bool DeleteBlockUnit(RescueBlockUnit *existingBlockUnit) 
                            {return ((*blockUnits) -= existingBlockUnit);}
  RescueBlockUnit *NthBlockUnit(int zeroBasedOrdinal)
    {return (RescueBlockUnit *) (*blockUnits).NthObject(zeroBasedOrdinal);}
                  // RescueUnit does not "own" RescueBlockUnits,
                  // so it does not create or delete them, merely
                  // catalogs relationships to them.
  bool IsNamed(char *possibleName);

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
#ifdef DB_HOOK
  void Archive(RescueModel *parentModel, char *earth_model_s, 
                           char *data_collection_s, char *local_data_collection_s,
                           RescueUnit *previousUnit, char *geoscience_ntrp_s);
  void ArchiveGroups(char *data_collection_s, char *geoscience_ntrp_s);
  RescueUnit(RescueModel *parentModel, char *unit_s, char *data_collection_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
  int PreviousId() {return previousId;}
#endif
  virtual void Archive(FILE *archiveFile);
  RescueUnit(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);

  RCHString *unitName;
  RescueModel *parentModel;
  RescueHorizon *horizonAboveMe;
  RescueHorizon *horizonBelowMe;
  cBagRescueBlockUnit *blockUnits;
  cSetRescueBlockUnitPropertyGroup *groups;

  int horizonAboveID;     // these are used only during
  int horizonBelowID;     // recovery from ASCII archive.

#ifdef DB_HOOK
  char surrogateKey[20];
  int previousId;
#endif

  friend class RescueBlockUnitPropertyGroup;
  friend class cSetRescueUnit;
  friend class RescueBlockUnit;
  friend class RescueVertex;
  friend class RescueProperty;
  friend class RescueHorizon;
};

#endif


RescueVertex

A RescueVertex may be used to describe the origin of a local RescueCoordinateSystem in terms of a point in some other coordinate system.

A RescueVertex is also used to describe a rotation point for various grids within the model. By convention, these RescueVertexes are all described in the coordinate system of the parent model.

  RescueVertex *modelVertex = new RescueVertex("model vertex",
                           ultimateCs, 96.5, 27.2, 1000);

/********************************************************************

  RescueVertex.h

  Vertex (used for Coordinate system) for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEVERTEX_H
#define RESCUEVERTEX_H

#include "myHeaders.h"
#include "RescueCoordinateSystem.h"

class RescueVertex:public RescueObject
{
public:
  RescueVertex(char *name, 
               RescueCoordinateSystem *existingCoordinateSystem,
               double xIn, double yIn, double zIn);
  int Dimensions() {return 3;}
  RCHString *VertexName() {return vertexName;}
  void SetVertexName(char *newName) {vertexName->Replace(newName);}
  RescueCoordinateSystem *CoordinateSystem() {return coordinateSystem;}
  double X() {return x;}
  double Y() {return y;}
  double Z() {return z;}

  virtual bool IsOfType(_RescueObjectType thisType);
					// Returns true if the object is a
					// member of the specified class.
  virtual bool IsValid();  		    // Returns true if object appears
					                        // to be currently valid.
  ~RescueVertex();
private:
  RescueVertex(FILE *archiveFile);
  virtual void Archive(FILE *archiveFile);

  RCHString *vertexName;           // Is this necessary?
  RescueCoordinateSystem *coordinateSystem;
  double x;
  double y;
  double z;

  friend class RescueCoordinateSystem;
  friend class RescueGrid;
};

#endif

RescueWellbore

A wellbore is used to describe the path of a wellbore through the model. It contains a one dimensional RescueGrid and a RescueTripletArray which defines the geometry of the wellbore as a polyline in the RescueCoordinateSystem of the RescueModel. Theoretically the RescueGrid could be rotated, but the constructors do not provide for this.

  RescueWellbore *testWell = new RescueWellbore(RescueCoordinateSystem::LUB,
                                                model, 
                                                "test wellbore", 
                                                -9999.0,
                                                borePath.Array(), 0, 6);

Properties measured along the wellbore are stored via a set of RescueWellboreSampling objects. In addition, the object contains a set of RescueWellboreSurface objects to record the locations where the wellbore pierces a surface, and a bag of RescueWellboreCell objects to record which RescueGeometry cells the wellbore traverses. The latter are added and deleted via the RescueGeometry object.

/********************************************************************

  RescueWellbore.h

  The wellbore for RESCUE's data model.

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEWELLBORE_H
#define RESCUEWELLBORE_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include "RDBMS.h"
#include <string.h>
#endif
#include "RCHString.h"
#include "RescueWellboreSampling.h"
#include "RescueGrid.h"
#include "RescueTripletArray.h"
#include "cSetRescueWellboreSampling.h"
#include "cSetRescueWellboreSurface.h"
#include "cBagRescueWellboreCell.h"
class RescueModel;

class RescueWellbore:public RescueObject
{
public:
  ~RescueWellbore();
  RescueWellbore(RescueCoordinateSystem::Orientation orientation,
                 RescueModel *parentModel,
                 char *wellboreName,
                 float missingValue,
                 int i_lowbound, int i_count);
  RescueWellbore(RescueCoordinateSystem::Orientation orientation,
                 RescueModel *parentModel,
                 char *wellboreName,
                 float missingValue,
                 float *tripletArray,
                 int i_lowbound, int i_count);
  // Create a new wellbore.
  // Delete with this->ParentModel()->DropRescueWellbore(this);
  RCHString *WellboreName() {return wellboreName;}
                                    // Do NOT drop the object returned.
  void SetWellboreName(char *newName);

  RescueModel *ParentModel() {return parentModel;}
  RescueGrid *WellboreGrid() {return wellboreGrid;}
  RescueTripletArray *WellboreGeometry() {return wellboreGeometry;}

  int WellboreSamplingCount() {return sampling->Count();}
  RescueWellboreSampling *NthRescueWellboreSampling(int zeroBasedOrdinal) 
                  {return sampling->NthObject(zeroBasedOrdinal);}
                                    // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.
  bool DropRescueWellboreSampling(RescueWellboreSampling *unitToDrop) 
                          {return ((*sampling) -= unitToDrop);}

  int WellboreSurfaceCount() {return surfaceIntersections->Count();}
  RescueWellboreSurface *NthRescueWellboreSurface(int zeroBasedOrdinal) 
                  {return surfaceIntersections->NthObject(zeroBasedOrdinal);}
                                    // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.
  bool DropRescueWellboreSurface(RescueWellboreSurface *surfaceToDrop) 
                          {return ((*surfaceIntersections) -= surfaceToDrop);}
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueWellbore(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  void Relink(RescueObject *parentObject);
#ifdef DB_HOOK
  void Archive(char *earth_model_s, 
               char *geoscience_ntrp_s,
               char *data_collection_s);
  RescueWellbore(char *well_s, RescueModel *parentModel,
                               char *parent_model_s,
                               char *data_collection_s, 
                               char *coordinate_sys_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());
                      strcpy(wellbore_s  , _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
  char *WellboreSurrogateKey() {return wellbore_s;}
#endif
  RCHString *wellboreName;
  RescueModel *parentModel;
  cSetRescueWellboreSampling *sampling;
  cSetRescueWellboreSurface *surfaceIntersections;
  cBagRescueWellboreCell *cellIntersections;
  RescueGrid *wellboreGrid;                   // 1d open grid.
  RescueTripletArray *wellboreGeometry;
#ifdef DB_HOOK
  char surrogateKey[20];
  char wellbore_s[20];
#endif

  friend class RescueWellboreSampling;
  friend class cSetRescueWellbore;
  friend class RescueWellboreSurface;
  friend class RescueWellboreCell;
  friend class RescueWellboreProperty;
  friend class RescueModel;
  friend class cSetRescueWellboreCell;
};

#endif


RescueWellboreProperty

A wellbore property is some property which is measured at a specific location in the wellbore. The parent RescueWellboreSampling gives the rate at which properties are measured along the wellbore, and the exact location can then be calculated from the geometry of the RescueWellbore.

  RescueWellboreProperty *property = new RescueWellboreProperty(sampling,
                                                                propertyName[propertyLoop],                                  
                                                                unitOfMeasure[propertyLoop], 
                                                                -999.9,                     
                                                                properties);
See the discussion in RescueProperty for a description of how to use the various constructors for different kinds of RescueArray's.
/********************************************************************

  RescueWellboreProperty.h

  Property for wellbores RESCUE's data model.  Attach to 

  Rod Hanks,  May 1996

*********************************************************************/
#ifndef RESCUEWELLBOREPROPERTY_H
#define RESCUEWELLBOREPROPERTY_H

#include "myHeaders.h"
#ifdef DB_HOOK
#include "RDBMS.h"
#include <string.h>
#endif
#include "RescueArray.h"
#include "RescueWellboreSampling.h"

class RescueLookup;
class RescueWellbore;

class RescueWellboreProperty:public RescueObject
{
public:
  RescueWellboreProperty(RescueWellboreSampling *parentSampling,
                         char *propertyName,
                         char *propertyType,
                         char *unitOfMeasure,
                         float nullValue,
                         float *values=0);
  // Create a Wellbore property for an array of floats.
  RescueWellboreProperty(RescueWellboreSampling *parentSampling,
                         char *propertyName,
                         char *propertyType,
                         char *unitOfMeasure,
                         unsigned char nullValue,
                         RescueLookup *lookupIn,
                         unsigned char *values=0);
  // Create a Wellbore property using a lookup table where there
  // are 255 or fewer entries in the table.
  RescueWellboreProperty(RescueWellboreSampling *parentSampling,
                         char *propertyName,
                         char *propertyType,
                         char *unitOfMeasure,
                         unsigned short nullValue,
                         RescueLookup *lookupIn,
                         unsigned short *values=0);
  // Create a Wellbore property using a lookup table where there
  // are 2^16-1 or fewer entries in the table.
  ~RescueWellboreProperty() {delete data;}
  // Delete with this->ParentSampling()->DropRescueWellboreProperty(this);
  RescueWellbore *ParentWellbore() {return parentSampling->ParentWellbore();}
  RescueWellboreSampling *ParentWellboreSampling() {return parentSampling;}
  RescueArray *Data() {return data;}
  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
private:
  RescueWellboreProperty(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  void Relink(RescueObject *parentObject);
#ifdef DB_HOOK
  void Archive(RescueWellbore *wellbore,
               char *sample_sk,
               char *data_collection_s, char *geoscience_ntrp_s);
  RescueWellboreProperty(char *well_log_trace_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
#endif
  RescueWellboreSampling *parentSampling;
  RescueArray *data;   // One value for each
#ifdef DB_HOOK
  char surrogateKey[20];
#endif

  friend class cSetRescueWellboreProperty;
};

#endif


RescueWellboreSampling

This object records the sampling rate at which wellbore properties were measured, and contains a reference to the parent wellbore and to a set of properties measured at that rate.

  sampling = new RescueWellboreSampling(wellbore, 7, 10, 0.5);
  
/********************************************************************

  RescueWellboreSampling.h

  Defines the sampling rate for a group of attached properties,
  in terms of distance along the parent wellbore's geometry.

  Rod Hanks,  January, 1997

*********************************************************************/
#ifndef RescueWellboreSampling_H
#define RescueWellboreSampling_H

#include "myHeaders.h"
class RescueWellbore;
#include "RescueGrid.h"
#include "cSetRescueWellboreProperty.h"

class RescueWellboreSampling:public RescueObject
{
public:
  ~RescueWellboreSampling();
  RescueWellboreSampling(RescueWellbore *parentWellbore,
                         int count, float origin, float step);
  RescueWellboreSampling(RescueWellbore *parentWellbore,
                         int count,
                         float *values);
  // Create a Wellbore sampling.  First is regular, second is irregular.
  // Points are defined in measured depth.
  // Delete with this->ParentWellbore()->DropRescueWellboreSampling(this);
  RescueWellbore *ParentWellbore() {return parentWellbore;}

  RescueGrid *SampleGrid() {return grid;}
  int Count() {return grid->Axis(0)->Count();}
  int WellborePropertyCount() {return properties->Count();}
  RescueWellboreProperty *NthRescueWellboreProperty(int zeroBasedOrdinal) 
                  {return properties->NthObject(zeroBasedOrdinal);}
                                    // Do NOT delete the object returned.
                                    // If you want to remove them from the
                                    // model use the corresponding Drop method.
  bool DropRescueWellboreProperty(RescueWellboreProperty *unitToDrop) 
                          {return ((*properties) -= unitToDrop);}

  
  float MeasuredDepthAt(int ndx);

  virtual bool IsOfType(_RescueObjectType thisType);
					// Returns true if the object is a
					// member of the specified class.
  virtual bool IsValid();  		    // Returns true if object appears
					                        // to be currently valid.
private:
  RescueWellboreSampling(FILE *archiveFile);
  void Archive(FILE *archiveFile);
  void Relink(RescueObject *parentObject);

  cSetRescueWellboreProperty *properties;

  RescueWellbore *parentWellbore;
  RescueGrid *grid;
  float *values; // grid is parentWellbore->wellboreGrid

  friend class cSetRescueWellboreSampling;
  friend class RescueWellboreProperty;
};

#endif

RescueWellboreSurface

This object records the intersection of a wellbore path with a RescueSurface (either a RescueSection or a RescueBlockUnitHorizonSurface).

  RescueWellboreSurface *wellboreSurface = new RescueWellboreSurface(testWell, 
                                                                     section1, 
                                                                     4.2, 2.25, 8.0);

It can be reached from both RescueWellbore and RescueSurface.

/********************************************************************

  RescueWellboreSurface.h

  The record of an intersect between a wellbore and a surface.

  Rod Hanks,  January 1997

*********************************************************************/
#ifndef RESCUEWellboreSurface_H
#define RESCUEWellboreSurface_H

#include "myHeaders.h"
#include <stdlib.h>
#ifdef DB_HOOK
#include "RDBMS.h"
#include <string.h>
#endif
class RescueWellbore;
class RescueSurface;

class RescueWellboreSurface:public RescueObject
{
public:
  RescueWellboreSurface(RescueWellbore *wellboreIn, 
                        RescueSurface *surfaceIn,
                        float uIn, float vIn, float mdIn);
  RescueWellbore *Wellbore() {return wellbore;}
  RescueSurface *Surface() {return surface;}
  float U() {return u;}
  float V() {return v;}
  float MD() {return md;}

  virtual bool IsOfType(_RescueObjectType thisType);
          // Returns true if the object is a
          // member of the specified class.
  virtual bool IsValid();          // Returns true if object appears
                                  // to be currently valid.
  ~RescueWellboreSurface();
private:
  virtual void Archive(FILE *archiveFile);
  RescueWellboreSurface(FILE *archiveFile);
  virtual void Relink(RescueObject *parent);
  void SetWellbore(RescueWellbore *wellboreIn) {wellbore = wellboreIn;}
#ifdef DB_HOOK
  void Archive(char *data_collection_s,
               char *md_sk,
               char *md_uom,
               char *surf_sk,
               char *surf_uom1,
               char *surf_uom2);
  RescueWellboreSurface(char *general_esrf_pt_s);
  void PreAssignSK() {strcpy(surrogateKey, _daeMakeSK());}
  char *SurrogateKey() {return surrogateKey;}
#endif
  RescueWellbore *wellbore;
  RescueSurface *surface;
  float u;
  float v;
  float md;
#ifdef DB_HOOK
  char surrogateKey[20];
#endif
  int surfaceID;   // used only during relinking.

  friend class RescueWellbore;
  friend class cSetRescueWellboreSurface;
};

#endif


RescueZStack

This object stores z values in a RescueGeometry when the x and y coordinates of the vertex are calculated from the origin and step information in the RescueGrid. This object is never instantiated or accessed directly by the programmer.

cBagInt

Each RescueObject has a unique 32 bit identifier. During unarchiving, forward references to objects are maintained by unique identifier. At the end of the unarchiving process the identifier is traded for a pointer. This is what is occuring in all of the private "Relink" methods. The ids are used only during the unarchiving process, never when the programmer has access to Rescue objects. In some cases, lists of IDs are stored during unarchiving in a cBagInt object. This object is never instantiated or accessed by the programmer.

cNameValuePair

RescueModel includes an object which is intended to assist vendors in the process of passing models back and forth between them. The object handles a list of named values. The names should be short, around 30 bytes, although no specific limit is imposed. Each vendor chooses a small set of names which it will instantiate. The system will break down if a large number of pairs are included, so each vendor should limit themselves to 2 or 3 names. The names should be something which a user would associate with the specific vendor.

The values should also be short, on the order of 200 or fewer bytes. Values longer than 80 bytes should be broken up with embedded \n's so they will break easily into displayable text.

Vendors may parse their own values when reading a model in order to determine critical information, such as a specific model name or file, but they should also be free to display names and values from other vendors, and hopefully these will be meaningful.

Example usage of this class is seen in the example program readModel.cpp.

/*************************************************************************

        cNameValuePair.h

        Keeps a list of named values.

        Rod Hanks               June 1998

****************************************************************************/

#ifndef cNameValuePair_H
#define cNameValuePair_H

#include "myHeaders.h"
class RCHString;

class cNameValuePair
{
protected:
  RCHString **names;
  RCHString **values;
  int allocated;
  int count;

  cNameValuePair();
  ~cNameValuePair();
  int NdxOf(char *name);
  void Archive(FILE *archiveFile);
  cNameValuePair(FILE *archiveFile);
public:
  char *NthName(int ordinal);  // DO NOT delete the object returned.
  char *NthValue(int ordinal); // DO NOT delete the object returned.
  int Count(void) {return count;}
  bool Contains(char *name);
  void SetNameValuePair(char *name, char *value);
                                     // cNameValuePair makes copies of character buffers you
                                     // pass, so they can be on the stack or the heap.  They
                                     // remain your responsibility.
  char *GetNameValuePair(char *name);  // DO NOT delete the object returned.

  friend class RescueModel;
};

#endif