SUBSYSTEM OVERVIEW
Mapping (MAP) Subsystem
The MAP subsystem provides a framework for creating single and multi-schema PDElib applications. The framework allows an application to access much of the functionality in PDElib with a single, consistent interface by encapsulating entity operations into discrete modules called mapping functions. These mapping functions are similar to methods in an object oriented language. This subsystem provides functions for defining, maintaining, and using mapping functions.
This manual page is organized so that all of the basic concepts are presented first followed by a summary of how the concepts are put together. A set of advanced topics appears at the end.
TERMINOLOGY
The following terms are used throughout the MAP subsystem:
An acronym for DDF/Type/Form. A DTF uniquely identifies an entity type within PDElib by specifying the DDF in which the entity is defined along with the type/form of the entity. DTFs are used within the MAP subsystem to support multi-schema operations. The DDF_DTF typedef is used to declare a DTF.
A general term which describes the process of applying an operation to an entity to generate one or more new entities.
A function with a predefined binding that takes an entity of one type and modifies it or generates one or more new entities. The resulting entities can reside either in a PDElib model or a native database. Mapping functions can perform operations such as entity conversion, approximation, decomposition, and data modification. Mapping functions can also perform simple operations such as entity copying. A mapping function is always associated with the specific DTF that it expects as input.
A data structure which contains the information associated with a particular mapping for a given DTF. Mapping definitions are identified by a character string which the application assigns. Mapping definitions provide a mechanism to associate mapping functions with the appropriate DTFs. PDElib includes a wide variety of mapping definitions and an application can create additional ones to operate on entities not supported by PDElib.
A set of mapping definitions that together provide selectivity of specified mapping operations. Conditional mapping definitions consist of a header mapping that serves as a logical link to optional component mappings. A component operation of a conditional mapping may consist of either a simple mapping, a mapping list, or another nested conditional mapping.
A mapping definition that consists of one single mapping operation. Simple mappings may be defined as part of a mapping list or conditional mapping or they may stand alone.
A set of mapping definitions which are chained end to end so that complex mappings can be created by combining several simple mappings.
A mapping which can be chained with other chainable mappings to form a mapping list. To be chainable, the mapping must produce only one type/form of entity. This definition is suitable for simple mappings that are combined within a mapping list. However, an extension to this rule is listed in the ADVANCED TOPICS section to specify limitations of conditional mappings and mapping lists with respect to chainability.
A data structure which contains a collection of mapping definitions and mapping lists. Multiple mapping tables can be created and used simultaneously. The MAP_TABLE typedef is used to declare a mapping table.
A name/value pair which defines a parameter to be used in a mapping function. Since all mapping functions must have a consistent binding, mapping parameters give an application additional control over the operation of a predefined mapping function.
A temporary entity generated by a mapping function.
A function which takes an entity as input and based on the DTF of the entity invokes some type of processing. There are two dispatchers associated with using the MAP subsystem. The first is part of the MAP subsystem (map_DispatchEntity). The second is an optional application defined dispatcher.
FRAMEWORK OVERVIEW
Components
There are seven interrelated components which work together to form the MAP subsystem framework. These components are:
The application dispatcher (optional)
The MAP subsystem dispatcher map_DispatchEntity()
The MAP subsystem conditional component invoker map_InvokeMapping()
Mapping functions
The MAP subsystem function map_ProcessEntity()
The MAP subsystem function map_CommitEntity()
The MAP subsystem function map_IsCommitMapping()
These components are recursively invoked until the desired result is obtained as shown below:
map_DispatchEntity ()
mapping_function ()
map_ProcessEntity ()
map_DispatchEntity ()
mapping_function ()
.
.
.
An application can also provide a dispatcher which is inserted into the call chain. map_IsCommitMapping can then be used to determine when mappings are finished. These topics are discussed further in the USING AN APPLICATION DISPATCHER section.
map_InvokeMapping is only utilized for invoking components of conditional mapping definitions. This is an advanced topic and thus more information may be found in the ADVANCED TOPICS section.
To demonstrate how this recursive processing works, the following example shows the call order for converting an IGES NURB to a STEP NURB. This conversion is performed using two mapping steps:
IGES NURB -> GDX NURB GDX NURB -> STEP NURB
The following call tree uses symbolic names for the mapping functions to make it obvious what part of the mapping they are performing. All arguments are input parameters.
map_DispatchEntity (IGES NURB)
IGES_NURB_To_GDX_NURB (IGES NURB) <- Mapping function
map_ProcessEntity (GDX NURB)
map_DispatchEntity (GDX NURB)
GDX_NURB_To_STEP_NURB (GDX NURB) <- Mapping function
map_ProcessEntity (STEP NURB) <- End of mapping
The map_ProcessEntity function uses several factors to determine when an entity mapping is complete. The simplest of these is a flag associated with the mapping which indicates that the result of the mapping is to be committed. In this case, the application would set this flag on the "GDX NURB -> STEP NURB" mapping. If an application dispatcher is involved in the processing, it can stop the mapping at any invocation. This is described further in the USING AN APPLICATION DISPATCHER section. Additionally, the mapping function itself can be defined so that it does not call map_ProcessEntity. This is described further in the MAPPING FUNCTIONS section.
As described above, the entity generated in the final mapping step is made permanent (the STEP NURB in this case). All other entities generated in mapping functions are transient entities which are automatically deleted by map_ProcessEntity when returning back up the call stack. In this example, the GDX NURB is a transient entity. In this example, the top level entity (the IGES NURB) is defined in a PDElib model. The MAP subsystem is based on applying mapping functions to entities which are defined in PDElib models. By incorporating an application dispatcher to handle native to/from PDElib conversions, the MAP subsystem can be used to access and map native entities. This is described further in the INCORPORATING NON-PDELIB BASED ENTITIES.
The MAP subsystem makes use of the MDA original database pointer field in each entity to maintain a link back to the entity it was created from. In this example, the original database pointer of the STEP NURB would be set to the database pointer of the IGES NURB. This allows attributes or other information not mapped by the mapping functions to be maintained in the final entity. See the mda_intro manual page for additional information on using original database pointers.
MAPPING FUNCTIONS
There are three types of mapping functions supported by the MAP subsystem. The two main types that will be encountered most often, the "End Mapping" and "General Mapping", will be discussed in this section. The third type, the "Conditional Mapping", will be described in the advanced topics section later in this document. The type is specified as part of the option argument when the mapping is defined. By default, the mapping is defined to be an "End Mapping". If the MAP_GENERAL flag is specified, the mapping is a "General Mapping". These two types are described below:
This is the simplest type of mapping function. End mapping functions do not call map_ProcessEntity to perform further processing on the resulting entities. This simplifies the requirements of the mapping function. This type of mapping function is normally used to map PDElib entities to native representations. The only requirement for this type of mapping is that it have the standard binding described later. If the results of an end mapping is an entity in a PDElib model, the mapping function must call map_CommitEntity to make the entity permanent.
This type of mapping function provides the maximum amount of re-usability. These mappings perform some operation on the input entity and pass the resulting entities to map_ProcessEntity for further processing or to be committed to the database. The downside of general mappings are that they must conform to several requirements that end mappings do not need to.
In order for the MAP subsystem to use mapping functions without any knowledge of what a particular mapping function does, each mapping function must have the following binding.
PDX_MSGT FunctionName ( MDA_PTR db_ptr, MAP_INFO *info )
The first argument is the database pointer of the entity to be mapped. The mapping function must not modify this entity in any way. The second argument is a structure containing information about the mapping. The contents of this structure is describe in the MAP_INFO section.
WRITING MAPPING FUNCTIONS
This section describes the requirements for general mapping functions only (those defined with the MAP_GENERAL option). The only requirements for end mappings are that they do not call map_ProcessEntity.
Code Structure
While there are no limitations on the type of processing performed by a mapping function, it must ensure that the following steps are carried out:
Perform the mapping operation. This may require calling other functions, allocating new entities, etc. If the mapping is defined with the MAP_TRANSIENT option, the results of this step must be one or more new entities created in the model specified by info->model. The new entity(ies) can reference other new entities but must not reference any existing entities. If this option is not used, the mapping function may pass an existing entity (which may in turn reference other existing entities), into map_ProcessEntity.
If the mapping was defined with the MAP_TRANSIENT option, assign the database pointer from the input entity to the original database pointer field in the new entity(ies).
Invoke map_ProcessEntity() with the resulting entity. In the case of 1 to many mappings, map_ProcessEntity() must be called once for each resulting entity. map_ProcessEntity will automatically commit or delete the entity so the mapping function should not modify or delete the entity after map_ProcessEntity returns.
The following code fragment shows a typical mapping function skeleton for a mapping defined with the MAP_TRANSIENT option:
PDX_MSGT mapping_function ( MDA_PTR db_ptr, MAP_INFO *info )
{
... Generate new entity in the model info->model
/* Assign original database pointer field */
mda_SetOrigDbptr ( MDA_NOOPT, new_ent, mda_GetOrigDbptr(old_ent) );
/* Pass entity back in for further processing */
rc = map_ProcessEntity ( MAP_NOOPT, new_db_ptr, info );
}
Additional Guidelines
Other caveats which should be observed when developing mapping functions are listed below. These guidelines are required when developing mapping functions that generate PDElib entities which are passed to map_ProcessEntity.
Due to the recursive processing structure used by the MAP subsystem, mapping functions should not declare large local arrays. All local variables will be allocated from the stack and may lead to a stack error if a deeply nested mapping is encountered. If a mapping function needs to use large local arrays, it is best to have the mapping function invoke a secondary function which does the mapping and returns the new database pointer to the mapping function.
Mapping functions must not modify the entity which is passed in. They must either generate a new entity or duplicate the entity passed in and make modifications to the new entity.
When invoking map_ProcessEntity with an entity that is referenced by other entities, the MAP_NO_DELETE option must be used.
Mapping functions should call one of the xxx_IssueError functions if an error is detected within the mapping function (not passed back from a called function). If an error is returned from another function, the mapping function must cleanup any memory, entities, etc. that were in use at the time the error was detected and then return the error back to the caller. Mapping functions which decompose or explode an entity can choose to ignore errors returned by map_ProcessEntity or stop the mapping and return the error.
A single mapping function can be used for multiple mapping definitions. This is useful if several entities can all be processed using the same or similar code. In some cases the mapping function may need to perform a slightly different set of actions based on which mapping was actually invoked. Usually the input entity type is enough to determine what actions to perform. If the actual mapping name needs to be examined, it can be obtained in info->mapping->hdr->name where it is stored as a character string.
The model which a mapping function creates entities in must have backpointers enabled. The mapping function must properly create/maintain backpointers before passing an entity to map_ProcessEntity.
Mapping functions must set the original database pointer when generating new entities.
All entities generated by a mapping function must be defined in the same DDF (which is specified when the mapping is defined). This DDF does not need to be the same as that which the input entity is defined in.
A mapping function can only be defined with the MAP_TRANSIENT option if it generates new entities. If it passes any existing entities into map_ProcessEntity, the MAP_TRANSIENT option can not be specified.
MAPPING DEFINITIONS
Simple Mappings
A simple mapping definition consists of a symbolic mapping name, the mapping function which performs the mapping, the DTF of the entity type which the mapping is to be applied to, and the DTF of the entity or entities which the mapping generates. There is also a flag associated with the mapping which specifies if the mapping can be chained together with other mappings to form a complex mapping definition (called a mapping list). In order for a mapping to be chainable, it must only generate a single DTF as output. It can generate multiple entities, but they must all have the same DTF.
Mapping Lists
A mapping list consists of a set of simple mappings and/or mapping lists which are to be applied in a sequence and treated as if they were a single mapping. This allows complex mappings to be created by chaining other mappings together. If the last simple mapping or mapping list in the sequence is flagged as being chainable, then the new mapping is also chainable. The mapping list can be treated much like a simple mapping. The DTF that the mapping list expects for input will be the same the DTF for the first mapping in the sequence.
MAPPING TABLES
Mapping tables define what mapping function(s) should be applied to each DTF encountered. Mapping tables are declared with the MAP_TABLE data type. Each mapping table contains a tree of mapping definitions and a tree of enabled mappings. By having these two trees, a single table may contain a variety of mappings, of which only a few are actually enabled. This allows PDElib to define all of the supported mapping functions in a single step. The application or end user can then selectively enable the mappings that they want to have applied. Mapping tables are created using the map_CreateTable function.
DEFINING MAPPINGS
Mappings must be defined before they can be used. To add pre-defined PDElib mappings to a mapping table, the application must call a PDElib interface specific function which defines the mappings for that particular interface. The name of this function will be xmap_DefineMappings where x is the interface prefix letter. The function gmp_DefineMappings can be used to define the GDX mappings.
Application mappings are defined using the function map_DefineMapping. This function takes a mapping name, mapping function, the DTF that the mapping expects as input, and the DTF of the output entity. Mapping lists can be defined using the function map_DefineMappingList. This function takes a mapping name and a list of previously defined mappings and/or mapping lists.
See the USING MAPPING DEFINITION FILES section for information on an alternative approach to calling map_DefineMapping.
ENABLING MAPPINGS
Once a mapping or mapping list has been defined, it must be enabled before the MAP subsystem will apply it. The function map_EnableMapping is used for this. In addition to specifying the mapping to be enabled, an application can specify the following items:
The model which the mapping results are to be placed in.
An option (MAP_COMMIT) indicating if the results of this mapping are to be made permanent.
Parameters to control characteristics of the mapping.
These items are described in detail in the map_EnableMapping manual page.
MAPPING PARAMETERS
The MAP subsystem allows optional parameters to be passed to mapping functions through the use of a name/value interface. This allows parameters (such as tolerance) to be specified differently for each mapping that is enabled.
A parameter is defined by specifying a name, type, default variable, and default value to the function map_DefineParameter. The default value can then be overridden for this parameter when the mapping is enabled using map_EnableMapping (see the map_EnableMapping manual page for details on the syntax to do this). Mapping parameters are global to all mapping tables.
Parameter names are represented using #defines for efficiency. In order to avoid duplication of #defines, the parameter name is placed in a .msg file which is compiled with the message table compiler (see the mtc manual page).
Mapping parameters can be defined as being one of the following data types:
A #define value generated from mtc. This type is typically used to simulate a C enumeration and allows a symbolic value to be used rather than a simple integer. The define must be generated from mtc.
A boolean value.
A long integer value.
A double value.
Defining New Mapping Parameters
Note that these steps are only needed to create new parameters. To use PDElib defined parameters, skip to the next section.
The default values for parameters are stored in global variables maintained by the application. This is done to minimize the overhead of retrieving parameters in the mapping functions. By registering the address of the global variable containing the default value for a parameter, the function map_SetParameterDefault can be used to modify default values.
The steps involved to add an application defined mapping parameter are shown below. This example shows how to add parameters named ASYS_PROC_METHOD, ASYS_CONVERT_TO_NURBS, and ASYS_TOL with types MAP_DEFINE, MAP_BOOLEAN, and MAP_DOUBLE respectfully. It assumes that an application subsystem called ASYS, and its associated message file "asys.msg", have already been created.
Define the parameter names by adding the following lines to asys.msg:
PROC_METHOD ""; CONVERT_TO_NURBS ""; TOL "";
The empty message strings are required in order to generate the proper defines in the message table.
Also add the following to define the values which ASYS_PROC_METHOD can use:
MODEL_MODE ""; DRAW_MODE "";
Compile the message table using mtc. The resulting asys__Messages.h file will contain the #defines to be used as parameter names.
Declare global variables to hold the default values for the parameters. The variables can be named anything but must be of the appropriate type and must be declared globally. The example below assumes that the variables are declared elsewhere without the extern keyword.
extern PDX_MSGT asys_proc_method; extern int asys_convert_to_nurbs; extern double asys_tol;
Call map_DefineParameter to register the parameters with the MAP subsystem and assign default values.
map_DefineParameter ( MAP_NOOPT, ASYS_PROC_METHOD, MAP_DEFINE,
&asys_proc_method, ASYS_MODEL_MODE );
map_DefineParameter ( MAP_NOOPT, ASYS_CONVERT_TO_NURBS, MAP_BOOLEAN,
&asys_convert_to_nurbs, PDX_FALSE );
map_DefineParameter ( MAP_NOOPT, ASYS_TOL, MAP_DOUBLE, &asys_tol, 0.01 );
The parameters can now be used in mapping functions as described in the next several sections.
Setting Mapping Parameter Defaults
The default value for a parameter can be set using the function map_SetParameterDefault. This value will then be used whenever a parameter is not explicitly specified to map_EnableMapping. To change the default value for the ASYS_TOL parameter, the following call would be made:
map_SetParameterDefault ( MAP_NOOPT, ASYS_TOL, .1 );
Note that this is equivalent to setting the asys_tol global to .1. Using the map_SetParameterDefault function provides a consistent way to set both application and PDElib defined parameter defaults.
Setting Mapping Parameters
The values for mapping parameters are specified when mappings are enabled using map_EnableMapping. They are specified using the MAP_PARAM token in the variable argument list. The map_EnableMapping manual page describes the syntax used. The following example shows a mapping being enabled with all three of the parameters defined in the previous section.
map_EnableMapping ( MAP_NOOPT, table, "application mapping",
MAP_PARAM, ASYS_PROC_METHOD, ASYS_MODEL_MODE,
MAP_PARAM, ASYS_CONVERT_TO_NURBS, PDX_TRUE,
MAP_PARAM, ASYS_TOL, .1,
MAP_END );
Using Parameters In Mapping Functions
Mapping functions access parameter values using the function map_GetParameter. This function takes a mapping name and a parameter name, and returns the corresponding value. If the parameter was not specified when the mapping was enabled, a return code of MAP_NO_VALUE will be returned.
The following code shows how to retrieve the ASYS_TOL parameter:
Declare a local variable to hold the default values for the parameter. This is then set to the appropriate default value (the global defined previously).
double tol = asys_tol;
Call map_GetParameter to obtain the parameter value if one was specified for the mapping. If the parameter was not specified, the value will not be changed and a return code of MAP_NO_VALUE will be returned. map_GetParameter ( MAP_NOOPT, mapping, ASYS_TOL, &tol );
Any mapping function which calls a GDX function should use the gmp_SetTolerances call to obtain and set the GDX tolerances. See the gdx_intro and gmp_intro manual pages.
MAP_INFO
The MAP_INFO structure contains information which is passed from one mapping to the next through map_DispatchEntity, map_ProcessEntity, map_CommitEntity, and the application dispatcher. This structure is also used by the application to specify certain parameters which are to be used in the mapping process including the mapping table, the application dispatcher function, and an OLM list to store the results of the mapping process in. The function map_InitMapInfo initializes a MAP_INFO structure with default values. The application can then override certain values.
The actual structure declaration is shown below followed by a detailed description of each field. Unless noted otherwise, a field can only be modified by the application before calling map_DispatchEntity or map_DispatchList (i.e. they can not be modified in a mapping function called under map_DispatchEntity). For the fields which the application can change at any time, a change will only be visible at the current recursion level and deeper because map_DispatchEntity duplicates the MAP_INFO structure at each recursion level.
typedef struct {
| long | options; | |
| void | *data; | |
| int | depth; | |
| int | model; | |
| MAP_TABLE | *table; | |
| MAP_MAPPING | *mapping; | |
| PDX_MSGT | (*dispatcher)(); | |
| EAM_STACK | *stack; | |
| OLM_LIST | *list; | |
| MAP__PS | _ps; |
Contains bit flags to control certain characteristics of the mapping process. Multiple options can be specified by or'ing together multiple bit masks. The valid options are:
Silently ignore non-mapped DTFs in map_DispatchEntity. Normally a MAP_NO_MAPPING error will be returned if an entity is passed to map_DispatchEntity which does not have a mapping enabled for its DTF. If this option is specified, no error will be generated.
data
A void pointer which the application can use to pass information through the MAP subsystem. This field is ignored by the MAP subsystem and can be modified at any time by the application.
depth (Read Only)
The current depth of recursion in map_DispatchEntity. At the top level (before map_DispatchEntity has been called), the depth will be 0. The depth is incremented at each recursive invocation of map_DispatchEntity.
model (Read Only)
Used to tell mapping functions what model the resulting entities should be created in. map_DispatchEntity will set this field based on the following rules:
If an explicit model was specified with MAP_MODEL when the mapping was enabled, the model field will be set to the model specified.
If the DDF for the resulting entity of the mapping is the same as the input entity DDF (i.e. both the input and output entities for the mapping are defined in the same DDF), the model field will be set to the model which the original entity is defined in.
If neither of the above rules apply, the first model with the appropriate DDF (as determined by calling mda_FindModelByDDF) will be used.
table
The mapping table containing the mappings to be applied. This field must be set by the application before invoking map_DispatchList or map_DispatchEntity. The table is created using map_CreateTable.
mapping (Read Only)
The mapping which is currently being applied. This field is only valid inside of mapping functions. Mapping functions need to pass this field into map_GetParameter to obtain mapping parameters. Mapping functions should not access the structure referenced by this field except to obtain the mapping name (stored in mapping->hdr->name as a char * string).
dispatcher
Specifies an application dispatcher to be called from map_ProcessEntity. See the USING AN APPLICATION DISPATCHER section for additional information.
stack
Used to track attributes through a mapping. Only used for interfaces which make use of the EAM subsystem.
list
Specifies an OLM list to add subsequently created entities to. This allows an application to capture the list of entities created by subsequent recursive processing. If this field is not NULL, map_ProcessEntity and/or map_CommitEntity will add the database pointer of each committed entity to the list (note that only the database pointer passed to map_ProcessEntity will be added, subordinate pointers will not be). The application can change this field at any time to have multiple lists active. The application is responsible for allocating and freeing any lists. The list should be allocated with a call similar to:
info.list = olm_CreateList ( OLM_NOOPT, sizeof(MDA_PTR), 50, NULL );
Application mapping functions can add additional entities to the list if needed.
_ps
This structure contains processing information maintained by the MAP subsystem and should not be accessed by application code.
PUTTING IT ALL TOGETHER
This section summarizes the steps required to use the MAP subsystem.
Write any needed mapping functions.
Create a mapping table using map_CreateMappingTable.
Define mappings using map_DefineMapping and/or xxxx_DefineMappings.
Enable mappings using map_EnableMapping and/or xxxx_EnableMappings.
Initialize a MAP_INFO structure using map_InitMapInfo and assign the info->table field to the table.
Invoke map_DispatchEntity with the entity to be mapped.
EXTERNAL FILE INTERFACE
The MAP subsystem provides a simple external file interface which allows the following to be controlled from an ASCII file:
Parameter defaults
Defining mapping lists
Enabling of mappings and mapping lists
The function map_LoadMapFile is used to process the entries in the external file. See the map_LoadMapFile manual page for the file format and additional information.
USING AN APPLICATION DISPATCHER
If an application needs more control over the mapping process than what the map_DispatchEntity/mapping function/map_ProcessEntity sequence provides, it can specify a function to be inserted into the call sequence prior to map_DispatchEntity on each entity. Application dispatchers are used primarily for the following purposes:
To gain access to the entity at the end of a mapping sequence so that attributes or other non-mapped fields can be translated from the original entity. The original entity can be obtained using the function mda_GetOrigDbptr on the mapped entity. The application dispatcher will be called with the entity and must then pass it on to map_DispatchEntity for further mapping or must do its own local processing (such as for attributes). If it calls map_DispatchEntity, the return code from map_DispatchEntity should be passed back from the application dispatcher. To commit the entity, the dispatcher can call map_CommitEntity instead of map_DispatchEntity. map_IsCommitMapping can be used to determine if an entity is to be committed or further mapped.
To allow entities from a non-PDElib based database or API to be passed into the MAP subsystem. In this case, the application dispatcher converts the native entity to an entity which is defined using a DDF (the DDF can be for GDX, a PDElib interface, or an application specific DDF). This entity is then passed into map_DispatchEntity to be mapped to its final type.
To allow context sensitive selection of mappings. By intercepting the result of each mapping, an application dispatcher can change the subsequent mappings based on the context of the current entity. This is useful in situations such as when entities subordinate to a structure entity need to be processed differently than when the entity is independent.
To use an application dispatcher, the info->dispatcher field in the MAP_INFO structure is set to the address of the dispatcher function. The application dispatcher has the same argument list as a mapping function. map_ProcessEntity will invoke then application dispatcher rather than map_DispatchEntity.
GENERIC MAPPINGS
Regular mapping functions expect a specific type of entity as input. However, some mapping type operations can be performed on any entity regardless of its DTF. These are called generic mappings. The MAP subsystem currently supports only a single type of generic mapping which copies an entity. This is useful for applications which map entities from an input model to an output model but may want to just copy certain entity types. Generic mappings are enabled just like a regular mapping. The mapping names used for generic mappings are based on the entity name and the type of generic mapping. For example, the generic mapping to copy an entity named "gdx_nurb_curve" would be "gdx_nurb_curve copy". The following table shows the types of generic mappings and their corresponding names:
| Mapping action | Mapping name |
| – | |
| Copy | "entity_name copy" |
Generic mappings can not be used as part of a mapping list.
ADVANCED TOPICS
The remaining sections describe the more advanced functionality available within the MAP subsystem.
CHAINABLE MAPPING RULES
Chainable mappings have a refined set of rules when considering the scope of mapping lists and conditionals. These rules are as follows:
Mapping lists are chainable only if the last mapping in the list is marked as chainable.
Mapping lists can only be created if every component of the list is chainable up to the last mapping. The last mapping need not be chainable to create a list.
Conditional mappings are only chainable if all available component mappings have identical output dtfs.
Conditional mappings can only be nested inside of a mapping list if the conditional is chainable. Nonchainable conditional mappings can only be nested as the last element in a mapping list.
Any type of mapping can be defined as a component of a conditional mapping as long as each of the components have an input dtf that matches the input dtf specified for the conditional.
CONDITIONAL MAPPINGS
Conditional mappings may be defined by calling map_DefineConditionalMapping. A conditional mapping definition consists of a symbolic mapping name, the mapping function that will select one of the defined component mappings, the DDF and TF of the entity type which the mapping is to be applied to, and a set of possible component mappings. Like mapping lists, conditional mappings are treated in a manner very similar to a single mapping. It is possible to define mapping lists as well as other conditional mappings as components of a conditional mapping as long as all rules for chaining mappings are followed. Likewise, conditional mappings may appear within mapping lists. All component mapping operations of a conditional mapping must be defined before they are included in a conditional definition.
For example, a conditional mapping could be set up to convert gdx_nurb_curve(s) to either gdx_arc(s) or gdx_polyline(s) based on a tolerance.
The conditional mapping could be defined with a call to map_DefineConditionalMapping as follows:
map_DefineConditionalMapping ( MAP_NOOPT, table,
"gdx_nurb_curve -> gdx_arc or gdx_polyline",
ddf, tf, mapping_function,
"gdx_nurb_curve -> gdx_arc",
"gdx_nurb_curve -> gdx_polyline" );
Once a conditional mapping has been defined, it must be enabled before the MAP subsystem will apply it. The function map_EnableMapping is used for this purpose. Parameters specified to map_EnableMapping in association with a conditional mapping will be copied down into each component. Thus there is no method for distinctly specifying independent parameters for each component.
The function, map_InvokeMapping, is used to invoke a selected component of a conditional mapping. It should be called from the function associated with the named conditional. map_ProcessEntity should never be called from the conditional function.
For the above example, the function could look like:
PDX_MSGT mapping_function ( MDA_PTR db_ptr, MAP_INFO *info )
{
/* Get parameters associated with mapping */
...
/* Select a mapping based on the parameters */
if ( operation & arc )
{
map_InvokeMapping ( "gdx_nurb_curve -> gdx_arc", db_ptr, info );
}
else
{
map_InvokeMapping ( "gdx_nurb_curve -> gdx_polyline", db_ptr, info );
}
}
DEFINING/ENABLING MAPPINGS WITH STRINGS
The functions map_DefineMappingList and map_EnableMapping support a string based interface which allows the variable argument lists to be specified with a character string rather than a combination of #define values. This allows the MAP subsystem to be configured at run-time. See the map_DefineMappingList and map_EnableMapping man pages for additional information.
STRUCTURE PROCESSING
Special circumstances sometimes exist that require a slightly modified approach to the standard mapping function algorithm. When processing a structure type of entity, such as an IGES group, it may be best to construct the mapping function in a two tiered approach. This approach will work best for entities that must be mapped by processing their subordinates first and then reformulating these into a new structure entity. The most notable difference between this methodology and the standard algorithm explained in the WRITING MAPPING FUNCTIONS section is that map_DispatchEntity is called from within the mapping function instead of map_ProcessEntity. The following steps outline the key points of structure processing:
Save the OLM list pointer in the info->list field.
Allocate a new OLM list and place the resulting pointer in info->list.
Loop through the structure entity and invoke map_DispatchEntity on each constituent entity.
Allocate the new target structure entity.
Add the OLM list of entities to the new structure entity.
Restore the info->list.
It is usually advisable to commit the target structure entity to the database without calling map_CommitEntity. Again, this is not in line with the traditional methodologies of standard mappings. The reasoning for this, is that map_CommitEntity will commit the new structure along with all of its subordinates. Since all subordinate entities have been mapped to the target model, it is not necessary to process them further.
Apply attributes to target structure entity.
For more insight on this topic, review the apls_GroupToIGES402.c sample function included in the apls_out sample program.
WILDCARDING
When a mapping is defined, the DTF that it operates on is specified as an argument to map_DefineMapping. In some cases, the same mapping function will operate on several different forms of the same entity. The MAP subsystem allows wildcarding the form portion of a DTF so that a mapping function will be associated with every form of the entity. The resulting mapping definition behaves the same as a regular mapping definition but applies to all forms of the entity. The form is wildcarded by specifying DDF_ANY_FORM for the form in DTF. See the map_DefineMapping manual page for additional information.
ENABLING MULTIPLE MAPPINGS PER DTF
The MAP subsystem allows multiple mappings to be enabled for a DTF. The order in which they are enabled determines the order that they will be applied. This allows mappings to output the same type of entity as was input. The MAP subsystem prevents infinite loops by keeping track of what mappings have already been applied to a given entity. If an application dispatcher is used in conjunction with multiple mappings for a DTF, the dispatcher will only be called with the results of the last enabled mapping. Normally all the mappings except the last should generate the same DTF as the input. If an intermediate mapping generates a different DTF, it will be dispatched according to the first mapping enabled for the new DTF. If an application dispatcher is defined, it will not be called until the last mapping for the new DTF is processed.
STORING THE RESULTS OF A MAPPING
The resulting database pointer(s) from a mapping can optionally be stored in an OLM list. To do this, the application allocates an OLM list (see the olm_CreateList manual page) and stores the resulting OLM_LIST pointer in the "list" field of the MAP_INFO structure. The final entities created from any subsequent mappings will be appended to this list. The list can be temporarily or permanently disabled by setting this field to NULL. Mapped entities are automatically added to the list by map_ProcessEntity when the entity is committed. Mapping functions may write other entities to the list if needed. See the MAP_INFO section for additional information.
USING MAPPING DEFINITION FILES
A mapping definition file (MDF) provides a method for defining and documenting mappings in a single file. A utility called mdc takes an MDF file and generates either C code for defining mappings or a manual page describing the available mappings. See the mdc manual page for additional information.
DEBUGGING FUNCTIONS
Several debugging functions are provided with the MAP subsystem. A summary of these appears in the following table. The map_DbgSetTracing function can be particularly useful in diagnosing problem mappings. Note that on some systems these can be called interactively from the system debugger. See the appropriate manual page for usage information.
| Funcion | Description |
| – | |
| map_DbgDumpTable | Lists the contents of a mapping table |
| map_DbgDumpMapping | Lists a mapping definition |
| map_DbgDumpParameter | Lists all defined parameters |
| map_DbgSetTracing | Enables several levels of tracing output |
INNER WORKINGS
Although the map subsystem can be used in its entirety without knowledge of the specifics of its inner workings, there are times when it may be helpful to know what goes on inside the black box. This section describes the mechanics of map_DispatchEntity, map_ProcessEntity, and map_CommitEntity.
map_ProcessEntity
map_ProcessEntity will process the entities generated by mapping functions. If an application dispatcher is defined, it will always be invoked on the entity. If no application dispatcher is used, the entity will either be committed (if info->mapping was enabled with MAP_COMMIT) or sent back into map_DispatchEntity otherwise. Entities that do not get committed are recursively deleted. The following pseudocode demonstrates:
Get DTF of entity
if (current mappings target dtf != DTF of entity)
Issue error message and return
if (application dispatcher is not defined)
if (current mapping enabled with MAP_COMMIT)
Commit entity (map_CommitEntity)
else
Dispatch on entity (map_DispatchEntity)
else /* Application dispatcher is defined */
Invoke application dispatcher on entity
if (entity not flagged as committed and
MAP_NO_DELETE option not set)
Delete entity (recursive delete)
map_DispatchEntity
map_DispatchEntity applies the mapping enabled for the type of entity passed in. If more than one mapping is defined for a single DTF, they are invoked in order for each call to map_DispatchEntity.
Get DTF of entity
if (multiple mappings exist for this DTF)
Invoke next mapping
else
Invoke appropriate mapping function based on DTF
map_CommitEntity
map_CommitEntity commits the results of a mapping. Entities that are not transient must be recursively copied before being flagged as committed. Transient entities, however, can simply be flagged as committed. Committed entities are added to the info->list if applicable. The following pseudocode demonstrates:
if (entity is not transient)
Recursively duplicate entity into appropriate model
committed_entity = new duplicate entity
else /* entity is transient */
committed_entity = entity
Flag committed_entity as committed so
map_ProcessEntity will not delete it
if (info->list is defined)
Add committed_entity to the list