SAT Save and Restore


ACIS provides the API functions api_save_entity_list and api_restore_entity_list for saving model data to and retrieving model data from standard stream files. Two additional API functions, api_save_entity_list_file and api_restore_entity_list_file, allow applications to target media other than stream files by providing input and output routines to the functions by deriving a custom FileInterface class object.

The standard ACIS save/restore process supports two types of stream file formats: Standard ACIS Text (file extension .sat) and Standard ACIS Binary (file extension .sab). The only difference between these files is that the data is stored as ASCII text in a .sat file and in binary form in a .sab file. The organization of the model data is identical in both formats; the term SAT file is generally used to refer to both types.

Text file saves have the advantages of being human-readable. Binary saves are not human-readable, but writing records in binary is roughly twice as fast as writing in text and the files are 10% to 20% smaller. ACIS can read and write any format of binary file on any platform. The selection of binary file format to be written is controlled by the binary_format option. The default format for writing a binary file is the native format of the machine on which it is being written.

Topics include:

Model Data Layout

An ACIS model data block begins with a header record, followed by a FileInfo record, followed by active entity records, then history stream records and history entity records (when saving with history), and finally the end of ACIS data terminator token.

The ACIS model data block is an atomic unit and should not be modified or broken up in any way. More than one ACIS model data block can be saved to a file however, and applications can surround the blocks with custom data. We call the later compound files and urge you to change the extension of these files and to provide a process to extract ACIS model data blocks so that they can be restored by any ACIS-based application.

The header record contains the ACIS version of the model data, entity counts, and history information. The FileInfo record contains the product ID of the model creator, the unit representation, and tolerances of the model data, among other items. The active entity records begin with the ones supplied to the save command whether or not these are actually the top-level entities with respect to the topological hierarchy. The entities returned from restore are the same entities supplied to save. Hence, always save top-level entities (that is, BODY entities) in order to preserve a logical entity sequence.

Note:  The product ID and units must be set correctly in the FileInfo record before SAT files can be saved. Refer to the reference templates for class FileInfo and function api_set_file_info for more information.

Save and Restore Details

Save Details

The standard ACIS save process is initiated by calling api_save_entity_list. This API function accepts an open stream pointer (FILE*), a logical indicating whether to save in binary or text format, and an ENTITY_LIST containing the entities to be saved. The api_save_entity_list_with_history function is similar and is used to additionally store history information. The save process, which writes the records one by one to the current output position in the stream, can be broken down into the following steps:

The header record consists of four numbers which represent: the version of the data (save version), the number of entities in the data block (saved entities), the number of entities originally supplied to the save process (top-level entities), and a bit-field, mainly used internally, that indicates whether history records are available in the data block.

The save version is simply the ACIS version to which the model data is formatted. This is typically the current version of ACIS but can be modified, with api_save_version, to target an earlier version of ACIS. This is useful when exchanging model data with applications based on older versions of ACIS, but has several drawbacks that are discussed in the topic Backward Compatibility.

Note:  Later versions of ACIS data cannot be restored by earlier versions of ACIS. Current model data, in other words, is not backwards compatible. The only way to make model data consumable by older versions of ACIS is to specifically target these versions with the save version value.

The saved entities value is now obsolete and only has value in very old versions of ACIS data (prior to 1.7). This value represents the number of ENTITY records actually saved to the stream. The difficulty of maintaining this value is mainly caused by the need to change the writing position of the stream (to record the number of records actually written), which is made problematic by different interpretations of end-of-line formatting characters. Changing the data output position may also be difficult or even impossible when the media does not support random access, such as tape. The modern format solves this problem with and end-of-data token, discussed later in this section. We may choose to use this value for other purposes in the future.

The top-level entity value represents the number of entities supplied to the save process in the ENTITY_LIST argument. These are the seed entities used to discover all other supporting entities that must also be saved in order to maintain the complete topological and geometric structure of the model. These are usually BODY entities and are the first records saved to the stream. The supporting entities, written to the stream after the top-level entities, are all entities that can be reached by scanning both up and down the topological hierarchy. These entities, when restored, duplicate the state of the model when it was saved.

The last value in the header record is a bit field. The least significant bit of this value indicates whether of not history records have also been saved in the data block. This bit is set when the model data is saved with the api_save_entity_list_with_history function. The remaining bits of the value are reserved for internal use and should be ignored.

All of the header data, with exception of the save version, is calculated by the save process and cannot be modified in any way. This data simplifies the restore process.

The FileInfo record is saved next. This record is unique to each ACIS based application because it contains a product identifier, unit representation, and tolerance values of the application. The FileInfo record must be setup correctly by calling the api_set_file_info function before model data can be saved. The save process fails, in other words, if this record is not correctly initialized. This is not only used to track the creator of the data, but also to help assure the correct representation of the data in the application model space, with respect to units and tolerances.

The ENTITY records are saved next, beginning with the top-level entities of the supplied ENTITY_LIST. These are followed by the supporting entities in no particular order. The HISTORY_STREAM records, including DELTA_STATE, BULLETIN_BOARD, and BULLETIN records, as well as the history entities, which are simply snapshots of entities at particular states, follow next if saving with history.

And finally, the "End-of-ACIS-data" terminator token is written to the file.

Restore Details

The standard ACIS restore process is initiated by calling api_restore_entity_list_file. This API function accepts an open stream pointer (FILE*), a logical indicating whether to restore in binary or text format, and an ENTITY_LIST to receive the entities that are restored, as arguments. The api_restore_entity_list_with_history_file function is similar and is used to additionally retrieve history information if available. The restore process, which reads the records one by one from the current read position in the stream, is analogous to the steps of the save process.

The header record is restored first, followed by the FileInfo record, the top-level entities, the history records and entities if applicable, ending with the terminator record.

The header record can be restored individually with the read_header function. This may be useful when applications need version information before calling standard restore functions. Care must be taken to reset the current read position so that standard restore can successfully re-read the header. Also, note that the binary format of the data block, in the case of an SAB file, is determined during the header read process.

The FileInfo record can also be restored, after the header record is restored, by calling the restore method on a FileInfo object. This may also be useful when applications need creator or unit information from the model data before calling the standard restore functions. The FileInfo record can also be evaluated after restore by getting the last one restored with the api_get_file_info function.

The ENTITY records are restored next, beginning with the top-level entities, which are added to the supplied ENTITY_LIST. The entities returned to the restore process are the same ones supplied to the save process. The HISTORY_STREAM records, including DELTA_STATE, BULLETIN_BOARD, and BULLETIN records, as well as the history entities, are restored next if restoring with history.

The restore process ends after the "End-of-ACIS-data" terminator token is restored from the file.

Applications are responsible for opening and closing the stream files, and for making sure that the file pointers are positioned correctly when the standard save and restore functions are called. Each function expects that the file is open and positioned at the byte where the save or restore is to begin. When the function finishes, the stream file is positioned after the last byte of the end of ACIS data terminator token.

Customizing Save and Restore

The standard ACIS save and restore functions read and write to stream files simply because the internal SatFile and SabFile FileInterface objects, defined in the sabfile.hxx and satfile.hxx, are implemented in this manner. You can modify this behavior by deriving your own FileInterface objects and passing them to the api_save_entity_list_file and api_restore_entity_list_file functions.

FileInterface is an abstract base class. By deriving classes from FileInterface, ACIS models can be saved and restored to media other than stream files. For example, it is possible to derive FileInterface classes that allow models to be saved and restored to blocks of memory or by using a pipe to transfer data between two processes.

If a new type of FileInterface class is being derived, derive it from BinaryFile, which is defined in the binfile.hxx file. The BinaryFile class implements most of the virtual methods of the FileInterface class in a generic manner, which leaves only a few methods, dealing specifically with input/output, to be implemented.

Refer to the example code in the Use Cases. section of the kernel component documentation.

Sequence Numbers

The indexing of the entity records depends on the active ACIS options when the model was saved. If they are indexed, the indexing is sequential starting at 0. All top level entities must appear before any other entities. Thereafter, the record order is not significant.

The optional sequence number represents the index assigned to a record and is intended to improve readability and simplify editing of ACIS save files. The option sequence_save_files controls whether ACIS writes sequence numbers to the part save file.

-0 body $1 $2 $-1 $-1 #
    .
    .
    .
-25 point $-1 10 0 25 #

In the example above from a SAT file, "-0" and "-25" are sequence numbers. In the first line, "$1 $2" happen to be pointers to records (not shown) with sequence numbers "-1" and "-2", respectively.

This sequence number itself can be turned on or off for the entity records in the save file. Even when the sequence number is not written to the file, it is implied by the order of the records in the file. Pointers to other records correspond to these implied sequence numbers. If sequence numbers are turned off, a record cannot be simply moved or removed from the save file, because this creates invalid index referencing when the file is restored.

If sequence numbers are turned on, an entity may be deleted by simply removing its record from the save file. Any references to the removed record's index become NULL pointers when the file is restored by ACIS. With sequence numbers on, records may also be rearranged within the file.

A mixture of records with sequence numbers and records without sequence numbers is permitted within the save file. Any record having a sequence number is given an index one greater than the previous entry in the file. Specified sequence numbers can be in any order. However, care must be taken that no sequence number repeat itself, either through manual specification of sequence numbers or the implied incrementing of other, non-specified, sequence numbers.

Regardless of what sequence numbers they contain, the entities represented by the first records are assumed to be the top-level entities. Top-level entities are part of the ACIS topology. Also, if the total entity count was written in the header and the last record's sequence number is not one less than that count, a dummy record with a sequence number equal to the count must be added at the end of the file.

Backward Compatibility

The ACIS version number for subsequent save operations is set using the function set_save_file_version, which takes two arguments, a major version and a minor version.

Throughout the system, all entity save functions, and related functions for curve, surface, for example, take into account the version number. This is the global value, save_version_number, which gives the version of save file format being written. This can be used to produce a save file in a previous version's format.

Objects can be modified to be compatible with an earlier version. This may or may not result in loss of information. If the modification involves loss of information or a possible error in the resulting save file, the system generates a warning, but still produces the save file. When saving to a previous version of 7.0 or later, the system may attempt to use tolerant modeling to remove gap errors in such modified models.

When restoring objects with shared subtypes, such as int_cur or spl_sur, from a save file in which they are not shared, the default is to share identical sub-objects rather than to leave them unshared.

Note:  The restore of pre-Release 1.6 save files causes the coedges in the entity restored to be ordered counterclockwise about their edge.

The version number is normally the current version, but the version may be set backwards to simulate save files generated by previous versions. A major version of 0 or less causes the version to default to the current ACIS version.

Set the save file version number:

void set_save_file_version(
    int = 0,          // major version number
    int = -1          // minor version number, default gives
                      // error unless major version is zero
    );

Decimal Point Representation

Some applications using earlier versions of ACIS were written using "internationalization" concepts and have written save files that contain representations of double precision numbers containing commas for decimal points. This occurs if the application writing the save file had made a call to the C standard library function setlocale to change the locale properties from the default C settings. Consequently, other applications not using this "internationalization" feature could not read these files.

Beginning with release 2.1, ACIS always writes a save file using the C locale, which uses the period representation for decimal points. ACIS makes a call to the function setlocale to change the environment to the C locale before writing a save file. The locale is reset to its original value after the file is written.

The option restore_locale enables applications to read pre-2.1 save files that were written with other locales. Before restoring the file, the option should be set to a string representing the locale in effect when the file was written. The option may be set with the function api_set_str_option, with the Scheme extension option:set. When a file is restored, ACIS makes a call to the function setlocale to set the environment to the value (string) specified by the option.

Option for Testing Shared Geometry

The test_share option checks for shared geometry when restoring SAT files. As entities are read into ACIS, int_cur and spl_sur types are compared with those that have already been restored to determine if they are identical to a previously restored int_cur or spl_sur. They can then be restored simply by incrementing a use count instead of restoring the entire object. This option significantly reduces the size of retrieved bodies and aids subsequent operations, but it can be expensive and can become noticeable when restoring large parts.

The option can be turned off to speed up the restore process. However, the amount of memory required to restore a model is larger, because sharing of geometry is not taking place. Also, evaluations of geometry during modeling operations may take longer because the test for coincidence takes place each time the objects are evaluated. This may cause the test to happen many times instead of once when the model is loaded.

If you are confident that your models contain little shared data or that the data has already been shared via modeling operations in ACIS, then turning the test_share option off may lead to faster load times.

Restore Logging

Functionality has been added to the SAT/SAB restore process that can be used to generate an entity record sanity log file when ACIS data cannot be restored because of errors. This log file contains a character-by-character copy of the loading file with error information, if any, inserted directly after the field of the entity record that did not meet the criteria of the restore logic. The information in this log file can be used to identify corrupt fields in entity records so that successful restores can be possible.

The following is a simple example of the structure of the log file and the information it contains. The first block contains the first few lines of a good SAT file; the second contains a few modifications to the same SAT file; the third shows the restore errors that result from loading the modified file.

1100 0 1 0
24 ACIS Scheme AIDE - 11.0 12 ACIS 11.0 NT 24 Wed Jun 18 14:50:34 2003
1 9.9999999999999995e-007 1e-010
body $-1 -1 -1 $-1 $1 $-1 $-1 F #
lump $-1 -1 -1 $-1 $-1 $2 $0 F #
shell $-1 -1 -1 $-1 $-1 $-1 $3 $-1 $1 F #
face $-1 -1 -1 $-1 $4 $5 $2 $-1 $6 forward single F F #
...
1100 0 1 0
24 ACIS Scheme AIDE - 11.0 12 ACIS 11.0 NT 24 Wed Jun 18 14:50:34 2003
1 9.9999999999999995e-007 1e-010
body -1 -1 -1 $-1 $1 $-1 $-1 F #
lump $-1 -1 a $-1 $-1 $2 $0 F #
shell $-1 -1 -1 $-1 $-1 $-1 $3 $-1 $1 F #
face $-1 -1 -1 $-1 $4 $5 $2 $-1 $6 forw single F F #
...
1100 0 1 0
24 ACIS Scheme AIDE - 11.0 12 ACIS 11.0 NT 24 Wed Jun 18 14:50:34 2003
1 9.9999999999999995e-007 1e-010
body -1
ERROR reading pointer: expected token '$' found '-'.
-1 -1 $-1 $1 $-1 $-1 F #
lump $-1 -1 a
ERROR reading number: expected number found 'a'.
$-1 $-1 $2 $0 F #
shell $-1 -1 -1 $-1 $-1 $-1 $3 $-1 $1 F #
face $-1 -1 -1 $-1 $4 $5 $2 $-1 $6 forw
ERROR reading bool: expected 'reversed' or 'forward' found 'forw'.
single F F #
...

The restore logging functionality can be enabled by setting the restore_log logical option to TRUE and disabled by setting the option to FALSE. It is set to FALSE by default. The output log file is by default named "restore.log" and is created in the current working directory, in overwrite mode. Setting the restore_file string option to the desired file name will change the name and location of the output log file.

The following lines demonstrate how the options can be changed in the ACIS Scheme AIDE example application:

(option:set "restore_log" #t)
(option:set "restore_file" "C:/ACISR12/my_restore.log")

A parse error can and often will cause cascading errors in the same entity record. When the restore_log option is enabled, the logic generates default values for missing or erroneous fields, which do not meet the field requirements, in order to allow the process to continue. When the parser encounters a character string where a number is expected, it simply returns the number zero instead of the string. An entity record containing multiple errors will be skipped and the restore logging will continue with the next entity.

Hence, the best strategy to repair the SAT file is to fix the first field error of a given entity and to then repeat the restore. This approach eventually eliminates the cascading errors and allows a successful restore.

Dealing with SAB files is different because these files are in binary form and are therefore not readily editable. When the restore_log option is enabled, the logic generates a one-to-one SAT representation of the SAB data in the log file. This file can then be edited and evaluated with the SAT restore logging capabilities.

Sample Code to Demonstrate How to Save and Restore ACIS Model Data to Media Other Than Stream Files

Applications may want to save and restore ACIS model data to media other than stream files. This can be accomplished by creating custom FileInterface objects to be used with api_save_entity_list_file and api_restore_entity_list_file. The following example shows how to derive a memory-based FileInterface object from BinaryFile, which is defined in binfile.hxx. This is the most straightforward approach because the BinaryFile class implements most of the virtual methods of the FileInterface class in a generic manner, which leaves only a few methods, dealing specifically with input and output, to be implemented.

This section contains snippets of C++ code to illustrate a custom memory-based FileInterface class. These snippets are designed to be very simple starting points for developing your own code; they are not complete, compiling, and runtime programs.

// define a simple memory-based FileInterface class

class MemoryFile : public BinaryFile {
private:
     char * name; // The name of the part.
     char * data; // The pointer to the data.
     size_t size; // The current size of the data block.
     FilePosition position; // Current read/write position.
public:
     MemoryFile( char * in_name = NULL )
          : name(NULL), data(NULL), size(0), position(0) {
          if( in_name != NULL ) // Copy the input name.
               name = ACIS_STRDUP( in_name);
     }
     ~MemoryFile() {
          if( name != NULL )
               ACIS_FREE( name); // Release the memory
          if( data != NULL )
               ACIS_FREE( data );
          name = NULL; data = NULL; size = 0; position = 0;
     }
     size_t read( void *buffer, size_t length, logical swap ) {
          if( size == 0 )
               length = 0; // Nothing to read.
          if( length > size - position ) // Do not read
               length = size - position; // passed the end.
          if( length ) {
               memcpy( buffer, data + position, length );
               position += length; // Update read position.
          }
          return length;
     }
     void write( const void *buffer, size_t length, logical swap ) {
          if( size == 0 ) // Initial call, get some memory.
               data = (char*) ACIS_MALLOC( size = 1024 );
          if( length > size - position )
               data = (char*) // We need more memory.
                    ACIS_SAFE_REALLOC( data, size, size *= 2 );
          if( length ) {
               memcpy( data + position, buffer, length );
               position += length; // Update the write position.
          }
     }
     FilePosition set_mark() { return position; }
     FilePosition goto_mark( FilePosition file_pos ) {
          if( file_pos == -1 || file_pos > size )
               return position = size; // Set to end of data.
          else
               return position = file_pos;
     }
};

[Top]