cgma
|
00001 00002 // Filename : BasicTopologyEntity.cpp 00003 // 00004 // Purpose : This file contains the implementation of the class 00005 // BasicTopologyEntity. 00006 // 00007 // Special Notes : 00008 // 00009 // Creator : Malcolm J. Panthaki 00010 // 00011 // Creation Date : 10/15/96 00012 // 00013 // Owner : Malcolm J. Panthaki 00014 //------------------------------------------------------------------------- 00015 00016 // ********** BEGIN STANDARD INCLUDES ********** 00017 // ********** END STANDARD INCLUDES ********** 00018 00019 // ********** BEGIN CUBIT INCLUDES ********** 00020 #include "CubitDefines.h" 00021 #include "SenseEntity.hpp" 00022 #include "BasicTopologyEntity.hpp" 00023 #include "GroupingEntity.hpp" 00024 #include "GeometryEntity.hpp" 00025 #include "DLIList.hpp" 00026 #include "ModelQueryEngine.hpp" 00027 // ********** END CUBIT INCLUDES ********** 00028 00029 // ********** BEGIN STATIC DECLARATIONS ********** 00030 // ********** END STATIC DECLARATIONS ********** 00031 00032 // ********** BEGIN PUBLIC FUNCTIONS ********** 00033 00034 //------------------------------------------------------------------------- 00035 // Purpose : destructor 00036 // 00037 // Special Notes : 00038 // 00039 // Creator : Jason Kraftcheck 00040 // 00041 // Creation Date : 07/22/03 00042 //------------------------------------------------------------------------- 00043 BasicTopologyEntity::~BasicTopologyEntity() 00044 { 00045 while (firstSenseEntity && remove_sense_entity(firstSenseEntity)); 00046 while (firstGroupingEntity && remove_grouping_entity(firstGroupingEntity)); 00047 assert(!firstSenseEntity && !firstGroupingEntity); 00048 } 00049 00050 00051 //------------------------------------------------------------------------- 00052 // Purpose : This function gets the list of GroupingEntities of this 00053 // BasicTopologyEntity. 00054 // 00055 // Special Notes : In the DAG, the GroupingEntities associated with the 00056 // current BasicTopologyEntity are linked from one GroupingEntity 00057 // to the next in order to maintain the order in 00058 // which the GroupingEntities were added to the BTE. 00059 // 00060 // Complete reimplementation - jk, July 2003 00061 // 00062 // Creator : Malcolm J. Panthaki 00063 // 00064 // Creation Date : 07/31/96 00065 //------------------------------------------------------------------------- 00066 CubitStatus BasicTopologyEntity::get_grouping_entity_list( 00067 DLIList<GroupingEntity*>& list) const 00068 { 00069 for (GroupingEntity* ptr = firstGroupingEntity; ptr; ptr = ptr->next()) 00070 { 00071 assert(ptr->get_basic_topology_entity_ptr() == this); 00072 list.append(ptr); 00073 } 00074 00075 return CUBIT_SUCCESS; 00076 } 00077 00078 //------------------------------------------------------------------------- 00079 // Purpose : Get the parent SenseEntities 00080 // 00081 // Special Notes : 00082 // 00083 // Creator : Jason Kraftcheck 00084 // 00085 // Creation Date : 06/08/99 00086 //------------------------------------------------------------------------- 00087 CubitStatus BasicTopologyEntity::get_sense_entity_list( 00088 DLIList<SenseEntity*>& list) const 00089 { 00090 for (SenseEntity* ptr = firstSenseEntity; ptr; ptr = ptr->next_on_bte()) 00091 { 00092 assert(ptr->get_basic_topology_entity_ptr() == this); 00093 list.append(ptr); 00094 } 00095 return CUBIT_SUCCESS; 00096 } 00097 00098 //------------------------------------------------------------------------- 00099 // Purpose : Attach a child grouping entity 00100 // 00101 // Special Notes : 00102 // 00103 // Creator : Jason Kraftcheck 00104 // 00105 // Creation Date : 07/22/03 00106 //------------------------------------------------------------------------- 00107 CubitStatus BasicTopologyEntity::add_grouping_entity( GroupingEntity* gpe_ptr) 00108 { 00109 if (gpe_ptr->dag_type().parent() != dag_type()) 00110 return CUBIT_FAILURE; 00111 00112 if (gpe_ptr->get_basic_topology_entity_ptr()) 00113 return CUBIT_FAILURE; 00114 00115 assert(!gpe_ptr->next()); 00116 00117 if (firstGroupingEntity) 00118 { 00119 if (!gpe_ptr->insert_after(lastGroupingEntity)) 00120 return CUBIT_FAILURE; 00121 } 00122 else 00123 { 00124 firstGroupingEntity = gpe_ptr; 00125 } 00126 00127 lastGroupingEntity = gpe_ptr; 00128 gpe_ptr->set_basic_topology_entity_ptr(this); 00129 return CUBIT_SUCCESS; 00130 } 00131 00132 //------------------------------------------------------------------------- 00133 // Purpose : Disconnect child grouping entity 00134 // 00135 // Special Notes : 00136 // 00137 // Creator : Jason Kraftcheck 00138 // 00139 // Creation Date : 07/22/03 00140 //------------------------------------------------------------------------- 00141 CubitStatus BasicTopologyEntity::remove_grouping_entity( GroupingEntity* gpe_ptr) 00142 { 00143 if (gpe_ptr->get_basic_topology_entity_ptr() != this) 00144 return CUBIT_FAILURE; 00145 00146 GroupingEntity* next_gpe_ptr = gpe_ptr->next(); 00147 GroupingEntity* prev_gpe_ptr = gpe_ptr->previous(); 00148 00149 if (!gpe_ptr->remove_from_list()) 00150 return CUBIT_FAILURE; 00151 00152 if (firstGroupingEntity == gpe_ptr) 00153 firstGroupingEntity = next_gpe_ptr; 00154 if (lastGroupingEntity == gpe_ptr) 00155 lastGroupingEntity = prev_gpe_ptr; 00156 00157 gpe_ptr->set_basic_topology_entity_ptr(0); 00158 return CUBIT_SUCCESS; 00159 } 00160 00161 //------------------------------------------------------------------------- 00162 // Purpose : Update list of child grouping entities 00163 // 00164 // Special Notes : 00165 // 00166 // Creator : Jason Kraftcheck 00167 // 00168 // Creation Date : 12/12/03 00169 //------------------------------------------------------------------------- 00170 CubitStatus BasicTopologyEntity::set_grouping_entity_list( 00171 DLIList<GroupingEntity*>& list, 00172 DLIList<GroupingEntity*>& removed ) 00173 { 00174 int i; 00175 00176 // Remove all? 00177 if (list.size() == 0) 00178 { 00179 get_grouping_entity_list( removed ); 00180 return disconnect_all_children(); 00181 } 00182 00183 // Check for error conditions before modifying anything 00184 list.reset(); 00185 for (i = list.size(); i--; ) 00186 { 00187 GroupingEntity* grouping_entity = list.get_and_step(); 00188 00189 // Check to make sure that we are getting the correct type of 00190 // GroupingEntity. 00191 if ( dag_type() != grouping_entity->dag_type().parent() ) 00192 return CUBIT_FAILURE ; 00193 00194 // Check that the grouping entity is not already in some other 00195 // basic topology entity 00196 if ( grouping_entity->get_basic_topology_entity_ptr() && 00197 grouping_entity->get_basic_topology_entity_ptr() != this ) 00198 return CUBIT_FAILURE; 00199 } 00200 00201 // Special case for first entity in list. 00202 list.reset(); 00203 GroupingEntity* new_first = list.get_and_step(); 00204 // No sense entities currently attached... 00205 if (!firstGroupingEntity) 00206 { 00207 firstGroupingEntity = lastGroupingEntity = new_first; 00208 new_first->set_basic_topology_entity_ptr(this); 00209 } 00210 // Already attached, but not first in list... 00211 else if( firstGroupingEntity != new_first ) 00212 { 00213 if (!new_first->get_basic_topology_entity_ptr()) 00214 new_first->set_basic_topology_entity_ptr(this); 00215 else 00216 { 00217 if (lastGroupingEntity == new_first) 00218 lastGroupingEntity = new_first->previous(); 00219 new_first->remove_from_list(); 00220 } 00221 00222 new_first->insert_before(firstGroupingEntity); 00223 firstGroupingEntity = new_first; 00224 } 00225 00226 // Now loop through remaining sense entities. 00227 GroupingEntity* prev = new_first; 00228 for (i = list.size() - 1; i--; ) 00229 { 00230 GroupingEntity* curr = list.get_and_step(); 00231 00232 // If next grouping entity in input list is not 00233 // next grouping entity in this BTE... 00234 if (prev->next() != curr) 00235 { 00236 if (!curr->get_basic_topology_entity_ptr()) 00237 curr->set_basic_topology_entity_ptr(this); 00238 else 00239 { 00240 if (lastGroupingEntity == curr) 00241 lastGroupingEntity = curr->previous(); 00242 curr->remove_from_list(); 00243 } 00244 curr->insert_after(prev); 00245 } 00246 00247 // update lastSenseEntity if necessary... 00248 if (lastGroupingEntity == prev) 00249 lastGroupingEntity = curr; 00250 00251 // iterate 00252 prev = curr; 00253 } 00254 00255 // Disconnect any grouping entities in this BTE 00256 // that were not in in the input list (they should now 00257 // be at the end of the list of grouping entities in this) 00258 // and pass them back in the 'removed' list. 00259 CubitStatus result = CUBIT_SUCCESS; 00260 while (prev != lastGroupingEntity) 00261 { 00262 removed.append(prev->next()); 00263 if (!remove_grouping_entity(prev->next())) 00264 { 00265 assert(0); 00266 result = CUBIT_FAILURE; 00267 prev = prev->next(); 00268 } 00269 } 00270 00271 return result; 00272 } 00273 00274 00275 00276 00277 //------------------------------------------------------------------------- 00278 // Purpose : Attach a parent sense entity 00279 // 00280 // Special Notes : 00281 // 00282 // Creator : Jason Kraftcheck 00283 // 00284 // Creation Date : 07/22/03 00285 //------------------------------------------------------------------------- 00286 CubitStatus BasicTopologyEntity::add_sense_entity( SenseEntity* se_ptr ) 00287 { 00288 if (se_ptr->dag_type() != dag_type().parent()) 00289 return CUBIT_FAILURE; 00290 00291 if (se_ptr->get_basic_topology_entity_ptr()) 00292 return CUBIT_FAILURE; 00293 00294 assert(!se_ptr->next_on_bte()); 00295 if (firstSenseEntity) 00296 { 00297 assert(!lastSenseEntity->next_on_bte()); 00298 lastSenseEntity->set_bte_next(se_ptr); 00299 } 00300 else 00301 { 00302 firstSenseEntity = se_ptr; 00303 } 00304 00305 lastSenseEntity = se_ptr; 00306 se_ptr->set_basic_topology_entity_ptr(this); 00307 return CUBIT_SUCCESS; 00308 } 00309 00310 //------------------------------------------------------------------------- 00311 // Purpose : Disconnect parent sense entity 00312 // 00313 // Special Notes : 00314 // 00315 // Creator : Jason Kraftcheck 00316 // 00317 // Creation Date : 07/22/03 00318 //------------------------------------------------------------------------- 00319 CubitStatus BasicTopologyEntity::remove_sense_entity( SenseEntity* se_ptr) 00320 { 00321 if (se_ptr->get_basic_topology_entity_ptr() != this) 00322 { assert(0); return CUBIT_FAILURE; } 00323 00324 if (!firstSenseEntity) 00325 return CUBIT_FAILURE; 00326 00327 if (firstSenseEntity == se_ptr) 00328 { 00329 if (lastSenseEntity == se_ptr) 00330 { 00331 firstSenseEntity = lastSenseEntity = 0; 00332 } 00333 else 00334 { 00335 firstSenseEntity = se_ptr->next_on_bte(); 00336 } 00337 } 00338 else 00339 { 00340 SenseEntity* prev = firstSenseEntity; 00341 while (prev->next_on_bte() != se_ptr) 00342 { 00343 prev = prev->next_on_bte(); 00344 if (!prev) 00345 return CUBIT_FAILURE; 00346 } 00347 00348 prev->set_bte_next( se_ptr->next_on_bte() ); 00349 if (lastSenseEntity == se_ptr) 00350 lastSenseEntity = prev; 00351 } 00352 00353 se_ptr->set_bte_next(0); 00354 se_ptr->set_basic_topology_entity_ptr(0); 00355 return CUBIT_SUCCESS; 00356 } 00357 00358 //------------------------------------------------------------------------- 00359 // Purpose : Find connecting sense entity 00360 // 00361 // Special Notes : 00362 // 00363 // Creator : Jason Kraftcheck 00364 // 00365 // Creation Date : 07/22/03 00366 //------------------------------------------------------------------------- 00367 SenseEntity* BasicTopologyEntity::find_sense_entity(GroupingEntity* gpe) const 00368 { 00369 SenseEntity *ptr, *result = 0; 00370 for (ptr = firstSenseEntity; ptr; ptr = ptr->next_on_bte()) 00371 { 00372 if (ptr->get_grouping_entity_ptr() == gpe) 00373 { 00374 if (result) 00375 return 0; 00376 result = ptr; 00377 } 00378 } 00379 00380 return result; 00381 } 00382 SenseEntity* BasicTopologyEntity::find_sense_entity(BasicTopologyEntity* bte) const 00383 { 00384 SenseEntity *ptr, *result = 0; 00385 for (ptr = firstSenseEntity; ptr; ptr = ptr->next_on_bte()) 00386 { 00387 GroupingEntity* gpe = ptr->get_grouping_entity_ptr(); 00388 BasicTopologyEntity* tmp_bte = gpe ? gpe->get_basic_topology_entity_ptr() : 0; 00389 if (tmp_bte == bte) 00390 { 00391 if (result) 00392 return 0; 00393 result = ptr; 00394 } 00395 } 00396 00397 return result; 00398 } 00399 00400 CubitStatus BasicTopologyEntity::get_sense_entities( 00401 DLIList<SenseEntity*>& result, 00402 GroupingEntity* in_this ) 00403 { 00404 int input_size = result.size(); 00405 00406 for (SenseEntity* ptr = firstSenseEntity; ptr; ptr = ptr->next_on_bte()) 00407 if (!in_this || ptr->get_grouping_entity_ptr() == in_this) 00408 result.append(ptr); 00409 00410 return result.size() > input_size ? CUBIT_SUCCESS : CUBIT_FAILURE; 00411 } 00412 00413 CubitStatus BasicTopologyEntity::get_sense_entities( 00414 DLIList<SenseEntity*>& result, 00415 BasicTopologyEntity* in_this ) 00416 { 00417 int input_size = result.size(); 00418 00419 for (SenseEntity* ptr = firstSenseEntity; ptr; ptr = ptr->next_on_bte()) 00420 if (!in_this || ptr->get_parent_basic_topology_entity_ptr() == in_this) 00421 result.append(ptr); 00422 00423 return result.size() > input_size ? CUBIT_SUCCESS : CUBIT_FAILURE; 00424 } 00425 00426 //------------------------------------------------------------------------- 00427 // Purpose : Check if this entity is nonmanifold in the parent 00428 // sense entity. 00429 // 00430 // Special Notes : 00431 // 00432 // Creator : Jason Kraftcheck 00433 // 00434 // Creation Date : 07/22/03 00435 //------------------------------------------------------------------------- 00436 CubitBoolean BasicTopologyEntity::is_nonmanifold(GroupingEntity* gpe) 00437 { 00438 int count = 0; 00439 for (SenseEntity* ptr = firstSenseEntity; ptr; ptr = ptr->next_on_bte()) 00440 if (ptr->get_grouping_entity_ptr() == gpe) 00441 count++; 00442 00443 assert(count); 00444 return count == 1 ? CUBIT_FALSE : CUBIT_TRUE; 00445 } 00446 00447 GeometryType BasicTopologyEntity::geometry_type() const 00448 { 00449 //- returns type of underlying geometry representation 00450 //- (see GeometryEntity.hpp for list of types) 00451 return get_geometry_entity_ptr()->geometry_type(); 00452 } 00453 00454 //------------------------------------------------------------------------- 00455 // Purpose : These functions return the GeometryEntity of this 00456 // BasicTopologyEntity. 00457 // 00458 // Special Notes : 00459 // 00460 // Creator : Malcolm J. Panthaki 00461 // 00462 // Creation Date : 07/31/96 00463 //------------------------------------------------------------------------- 00464 GeometryEntity* BasicTopologyEntity::get_geometry_entity_ptr() const 00465 { 00466 TopologyBridge* bridge = bridge_manager()->topology_bridge(); 00467 return dynamic_cast<GeometryEntity*>(bridge); 00468 } 00469 00470 00471 CubitBox BasicTopologyEntity::bounding_box() 00472 { 00473 return get_geometry_entity_ptr()->bounding_box() ; 00474 } 00475 00476 // Function to get the bounding box of all of the entities in the merge. This 00477 // loop through all of the bridges in the bridge list of a merged entity 00478 // and get an aggregate bounding box for all of them. 00479 CubitBox BasicTopologyEntity::unmerged_bounding_box() 00480 { 00481 if(bridge_manager()->number_of_bridges() == 1) 00482 { 00483 return get_geometry_entity_ptr()->bounding_box() ; 00484 } 00485 else 00486 { 00487 CubitBox aggregate_box; 00488 DLIList<TopologyBridge*> bridges; 00489 bridge_manager()->get_bridge_list(bridges); 00490 GeometryEntity *ge = dynamic_cast<GeometryEntity*>(bridges.get_and_step()); 00491 if(ge) 00492 aggregate_box = ge->bounding_box(); 00493 int i; 00494 for(i=bridges.size(); i>1; i--) 00495 { 00496 ge = dynamic_cast<GeometryEntity*>(bridges.get_and_step()); 00497 if(ge) 00498 aggregate_box |= ge->bounding_box(); 00499 } 00500 return aggregate_box; 00501 } 00502 } 00503 00504 //------------------------------------------------------------------------- 00505 // Purpose : Set the GeometryEntity pointer of this BTE 00506 // 00507 // Special Notes : 00508 // 00509 // Creator : Raikanta Sahu 00510 // 00511 // Creation Date : 10/24/96 00512 //------------------------------------------------------------------------- 00513 CubitStatus BasicTopologyEntity::set_geometry_entity_ptr( 00514 GeometryEntity* GE_ptr) 00515 { 00516 // if (dag_type().dimension() != GE_ptr.dimension()) 00517 // { 00518 // PRINT_ERROR("Internal Error: %s:%d: Mismatched BTE/GeometryEntity.\n", 00519 // __FILE__,__LINE__); 00520 // return CUBIT_FAILURE; 00521 // } 00522 return TopologyEntity::set_topology_bridge(GE_ptr); 00523 } 00524 00525 double BasicTopologyEntity::measure() 00526 { return get_geometry_entity_ptr()->measure(); } 00527 00528 //------------------------------------------------------------------------- 00529 // Purpose : get parent sense entities 00530 // 00531 // Special Notes : 00532 // 00533 // Creator : Jason Kraftcheck 00534 // 00535 // Creation Date : 07/22/03 00536 //------------------------------------------------------------------------- 00537 int BasicTopologyEntity::get_parents( DLIList<TopologyEntity*>* list ) const 00538 { 00539 if (!firstSenseEntity) 00540 return 0; 00541 00542 int count = 0; 00543 SenseEntity* ptr; 00544 00545 for (ptr = firstSenseEntity; ptr; ptr = ptr->next_on_bte()) 00546 { 00547 count++; 00548 if (list) 00549 list->append(ptr); 00550 } 00551 00552 return count; 00553 } 00554 00555 00556 00557 //------------------------------------------------------------------------- 00558 // Purpose : get child grouping entities 00559 // 00560 // Special Notes : 00561 // 00562 // Creator : Jason Kraftcheck 00563 // 00564 // Creation Date : 07/22/03 00565 //------------------------------------------------------------------------- 00566 int BasicTopologyEntity::get_children( DLIList<TopologyEntity*>* list ) const 00567 { 00568 if (!firstGroupingEntity) 00569 return 0; 00570 00571 int count = 0; 00572 GroupingEntity* ptr; 00573 00574 for (ptr = firstGroupingEntity; ptr; ptr = ptr->next()) 00575 { 00576 count++; 00577 if (list) 00578 list->append(ptr); 00579 } 00580 00581 return count; 00582 } 00583 00584 //------------------------------------------------------------------------- 00585 // Purpose : Functions to support ModelQueryEngine 00586 // 00587 // Special Notes : 00588 // 00589 // Creator : Jason Kraftcheck 00590 // 00591 // Creation Date : 07/24/03 00592 //------------------------------------------------------------------------- 00593 CubitBoolean BasicTopologyEntity::query_append_parents( DLIList<TopologyEntity*>& list ) 00594 { 00595 if (!firstSenseEntity) 00596 return CUBIT_FALSE; 00597 00598 00599 CubitBoolean found_some = CUBIT_FALSE; 00600 ModelQueryEngine *const mqe = ModelQueryEngine::instance(); 00601 for (SenseEntity* ptr = firstSenseEntity; ptr; ptr = ptr->next_on_bte()) 00602 if (!mqe->encountered(ptr)) 00603 { 00604 list.append(ptr); 00605 found_some = CUBIT_TRUE; 00606 } 00607 00608 return found_some; 00609 } 00610 CubitBoolean BasicTopologyEntity::query_append_children( DLIList<TopologyEntity*>& list ) 00611 { 00612 if (!firstGroupingEntity) 00613 return 0; 00614 00615 CubitBoolean found_some = CUBIT_FALSE; 00616 ModelQueryEngine *const mqe = ModelQueryEngine::instance(); 00617 GroupingEntity* ptr; 00618 00619 for (ptr = firstGroupingEntity; ptr; ptr = ptr->next()) 00620 { 00621 if (!mqe->encountered(ptr)) 00622 { 00623 found_some = CUBIT_TRUE; 00624 list.append(ptr); 00625 } 00626 } 00627 00628 return found_some; 00629 } 00630 00631 //------------------------------------------------------------------------- 00632 // Purpose : Generic function to remove child grouping entity 00633 // 00634 // Special Notes : 00635 // 00636 // Creator : Jason Kraftcheck 00637 // 00638 // Creation Date : 07/22/03 00639 //------------------------------------------------------------------------- 00640 CubitStatus BasicTopologyEntity::remove_child_link(TopologyEntity* entity_ptr) 00641 { 00642 GroupingEntity* gpe_ptr = dynamic_cast<GroupingEntity*>(entity_ptr); 00643 if (!gpe_ptr) 00644 return CUBIT_FAILURE; 00645 00646 return remove_grouping_entity(gpe_ptr); 00647 } 00648 00649 //------------------------------------------------------------------------- 00650 // Purpose : Remove from parent SenseEntitys 00651 // 00652 // Special Notes : 00653 // 00654 // Creator : Jason Kraftcheck 00655 // 00656 // Creation Date : 07/22/03 00657 //------------------------------------------------------------------------- 00658 CubitStatus BasicTopologyEntity::disconnect_all_parents( DLIList<TopologyEntity*>* list ) 00659 { 00660 while (firstSenseEntity) 00661 { 00662 SenseEntity* se_ptr = firstSenseEntity; 00663 00664 if (!remove_sense_entity(se_ptr)) 00665 return CUBIT_FAILURE; 00666 00667 if (list) 00668 list->append(se_ptr); 00669 } 00670 return CUBIT_SUCCESS; 00671 } 00672 00673 //------------------------------------------------------------------------- 00674 // Purpose : Disconnect child GroupingEntities 00675 // 00676 // Special Notes : 00677 // 00678 // Creator : Jason Kraftcheck 00679 // 00680 // Creation Date : 07/22/03 00681 //------------------------------------------------------------------------- 00682 CubitStatus BasicTopologyEntity::disconnect_all_children( DLIList<TopologyEntity*>* list ) 00683 { 00684 while (firstGroupingEntity) 00685 { 00686 GroupingEntity* gpe_ptr = firstGroupingEntity; 00687 00688 if (!remove_grouping_entity(gpe_ptr)) 00689 return CUBIT_FAILURE; 00690 00691 if (list) 00692 list->append(gpe_ptr); 00693 } 00694 return CUBIT_SUCCESS; 00695 } 00696 00697 00698 00699 // ********** END PUBLIC FUNCTIONS ********** 00700 00701 // ********** BEGIN PROTECTED FUNCTIONS ********** 00702 00703 // ********** END PROTECTED FUNCTIONS ********** 00704 00705 // ********** BEGIN PRIVATE FUNCTIONS ********** 00706 00707 // ********** END PRIVATE FUNCTIONS ********** 00708 00709 // ********** BEGIN HELPER CLASSES ********** 00710 // ********** END HELPER CLASSES ********** 00711 00712 // ********** BEGIN EXTERN FUNCTIONS ********** 00713 // ********** END EXTERN FUNCTIONS ********** 00714 00715 // ********** BEGIN STATIC FUNCTIONS ********** 00716 // ********** END STATIC FUNCTIONS ********** 00717