SEDRIS Reference Manual
Section 2_-_STANDARD SEDRIS FUNCTIONS AND DATA STRUCTURES
.
2 _ STANDARD SEDRIS FUNCTIONS AND DATA STRUCTURES
.
This section deals with the standard SEDRIS function calls, as well as critical data structures. The parameters associated with each function call are detailed, and the resultant processing is described. The function calls are listed alphabetically, each in a separate appendix associated with its SEDRIS component.
.
Function call information has been extracted from the version 3.0.3 source code files shown in the table below.
.
COMPONENT
SOURCE CODE FILES
SRM
se_conv.h
se_conv_print.h
se_conv_util.h
se_conv_valid.h
se_conv_default.h
EDCS
edcs.h
edcs_types.h
edcs_ac.h
edcs_cc.h
edcs_ac_enum.h
DRM
sedris.h
se_data_model.h
se_drm_print.h
se_drm_util.h
se_drm_valid.h
Level 0 Read API
se_extract.h
se_extract_print.h
se_extract_types.h
se_extract_valid.h
se_extract_util.h
Level 0 Write API
se_insert.h
se_insert_print.h
se_insert_types.h
Level 1 Read API
se_read1_data_table.h
se_read1_error.h
se_read1_image.h
se_read1_print.h
se_read1_utils.h
se_read1_valid.h
Level 1 Write API
se_write1.h
    NOTES:
      1. . For items that follow, names in all capital letters indicate data types or enumerators.
      2. . A greater level of comprehension can be achieved by reviewing the commented source code contained in the associated modules.
2.1 _ Spatial Reference Model (SRM) Functions and Data Structures
.
The SRM functions and data structures are listed alphabetically in Appendix A.
.
Coordinate conversion is a multi-step process as outlined below.
  • Specify the source and destination coordinate systems, including any parameters needed to define those systems. The SE_SRF_PARAMETERS contain the parameters for each coordinate system within the structure.
  • .
      Make a call to the SE_CreateCoordConversionConstants() function, passing in the parameters for the source and destination coordinate systems, and receiving an SE_CONVERT_COORD_SYSTEM_PAIR. Hold on to this SE_CONVERT_COORD_SYSTEM_PAIR - you will need it every time you want to convert a coordinate from the source system to the destination system.
    .
  • Call either:
    • - SE_ConvertCoordToGivenSystem() or 
      - SE_ConvertCoordToGivenSystemWithoutBoundaryChecking(), 
      passing in the SE_CONVERT_COORD_SYSTEM_PAIR and the source coordinate, and receiving the coordinate converted into the destination system.
    .
      Repeat the second step as needed, once for every coordinate to convert between the source and destination coordinate system pairing defined in the first step.
    .
      Note that not all SRFpairings are currently supported. See the explanation of supported conversions in the following subsections.
    .
  • When finished converting coordinates between two systems, call SE_FreeCoordConversionConstants() to release the SE_CONVERT_COORD_SYSTEM_PAIR that was allocated by the first step.
2.1.1 _ Directly Supported Conversions
.
The following coordinate system conversions are directly supported.
    GD <=> GC
    GD <=> PS
    GD <=> LCC
    GD <=> TM
    GD <=> UTM
    GD <=> M
2.1.2 _ Reflexive Conversions
.
Reflexive conversions are also allowed. For example, asking to convert from GC to GC does not produce an error. No actual work is done in the conversion in this case, but no errors are returned for this conversion. Some reflexive conversions (e.g., LCC to LCC) will convert their elevation values from feet to meters or from meters to feet, depending on the units specified in the source and destination SRFs. Also, some reflexive conversions (e.g., GCS to GCS) will convert coordinates based on the possibly different system offsets defined in the source and destination coordinate systems.
.
2.1.3 _ Indirectly Supported Conversions
.
Some conversions are supported as a two-step process, converting from the source system to GD, and then converting from GD to the destination system. Since two coordinate conversions are being performed in these cases, these cases can take twice as long and may have up to twice the error compared to the directly supported conversions. (Directly supported conversions should not have an error of more than 0.001 meters, and the indirect conversion errors should not exceed 0.002 meters.) In the future, we expect to add code so that the conversions that are currently indirect will be directly supported instead. For example, we expect to add code to directly convert from LCC to UTM, instead of performing the two-step conversion currently required of LCC to GD and then GD to UTM. Sometimes indirectly supported conversions are referred to as "transitive" or "chained" conversions. The user does not need to treat these conversions any differently, as far as the function calls are concerned. In order to convert from LCC to UTM, just ask for LCC to UTM. The fact that an intermediate conversion through GD is taking place is automatically handled by the conversion code.
.
The user calls the same functions, regardless of whether the conversion is directly supported, reflexive, or indirectly supported. If a conversion is not supported between the two systems selected by the user, then the call to SE_CreateCoordConversionConstants() will return the error code SE_COORD_UNSUPPORTED
.
The chart below is provided as a reference to indicate which conversions are supported.
  • D - directly supported conversion
  • R - reflexive conversion (these are supported)
  • I - indirectly supported conversion (a.k.a. "chained" or "transitive")
GD
GC
GM
GEI
GSE
GSM
SM
GCS
EC
PS
LCC
TM
UTM
LTP
LSR
.M.
OM
UPS
GD
R
D
.
.
.
.
.
.
.
D
D
D
D
.
.
D
.
.
GC
D
R
.
.
.
.
.
.
.
I
I
I
I
.
.
I
.
.
GM
.
.
R
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
GEI
.
.
.
R
.
.
.
.
.
.
.
.
.
.
.
.
.
.
GSE
.
.
.
.
R
.
.
.
.
.
.
.
.
.
.
.
.
.
GSM
.
.
.
.
.
R
.
.
.
.
.
.
.
.
.
.
.
.
SM
.
.
.
.
.
.
R
.
.
.
.
.
.
.
.
.
.
.
GCS
.
.
.
.
.
.
.
R
.
.
.
.
.
.
.
.
.
.
EC
.
.
.
.
.
.
.
.
R
.
.
.
.
.
.
.
.
.
PS
D
I
.
.
.
.
.
.
.
R
I
I
I
.
.
I
.
.
LCC
D
I
.
.
.
.
.
.
.
I
R
I
I
.
.
I
.
.
TM
D
I
.
.
.
.
.
.
.
I
I
R
I
.
.
I
.
.
UTM
D
I
.
.
.
.
.
.
.
I
I
I
R
.
.
I
.
.
LTP
.
.
.
.
.
.
.
.
.
.
.
.
.
R
.
.
.
.
LSR
.
.
.
.
.
.
.
.
.
.
.
.
.
.
R
.
.
.
M
D
I
.
.
.
.
.
.
.
I
I
I
I
.
.
R
.
.
OM
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
R
.
UPS
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
R
.
Note that supporting a source to destination conversion doesn't always mean being able to convert all coordinates between the two systems. For example, when converting from GD to UTM, the GD latitude must be between -80.0 and 84.0; otherwise, an error is produced. If a call is made to SE_ConvertCoordToGivenSystem() to go from GD to UTM, but the GD latitude is less than -80.0, then SE_ConvertCoordToGivenSystem() will return the error value of SE_COORD_INVALID_DEST_SRF_PARAMETERS, and no conversion will occur. If the same call is made (if the same values are passed) to SE_ConvertCoordToGivenSystemWithoutBoundaryChecking(), then no error value is returned, but the resulting conversion is meaningless.
.
The WithoutBoundaryChecking() version of the conversion function is meant to be called only when the user is sure that the source and destination coordinates are both within the allowed conversion boundaries. The WithoutBoundaryChecking() version of the conversion function is slightly faster than the regular conversion function, but the regular conversion function should be used unless the user knows for certain that the coordinates being converted fall within the supported boundaries.
.
2.2 _ Data Representation Model (DRM) Functions and Data Structures
.
The DRM functions and data structures are listed alphabetically in Appendix B.
.
2.3 _ Environmental Data Coding Specification (EDCS) Functions and Data Structures
.
The EDCS functions and data structures are listed alphabetically in Appendix C.
.
2.4 _ Level 0 Read and Write API Functions and Data Structures
.
The Level 0 Read and Write API functions and data structures are listed alphabetically in Appendix D.
.
2.4.1 _ Level 0 Read API Functions and Data Structures
.
Iterators are the heart of the Level 0 Read API. Stepping through the list provided by an iterator is a multi-step process, as outlined below.
  • Specify any search rules needed to limit the search (this is optional). The search macros (see SE_RULE_TYPE_ENUM for a list) can be used to specify search rules. They are designed to make arrays of search rules more readable. By using these macros, search rules can appear to be defined with in-fix notation expressions even though the macros actually build up a post-fix notation expression stored in an array.
  • .
  • If any search rules were specified, pass the array of search rules to SE_CreateSearchFilter() to create a search filter. (Note that a search filter is valid only for the API implementation for which it was created.)
  • .
  • Call one of the following functions to create the iterator, passing in the start object of the search (depending on the type of iterator needed):
    • .
    • SE_InitializeAggregateIterator(), to iterate over the aggregates of which the start object is a component,
    • .
    • SE_InitializeAssociateIterator(), to iterate over the associates of the start object,
    • .
    • SE_InitializeComponentIterator(), to iterate over the components of the start object, or
    • .
    • SE_InitializeInheritedComponentIterator(), to iterate over the inherited components of the start object.
    .
  • If you specified a search filter, and if you will not be using it to create more iterators, free it at this point. (The iterator maintains a copy of the search filter in the API's memory space.) If the search filter isn't freed at this point, remember that it must be freed eventually, to avoid "orphaning" the memory associated with the search filter.
  • .
  • Use SE_GetNextObject() to retrieve objects from the iterator. Don't forget to call SE_FreeObject() for each object retrieved (including the link objects, a.k.a. "horse-collar attached" objects). (For tasks that don't need link objects, use SE_GetNextObjectOnly()).
  • .
    Repeat this step as needed.
    .
  • When finished retrieving objects from the iterator, call SE_FreeIterator() to release the iterator that was allocated by the third step.
2.4.1.1 _ Component Iterators: Selection Parameters
.
SE_InitializeComponentIterator()'s SE_HIERARCHY_SELECT_PARAMETERS argument (select_parameters_ptr) can be used to restrict the scope of a search. If the parameter is "NULL", it is ignored. If it is non-NULL, then it is used to determine which components to traverse when an Aggregate Feature or Aggregate Geometry object is encountered.
.
The SE_HIERARCHY_SELECT_PARAMETERS type is defined in se_extract_types.h in the Level 0 Read API. To use this structure:
  • Use SE_InitializeHierarchySelectParameters() (defined in the Level 1 Read API) to initialize this structure, or initialize it yourself.
  • .
  • Fill out the booleans in general_hierarchy_mask to specify which of the rest of the fields will be used. All of the booleans must be initialized to either "SE_TRUE" or "SE_FALSE". (Exception: if time_related is "SE_FALSE", the related booleans are ignored, and if level_of_detail_related is "SE_FALSE", its related booleans are ignored).
  • .
  • For each of the fields within the general_hierarchy_mask, the corresponding _branches field MUST be initialized. (Otherwise, the iterator will be using garbage values to prune its search).
To clarify the use of SE_HIERARCHY_SELECT_PARAMETERS, consider the following example. Suppose that a search is being created to retrieve only the geometry and features associated with trees (specifically, with the SEDRIS Classification Codes represented by EDCS_CC_TREES and EDCS_CC_FOREST). The selection parameters would be created as follows.
.
    SE_HIERARCHY_SELECT_PARAMETERS select_param;
    SE_GENERAL_HIERARCHY_SELECT *mask_ptr;
    SE_CLASSIFICATION_PARAMETERS *cl_ptr; 
    .
    SE_InitializeHierarchySelectParameters(&select_param);
    mask_ptr = &select_param.general_hierarchy_mask
    mask_ptr->classification_related = SE_TRUE;
    mask_ptr->union_of_features = SE_TRUE;
    mask_ptr->union_of_geometry_hierarchies = SE_TRUE;
    mask_ptr->union_of_geometry_primitives = SE_TRUE; 
.
Now fill out the _branches fields that we've indicated we'd use - in this case, just classification_branches.
.
    cl_ptr = &select_param.classification_branches;
    cl_ptr->classification_count = 2;
    cl_ptr->classification_array = (SE_BASE_CLASSIFICATION_DATA_FIELDS *)
    calloc(SE_BASE_CLASSIFICATION_DATA_FIELDS, 2); 
    .
    cl_ptr->classification_array[0].tag = EDCS_CC_TREES;
    cl_ptr->classification_array[0].tag = EDCS_CC_FOREST; 
.
Consider the result when this select_param is passed to SE_InitializeComponentIterator().
  • Any Classification Related Geometry or Classification Related Features encountered will have its components' link objects check against the classification_array specified in select_param. If such a link does not match any of the entries in classification_array, then that branch is discarded (pruned).
  • .
  • Any Union of Features, Union of Geometry Hierarchy, or Union of Primitive Geometry encountered will be followed.
  • .
  • Any other Aggregate Geometry or Aggregate Feature objects will be ignored. For example, if we encounter a Spatial Index Related Geometry, none of its branches will be followed, because its entry within the selection mask is false.
  • .
  • No other type of object will be affected.
2.4.1.2 _ Component Iterators: Ordering Parameters
.
SE_InitializeComponentIterator()'s SE_HIERARCHY_ORDER_PARAMETERS argument (traversal_order_parameters_ptr) can be used to control the order in which the branches of an aggregate will be searched. If the parameter is "NULL", it is ignored. If it is non-NULL, then it is used to determine the traversal order of the branches when an Aggregate Feature or Aggregate Geometry object is encountered.
.
The SE_HIERARCHY_ORDER_PARAMETERS type is defined in se_extract_types.h in the Level 0 Read API. To use this structure:
  • Use SE_InitializeHierarchyOrderParameters() (defined in the Level 1 Read API) to initialize this structure, or initialize it yourself.
  • .
  • Fill out the booleans in general_hierarchy_mask to specify which of the rest of the fields will be used. All of the booleans must be initialized to either "SE_TRUE" or "SE_FALSE".
  • .
  • For each of the fields within the general_hierarchy_mask, the corresponding traversal_order field MUST be initialized. (Otherwise, the iterator will be using garbage values to determine the traversal order).
2.4.1.3 _ Component Iterators: Search Boundaries
.
A component iterator, unlike the other types of iterators, may use spatial search boundaries to restrict the scope of its search. To use such a boundary, several extra steps are required before initializing the iterator.
  • Specify the search bounds in an SE_SEARCH_BOUNDS variable. The search bounds must be specified using the coordinate system that will be in effect when the iterator is in use.
  • .
  • Pass the search bounds to SE_CreateSpatialSearchBoundary(), which will allocate and create the search boundary itself. (This boundary must be freed later by SE_FreeSearchBoundary()).
  • .
  • Pass the search boundary to SE_InitializeComponentIterator() for any iterator that should be restricted to search only that search boundary's specified spatial area. Once the iterator has been created, the search boundary may be freed safely, since the iterator maintains a copy of the search boundary in the API's memory space.
  • .
  • While search bounds are in use, do NOT reset the API's SRFparameters.
See Search Bounds for more details.
.
2.4.2 _ Level 0 Read API: Search Bounds
.
A search boundary has several characteristics that must be determined before the search is performed:
    1) . the area to be searched,
    2) . whether the boundary of the search area is part of the search area,
    3) . whether to include objects that touch the boundary of the search area,
    4) . the dimensionality of the search (2-D vs. 3D), and
    5) . how an object is to be approximated.
The area (or volume) to be searched is specified via the SE_SEARCH_BOUNDS structure, and by specifying whether the search area's boundary is part of the search area. The SE_SEARCH_BOUNDS structure specifies the ranges of the coordinates to be considered in the search. (To create unlimited search areas, use SE_NEGATIVE_INFINITY and SE_POSITIVE_INFINITY, as appropriate.)
.
Given the search bounds, SEDRIS allows for two possibilities (this is done using SE_SEARCH_BOUNDS_CLOSURE_ENUM). The search bounds can be fully closed, or partly closed. Fully closed search bounds are topologically closed, so that the entire boundary is included. This is appropriate for finding all objects in an area of interest, since the objects on the border may affect the interior of the search bounds. Partly closed search bounds, on the other hand, are topologically half-closed; that is, only the lower endpoints of the coordinate ranges are in the search bounds. This is useful if a large area is being tessellated, so that each point will belong to exactly one tile of the tesselation.
.
Apart from specifying whether the boundary of the search bounds is included within the bounds, the user must specify how to handle boundary cases (see SE_INCLUSION_CHOICE_ENUM). An object can be fully contained within the search bounds (i.e., the intersection of the search bounds and the object equals the object), or partly contained within the search bounds (i.e., the intersection of the object and the search bounds is non-empty). Full inclusion implies partial inclusion. Consequently, a search specified with SE_PARTLY_INCLUDED is less restrictive than a search specified with SE_FULLY_INCLUDED. (To check whether an object includes the search bounds, see SE_DetermineSpatialInclusion).
.
Search dimensionality (specified by SE_SEARCH_DIMENSION_ENUM) determines whether the search considers 2D objects only, 3D objects only, or both. Note that SE_2D_SEARCH is only valid for coordinate systems that support 2D Locations, such as geodetic (GD). For a 2D search, the height/elevation portion of both the search bounds and of any 3D objects encountered will be ignored.
.
Finally, the user must specify how objects are to be approximated during the search (see SE_SEARCH_QUALITY_ENUM). SEDRIS provides two kinds of approximation: point searches and bounding box searches. (A third type of search, exact search, is described in the interface, but is not yet available; this type would use the exact representation of the object rather than an approximation).
.
The following kinds of objects can be approximated for a spatial search: ·
  • Aggregate Features
  • Aggregate Geometries
  • Arcs
  • Areal Features
  • Camera Points
  • Ellipses
  • Elliptic Cylinders
  • Feature Edges
  • Feature Faces
  • Feature Model Instances
  • Feature Nodes
  • Finite Element Meshes
  • Geometry Model Instances
  • Property Grid Hook Points
  • Lines
  • Points
  • Point Features
  • Polygons
  • Positional Lights
  • Property Grids
For details on the specific functions involved in specifying and using search bounds, see SE_CreateSpatialSearchBoundary, SE_DetermineSpatialInclusion.
.
2.4.2.1 _ Point Searching
.
For point searching, a non-aggregate SEDRIS object is approximated by a single point. In general, this search point is the average of the Location components of the object being represented. This type of search is fast, but may not be sufficiently accurate. (Note that for point searches, full and partial inclusion have the same meaning.)
.
For an aggregate object whose components are all of the same dimensionality, the search point is constructed as the average of the component search points. For an aggregate object containing both 2D and 3D components, however, two unions are maintained, one for the 2D components and one for the 3D components.
.
For point searches, coordinate system transformations introduce no distortion; this is not the case for bounding boxes.
.
2.4.2.2 _ Bounding Box Searching
.
Bounding box searches are more accurate than point searches. To construct the bounding box for a non-aggregate object, the extrema for each coordinate in the object's native coordinate system are computed, and used to create a 2D or 3D box. This box then represents the object in the search.
.
For an aggregate object whose components are all of the same dimensionality, the bounding box is constructed as the union of the component bounding boxes. For an aggregate object containing both 2D and 3D components, however, two unions are maintained, one for the 2D components and one for the 3D components.
.
Bounding box searches introduce complications when coordinate system transformations are involved. The faces and edges of a bounding box can be distorted by the transformation (e.g., a straight line in one system may be a curve in a different system).
    The rest of this segment describes the
    algorithms used for bounding box searches.
In an attempt to overcome the distortion issue, the ideas of inscribed and circumscribed boxes were introduced. For an arbitrary shape, an inscribed box is the largest box that fits inside the shape, while a circumscribed box is the smallest box that contains the shape.
    In the algorithms below, "the search succeeds" means that
    the iterator will pass the object as being inside the boundary;
    "the search fails" means that the object will be rejected.
For a full inclusion bounding box search, first find the object's bounding box in its native coordinate system, then convert the vertices of the box to the user's coordinate system. If any vertex is outside the search boundary, reject this object. If the search continues, compute the circumscribed bounding box of the object; if it is within the search bounds, this object is accepted by the search. Otherwise, compute the inscribed search box of the search bounds in the object's coordinate system; if the object's bounding box is inside the inscribed search boundary, the search succeeds for the object; otherwise, it fails.
.
For a partial inclusion bounding box search, first find the object's bounding box in its native coordinate system, then convert the vertices of the box to the user's coordinate system. If any vertex is inside the search boundary, the search succeeds for this object. If the search continues, compute the inscribed bounding box of the object; if it intersects the search bounds, this object is accepted by the search. Otherwise, compute the circumscribed search box of the search bounds in the object's coordinate system; if the object's bounding box intersects the circumscribed search boundary, the search succeeds for the object; otherwise, it fails.
.
2.4.3 _ Level 0 Write API Functions and Data Structures
.
To create a transmittal using the Write API, you must pay careful attention to the order of operations. First, you must create the transmittal with a call to SE_OpenTransmittalByFile or SE_OpenTransmittalByName:
    status = SE_OpenTransmittalByFile("filename", impl_id, transmittal, SE_CREATE);
This call creates a transmittal containing no objects using the API implmentation indicated by the impl_id. The <Transmittal Root>, like any object, must be added to the transmittal before it can have any component objects attached. Consequently, the first task is to finish creating the <Transmittal Root>.
    status = SE_CreateObject(impl_id, &transmittal_root);
    status = SE_PutFields(transmittalroot, &new_fields);
where new_fields is an SE_FIELDS variable containing the fields for your new <Transmittal Root>, then
    status = SE_AddToTransmittal(transmittalroot, transmittalroot_out);
For any object, if you want to change its field values from the default values for an object of that object's class, you must call SE_PutFields before adding the object to the transmittal. You must then add the object to the transmittal before you can add any components or associates to the object, and before you can add it as a component of any other object.
.
So for any transmittal, the correct sequence of function calls is:
  • SE_OpenTransmittalByFile
  • SE_PutFields
  • SE_AddToTransmittal
Then create any components for the <Transmittal Root>.
.
For any object, SE_CreateObject must initially be called to create the object. The correct sequence of function calls is:
  • SE_CreateObject
  • SE_PutFields (optional; only if you don't want the default fields values)
  • SE_AddToTransmittal
  • Add the object as a component of some object that's already in the transmittal (except for <Transmittal Root>, which is passed to SE_SetRootObject)
  • (optional) add any associations between this object and objects that are already in the transmittal, if there are any
Note that SE_AddToTransmittal does NOT create any component or association relationships for the object; you still have to add it as a component of its parent (or parents, if it is a component of more than one object).
.
For an <Image> object, there is an extra step. Once the <Image> has been added to the transmittal, you must call SE_PutImageData to add the pixels/texels of the <Image> to the object.
.
The most complicated operation is to add a <Data Table> to a transmittal. Here the sequence is:
  • SE_CreateObject to create the <Data Table> object
  • SE_PutFields to set the fields of the <Data Table>
  • SE_AddToTransmittal
  • Add all the 'structural' components of the <Data Table>
    • Create all the Axis components of the <Data Table>, set their fields, add them to the transmittal, and add them as components of the <Data Table>
    • Create all the Table Property Description components of the <Data Table>, set their fields, add them to the transmittal, and add them as components of the <Data Table>
  • Call one of the SE_PutDataTable() functions to add the cells of the <Data Table>, or make a series of calls to one of the SE_PutDataTableExtents() functions to add the cells of the <Data Table> in chunks
2.5 _ Level 1 Read and Write API Functions and Data Structures
.
The Level 1 Read and Write API functions and data structures are listed alphabetically in Appendix E.
.
.
Return to: Top of this Page
Last updated: April 20, 2001