cgma
|
00001 //------------------------------------------------------------------------- 00002 // 00003 // Filename : RefEdge.hpp 00004 // 00005 // Purpose : This file contains the declarations of the class 00006 // RefEdge. 00007 // 00008 // Special Notes : 00009 // 00010 // Creator : Xuechen Liu 00011 // 00012 // Creation Date : 07/11/96 00013 // 00014 // Owner : Malcolm J. Panthaki 00015 //------------------------------------------------------------------------- 00016 00017 #ifndef REF_EDGE_HPP 00018 #define REF_EDGE_HPP 00019 00020 #include "BasicTopologyEntity.hpp" 00021 #include "CastTo.hpp" 00022 00023 const double maxSegmentLengthError = 0.005; 00024 00025 class CoEdge; 00026 00027 class CubitVector; 00028 class FacetEvalTool; 00029 class Curve; 00030 00031 class GMem; 00032 00033 // ********** END FORWARD DECLARATIONS ********** 00034 00035 class CUBIT_GEOM_EXPORT RefEdge : public BasicTopologyEntity 00036 { 00037 public : 00038 00039 typedef RefVertex ChildType; 00040 typedef RefFace ParentType; 00041 00042 // ********** BEGIN STATIC FUNCTION DECLARATIONS ********** 00043 // ********** END STATIC FUNCTION DECLARATIONS ********** 00044 00045 friend class RefEntityFactory; 00046 //- the factory is allowed to call the (private) constructors 00047 00048 virtual ~RefEdge() ; 00049 //- The destructor 00050 00051 static const char* get_class_name() 00052 { 00053 return "Curve"; 00054 } 00055 00056 virtual const char* class_name() const 00057 { 00058 return get_class_name(); 00059 } 00060 00061 DagType dag_type() const { return DagType::ref_edge_type(); } 00062 const std::type_info& entity_type_info() const { return typeid(RefEdge); } 00063 00064 void get_parent_ref_entities(DLIList<RefEntity*>& entity_list); 00065 00066 virtual CubitStatus get_point_direction( CubitVector& origin, 00067 CubitVector& direction ); 00068 //- Only valid for straight lines 00069 //- Finds the underlying line's origin and direction unit vector 00070 //- Returns CUBIT_FAILURE if curve is not a line 00071 00072 virtual CubitStatus get_center_radius( CubitVector& center, double& radius ); 00073 //- Only valid for arcs 00074 //- Finds the underlying arc's center point and radius 00075 //- Returns CUBIT_FAILURE if curve is not an arc 00076 00077 // ********* TOPOLOGY ******************** 00078 00079 RefVertex* start_vertex(); 00080 RefVertex* end_vertex(); 00081 //R RefVertex* 00082 //R- Returned RefVertex pointer 00083 //- These functions get the start and end RefVertex'es of this 00084 //- RefEdge. 00085 //- 00086 //- MJP Notes: 00087 //- The start and end RefVertices are cached in the RefEdge (see 00088 //- private member data, start/end_RefVertex). These need to be 00089 //- updated if the end RefVertices could have changed during a 00090 //- geometric operation. See the routine, RefEdge::update to 00091 //- see how this is done. 00092 00093 virtual void reverse_topology(); 00094 00095 Chain* get_chain_ptr(); 00096 //R Chain* 00097 //R- Pointer to the first Chain 00098 //- This function returns a pointer to the first Chain that this 00099 //- RefEdge points to. 00100 00101 CubitStatus get_co_edges( DLIList<CoEdge*> &co_edges_found_list, 00102 RefFace *input_ref_face_ptr = NULL ); 00103 //R CubitStatus 00104 //R-CubitSucces/CubitFailure 00105 //O co_edges_found_list and optional input_ref_face_ptr 00106 //O- Gets the coedges that 00107 //- correspond to "this" RefEdge, they are populated into the 00108 //- co_edges_found_list. If an input_ref_face_ptr is sent it 00109 //- gets the co_edges that are just associated with that ref_face. 00110 //- Remember that usually there will be only one but for hard lines 00111 //- and sipes there may be two co-edges/ref-edge/ref-face. 00112 //- Note: This function will just blindly append the co-edges it 00113 //- finds into the co_edges_found_list. A merge-unique might be 00114 //- more expensive than we want. 00115 00116 double angle_between( RefEdge *other_edge_ptr, RefFace *face_ptr ); 00117 //- Returns the "inside" angle between this edge and 00118 // other_edge_ptr. Figures out which edge comes first. Only 00119 // requirement is that both edges must be on face_ptr and on 00120 // the same loop. Angle is in radians. 00121 00122 CubitSense sense( RefFace *face ); 00123 //- Sense of this edge wrt the given face. 00124 //- Return CUBIT_FORWARD or CUBIT_REVERSED. 00125 //- Returns CUBIT_UNKNOWN if there is more than one coedge, and 00126 //- senses don't agree, or if there are no coedges. 00127 00128 virtual int dimension() const; 00129 //- returns dimension of the actual entity. 00130 00131 int num_of_common_ref_face( RefEdge *other_edge ); 00132 // get the number of common refFace for two refEdges. 00133 00134 RefFace * common_ref_face (RefEdge* otherRefEdgePtr); 00135 // - Find one common RefFace 00136 00137 int common_ref_faces ( RefEdge* otherRefEdgePtr, DLIList<RefFace*> &common_face_list ); 00138 //- Returns all common RefFaces that this edge shares with the input edge 00139 00140 RefVertex* common_ref_vertex( RefEdge* otherRefEdgePtr ); 00141 //- Find common RefVertex 00142 00143 RefVertex* common_ref_vertex( RefEdge* next_ref_edge, 00144 RefFace* ref_face_ptr ); 00145 //- Finds the common vertex between the next_ref_edge and 00146 //- this edge, assuming that this edge comes before next_ref_edge 00147 //- in a the loop around the surface. This is needed because 00148 //- two edges may share two vertices... 00149 00150 CubitBoolean common_vertices( RefEdge* otherRefEdgePtr, 00151 DLIList<RefVertex*> &common_verts); 00152 //-Populates the common_verts with the vertices that are common 00153 //-between the two curves. 00154 //-Returns CUBIT_TRUE if there are common vertices/ false otherwise. 00155 00156 RefEdge* get_other_curve(RefVertex* common_vertex, 00157 RefFace* ref_face_ptr); 00158 //- Finds the other curve on the ref_face_ptr that shares 00159 //- the common vertex 00160 00161 CubitStatus get_two_co_edges( RefEdge *next_ref_edge, 00162 RefFace *ref_face_ptr, 00163 CoEdge *&co_edge_this, 00164 CoEdge *&co_edge_next ); 00165 //R CubitStatus 00166 //R- CUBIT_SUCCESS/CUBIT_FAILURE 00167 //O next_ref_edge, ref_face_ptr, co_edge_this, co_edge_next 00168 //O-Returns the co_edge that corrisponds to 'this' ref_edge 00169 //- and the one that corrisponds to next_ref_edge, with 00170 //- respect to the ref_face_ptr. 00171 //- Special Note : next_ref_edge must follow 'this' ref_edge in a Loop 00172 //- on the ref_face_ptr, this is assumed so the function 00173 //- will assert if this is not done... 00174 00175 RefFace *other_face(RefFace *not_face, RefVolume *ref_volume = NULL); 00176 //- return the (an) other face sharing this edge, which also borders 00177 //- ref_volume if non-NULL 00178 00179 RefVertex* other_vertex( RefVertex* refVertexPtr ); 00180 //- Returns the vertex at the other end of the edge. 00181 00182 RefVertex* closest_vertex(const CubitVector &point3); 00183 00184 // ********* GEOMETRY ******************** 00185 00186 Curve* get_curve_ptr() ; 00187 Curve const* get_curve_ptr() const ; 00188 //R Curve* 00189 //R- A pointer to the Curve to which this RefEdge points. 00190 //- This function returns a pointer to the Curve 00191 //- to which the current RefEdge points. 00192 00193 CubitVector start_coordinates(); 00194 CubitVector end_coordinates(); 00195 //R CubitVector 00196 //R- Returned location. 00197 //- These functions return the start and end global coordinate 00198 //- locations of the RefEdge. 00199 //- 00200 //- NOTE: 00201 //- These coordinates remain consistent throughout the life of the 00202 //- RefEdge, regardless of the fact that the actual start and 00203 //- end RefVerex'es may change (e.g., after a merge operation). 00204 00205 virtual void move_to_curve ( CubitVector& vector ); 00206 //- Moves the given location (CubitVector or CubitNode) to the closest 00207 //- point on the Curve 00208 00209 CubitStatus get_interior_extrema(DLIList<CubitVector*>& interior_points, 00210 CubitSense& return_sense) const; 00211 00212 CubitStatus closest_point_trimmed( CubitVector const& location, 00213 CubitVector& closest_location); 00214 //R void 00215 //I location 00216 //I- The point to which the closest point on the Curve is desired. 00217 //O closest_location 00218 //O- The point on the Curve, closest to the input location which 00219 //O- will be on the Curve. This is input as a reference 00220 //O- so that the function can modify its contents. 00221 00222 00223 CubitStatus closest_point( CubitVector const& location, 00224 CubitVector& closest_location, 00225 CubitVector* tangent_ptr = NULL, 00226 CubitVector* curvature_ptr = NULL); 00227 //R void 00228 //I location 00229 //I- The point to which the closest point on the Curve is desired. 00230 //O closest_location 00231 //O- The point on the Curve, closest to the input location which 00232 //O- might not be on the Curve. This is input as a reference 00233 //O- so that the function can modify its contents. 00234 //O tangent_ptr 00235 //O- The tangent to the Curve (output as a unit vector) at the 00236 //O- closest_location. 00237 //O curvature_ptr 00238 //O- The curvature of the Curve at the closest_location. 00239 //- This function computes the point on the Curve closest to the input 00240 //- location. 00241 //- 00242 //- If the tangent and/or curvature is required, then the calling code 00243 //- is responsible for allocating space for the CubitVector(s) and 00244 //- sending in the relevant non-NULL pointers. If either of these 00245 //- pointers is NULL, the related quantity is not computed. 00246 //- 00247 //- Notes: 00248 //- The tangent direction is always in the positive direction of the 00249 //- *owning RefEdge*, regardless of the positive direction of the 00250 //- underlying solid model entities, if any. 00251 00252 CubitPointContainment point_containment( const CubitVector &point ); 00253 //R CubitPointContainment - is the point on bounds of the curve? 00254 //R- CUBIT_PNT_OFF, CUBIT_PNT_ON, CUBIT_PNT_UNKNOWN 00255 //I CubitVector 00256 //I- position to check, known to be on the Curve 00257 // NOTE: POINT MUST LIE ON THE CURVE FOR THIS FUNCTION TO WORK PROPERLY. 00258 00259 void tangent ( const CubitVector &point, CubitVector& tangent_vec ); 00260 //- Return the tangent for the point on this RefEdge that is closest 00261 //- to the input "point". The tangent direction is always in the 00262 //- positive direction of the RefEdge. The positive direction of 00263 //- the RefEdge is an invariant through its lifecycle. 00264 00265 00266 CubitStatus tangent( const CubitVector &point, 00267 CubitVector& tangent_vec, 00268 RefFace *ref_face_ptr ); 00269 //R CubitStatus 00270 //R- CUBIT_SUCCESS/CUBIT_FAILURE 00271 //O point, tangent_vec, ref_face_ptr 00272 //O- Get the correct tangent with respect to 00273 //- the ref_face_ptr. 00274 //- This tangent function is not the safest method for getting 00275 //- the tangent on a surface. In face if there could be 00276 //- another direction, this function could fail...(assert). 00277 //- This function assumes that there is only 1 co-edge per 00278 //- this ref_face for this REfEdge. 00279 00280 CubitStatus tangent( const CubitVector &point, CubitVector& tangent_vec, 00281 RefEdge *next_ref_edge, RefFace *ref_face_ptr ); 00282 //- Retruns the tangent for the point on this RefEdge that is closest 00283 //- to the input "point". Also, because the next_ref_edge and 00284 //- the ref_face_ptr are given, the tangent is oriented correctly. 00285 //- NOTE: It is assumed that 'this' RefEdge and next_ref_edge are 00286 //- in order in a "Loop" sense on the given ref_face_ptr. The next 00287 //- ref_edge obviously must follow 'this' edge in this loop. 00288 00289 virtual double measure(); 00290 //- A generic geometric extent function. 00291 //- Returns volume for RefVolumes, area for RefFaces, length for RefEdge, 00292 //- and 1.0 for RefVertices 00293 //- A RefGroup calculates the maximum dimension of its contained 00294 //- entities and returns the sum of the measures() of all entities 00295 //- of that dimension. 00296 //- Default return value is 0.0 for all other RefEntities. 00297 00298 virtual CubitString measure_label(); 00299 //- Returns the type of measure: (volume, area, length, or N/A) 00300 00301 double get_arc_length(); 00302 double get_arc_length ( const CubitVector &point1, 00303 const CubitVector &point2 ); 00304 double get_arc_length ( const CubitVector &point1, int whichEnd ); 00305 //- Various arc length calculations, some are redundant 00306 //- the length returned is always positive. 00307 00308 double get_chord_length(); 00309 //- Calculates and returns the straight-line distance 00310 //- between the startRefVertex and the endRefVertex 00311 00312 CubitVector curve_center(); 00313 //- return a guess at the "centroid" of the curve, not the midpoint. 00314 //- For a non-periodic curves, returns the average of vertices 00315 //- For periodic curves, returns the average of the midpoint and the vertex. 00316 00317 virtual CubitVector center_point(); 00318 //- Returns location at the "actual" center of this RefEdge (along the 00319 //- arc of the RefEdge) 00320 00321 CubitStatus mid_point ( const CubitVector &point1, const CubitVector &point2, 00322 CubitVector& midPoint ); 00323 //- Calculate midpoint between the 2 points on this RefEdge 00324 00325 CubitStatus mid_point ( CubitVector &mid_point); 00326 //- Calculate midpoint on this RefEdge 00327 00328 CubitStatus position_from_fraction( double fraction_along_curve, 00329 CubitVector &ouput_position ); 00330 //R CubitStatus 00331 //I fraction in parameter space along refedge. (1/3,2/3,4/5...) 00332 //O- position where percent in parameter space lies. 00333 //-This function takes the given fraction, finds the parameter value, 00334 //-and calculates this position. This is based off the vgi curve. 00335 00336 double start_param(); 00337 //R double 00338 //- this function returns the starting parameter of the underlying curve 00339 00340 double end_param(); 00341 //R double 00342 //- this function returns the ending parameter of the underlying curve 00343 00344 CubitBoolean get_param_range( double& start_param, 00345 double& end_param ); 00346 //R CubitBoolean 00347 //R- CUBIT_TRUE/FALSE 00348 //O start_param, end_param 00349 //O- The "lower" and "upper" parameter values of the RefEdge. 00350 //- This function returns the parameter bounds for the RefEdge. 00351 //- The start_param represents the parameter value of the 00352 //- start location of the RefEdge and the end_param that of the 00353 //- end location. 00354 //- 00355 //- CUBIT_TRUE is returned if the RefEdge is defined parametrically 00356 //- and CUBIT_FALSE if it is not. In the latter case, the 00357 //- output values of start_ and end_param are undetermined. 00358 //- 00359 //- MJP Note: 00360 //- The numercial value of the start_param could be higher 00361 //- than that of the end_param. 00362 00363 double u_from_position (const CubitVector& input_position); 00364 //R double 00365 //R- The returned "u" parameter value in local parametric space 00366 //I input_position 00367 //I- The input position for which "u" is to be computed. 00368 //- This function returns the coordinate of a point in the local 00369 //- parametric (u) space that corresponds to the input position in 00370 //- global (world) space. The input point is first moved to the 00371 //- closest point on the Curve and the parameter value of that 00372 //- point is determined. 00373 00374 CubitStatus position_from_u (double u_value, 00375 CubitVector& output_position); 00376 //R CubitStatus 00377 //R- CUBIT_SUCCESS/FAILURE 00378 //I u_value 00379 //I- The input u parameter value 00380 //O output_position 00381 //O- The output position 00382 //- This function returns the coordinates of a point in the global 00383 //- (world) space that corresponds to the input parametric position 00384 //- in the local space. 00385 //- 00386 //- If the input parameter value is not defined for the Curve, then 00387 //- the input CubitVector is not modified and CUBIT_FAILURE is 00388 //- returned. Otherwise, position is appropriately modified and 00389 //- CUBIT_SUCCESS is returned. 00390 //- 00391 //- If the curve is periodic, the input u_value is first "normalized" 00392 //- to the fundamental period of the Curve before its position 00393 //- in global space is determined. 00394 00395 double u_from_arc_length ( double root_param, 00396 double arc_length ); 00397 //R double 00398 //R- Returned parameter value 00399 //I root_param 00400 //I- The parameter value of the "root point" 00401 //I arc_length 00402 //I- A distance along the Curve 00403 //- This function returns the parameter value of the point that is 00404 //- "arc_length" away from the root point in the 00405 //- positive sense direction of the owning RefEdge. 00406 //- 00407 //- A negative value for distance would force the search to go in the 00408 //- negative (sense) direction of the RefEdge. 00409 //- 00410 //- NOTE: 00411 //- The important assumption that is made in this routine is that 00412 //- the end points of the RefEdge that owns this Curve are the same 00413 //- as the end points of the first solid model entity in the list of 00414 //- solid model entities associated with this Curve. 00415 00416 double fraction_from_arc_length(RefVertex *root_vertex, 00417 double length); 00418 00419 CubitStatus point_from_arc_length ( double root_param, 00420 double arc_length, 00421 CubitVector& new_point ); 00422 //- See below. This allows you to directly specify the starting parameter, 00423 //- instead of it being determined from the root_point. 00424 00425 CubitStatus point_from_arc_length ( const CubitVector& root_point, 00426 double arc_length, 00427 CubitVector& new_point ); 00428 //- Return a point arc_length distance from root_point 00429 //- on this RefEdge. 00430 //- 00431 //- If arc_length is negative, the new point 00432 //- is in the negative sense direction (along the RefEdge) from 00433 //- the root point. 00434 //- 00435 //- If the curve is not periodic and the point arc_length away 00436 //- from root_point in the appropriate direction goes beyond 00437 //- the end point of the RefEdge, that end point is returned 00438 //- as new_point. 00439 //- 00440 //- If the curve is periodic and the point arc_length away 00441 //- from root_point in the appropriate direction goes beyond 00442 //- the end point of the RefEdge, wrap around is done. 00443 //- 00444 //- NOTE: I have had problems with this function if the root point 00445 //- is the start vertex, for some reason by a factor of 1e-7 the 00446 //- parameter value is different between the start_param and the 00447 //- parameter found from the start_vertex location. So I will switch 00448 //- EdgeMeshTool to go off the start parameter instead of this function. 00449 00450 00451 double length_from_u( double parameter1, 00452 double parameter2 ); 00453 //R double arc length 00454 //I double parameter1, parameter value of one end of arc 00455 //I double parameter2, parameter value of the other end of arc 00456 // 00457 // Calculates, the distance along the curve between parameters 00458 // parameter1 and parameter2. 00459 // 00460 // The order of the paramters does affect the result. 00461 // That is, if parameter1 is closer to the start parameter, 00462 // the result is positive. If parameter1 is closer to 00463 // the end parameter, the result is negative. 00464 // 00465 // For periodic curves, the length is calculated along 00466 // the curve in the diretion of increasing parameter value. 00467 // Therefore, if the caller wants the length calculation 00468 // to be in a direction that crosses the periodic break, 00469 // the interval [parameter1, parameter2] should span a 00470 // break point in the period. 00471 00472 00473 CubitBoolean is_periodic(); 00474 //R CubitBoolean 00475 //R- CUBIT_TRUE/CUBIT_FALSE 00476 //- This function determines whether the underlying geometry of the 00477 //- Curve is periodic or not. Returns CUBIT_TRUE if it is and 00478 //- CUBIT_FALSE if it is not. 00479 00480 CubitBoolean is_periodic( double& period); 00481 //R CubitBoolean 00482 //R- CUBIT_TRUE/CUBIT_FALSE 00483 //O period 00484 //O- Returned period value 00485 //- This function determines whether the underlying geometry of the 00486 //- Curve is periodic or not. Returns CUBIT_TRUE if it is and 00487 //- CUBIT_FALSE if it is not. 00488 //- 00489 //- If it is periodic, then it returns the period in the input 00490 //- reference variable, "period". This value is set to 0.0 if 00491 //- the Curve is not periodic. 00492 00493 int get_mark(); 00494 void set_mark( int set_value ); 00495 //- get/set generic 2-bit mark. 00496 00497 CubitStatus relative_sense( RefEdge *ref_edge_ptr_2, 00498 double tolerance_factor, 00499 CubitSense *sense, 00500 CubitBoolean &spatially_equal, 00501 CubitBoolean force_merge = CUBIT_FALSE); 00502 //- calculates the relative sense of two refedges and tries to 00503 //- see if there are two points that are close on each edge (1/3 and 2/3 00504 //- param value). 00505 00506 00507 CubitBoolean about_spatially_equal( RefEdge* ref_edge_ptr_2, 00508 double tolerance_factor = 1.0, 00509 CubitSense* sensePtr = NULL, 00510 CubitBoolean notify_refEntity = 00511 CUBIT_FALSE ); 00512 00513 //R CubitBoolean 00514 //R-CUBIT_TRUE/CUBIT_FALSE 00515 //I RefEdge, double, CubitSense*, CubitBoolean 00516 //I- Second RefEdge to compare, Tolerance factor to for GEOMETRY_RESABS, 00517 //I- and flag for notifying compared RefEntities. 00518 //O CubitSense*, and returned CubitBoolean. 00519 //O- if the two refEdges are spatially equal within the GEOMETRY_RESABS* 00520 //- the tolerance_factor, then CUBIT_TRUE will be returned. Otherwise 00521 //- CUBIT_FALSE is returned. If there is a non-null sesnePtr sent in, 00522 //- the sense pointer value will be assinged the relative sense of the 00523 //- RefEdges, ie, CUBIT_FORWARD/CUBIT_REVERSED. 00524 //- To do the comparison, the end points, 1/3 and 2/3 world 00525 //- points are spatially compared. 00526 00527 virtual int validate(); 00528 //- Check that entity is valid. Returns number of problems detected. 00529 00530 CubitStatus evaluate_exterior_angle(double *exterior_angle); 00531 //- Calculate the exterior angle between this curve and the 00532 //- attached surfaces. This function assumes that the curve is 00533 //- only attached to two (2) surfaces, otherwise it returns CUBIT_FAILURE; 00534 00535 00536 //========= Add Code by SRS of Cat, 3/3/99 2:28:31 PM ========= 00537 CubitBoolean is_tolerant(); 00538 //- Returns CUBIT_TRUE if refedge is a tolerant edge. Tolerant 00539 //- edges can be created in the healer if it is unable to 00540 //- heal the edge. 00541 //========= Code End by SRS of Cat, 3/3/99 2:28:31 PM ========= 00542 00543 CubitStatus get_graphics( GMem& polyline, double angle_tolerance=0, 00544 double distance_tolerance=0, 00545 double max_edge_length=0 ); 00546 00547 void reverse_tangent(); 00548 00549 static void suppress_edge_length_warning(bool flag); 00550 00551 00552 protected: 00553 00554 RefEdge(Curve* curvePtr) ; 00555 //- The constructor with a pointer to a Curve. 00556 00557 private: 00558 void initialize(); 00559 //- Initializes all member data 00560 00561 double get_lower_param_bound(); 00562 double get_upper_param_bound(); 00563 //- Get the parameter values at the start and end locations of 00564 //- the RefEdge. If it is periodic, this is taken into account 00565 //- and the lower and upper bounds of the period are returned. 00566 00567 int refEdgeClone; 00568 00569 cBit markedFlag : 2; //- generic flag, one or two bits? 00570 00571 RefEdge( const RefEdge& ); 00572 void operator=( const RefEdge& ); 00573 static bool mSuppressEdgeLengthWarning; 00574 }; 00575 00576 // ********** BEGIN HELPER CLASSES ********** 00577 // ********** END HELPER CLASSES ********** 00578 00579 // ********** BEGIN INLINE FUNCTIONS ********** 00580 00581 inline int 00582 RefEdge::get_mark() 00583 { return markedFlag; } 00584 00585 inline void 00586 RefEdge::set_mark( int set_value ) 00587 { markedFlag = set_value; } 00588 00589 template <> struct DLIListSorter<RefEdge*> 00590 { 00591 bool operator()(RefEdge* a, RefEdge* b) { return a->id() < b->id(); } 00592 }; 00593 00594 00595 // ********** END INLINE FUNCTIONS ********** 00596 00597 // ********** BEGIN FRIEND FUNCTIONS ********** 00598 // ********** END FRIEND FUNCTIONS ********** 00599 00600 // ********** BEGIN EXTERN FUNCTIONS ********** 00601 // ********** END EXTERN FUNCTIONS ********** 00602 00603 #endif 00604