Branch data Line data Source code
1 : : //-------------------------------------------------------------------------
2 : : // Copyright Notice
3 : : //
4 : : // Copyright (c) 1996
5 : : // by Malcolm J. Panthaki, DBA, and the University of New Mexico.
6 : : //-------------------------------------------------------------------------
7 : :
8 : : //-------------------------------------------------------------------------
9 : : //
10 : : // Filename : RefFace.hpp
11 : : //
12 : : // Purpose : A RefFace is a BasicTopologyEntity. It is a topological
13 : : // entity that represents a bounded surface. A RefFace is a
14 : : // contiguous point set, but can have multiple "holes"
15 : : // within it. It is a topologically 2-D entity.
16 : : //
17 : : // A RefFace can be meshed.
18 : : //
19 : : // Special Notes :
20 : : //
21 : : // Creator : Malcolm J. Panthaki
22 : : //
23 : : // Creation Date : 07/11/96
24 : : //
25 : : // Owner : Malcolm J. Panthaki
26 : : //-------------------------------------------------------------------------
27 : :
28 : : #ifndef REFFACE_HPP
29 : : #define REFFACE_HPP
30 : :
31 : : // ********** BEGIN STANDARD INCLUDES **********
32 : : // ********** END STANDARD INCLUDES **********
33 : :
34 : : // ********** BEGIN MOTIF INCLUDES **********
35 : : // ********** END MOTIF INCLUDES **********
36 : :
37 : : // ********** BEGIN OPEN INVENTOR INCLUDES **********
38 : : // ********** END OPEN INVENTOR INCLUDES **********
39 : :
40 : : // ********** BEGIN CUBIT INCLUDES **********
41 : : #include "CastTo.hpp"
42 : : #include "BasicTopologyEntity.hpp"
43 : : #include "LocalStart.h"
44 : :
45 : :
46 : : // ********** END CUBIT INCLUDES **********
47 : :
48 : : // ********** BEGIN MACROS DEFINITIONS **********
49 : : // ********** END MACROS DEFINITIONS **********
50 : :
51 : : // ********** BEGIN TYPEDEF DEFINITIONS **********
52 : : // ********** END TYPEDEF DEFINITIONS **********
53 : :
54 : : // ********** BEGIN ENUM DECLARATIONS **********
55 : : // ********** END ENUM DECLARATIONS **********
56 : :
57 : : // ********** BEGIN FORWARD DECLARATIONS **********
58 : :
59 : :
60 : : class CoEdge;
61 : : template <class X> class DLIList;
62 : : class RefVertex;
63 : : class CoFace;
64 : : class Loop;
65 : : class CoFace;
66 : : class SurfMeshTool;
67 : : class SurfVertexType;
68 : : class TDUVSpace;
69 : : class Surface;
70 : : class GMem;
71 : :
72 : : // ********** END FORWARD DECLARATIONS **********
73 : :
74 : : class CUBIT_GEOM_EXPORT RefFace : public BasicTopologyEntity
75 : : {
76 : : public :
77 : :
78 : : typedef RefEdge ChildType;
79 : : typedef RefVolume ParentType;
80 : :
81 : : friend class RefEntityFactory;
82 : : //- the factory is allowed to call the (private) constructors
83 : :
84 : : /* constructors/destructors */
85 : :
86 : : virtual ~RefFace() ;
87 : : //- The destructor
88 : :
89 : 1300 : static const char* get_class_name()
90 : : {
91 : 1300 : return "Surface";
92 : : }
93 : :
94 : 1300 : virtual const char* class_name() const
95 : : {
96 : 1300 : return get_class_name();
97 : : }
98 : :
99 : : /* topology */
100 : 381960 : DagType dag_type() const { return DagType::ref_face_type(); }
101 : 4478 : const std::type_info& entity_type_info() const { return typeid(RefFace); }
102 : :
103 : : void get_parent_ref_entities(DLIList<RefEntity*>& entity_list);
104 : :
105 : : CubitStatus get_co_faces( DLIList<CoFace*> &co_faces_found_list,
106 : : RefVolume *input_ref_volume_ptr );
107 : : //R CubitStatus
108 : : //R- CubitSuccess/CubitFailure
109 : : //O co_faces_found_list
110 : : //O-Populates the co_faces_found_list with the CoFaces that are
111 : : //-associated with this RefFace. Because the input RefVolume is sent
112 : : //-in it fills the list just with the CoFaces that are associated with
113 : : //-this RefVolume. Note that usually there will be only one CoFace with
114 : : //-the RefVolume but with HardSurfaces there may be more (2).
115 : :
116 : : CubitStatus ordered_loops( DLIList<Loop*> &loop_list );
117 : : //- Gets the loops in order from outside to inside.
118 : : //- This function is used for all the loop extracting from the refface,
119 : : //- i.e., nodes, ref-edges, ref-vertices. This function orders the
120 : : //- loops based on the angle metric calculation. I believe this metric
121 : : //- is actually currently calculated in OCCGeometryEngine but I see
122 : : //- no reason that it should be done there. I believe it could be
123 : : //- done in the Loop class.
124 : :
125 : : int co_edge_loops ( DLIList<DLIList<CoEdge*> >& co_edge_loops );
126 : : //- Returns a list of lists. Each of the included lists contains a list
127 : : //- of CoEdges and represents an ordered list of CoEdges associated
128 : : //- with each of the Loops of this RefFace.
129 : :
130 : : int ref_edge_loops ( DLIList<DLIList<RefEdge*> >& ref_edge_loops );
131 : : //- Returns a list of lists. Each of the included lists contains a list
132 : : //- of RefEdges and represents an ordered list of RefEdges associated
133 : : //- with each of the Loops of this RefFace.
134 : : //- NOTE: All of the ref_edge_lists in ref_edge_loops will
135 : : //- need to be deleted by the *calling* function.
136 : :
137 : : void ref_vertex_loops( DLIList<DLIList<RefVertex*> >& ref_vert_loop_list );
138 : : //- Returns a list of lists. Each of the included lists contains a list
139 : : //- of RefVertex'es and represents an ordered list of RefVertex'es
140 : : //- associated with each of the Loops of this RefFace.
141 : : //- NOTE: All of the ref_vertex_lists in the ref_vert_loop_list will
142 : : //- need to be deleted by the *calling* function.
143 : :
144 : : int number_of_Loops ();
145 : : //- Returns the number of Loops associated with this RefFace
146 : :
147 : :
148 : : RefVolume* ref_volume();
149 : : //- Return the first RefVolume pointer to the volume which owns
150 : : //- this RefFace
151 : : //- Note: There may be more than one RefVolume that owns this RefFace.
152 : : //- This method just gets the first in the list.
153 : :
154 : : void hard_points( DLIList<RefVertex*>& new_hard_point_list );
155 : : //- Populate the input DLIList<RefVertex*> with the list of hard points
156 : : //- that are defined for this RefFace
157 : :
158 : : int adjoins ( RefFace* input_face_ptr );
159 : : //- Returns CUBIT_TRUE if this RefFace adjoins (is connected via a RefEdge)
160 : : //- the input RefFace
161 : :
162 : : RefVolume* common_ref_volume ( RefFace* input_face_ptr );
163 : : //- Returns a common RefVolume* if this RefFace shares one with the
164 : : //- input RefFace
165 : :
166 : : RefEdge* common_ref_edge ( RefFace* input_face_ptr );
167 : : //- Returns a common RefEdge* if this RefFace shares one with the
168 : : //- input RefFace
169 : :
170 : : int common_ref_edges ( RefFace* input_face_ptr, DLIList<RefEdge*> &common_edge_list );
171 : : //- Returns all common RefEdges that this face shares with the input face
172 : :
173 : : CoFace* get_matching_CoFace(RefVolume* ref_volume_ptr) ;
174 : : //R CoFace*
175 : : //R- Returned CoFace pointer
176 : : //I ref_volume_ptr
177 : : //I- The RefVolume to which matching is done.
178 : : //- This function returns the CoFace that is associated with both "this"
179 : : //- RefFace as well as with the input RefVolume. The function is useful
180 : : //- when a merge operation has resulted in a RefFace that is shared by
181 : : //- more than 1 RefVolume (most often, two). In this case, the RefFace
182 : : //- would be associated with more than one CoFace, each belonging to a
183 : : //- different RefVolume.
184 : : //- If there is no match (i.e., this RefFace is not associated with the
185 : : //- input RefVolume) then a NULL pointer is returned.
186 : :
187 : : int genus();
188 : : //- return genus of this surfaces, which is defined as
189 : : //- g = (L ? L-1 : -(P+1)) where L = # loops, P = # poles
190 : :
191 : : int num_poles();
192 : : //- return the number of singular poles on this surface
193 : :
194 : : /* geometry */
195 : :
196 : : virtual CubitVector center_point();
197 : : //- Return the approximate (spatial) center of this RefFace
198 : :
199 : : CubitSense sense(RefVolume* volume);
200 : : //-Determines the sense of "this" with respect to the passed-in volume.
201 : :
202 : : CubitSense sense(RefFace* face_ptr);
203 : : //-Determine the relative sense of the passed face with respect to
204 : : //-this face using the senses of common RefEdges. i.e. if
205 : : //-CUBIT_REVERSED is returned, than the sense of the passed face
206 : : //-should be the opposite of that of this face with respect to
207 : : //-any volume. CUBIT_UNKNOWN is returned if there are no
208 : : //-common RefEdges between RefFaces or there is more than one
209 : : //-common RefEdge.
210 : :
211 : : CubitSense get_geometry_sense();
212 : : //- Gets the sense of the reface with respect to the underlying
213 : : //- geometry engines representation of the surface.
214 : :
215 : : CubitBoolean about_spatially_equal ( RefFace* ref_face_ptr_2,
216 : : double tolerance_factor = 1.0,
217 : : CubitBoolean notify_refEntity =
218 : : CUBIT_FALSE,
219 : : CubitBoolean test_bbox = CUBIT_TRUE,
220 : : int test_internal = 0 );
221 : :
222 : : //R CubitBoolean
223 : : //R-CUBIT_TRUE/CUBIT_FALSE
224 : : //I RefFace*, double, CubitBoolean
225 : : //I- Second RefFace to compare, Tolerance factor to for GEOMETRY_RESABS,
226 : : //I- and flag for notifying compared RefEntities.
227 : : //O CubitBoolean
228 : : //O- If the two RefFaces are spatially equal within the GEOMETRY_RESABS*
229 : : //- the tolerance_factor, then CUBIT_TRUE will be returned. Otherwise
230 : : //- CUBIT_FALSE is returned.
231 : : //- The comparison is done by first checking the bounding boxes of the
232 : : //- RefFaces. If this test is passed then the ref_edges of each face
233 : : //- are looped through and compared. A bounding box check for each
234 : : //- edge is also done first before a comparison, for speed.
235 : :
236 : : CubitSense compare_alignment( RefFace* second_ref_face_ptr );
237 : : //R CubitSense
238 : : //R- Sense of this reface with respect to the second one passed in.
239 : : //I RefFace *
240 : : //I- pointer to second ref face with which the alignment is compared.
241 : : //- This function will compare the sense of the two ref-faces, or
242 : : //- rather their normals.
243 : : //- NOTE: It is ASSUMED that BOTH reffaces are SPATIALLY EQUAL.
244 : : //- If this is not followed this could explode.
245 : :
246 : :
247 : : CubitVector normal_at(const CubitVector& location, RefVolume* volume=NULL, double* u_guess = NULL, double* v_guess = NULL);
248 : : //- Calculate normal for input location (optional input RefVolume to
249 : : //- allow for feature consolidation).
250 : : //- Note that the input location is modified to the coordinates
251 : : //- of the closest point on the surface.
252 : : //-
253 : : //- MJP NOTE:
254 : : //- In the previous implementation, the result of this function call
255 : : //- would not only be the returned unit vector which is the normal
256 : : //- at the location, but the function would also fill in the myPosition
257 : : //- and myParametricPosition data members of RefFace. These data
258 : : //- members have been removed in this implementation of RefFace.
259 : : //- However, the Surface::normal_at function that gets called returns
260 : : //- an additional parameter which is the location on the underlying
261 : : //- surface that is closest to the input location.
262 : : void reverse_normal();
263 : : //- switch the sense of this face with respect to the underlying
264 : : //- geometry, so that all normals point in the opposite
265 : : //- direction. The orientation of quads on the surface are switched
266 : : //- to agree with this normal.
267 : : virtual void reverse_topology();
268 : :
269 : : //======== Change Code by DZ of Cat, on 10/29/98 8:46:59 AM ========
270 : : CubitBoolean set_outward_normal( RefVolume *volume );
271 : : //- Set the normal of this face to point outward wrt to given volume.
272 : : //- Assumes there is only one coface of the volume for this RefFace.
273 : : //- Uses the above "reverse_normal" function.
274 : : //- return true only if reverse_normal function called.
275 : : //======== Change End by DZ of Cat, on 10/29/98 8:46:59 AM ========
276 : :
277 : : virtual void move_to_surface ( CubitVector& location, double* u_guess = NULL, double* v_guess = NULL);
278 : : //- Moves the given node back onto its surface
279 : :
280 : : virtual CubitStatus move_to_surface( CubitVector& location, CubitVector& along_vec );
281 : : //- Moves the given location onto surface along the specified direction
282 : :
283 : : void find_closest_point_trimmed(CubitVector from_point,
284 : : CubitVector& point_on_surface);
285 : : //R void
286 : : //I CubitVector
287 : : //I- point from which to find closest point on trimmed surface
288 : : //O CubitVector
289 : : //O- point on trimmed surface closest to passed-in point
290 : : //- This function finds the closest point on a TRIMMED surface to the
291 : : //- passed-in point.
292 : :
293 : : void find_closest_points_trimmed(std::vector<CubitVector> &from_points,
294 : : std::vector<CubitVector> &points_on_surface );
295 : :
296 : : CubitPointContainment point_containment( const CubitVector &point );
297 : : CubitPointContainment point_containment( double u, double v );
298 : : // CubitPointContainment point_containment( CubitVector &point, double u, double v );
299 : : //R CubitPointContainment - is the point outside, inside or on the boundary?
300 : : //R- CUBIT_PNT_OUTSIDE, CUBIT_PNT_INSIDE, CUBIT_PNT_BOUNDARY,
301 : : // CUBIT_PNT_UNKNOWN
302 : : //I CubitVector
303 : : //I- position to check, known to be on the Surface
304 : : //I double
305 : : //I- u coordinate, if known (significantly faster, if this is known - however
306 : : // if not known let the function figure it out)
307 : : //I double
308 : : //I- v coordinate, if known (significantly faster, if this is known - however
309 : : // if not known let the function figure it out)
310 : : // NOTE: POINT MUST LIE ON THE SURFACE FOR THIS FUNCTION TO WORK PROPERLY.
311 : :
312 : : CubitStatus get_principal_curvatures( const CubitVector& point,
313 : : double& curvature1,
314 : : double& curvature2,
315 : : RefVolume* ref_volume_ptr = NULL );
316 : : //R CubitStatus
317 : : //R- CUBIT_SUCCESS/FAILURE
318 : : //I point
319 : : //I- Input location. The coordinates of this input point are
320 : : //I- modified to those of the point closest to this one, on the
321 : : //I- surface of this RefFace.
322 : : //O curvature1/curvature2
323 : : //O- Output principal curvature values.
324 : : //I ref_volume_ptr
325 : : //I- Input RefVolume pointer
326 : : //- This function first computes the point on the surface closest to the
327 : : //- input point and sets the values of "point" to this closest
328 : : //- location. Then, the principal curvatures of the surface at this
329 : : //- new point are computed and returned. If the input RefVolume pointer
330 : : //- is not NULL, it is used when computing the curvatures.
331 : :
332 : : //Given a u and v, evaluate position and/or normal and/or curvature
333 : : CubitStatus evaluate( double u, double v,
334 : : CubitVector *position,
335 : : CubitVector *normal,
336 : : CubitVector *curvature1,
337 : : CubitVector *curvature2 );
338 : :
339 : : CubitVector position_from_u_v (double u, double v);
340 : : //- Return a CubitVector (representing a position vector corresponding
341 : : //- to the input point in {u,v} space
342 : :
343 : : CubitStatus u_v_from_position (CubitVector const& location,
344 : : double& u,
345 : : double& v,
346 : : CubitVector* closest_location = NULL );
347 : : //R CubitStatus
348 : : //R- CUBIT_SUCCESS/FAILURE
349 : : //I location
350 : : //I- The input point in global space
351 : : //O u, v
352 : : //O- The returned u, v coordinate values (in local parametric space)
353 : : //O- of the closest_point
354 : : //O closest_location
355 : : //O- The point on the Surface closest to the input location
356 : : //I refvolume_ptr
357 : : //I- The reference RefVolume with respect to which, the normal
358 : : //I- is to be computed. If the pointer is NULL, then the
359 : : //I- first underlying solid model entity is used to compute the
360 : : //I- normal.
361 : : //- This function returns the {u, v} coordinates of the point
362 : : //- on the Surface closest to the input point (specified in global
363 : : //- space). The closest_location is also returned.
364 : :
365 : : CubitBoolean is_parametric();
366 : : //R CubitBoolean
367 : : //R- CUBIT_TRUE/CUBIT_FALSE
368 : : //- This function determines whether the underlying geometry of the
369 : : //- Surface is parametrically defined or not. Returns CUBIT_TRUE if
370 : : //- it is and CUBIT_FALSE if it is not.
371 : :
372 : : CubitBoolean get_param_range_U( double& lower_bound,
373 : : double& upper_bound );
374 : : //R CubitBoolean
375 : : //R- CUBIT_TRUE/CUBIT_FALSE
376 : : //O lower_bound
377 : : //O- The lower bound of the parametric range in the U direction.
378 : : //O- This is set to 0.0 if the surface is not parametric.
379 : : //O upper_bound
380 : : //O- The upper bound of the parametric range in the U direction.
381 : : //O- This is set to 0.0 if the surface is not parametric.
382 : : //- Returns the lower and upper parametric bounds of the
383 : : //- surface in U, if it is parametric. Otherwise, it returns
384 : : //- CUBIT_FALSE and zeroes for the upper and lower parametric
385 : : //- bounds.
386 : :
387 : : CubitBoolean get_param_range_V( double& lower_bound,
388 : : double& upper_bound );
389 : : //R CubitBoolean
390 : : //R- CUBIT_TRUE/CUBIT_FALSE
391 : : //O lower_bound
392 : : //O- The lower bound of the parametric range in the V direction.
393 : : //O- This is set to 0.0 if the surface is not parametric.
394 : : //O upper_bound
395 : : //O- The upper bound of the parametric range in the V direction.
396 : : //O- This is set to 0.0 if the surface is not parametric.
397 : : //- Returns the lower and upper parametric bounds of the
398 : : //- surface in V, if it is parametric. Otherwise, it returns
399 : : //- CUBIT_FALSE and zeroes for the upper and lower parametric
400 : : //- bounds.
401 : :
402 : : CubitBoolean is_periodic();
403 : : //R CubitBoolean
404 : : //R- CUBIT_TRUE/CUBIT_FALSE
405 : : //- This function determines whether the underlying geometry of the
406 : : //- Surface is periodic or not. Returns CUBIT_TRUE if it is and
407 : : //- CUBIT_FALSE if it is not.
408 : :
409 : : CubitBoolean is_periodic_in_U( double& period );
410 : : //R CubitBoolean
411 : : //R- CUBIT_TRUE/CUBIT_FALSE
412 : : //O period
413 : : //O- The value of the period in the U direction.
414 : : //- Determines whether the surface object is
415 : : //- periodic in the U direction or not. If it is, it
416 : : //- returns CUBIT_TRUE and the value of the period. Otherwise,
417 : : //- it returns CUBIT_FALSE and a value of 0.0 or the period.
418 : :
419 : : CubitBoolean is_periodic_in_V( double& period );
420 : : //R CubitBoolean
421 : : //R- CUBIT_TRUE/CUBIT_FALSE
422 : : //O period
423 : : //O- The value of the period in the V direction.
424 : : //- Determines whether the surface object is
425 : : //- periodic in the V direction or not. If it is, it
426 : : //- returns CUBIT_TRUE and the value of the period. Otherwise,
427 : : //- it returns CUBIT_FALSE and a value of 0.0 or the period.
428 : :
429 : : CubitBoolean is_singular_in_U( double u_param );
430 : : CubitBoolean is_singular_in_V( double v_param );
431 : : //R CubitBoolean
432 : : //R- CUBIT_TRUE/CUBIT_FALSE
433 : : //I double u/v parameter value.
434 : : //- Determines if the surface is singular in a given direction
435 : : //- at a given parameter value.
436 : :
437 : : CubitBoolean is_closed_in_U();
438 : : CubitBoolean is_closed_in_V();
439 : : //R CubitBoolean
440 : : //R- CUBIT_TRUE/CUBIT_FALSE
441 : : //- Determines if the surface is closed, smoothly or not in the
442 : : //- given parameter direction.
443 : : //- A periodic surface is always closed but a closed surface is
444 : : //- is not always periodic.
445 : :
446 : : CubitStatus uv_derivitives( double u_param,
447 : : double v_param,
448 : : CubitVector &du,
449 : : CubitVector &dv );
450 : : //R CubitStatus
451 : : //R- CUBIT_SUCCESS/CUBIT_FAILURE
452 : : //O- du, dv
453 : : //- Determines the u and v derivitives from the given parameter
454 : : //- values.
455 : :
456 : : virtual int dimension() const;
457 : : //- Returns the geometric dimension of RefFace entities.
458 : :
459 : : double area();
460 : : //- get the area of the underlying surface
461 : :
462 : : virtual double measure();
463 : : virtual CubitString measure_label();
464 : :
465 : : CubitBoolean is_planar();
466 : : //R CubitBoolean
467 : : //R CUBIT_TRUE/CUBIT_FALSE
468 : : //- This function returns CUBIT_TRUE if the underlying geometry
469 : : //- of the face is planar. CUBIT_FALSE otherwise.
470 : :
471 : : CubitBoolean is_cylindrical();
472 : : //R CubitBoolean
473 : : //R CUBIT_TRUE/CUBIT_FALSE
474 : : //- This function returns CUBIT_TRUE if the underlying geometry
475 : : //- of the face is conical (cylinders are subsets of cones).
476 : : //- CUBIT_FALSE otherwise.
477 : :
478 : : CubitStatus get_point_normal( CubitVector& origin, CubitVector& normal );
479 : : //- Only valid for planar surfaces
480 : : //- Finds the underlying plane's origin and normal (unit) vector
481 : : //- Returns CUBIT_FAILURE if surface is not a plane
482 : :
483 : : virtual int validate();
484 : : //- Check that entity is valid. Returns number of problems detected.
485 : :
486 : : double get_crack_length();
487 : : //- return the length of the periodic crack, or 0.0 if non-periodic.
488 : :
489 : : /* geometry modification */
490 : :
491 : : void add_hard_point( RefVertex* ref_vertex_ptr );
492 : : //- Add a hard point to this RefFace.
493 : : //-***************************************************************
494 : : //- MJP Note:
495 : : //- Currently, the new RefVertex that is created is NOT PART OF THE
496 : : //- main DAG datastructure. The new RefVertex, however, has its
497 : : //- own little mini-DAG which consists of a single DAGNode.
498 : : //- Discuss this with the team before making it a part of the main DAG.
499 : : //- It is, however, deleted appropriately when the RefFace is deleted.
500 : : //-***************************************************************
501 : :
502 : : /* other functions */
503 : :
504 : : Surface* get_surface_ptr() ;
505 : : Surface const* get_surface_ptr() const ;
506 : : //R Surface*
507 : : //R- A pointer to the Surface to which the current
508 : : //R- face points.
509 : : //- This function returns a pointer to the Surface
510 : : //- to which the current face points.
511 : :
512 : : CubitStatus get_graphics( GMem& results,
513 : : unsigned short normal_tolerance = 15,
514 : : double distance_tolerance = 0.0,
515 : : double longest_edge = 0.0 );
516 : :
517 : : CubitStatus get_projected_distance_on_surface( CubitVector *pos1,
518 : : CubitVector *pos2,
519 : : double &distance );
520 : :
521 : : protected :
522 : :
523 : : RefFace(Surface* surfacePtr) ;
524 : : //- The constructor with a pointer to a Surface.
525 : :
526 : : DLIList<RefVertex*> hardPointList;
527 : :
528 : : private:
529 : :
530 : : RefFace( const RefFace& );
531 : : void operator=( const RefFace& );
532 : :
533 : : void initialize ();
534 : : //- initialization method
535 : :
536 : : double maxPositionDeviation;
537 : :
538 : : int hardPointColor;
539 : :
540 : : };
541 : :
542 : : template <> struct DLIListSorter<RefFace*>
543 : : {
544 : : bool operator()(RefFace* a, RefFace* b) { return a->id() < b->id(); }
545 : : };
546 : :
547 : : #endif
548 : :
|