Home > User Guide > Model Management
SPACOLLECTION
A SPACOLLECTION is a specialized type of entity used to represent a collection of entities. SPACOLLECTION can grow to contain as many entities as needed. Various class methods and APIs are provided to perform operations on a collection such as adding an entity, removing an entity, and iterating the entities within the collection.
A SPACOLLECTION is capable of being notified when one of its members has been modified during a modeling operation (such as copying, merging, and splitting). Various predefined actions are available that allow the SPACOLLECTION designer to choose how the collection behaves for the different types of member notifications. If these predefined actions do not satisfy the application’s need, you may choose to derive from SPACOLLECTION and implement one or more of the notification methods directly.
SPACOLLECTION also provides configurable behaviors that control how the collection is to behave when copied, saved, or emptied.
Finally, note that a SPACOLLECTION can be persisted to SAT/SAB. When saved, a SPACOLLECTION also saves its actions and behavior settings. This ensures that "unknown" collections (those unrecognized by the restoring application) are handled robustly and according to the intent of the designer.
Topics include:
- Controlling Collection Actions
- Controlling Collection Behaviors
- Collection Behavior Use Cases
- Creating a Customized Collection Class
Controlling Collection Actions
An important feature of SPACOLLECTION is the ability to control its behavior as it is notified when its member entities are changed during a modeling operation. SPACOLLECTION provides predefined actions represented by enumeration fields for SPACOLLECTION designers to choose how the collection behaves for the different types of member notifications. If the predefined actions do not satisfy the application need, you may choose to derive from SPACOLLECTION and override one or more of the notification methods directly.
Split Member Notification
If a member entity is split, a new entity is created. After the split, the collection’s split_member method is invoked and controls the collection’s reaction to this split operation. It accepts the pointer to the old entity that is in the collection and the pointer to the created entity from split.
virtual void split_member( ENTITY* old_ent, ENTITY* new_ent );The enumeration field split_member_action provides the predefined actions to be performed when one of collection member entities is split into two entities. When you do not override the split_member method, the collection action is determined by one of the split action types defined in split_member_action.
- SplitMemberAdd
- Both result entities are in the collection after a split. Default split action.
- SplitMemberRemove
- Both result entities are not in the collection after a split.
- SplitMemberLose
- Un-collect the entities in collection and destroy the collection.
- SplitMemberIgnore
- Do nothing.
Merge Member Notification
When two entities are merged into one, one of the entities goes away. Before the merge, the collection is notified by the merge_member method. This method accepts the collection member entity and another entity. These two entities are involved in the merge operation. The method also accepts a logical flag indicating whether the collection member entity is to kept after the merge.
virtual void merge_member( ENTITY* ent, ENTIY* other_ent, logical del_member );The enumeration field merge_member_action provides the predefined actions to be performed when one of the collection member entities merges with other entity. When the merge_member method is not implemented directly, the collection action is determined by one of the action types defined in merge_member_action.
- MergeMemberAdd
- The final merged entity will be in the collection after the merge. Default merge action.
- MergeMemberRemove
- The final merged entity will not be in the collection after the merge.
- MergeMemberLose
- Un-collect the entities in collection and destroy the collection.
- MergeMemberIgnore
- Do nothing. Not recommended.
Note: Using MergeMemberIgnore is not recommended due to an unpredictable outcome.
An example:
Assume an entity E1 belongs to collection C1 and that E1 is planned to merge with another entity, E2. Entity E1 may or may not be the entity that is kept after the merge. If E1 is the "keep" entity, then after the merge, the final merged entity, E1, will be in the collection. On the other hand, if E1 is the "go" entity, then after the merge, E1 will be deleted, and the final merged entity, E2, will not be in the collection. Therefore, you may not know if the final merged entity will or will not be in the collection after the merge.Copy Member Notification
When one of the member entities is copied, a new entity is created as the copy of the original entity. The collection is notified about the copy operation through the copy_member method after the copy. This method takes both the old entity and the new copy as input arguments.
virtual void copy_member( ENTITY *old_ent, ENTITY *new_ent );The enumeration field copy_member_action provides the predefined actions to be performed when one of collection member entities is copied. When the copy_member method is not implemented directly, the collection action is determined by one of the action types defined in copy_member_action.
- CopyMemberKeep
- Keep the original entity in the collection. The copy of the entity is not added to the collection. Default copy action.
- CopyMemberAdd
- Copy of the member entity is added to the collection after the copy. The original member entity remains in the collection.
- CopyMemberRemove
- The original member entity is removed from the collection after the copy.
- CopyMemberSwap
- The original member entity is removed from the collection and the copy of the member entity is added to the collection after the copy.
- CopyMemberLose
- Un-collect the entities in collection and destroy the collection.
- CopyMemberIgnore
- Do nothing. Same as CopyMemberKeep.
Transform Member Notification
Before a collection member entity is to be transformed, the trans_member method is called and notifies the collection about the transform. Both the member entity and the transform are passed to the trans_member method.
virtual void trans_member( ENTITY* ent, const SPAtransf& transf );The enumeration field trans_member_action provides the predefined actions to be performed when one of the collection member entities is transformed. When the trans_member method is not implemented directly, the collection action is determined by one of the action types defined in trans_member_action.
- TransMemberKeep
- The transformed entity will be in the collection. Default trans member action.
- TransMemberRemove
- The transformed entity will be removed from the collection.
- TransMemberLose
- Un-collect the entities in the collection and destroy the collection.
- TransMemberIgnore
- Do nothing. Same as TransMemberKeep.
Replace Member Notification
When an entity is replaced by another entity, the original entity is destroyed after the replacement. Before the replacement takes place, the collection is notified by the replace_member action. The method accepts the two entities to be involved in the replacement and a logical flag indicating whether the collection member entity is the entity that is to be destroyed.
virtual replace_owner( ENTITY* ent, ENTITY * other_ent, logical del_member );The enumeration field replace_member_action provides the predefined actions to be performed when replacement takes place. When the replace_member method is not implemented directly, the collection action is determined by one of the action types defined in replace_member_action.
- ReplaceMemberSwap
- The new entity is to be added to the collection. The original entity is to be removed from the collection. Default replace action.
- ReplaceMemberRemove
- The new entity is not to be added to the collection.
- ReplaceMemberLose
- Un-collect the entities in the collection and destroy the collection.
- ReplaceMemberIgnore
- Do nothing. Not recommended.
Note: Similar to MergeMemberIgnore, using ReplaceMemberIgnore is not recommended due to an unpredictable outcome.Tolerant Member Notification
The tolerant_member notification is similar to replace_member. It is invoked before a collection member entity’s "tolerantness" is changing. In other words, this notification is sent when the member entity is being made tolerant (if it is currently non-tolerant), or being made non-tolerant (if it is currently tolerant). It accepts the old entity and the new entity as input arguments.
virtual tolerant_member (ENTITY *old_ent, ENTITY *new_ent );The enumeration field tolerant_member_action provides the predefined actions to be performed when the member’s "tolerantness" is being changed. When the tolerant_member method is not implemented directly, the collection action is determined by one of the action types defined in tolerant_member_action.
- TolerantMemberSwap
- The new entity will be in the collection after tolerant operation. Default tolerant action.
- TolerantMemberRemove
- The new entity will not be in the collection after tolerant operation.
- TolerantMemberLose
- Un-collect the entities in the collection and destroy the collection.
- TolerantMemberIgnore
- Do nothing. Same as TolerantMemberRemove.
Geometry Changed Member Notification
The geomchanged_member notification is used to notify the collection that one of the member entities is undergoing a geometric modification during a modeling operation (such as, reverse sense bit of a face, and LOP operation) The method accepts the member entity whose geometry is being modified.
virtual geomchanged_member( ENTITY *ent);The enumeration filed of type geomchanged_member_action provides the predefined actions to be performed when geometric modification takes place. When the geomchanged_member method is not implemented directly, the collection action is determined by one of the action types defined in geomchanged_member_action.
- GeomChangedMemberKeep
- The changed member should remain in the collection. Default geomchanged action.
- GeomChangeMemberRemove
- The changed member will be removed from the collection.
- GeomChangedMemberLose
- Un-collect the entities in the collection and destroy the collection.
- GeomChangedMemberIgnore
- Do nothing. Same as GeomChangedMemberKeep.
Add Member & Remove Member Notifications
Two notification methods notify the collection about membership changes. They are add_member and remove_member. add_member is called when an entity is added to the collection. remove_member is called when an entity is removed from the collection. The default action for both methods is to do nothing. You may derive from the collection and override these two methods to perform application specific tasks.
Note: Use caution when utilizing the add_member and remove_member methods. Because the other notifications can be configured to remove and add members, the collection is doubly notified. For example, if you override the split_member notification to add the new member, you will also receive an add_member notification.
Controlling Collection Behaviors
The enumerations collection_copy_behavior, collection_save_behavior, and collection_empty_behavior control the behaviors of a collection when copied, saved, and when the collection becomes empty, respectively.
collection_copy_behavior
- CopyPartial
- When the collection is copied during the full model copy process through SCAN_DEF, COPY_DEF and FIX_POINTER_DEF, it will copy the collection object, but will not force the copy of its members. If one or more of the collection’s members is involved in the copy, though, they will reside in the copy of the collection.
- CopyAll
- When the collection is copied during the full model copy process through SCAN_DEF, COPY_DEF and FIX_POINTER_DEF, the member entities of the collection will be copied also and added to the copy the collection. Default behavior.
collection_save_behavior
- SavePartial
- When the collection is saved to file, only the collection object itself will be saved. The member entities of the collection will not be saved.
- SaveAll
- When the collection is saved to file, the member entities of the collection will be saved along with the collection object. Default behavior.
collection_empty_behavior
- EmptyKeep
- The collection will not be destroyed when made empty. Default empty behavior.
- EmptyRemove
- The collection will be destroyed when made empty.
Collection Behavior Use Cases
When deriving or using SPACOLLECTION directly, choose the appropriate combination of behavior and "able" settings to achieve your application needs. Refer to the following use case for a demonstration of collection behaviors. This example assumes that Collection C contains two entities, E1 and E2. Refer to the following illustration.
Figure. Collection C with two members: E1 and E2
Collection Copy Combinations
When a collection is copied during the full model copy process through SCAN_DEF, COPY_DEF and FIX_POINTER_DEF (for example, api_copy_entity()), the various results are shown in the following table:
Note: C’, E1’, and E2’ represent the copy of C, E1, and E2 respectively. Notice that the collection can be either copied directly (it is passed to the copy API as an argument), or copied indirectly (one of its members is passed to the copy API as an argument).
Direct/Indirect Copy Copy Behavior Is Copyable? Result of Copy Direct api_copy_entity(C) CopyPartial Yes or No Direct api_copy_entity(C) CopyAll Yes Direct api_copy_entity(C) CopyAll No Indirect api_copy_entity(E1) CopyPartial or CopyAll No Indirect api_copy_entity(E1) CopyAll Yes Indirect api_copy_entity(E1) CopyPartial Yes Table. Collection Copy Behavior Combination and Result
Collection Save Combinations
The save behavior use cases are very similar to the copy behavior use cases: the process for saving a collection is similar to creating a copy of the collection in the file. The entities passed explicitly to the saving API are viewed as "top-level" in the SAT/SAB file. Thus, only those entities are restored as top-level entities and the remaining entities are restored but not recognized as top-level entities. Therefore, the top-level entity in the SAT/SAB file when the collection is saved depends on whether the collection is saved directly or indirectly.
The following table illustrates the various results of saving a collection.
Direct/Indirect Save Save Behavior Is Savable? Top-level Entities in File Result of Save Direct api_save_entity_list(C) SavePartial Yes or No C Direct api_save_entity_list(C) SaveAll Yes C Direct api_save_entity_list(C) SaveAll No C Indirect api_save_entity_list(E1) SavePartial or SaveAll No E1 Indirect api_save_entity_list(E1) SaveAll Yes E1 Indirect api_save_entity_list(E1) SavePartial Yes E1 Table. Collection Save Behavior Combination and Result
When calling api_del_entity on a collection, it un-collects the entities within the collection and then destroys the collection. Calling < api_delete_collection_entities destroys the collection and its members simultaneously. If a member entity is destroyed during a modeling operation, it is automatically removed from all collections to which it belongs.
Creating a Customized Collection Class
This section illustrates how to create a customized collection class. The following example collection (BOUNDING_COLLECTION) contains a member data "bounding_box" which is the bounding box for all the entities within the collection. When member entities change during a modeling operation, the bounding box is automatically updated. Thus, you need to override some of the notification callback methods to add some "application-specific" intelligence.
These notification methods include:
- transf_member
- geomchanged_member
- add_member
- remove_member
The merge_member, tolerant_member, and replace_member notifications are configured to remove and add members. Thus, in this example, the notifications do not need to be overridden, otherwise the collection is doubly notified.
To create a header file (bound_coll.hxx) for BOUNDING_COLLECTION, follow these steps:
- Enter the #if !defined . . . #endif preprocessor commands to prevent duplicating the declaration.
- Define the symbol BOUNDING_COLLECTION.
- Declare the global, dynamically assigned integer identifier for this collection class.
- Declare the identification level of this data type to be one level removed from the SPACOLLECTION base class.
- Declare that BOUNDING_COLLECTION is derived from SPACOLLECTION.
- Declare a SPAbox that defines the bounding_box.
- Enter a constructor to create a BOUNDING_COLLECTION
- Call the ENTITY_FUNCTIONS and FULLSIZE_FUNCTION macros to declare the functions required to complete the declaration of an entity.
- Create the member access (get) and setting (set) functions.
- Create utility methods update_box() and print_box().
- Declare the methods for notification methods.
The following example illustrates a typical BOUNDING_COLLECTION header file.
#if !defined(BOUNDING_COLLECTION_CLASS) #define BOUNDING_COLLECTION_CLASS #define BOUNDING_COLLECTION_LEVEL (SPACOLLECTION_LEVEL + 1) ENTITY_IS_PROTOTYPE(BOUNDING_COLLECTION, NONE ) class DECL_NONE BOUNDING_COLLECTION: public SPACOLLECTION { SPAbox bounding_box; void set_default(); public: ENTITY_FUNCTIONS( BOUNDING_COLLECTION, NONE ) FULLSIZE_FUNCTION BOUNDING_COLLECTION(); BOUNDING_COLLECTION( ENTITY * e ); BOUNDING_COLLECTION( ENTITY_LIST& ents ); SPAbox get_bound( ) const; void update_box(); void print_box(); virtual void trans_member( ENTITY *ent, const SPAtransf& transf ); virtual void geomchanged_member( ENTITY *ent ); virtual void add_member( ENTITY *ent ); virtual void remove_member( ENTITY *ent ); }; #endifTo create a BOUNDING_COLLECTION implementation file, follow these steps:
- Define THIS, THIS_LIB, PARENT, and PARENT_LIB macros to make subsequent definitions of this BOUNDING_COLLECTION and its parent easier.
- Define the identifier used externally to identify a particular entity type.
- Call macros used to implement the standard entity methods and data.
- Write any additional functions that were declared in the header file.
The following example illustrates a typical BOUNDING_COLLECTION implementation file.
#define THIS() BOUNDING_COLLECTION #define THIS_LIB NONE #define PARENT() SPACOLLECTION #define PARENT_LIB KERN #define BOUNDING_COLLECTION_NAME "collection_example" ENTITY_DEF( BOUNDING_COLLECTION_NAME ) SAVE_DEF RESTORE_DEF LOSE_DEF DTOR_DEF COPY_WITH_DEEP_COPY_DEF FULLSIZE_DEF SCAN_DEF FIX_POINTER_DEF update_box(); TERMINATE_DEF BOUNDING_COLLECTION::BOUNDING_COLLECTION() { set_default(); } BOUNDING_COLLECTION::BOUNDING_COLLECTION( ENTITY * e ): SPACOLLECTION(e) { set_default(); update_box(); } BOUNDING_COLLECTION::BOUNDING_COLLECTION( ENTITY_LIST& ents ): SPACOLLECTION(ents) { set_default(); update_box(); } void BOUNDING_COLLECTION::fixup_copy( BOUNDING_COLLECTION *rollback ) const { PARENT()::fixup_copy( rollback ); } void BOUNDING_COLLECTION::set_default() { bounding_box = SPAbox( SPAposition(0,0,0), SPAposition(0,0,0) ); } SPAbox BOUNDING_COLLECTION::get_bound( ) const { return bounding_box; } void BOUNDING_COLLECTION::print_box( ) { SPAposition low = bounding_box.low(); SPAposition high = bounding_box.high(); printf( "(position %g %g %g) (position %g %g %g)\n", low.x(), low.y(), low.z(), high.x(),high.y(),high.z() ); } // trans_member notification void BOUNDING_COLLECTION::trans_member( ENTITY *ent, const SPAtransf& transf ) { ENTITY_LIST ents; ENTITY *col_ent = NULL; init(); if( iteration_count() == 0 ) { bounding_box = SPAbox( SPAposition(0,0,0), SPAposition(0,0,0) ); return; } // get a list of live entities excluding the entity that is going to be // transformed from the collection while( (col_ent = next()) != NULL ) { if( col_ent != ent ) ents.add( col_ent ); } SPAposition pt_min, pt_max; // get the box of the entity that is going to be transformed check_outcome( api_get_entity_box( ent, pt_min, pt_max ) ); bounding_box = SPAbox( pt_min, pt_max ); // apply transform to the bounding box bounding_box *= transf; if( ents.iteration_count() > 0 ) { // get the box of rest of the entities check_outcome( api_get_entity_box( ents, pt_min, pt_max ) ); SPAbox ent_box = SPAbox( pt_min, pt_max ); // combine two bounding boxes bounding_box |= ent_box; } } // geomchanged_member notification void BOUNDING_COLLECTION::geomchanged_member( ENTITY * ) { update_box(); } // add_member notification void BOUNDING_COLLECTION::add_member( ENTITY * ) { update_box(); } // remove_member notification void BOUNDING_COLLECTION::remove_member( ENTITY * ) { update_box(); } void BOUNDING_COLLECTION::update_box() { ENTITY_LIST ents; ENTITY *ent = NULL; init(); if( iteration_count() == 0 ) { bounding_box = SPAbox( SPAposition(0,0,0), SPAposition(0,0,0) ); return; } while( (ent = next()) != NULL ) { ents.add( ent ); } SPAposition pt_min, pt_max; check_outcome( api_get_entity_box( ents, pt_min, pt_max ) ); bounding_box = SPAbox( pt_min, pt_max ); }[Top]
© 1989-2007 Spatial Corp., a Dassault Systèmes company. All rights reserved.