Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 1991-03-08 |
2 | // Created by: Christophe MARION | |
3 | // Copyright (c) 1991-1999 Matra Datavision | |
973c2be1 | 4 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
aa396061 | 5 | // |
973c2be1 | 6 | // This file is part of Open CASCADE Technology software library. |
b311480e | 7 | // |
d5f74e42 | 8 | // This library is free software; you can redistribute it and/or modify it under |
9 | // the terms of the GNU Lesser General Public License version 2.1 as published | |
973c2be1 | 10 | // by the Free Software Foundation, with special exception defined in the file |
11 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT | |
12 | // distribution for complete text of the license and disclaimer of any warranty. | |
b311480e | 13 | // |
973c2be1 | 14 | // Alternatively, this file may be used under the terms of Open CASCADE |
15 | // commercial license or contractual agreement. | |
b311480e | 16 | |
42cf5bc1 | 17 | #include <Bnd_Box.hxx> |
18 | #include <gp_Dir.hxx> | |
19 | #include <gp_Lin.hxx> | |
20 | #include <gp_Pln.hxx> | |
21 | #include <gp_Pnt.hxx> | |
22 | #include <gp_Trsf.hxx> | |
23 | #include <Standard_ConstructionError.hxx> | |
0904aa63 | 24 | #include <Standard_Dump.hxx> |
7fd59977 | 25 | |
7fd59977 | 26 | // set the flag to one |
7fd59977 | 27 | #define ClearVoidFlag() ( Flags &= ~VoidMask ) |
28 | ||
29 | #include <Standard_Stream.hxx> | |
30 | #include <gp.hxx> | |
31 | // #include <Precision.hxx> | |
32 | #define Bnd_Precision_Infinite 1e+100 | |
33 | ||
34 | //======================================================================= | |
35 | //function : Bnd_Box | |
36 | //purpose : | |
37 | //======================================================================= | |
7fd59977 | 38 | Bnd_Box::Bnd_Box() |
04f0f1b0 | 39 | : Xmin (RealLast()), Xmax (-RealLast()), |
40 | Ymin (RealLast()), Ymax (-RealLast()), | |
41 | Zmin (RealLast()), Zmax (-RealLast()), | |
42 | Gap (0.0) | |
7fd59977 | 43 | { |
44 | SetVoid(); | |
45 | } | |
46 | ||
0904aa63 | 47 | //======================================================================= |
48 | //function : Bnd_Box | |
49 | //purpose : | |
50 | //======================================================================= | |
51 | Bnd_Box::Bnd_Box (const gp_Pnt theMin, const gp_Pnt theMax) | |
52 | : Gap (0.0) | |
53 | { | |
54 | SetVoid(); | |
55 | Update (theMin.X(), theMin.Y(), theMin.Z(), theMax.X(), theMax.Y(), theMax.Z()); | |
56 | } | |
57 | ||
58 | ||
7fd59977 | 59 | //======================================================================= |
60 | //function : Set | |
61 | //purpose : | |
62 | //======================================================================= | |
63 | ||
64 | void Bnd_Box::Set(const gp_Pnt& P) | |
65 | { | |
66 | SetVoid(); | |
67 | Add(P); | |
68 | } | |
69 | ||
70 | //======================================================================= | |
71 | //function : Set | |
72 | //purpose : | |
73 | //======================================================================= | |
74 | ||
75 | void Bnd_Box::Set(const gp_Pnt& P, const gp_Dir& D) | |
76 | { | |
77 | SetVoid(); | |
78 | Add(P,D); | |
79 | } | |
80 | ||
81 | ||
82 | //======================================================================= | |
83 | //function : Update | |
84 | //purpose : | |
85 | //======================================================================= | |
86 | ||
87 | void Bnd_Box::Update (const Standard_Real x, | |
88 | const Standard_Real y, | |
89 | const Standard_Real z, | |
90 | const Standard_Real X, | |
91 | const Standard_Real Y, | |
92 | const Standard_Real Z) | |
93 | { | |
dde68833 | 94 | if (IsVoid()) |
95 | { | |
7fd59977 | 96 | Xmin = x; |
97 | Ymin = y; | |
98 | Zmin = z; | |
99 | Xmax = X; | |
100 | Ymax = Y; | |
101 | Zmax = Z; | |
102 | ClearVoidFlag(); | |
103 | } | |
04f0f1b0 | 104 | else |
105 | { | |
106 | if (x < Xmin) Xmin = x; | |
107 | if (X > Xmax) Xmax = X; | |
108 | if (y < Ymin) Ymin = y; | |
109 | if (Y > Ymax) Ymax = Y; | |
110 | if (z < Zmin) Zmin = z; | |
111 | if (Z > Zmax) Zmax = Z; | |
7fd59977 | 112 | } |
113 | } | |
114 | ||
115 | //======================================================================= | |
116 | //function : Update | |
117 | //purpose : | |
118 | //======================================================================= | |
119 | ||
120 | void Bnd_Box::Update (const Standard_Real X, | |
121 | const Standard_Real Y, | |
122 | const Standard_Real Z) | |
123 | { | |
dde68833 | 124 | if (IsVoid()) |
125 | { | |
7fd59977 | 126 | Xmin = X; |
127 | Ymin = Y; | |
128 | Zmin = Z; | |
129 | Xmax = X; | |
130 | Ymax = Y; | |
131 | Zmax = Z; | |
132 | ClearVoidFlag(); | |
133 | } | |
134 | else { | |
04f0f1b0 | 135 | if (X < Xmin) Xmin = X; |
136 | else if (X > Xmax) Xmax = X; | |
137 | if (Y < Ymin) Ymin = Y; | |
138 | else if (Y > Ymax) Ymax = Y; | |
139 | if (Z < Zmin) Zmin = Z; | |
140 | else if (Z > Zmax) Zmax = Z; | |
7fd59977 | 141 | } |
142 | } | |
143 | ||
144 | //======================================================================= | |
145 | //function : GetGap | |
146 | //purpose : | |
147 | //======================================================================= | |
148 | ||
149 | Standard_Real Bnd_Box::GetGap () const | |
150 | { | |
151 | return Gap; | |
152 | } | |
153 | ||
154 | //======================================================================= | |
155 | //function : SetGap | |
156 | //purpose : | |
157 | //======================================================================= | |
158 | ||
159 | void Bnd_Box::SetGap (const Standard_Real Tol) | |
160 | { | |
161 | Gap = Tol; | |
162 | } | |
163 | ||
164 | //======================================================================= | |
165 | //function : Enlarge | |
166 | //purpose : | |
167 | //======================================================================= | |
168 | ||
169 | void Bnd_Box::Enlarge (const Standard_Real Tol) | |
170 | { | |
171 | Gap=Max(Gap, Abs(Tol)); | |
172 | } | |
173 | ||
174 | //======================================================================= | |
175 | //function : Get | |
176 | //purpose : | |
177 | //======================================================================= | |
178 | ||
ed063270 | 179 | void Bnd_Box::Get (Standard_Real& theXmin, |
180 | Standard_Real& theYmin, | |
181 | Standard_Real& theZmin, | |
182 | Standard_Real& theXmax, | |
183 | Standard_Real& theYmax, | |
184 | Standard_Real& theZmax) const | |
7fd59977 | 185 | { |
dde68833 | 186 | if (IsVoid()) |
ed063270 | 187 | { |
9775fa61 | 188 | throw Standard_ConstructionError("Bnd_Box is void"); |
ed063270 | 189 | } |
190 | ||
dde68833 | 191 | if (IsOpenXmin()) theXmin = -Bnd_Precision_Infinite; |
192 | else theXmin = Xmin - Gap; | |
193 | if (IsOpenXmax()) theXmax = Bnd_Precision_Infinite; | |
194 | else theXmax = Xmax + Gap; | |
195 | if (IsOpenYmin()) theYmin = -Bnd_Precision_Infinite; | |
196 | else theYmin = Ymin - Gap; | |
197 | if (IsOpenYmax()) theYmax = Bnd_Precision_Infinite; | |
198 | else theYmax = Ymax + Gap; | |
199 | if (IsOpenZmin()) theZmin = -Bnd_Precision_Infinite; | |
200 | else theZmin = Zmin - Gap; | |
201 | if (IsOpenZmax()) theZmax = Bnd_Precision_Infinite; | |
202 | else theZmax = Zmax + Gap; | |
ed063270 | 203 | } |
204 | ||
205 | //======================================================================= | |
206 | //function : CornerMin | |
207 | //purpose : | |
208 | //======================================================================= | |
209 | ||
210 | gp_Pnt Bnd_Box::CornerMin() const | |
211 | { | |
212 | gp_Pnt aCornerMin; | |
dde68833 | 213 | if (IsVoid()) |
ed063270 | 214 | { |
9775fa61 | 215 | throw Standard_ConstructionError("Bnd_Box is void"); |
ed063270 | 216 | } |
dde68833 | 217 | if (IsOpenXmin()) aCornerMin.SetX (-Bnd_Precision_Infinite); |
218 | else aCornerMin.SetX (Xmin - Gap); | |
219 | if (IsOpenYmin()) aCornerMin.SetY (-Bnd_Precision_Infinite); | |
220 | else aCornerMin.SetY (Ymin - Gap); | |
221 | if (IsOpenZmin()) aCornerMin.SetZ (-Bnd_Precision_Infinite); | |
222 | else aCornerMin.SetZ (Zmin - Gap); | |
ed063270 | 223 | return aCornerMin; |
224 | } | |
225 | ||
226 | //======================================================================= | |
227 | //function : CornerMax | |
228 | //purpose : | |
229 | //======================================================================= | |
230 | ||
231 | gp_Pnt Bnd_Box::CornerMax() const | |
232 | { | |
233 | gp_Pnt aCornerMax; | |
dde68833 | 234 | if (IsVoid()) |
ed063270 | 235 | { |
9775fa61 | 236 | throw Standard_ConstructionError("Bnd_Box is void"); |
ed063270 | 237 | } |
dde68833 | 238 | if (IsOpenXmax()) aCornerMax.SetX (Bnd_Precision_Infinite); |
239 | else aCornerMax.SetX (Xmax + Gap); | |
240 | if (IsOpenYmin()) aCornerMax.SetY (Bnd_Precision_Infinite); | |
241 | else aCornerMax.SetY (Ymax + Gap); | |
242 | if (IsOpenZmin()) aCornerMax.SetZ (Bnd_Precision_Infinite); | |
243 | else aCornerMax.SetZ (Zmax + Gap); | |
ed063270 | 244 | return aCornerMax; |
7fd59977 | 245 | } |
246 | ||
7fd59977 | 247 | //======================================================================= |
248 | //function : IsXThin | |
249 | //purpose : | |
250 | //======================================================================= | |
251 | ||
252 | Standard_Boolean Bnd_Box::IsXThin (const Standard_Real tol) const | |
253 | { | |
254 | if (IsWhole()) return Standard_False; | |
255 | if (IsVoid()) return Standard_True; | |
dde68833 | 256 | if (IsOpenXmin()) return Standard_False; |
257 | if (IsOpenXmax()) return Standard_False; | |
7fd59977 | 258 | if (Xmax-Xmin < tol) return Standard_True; |
259 | return Standard_False; | |
260 | } | |
261 | ||
262 | //======================================================================= | |
263 | //function : IsYThin | |
264 | //purpose : | |
265 | //======================================================================= | |
266 | ||
267 | Standard_Boolean Bnd_Box::IsYThin (const Standard_Real tol) const | |
268 | { | |
269 | if (IsWhole()) return Standard_False; | |
270 | if (IsVoid()) return Standard_True; | |
dde68833 | 271 | if (IsOpenYmin()) return Standard_False; |
272 | if (IsOpenYmax()) return Standard_False; | |
7fd59977 | 273 | if (Ymax-Ymin < tol) return Standard_True; |
274 | return Standard_False; | |
275 | } | |
276 | ||
277 | //======================================================================= | |
278 | //function : IsZThin | |
279 | //purpose : | |
280 | //======================================================================= | |
281 | ||
282 | Standard_Boolean Bnd_Box::IsZThin (const Standard_Real tol) const | |
283 | { | |
284 | if (IsWhole()) return Standard_False; | |
285 | if (IsVoid()) return Standard_True; | |
dde68833 | 286 | if (IsOpenZmin()) return Standard_False; |
287 | if (IsOpenZmax()) return Standard_False; | |
7fd59977 | 288 | if (Zmax-Zmin < tol) return Standard_True; |
289 | return Standard_False; | |
290 | } | |
291 | ||
292 | //======================================================================= | |
293 | //function : IsThin | |
294 | //purpose : | |
295 | //======================================================================= | |
296 | ||
297 | Standard_Boolean Bnd_Box::IsThin (const Standard_Real tol) const | |
298 | { | |
299 | if (!IsXThin(tol)) return Standard_False; | |
300 | if (!IsYThin(tol)) return Standard_False; | |
301 | if (!IsZThin(tol)) return Standard_False; | |
302 | return Standard_True; | |
303 | } | |
304 | ||
305 | //======================================================================= | |
306 | //function : Transformed | |
307 | //purpose : | |
308 | //======================================================================= | |
309 | ||
310 | Bnd_Box Bnd_Box::Transformed (const gp_Trsf& T) const | |
311 | { | |
04f0f1b0 | 312 | if (IsVoid()) |
313 | { | |
314 | return Bnd_Box(); | |
7fd59977 | 315 | } |
04f0f1b0 | 316 | else if (T.Form() == gp_Identity) |
317 | { | |
318 | return *this; | |
319 | } | |
320 | else if (T.Form() == gp_Translation) | |
321 | { | |
322 | if (!HasFinitePart()) | |
dde68833 | 323 | { |
04f0f1b0 | 324 | return *this; |
7fd59977 | 325 | } |
04f0f1b0 | 326 | |
327 | const gp_XYZ& aDelta = T.TranslationPart(); | |
328 | Bnd_Box aNewBox (*this); | |
329 | aNewBox.Xmin += aDelta.X(); | |
330 | aNewBox.Xmax += aDelta.X(); | |
331 | aNewBox.Ymin += aDelta.Y(); | |
332 | aNewBox.Ymax += aDelta.Y(); | |
333 | aNewBox.Zmin += aDelta.Z(); | |
334 | aNewBox.Zmax += aDelta.Z(); | |
335 | return aNewBox; | |
336 | } | |
337 | ||
338 | Bnd_Box aNewBox; | |
339 | if (HasFinitePart()) | |
340 | { | |
341 | gp_Pnt aCorners[8] = | |
dde68833 | 342 | { |
04f0f1b0 | 343 | gp_Pnt (Xmin, Ymin, Zmin), |
344 | gp_Pnt (Xmax, Ymin, Zmin), | |
345 | gp_Pnt (Xmin, Ymax, Zmin), | |
346 | gp_Pnt (Xmax, Ymax, Zmin), | |
347 | gp_Pnt (Xmin, Ymin, Zmax), | |
348 | gp_Pnt (Xmax, Ymin, Zmax), | |
349 | gp_Pnt (Xmin, Ymax, Zmax), | |
350 | gp_Pnt (Xmax, Ymax, Zmax), | |
351 | }; | |
352 | for (Standard_Integer aCornerIter = 0; aCornerIter < 8; ++aCornerIter) | |
dde68833 | 353 | { |
04f0f1b0 | 354 | aCorners[aCornerIter].Transform (T); |
355 | aNewBox.Add (aCorners[aCornerIter]); | |
7fd59977 | 356 | } |
04f0f1b0 | 357 | } |
358 | aNewBox.Gap = Gap; | |
359 | if (!IsOpen()) | |
360 | { | |
361 | return aNewBox; | |
362 | } | |
7fd59977 | 363 | |
04f0f1b0 | 364 | gp_Dir aDirs[6]; |
365 | Standard_Integer aNbDirs = 0; | |
366 | if (IsOpenXmin()) | |
367 | { | |
368 | aDirs[aNbDirs++].SetCoord(-1., 0., 0.); | |
369 | } | |
370 | if (IsOpenXmax()) | |
371 | { | |
372 | aDirs[aNbDirs++].SetCoord( 1., 0., 0.); | |
373 | } | |
374 | if (IsOpenYmin()) | |
375 | { | |
376 | aDirs[aNbDirs++].SetCoord( 0.,-1., 0.); | |
7fd59977 | 377 | } |
04f0f1b0 | 378 | if (IsOpenYmax()) |
379 | { | |
380 | aDirs[aNbDirs++].SetCoord( 0., 1., 0.); | |
381 | } | |
382 | if (IsOpenZmin()) | |
383 | { | |
384 | aDirs[aNbDirs++].SetCoord( 0., 0.,-1.); | |
385 | } | |
386 | if (IsOpenZmax()) | |
387 | { | |
388 | aDirs[aNbDirs++].SetCoord( 0., 0., 1.); | |
389 | } | |
390 | ||
391 | for (Standard_Integer aDirIter = 0; aDirIter < aNbDirs; ++aDirIter) | |
392 | { | |
393 | aDirs[aDirIter].Transform (T); | |
394 | aNewBox.Add (aDirs[aDirIter]); | |
395 | } | |
396 | ||
397 | return aNewBox; | |
7fd59977 | 398 | } |
399 | ||
400 | //======================================================================= | |
401 | //function : Add | |
402 | //purpose : | |
403 | //======================================================================= | |
404 | ||
405 | void Bnd_Box::Add (const Bnd_Box& Other) | |
406 | { | |
04f0f1b0 | 407 | if (Other.IsVoid()) |
7fd59977 | 408 | { |
04f0f1b0 | 409 | return; |
410 | } | |
411 | else if (IsVoid()) | |
412 | { | |
413 | *this = Other; | |
414 | return; | |
7fd59977 | 415 | } |
04f0f1b0 | 416 | |
417 | if (Xmin > Other.Xmin) Xmin = Other.Xmin; | |
418 | if (Xmax < Other.Xmax) Xmax = Other.Xmax; | |
419 | if (Ymin > Other.Ymin) Ymin = Other.Ymin; | |
420 | if (Ymax < Other.Ymax) Ymax = Other.Ymax; | |
421 | if (Zmin > Other.Zmin) Zmin = Other.Zmin; | |
422 | if (Zmax < Other.Zmax) Zmax = Other.Zmax; | |
423 | Gap = Max (Gap, Other.Gap); | |
424 | ||
425 | if (IsWhole()) | |
426 | { | |
427 | return; | |
428 | } | |
429 | else if (Other.IsWhole()) | |
430 | { | |
431 | SetWhole(); | |
432 | return; | |
433 | } | |
434 | ||
435 | if (Other.IsOpenXmin()) OpenXmin(); | |
436 | if (Other.IsOpenXmax()) OpenXmax(); | |
437 | if (Other.IsOpenYmin()) OpenYmin(); | |
438 | if (Other.IsOpenYmax()) OpenYmax(); | |
439 | if (Other.IsOpenZmin()) OpenZmin(); | |
440 | if (Other.IsOpenZmax()) OpenZmax(); | |
7fd59977 | 441 | } |
442 | ||
443 | //======================================================================= | |
444 | //function : Add | |
445 | //purpose : | |
446 | //======================================================================= | |
447 | ||
448 | void Bnd_Box::Add (const gp_Pnt& P) | |
449 | { | |
450 | Standard_Real X,Y,Z; | |
451 | P.Coord(X,Y,Z); | |
452 | Update(X,Y,Z); | |
453 | } | |
454 | ||
455 | //======================================================================= | |
456 | //function : Add | |
457 | //purpose : | |
458 | //======================================================================= | |
459 | ||
460 | void Bnd_Box::Add (const gp_Pnt& P, const gp_Dir& D) | |
461 | { | |
462 | Add(P); | |
463 | Add(D); | |
464 | } | |
465 | ||
466 | ||
467 | //======================================================================= | |
468 | //function : Add | |
469 | //purpose : | |
470 | //======================================================================= | |
471 | ||
472 | void Bnd_Box::Add (const gp_Dir& D) | |
473 | { | |
474 | Standard_Real DX,DY,DZ; | |
475 | D.Coord(DX,DY,DZ); | |
44d9ae89 A |
476 | |
477 | if (DX < -RealEpsilon()) | |
478 | OpenXmin(); | |
479 | else if (DX > RealEpsilon()) | |
480 | OpenXmax(); | |
481 | ||
482 | if (DY < -RealEpsilon()) | |
483 | OpenYmin(); | |
484 | else if (DY > RealEpsilon()) | |
485 | OpenYmax(); | |
486 | ||
487 | if (DZ < -RealEpsilon()) | |
488 | OpenZmin(); | |
489 | else if (DZ > RealEpsilon()) | |
490 | OpenZmax(); | |
7fd59977 | 491 | } |
492 | ||
493 | //======================================================================= | |
494 | //function : IsOut | |
495 | //purpose : | |
496 | //======================================================================= | |
497 | ||
498 | Standard_Boolean Bnd_Box::IsOut (const gp_Pnt& P) const | |
499 | { | |
500 | if (IsWhole()) return Standard_False; | |
501 | else if (IsVoid()) return Standard_True; | |
502 | else { | |
503 | Standard_Real X,Y,Z; | |
504 | P.Coord(X,Y,Z); | |
dde68833 | 505 | if (!IsOpenXmin() && (X < (Xmin-Gap))) return Standard_True; |
506 | else if (!IsOpenXmax() && (X > (Xmax+Gap))) return Standard_True; | |
507 | else if (!IsOpenYmin() && (Y < (Ymin-Gap))) return Standard_True; | |
508 | else if (!IsOpenYmax() && (Y > (Ymax+Gap))) return Standard_True; | |
509 | else if (!IsOpenZmin() && (Z < (Zmin-Gap))) return Standard_True; | |
510 | else if (!IsOpenZmax() && (Z > (Zmax+Gap))) return Standard_True; | |
7fd59977 | 511 | else return Standard_False; |
512 | } | |
513 | } | |
514 | ||
515 | ||
516 | //======================================================================= | |
517 | //function : IsOut | |
518 | //purpose : | |
519 | //======================================================================= | |
520 | ||
521 | Standard_Boolean Bnd_Box::IsOut (const gp_Pln& P) const | |
522 | { | |
523 | if (IsWhole()) return Standard_False; | |
524 | else if (IsVoid()) return Standard_True; | |
525 | else { | |
526 | Standard_Real A,B,C,D; | |
527 | P.Coefficients (A, B ,C ,D); | |
528 | Standard_Real d = A * (Xmin-Gap) + B * (Ymin-Gap) + C * (Zmin-Gap) + D; | |
529 | // Standard_Boolean plus = d > 0; | |
530 | Standard_Integer plus = d > 0; | |
531 | if (plus != ((A*(Xmin-Gap) + B*(Ymin-Gap) + C*(Zmax+Gap) + D) > 0)) | |
532 | return Standard_False; | |
533 | if (plus != ((A*(Xmin-Gap) + B*(Ymax+Gap) + C*(Zmin-Gap) + D) > 0)) | |
534 | return Standard_False; | |
535 | if (plus != ((A*(Xmin-Gap) + B*(Ymax+Gap) + C*(Zmax+Gap) + D) > 0)) | |
536 | return Standard_False; | |
537 | if (plus != ((A*(Xmax+Gap) + B*(Ymin-Gap) + C*(Zmin-Gap) + D) > 0)) | |
538 | return Standard_False; | |
539 | if (plus != ((A*(Xmax+Gap) + B*(Ymin-Gap) + C*(Zmax+Gap) + D) > 0)) | |
540 | return Standard_False; | |
541 | if (plus != ((A*(Xmax+Gap) + B*(Ymax+Gap) + C*(Zmin-Gap) + D) > 0)) | |
542 | return Standard_False; | |
543 | if (plus != ((A*(Xmax+Gap) + B*(Ymax+Gap) + C*(Zmax+Gap) + D) > 0)) | |
544 | return Standard_False; | |
545 | else return Standard_True; | |
546 | } | |
547 | } | |
548 | ||
549 | //======================================================================= | |
550 | //function : IsOut | |
551 | //purpose : | |
552 | //======================================================================= | |
553 | ||
554 | Standard_Boolean Bnd_Box::IsOut (const gp_Lin& L) const | |
555 | { | |
556 | if (IsWhole()) return Standard_False; | |
557 | else if (IsVoid()) return Standard_True; | |
558 | else { | |
559 | Standard_Real xmin = 0, xmax = 0, ymin = 0, ymax = 0, zmin, zmax; | |
560 | Standard_Real parmin, parmax, par1, par2; | |
561 | Standard_Boolean xToSet, yToSet; | |
562 | Standard_Real myXmin, myYmin, myZmin, myXmax, myYmax, myZmax; | |
563 | Get (myXmin, myYmin, myZmin, myXmax, myYmax, myZmax); | |
564 | ||
565 | if (Abs(L.Direction().XYZ().X())>0.) { | |
566 | par1=(myXmin-L.Location().XYZ().X())/L.Direction().XYZ().X(); | |
567 | par2=(myXmax-L.Location().XYZ().X())/L.Direction().XYZ().X(); | |
568 | parmin=Min(par1, par2); | |
569 | parmax=Max(par1, par2); | |
570 | xToSet=Standard_True; | |
571 | } | |
572 | else { | |
573 | if (L.Location().XYZ().X()<myXmin || myXmax<L.Location().XYZ().X()) { | |
574 | return Standard_True; | |
575 | } | |
576 | xmin=L.Location().XYZ().X(); | |
577 | xmax=L.Location().XYZ().X(); | |
578 | parmin=-Bnd_Precision_Infinite; | |
579 | parmax=Bnd_Precision_Infinite; | |
580 | xToSet=Standard_False; | |
581 | } | |
582 | ||
583 | if (Abs(L.Direction().XYZ().Y())>0.) { | |
584 | par1=(myYmin-L.Location().XYZ().Y())/L.Direction().XYZ().Y(); | |
585 | par2=(myYmax-L.Location().XYZ().Y())/L.Direction().XYZ().Y(); | |
586 | //=================DET change 06/03/01==================== | |
587 | if(parmax < Min(par1,par2) || parmin > Max(par1,par2)) | |
588 | return Standard_True; | |
589 | //======================================================== | |
590 | parmin=Max(parmin, Min(par1,par2)); | |
591 | parmax=Min(parmax, Max(par1,par2)); | |
592 | yToSet=Standard_True; | |
593 | } | |
594 | else { | |
595 | if (L.Location().XYZ().Y()<myYmin || myYmax<L.Location().XYZ().Y()) { | |
596 | return Standard_True; | |
597 | } | |
598 | ymin=L.Location().XYZ().Y(); | |
599 | ymax=L.Location().XYZ().Y(); | |
600 | yToSet=Standard_False; | |
601 | } | |
602 | ||
603 | if (Abs(L.Direction().XYZ().Z())>0.) { | |
604 | par1=(myZmin-L.Location().XYZ().Z())/L.Direction().XYZ().Z(); | |
605 | par2=(myZmax-L.Location().XYZ().Z())/L.Direction().XYZ().Z(); | |
606 | //=================DET change 06/03/01==================== | |
607 | if(parmax < Min(par1,par2) || parmin > Max(par1,par2)) | |
608 | return Standard_True; | |
609 | //======================================================== | |
610 | parmin=Max(parmin, Min(par1,par2)); | |
611 | parmax=Min(parmax, Max(par1,par2)); | |
612 | par1=L.Location().XYZ().Z()+parmin*L.Direction().XYZ().Z(); | |
613 | par2=L.Location().XYZ().Z()+parmax*L.Direction().XYZ().Z(); | |
614 | zmin=Min(par1, par2); | |
615 | zmax=Max(par1, par2); | |
616 | } | |
617 | else { | |
618 | if (L.Location().XYZ().Z()<myZmin || myZmax<L.Location().XYZ().Z()) | |
619 | return Standard_True; | |
620 | zmin=L.Location().XYZ().Z(); | |
621 | zmax=L.Location().XYZ().Z(); | |
622 | } | |
623 | if (zmax<myZmin || myZmax<zmin) return Standard_True; | |
624 | ||
625 | if (xToSet) { | |
626 | par1=L.Location().XYZ().X()+parmin*L.Direction().XYZ().X(); | |
627 | par2=L.Location().XYZ().X()+parmax*L.Direction().XYZ().X(); | |
628 | xmin=Min(par1, par2); | |
629 | xmax=Max(par1, par2); | |
630 | } | |
631 | if (xmax<myXmin || myXmax<xmin) return Standard_True; | |
632 | ||
633 | if (yToSet) { | |
634 | par1=L.Location().XYZ().Y()+parmin*L.Direction().XYZ().Y(); | |
635 | par2=L.Location().XYZ().Y()+parmax*L.Direction().XYZ().Y(); | |
636 | ymin=Min(par1, par2); | |
637 | ymax=Max(par1, par2); | |
638 | } | |
639 | if (ymax<myYmin || myYmax<ymin) return Standard_True; | |
640 | } | |
641 | return Standard_False; | |
642 | } | |
643 | ||
644 | //======================================================================= | |
645 | //function : IsOut | |
646 | //purpose : | |
647 | //======================================================================= | |
648 | ||
649 | Standard_Boolean Bnd_Box::IsOut (const Bnd_Box& Other) const | |
aa396061 P |
650 | { |
651 | //modified by NIZNHY-PKV Fri Jul 08 11:03:43 2011f | |
652 | if (!Flags && !Other.Flags) { | |
653 | Standard_Boolean bRet; | |
654 | Standard_Real delta; | |
655 | // | |
656 | delta = Other.Gap + Gap; | |
657 | bRet=((Xmin - Other.Xmax > delta) || | |
658 | (Other.Xmin - Xmax > delta) || | |
659 | (Ymin - Other.Ymax > delta) || | |
660 | (Other.Ymin - Ymax > delta) || | |
661 | (Zmin - Other.Zmax > delta) || | |
662 | (Other.Zmin - Zmax > delta)); | |
663 | return bRet; | |
664 | } | |
665 | //modified by NIZNHY-PKV Fri Jul 08 11:03:46 2011t | |
7fd59977 | 666 | if (IsVoid()) return Standard_True; |
667 | if (Other.IsVoid()) return Standard_True; | |
668 | if (IsWhole()) return Standard_False; | |
669 | if (Other.IsWhole()) return Standard_False; | |
670 | ||
671 | Standard_Real delta = Other.Gap + Gap; | |
672 | ||
dde68833 | 673 | if (!IsOpenXmin() && !Other.IsOpenXmax()) |
7fd59977 | 674 | if (Xmin - Other.Xmax > delta) return Standard_True; |
dde68833 | 675 | if (!IsOpenXmax() && !Other.IsOpenXmin()) |
7fd59977 | 676 | if (Other.Xmin - Xmax > delta) return Standard_True; |
677 | ||
dde68833 | 678 | if (!IsOpenYmin() && !Other.IsOpenYmax()) |
7fd59977 | 679 | if (Ymin - Other.Ymax > delta) return Standard_True; |
dde68833 | 680 | if (!IsOpenYmax() && !Other.IsOpenYmin()) |
7fd59977 | 681 | if (Other.Ymin - Ymax > delta) return Standard_True; |
682 | ||
dde68833 | 683 | if (!IsOpenZmin() && !Other.IsOpenZmax()) |
7fd59977 | 684 | if (Zmin - Other.Zmax > delta) return Standard_True; |
dde68833 | 685 | if (!IsOpenZmax() && !Other.IsOpenZmin()) |
7fd59977 | 686 | if (Other.Zmin - Zmax > delta) return Standard_True; |
687 | ||
688 | return Standard_False; | |
689 | } | |
690 | ||
691 | //======================================================================= | |
692 | //function : IsOut | |
693 | //purpose : | |
694 | //======================================================================= | |
695 | ||
696 | Standard_Boolean Bnd_Box::IsOut (const Bnd_Box& Other, | |
697 | const gp_Trsf& T) const | |
698 | { | |
699 | return IsOut(Other.Transformed(T)); | |
700 | } | |
701 | ||
702 | //======================================================================= | |
703 | //function : IsOut | |
704 | //purpose : | |
705 | //======================================================================= | |
706 | ||
707 | Standard_Boolean Bnd_Box::IsOut (const gp_Trsf& T1, | |
708 | const Bnd_Box& Other, | |
709 | const gp_Trsf& T2) const | |
710 | { | |
711 | return Transformed(T1).IsOut(Other.Transformed(T2)); | |
712 | } | |
713 | ||
714 | ||
715 | //======================================================================= | |
0ebaa4db | 716 | //function : IsSegmentOut |
7fd59977 | 717 | //purpose : |
718 | //======================================================================= | |
719 | ||
720 | static Standard_Boolean IsSegmentOut(Standard_Real x1,Standard_Real y1, | |
721 | Standard_Real x2,Standard_Real y2, | |
722 | Standard_Real xs1,Standard_Real ys1, | |
723 | Standard_Real xs2,Standard_Real ys2) | |
724 | { | |
725 | Standard_Real eps = RealSmall(); | |
726 | Standard_Real xsmin = Min (xs1, xs2); | |
727 | Standard_Real xsmax = Max (xs1, xs2); | |
728 | Standard_Real ysmin = Min (ys1, ys2); | |
729 | Standard_Real ysmax = Max (ys1, ys2); | |
730 | ||
731 | if (ysmax-ysmin < eps && (y1-ys1 < eps && ys1-y2 < eps) && | |
0ebaa4db | 732 | ((xsmin-x1 < eps && x1-xsmax < eps) || |
733 | (xsmin-x2 < eps && x2-xsmax < eps) || | |
734 | (x1-xs1 < eps && xs1-x2 < eps))) | |
7fd59977 | 735 | return Standard_False; |
736 | if (xsmax-xsmin < eps && (x1-xs1 < eps && xs1-x2 < eps) && | |
0ebaa4db | 737 | ((ysmin-y1 < eps && y1-ysmax < eps) || |
738 | (ysmin-y2 < eps && y2-ysmax < eps) || | |
739 | (y1-ys1 < eps && ys1-y2 < eps))) | |
7fd59977 | 740 | return Standard_False; |
741 | ||
742 | if ((xs1 < x1 && xs2 < x1) || (xs1 > x2 && xs2 > x2) || | |
743 | (ys1 < y1 && ys2 < y1) || (ys1 > y2 && ys2 > y2) ) | |
744 | return Standard_True; | |
745 | ||
746 | if (Abs(xs2-xs1) > eps) | |
747 | { | |
748 | Standard_Real ya = ( Min(x1, x2) - xs1 ) * ( ys2 - ys1 ) / ( xs2 - xs1 ) + ys1; | |
749 | Standard_Real yb = ( Max(x1, x2) - xs1 ) * ( ys2 - ys1 ) / ( xs2 - xs1 ) + ys1; | |
750 | if ( (ya < y1 && yb < y1) || (ya > y2 && yb > y2) ) return Standard_True; | |
751 | } | |
752 | else if (Abs(ys2-ys1) > eps) | |
753 | { | |
754 | Standard_Real xa = ( Min(y1, y2) - ys1 ) * ( xs2 - xs1 ) / ( ys2 - ys1 ) + xs1; | |
755 | Standard_Real xb = ( Max(y1, y2) - ys1 ) * ( xs2 - xs1 ) / ( ys2 - ys1 ) + xs1; | |
756 | if ( (xa < x1 && xb < x1) || (xa > x2 && xb > x2) ) return Standard_True; | |
757 | } | |
758 | else | |
759 | return Standard_True; | |
760 | ||
761 | return Standard_False; | |
762 | } | |
763 | ||
764 | Standard_Boolean Bnd_Box::IsOut(const gp_Pnt& P1, const gp_Pnt& P2, const gp_Dir& D) const | |
765 | { | |
766 | ||
767 | if (IsWhole()) return Standard_False; | |
768 | else if (IsVoid()) return Standard_True; | |
769 | ||
770 | Standard_Real eps = RealSmall(); | |
771 | Standard_Real myXmin, myYmin, myZmin, myXmax, myYmax, myZmax; | |
772 | Get (myXmin, myYmin, myZmin, myXmax, myYmax, myZmax); | |
773 | ||
774 | if(Abs(D.X()) < eps && Abs(D.Y()) < eps) | |
775 | return IsSegmentOut(myXmin, myYmin, myXmax, myYmax, P1.X(), P1.Y(), P2.X(), P2.Y()); | |
776 | ||
777 | if(Abs(D.X()) < eps && Abs(D.Z()) < eps) | |
778 | return IsSegmentOut(myXmin, myZmin, myXmax, myZmax, P1.X(), P1.Z(), P2.X(), P2.Z()); | |
779 | ||
780 | if(Abs(D.Y()) < eps && Abs(D.Z()) < eps) | |
781 | return IsSegmentOut(myYmin, myZmin, myYmax, myZmax, P1.Y(), P1.Z(), P2.Y(), P2.Z()); | |
782 | ||
783 | if(Abs(D.X()) < eps) | |
784 | { | |
785 | if(!IsSegmentOut(myXmin, myZmin, myXmax, myZmax, | |
786 | P1.X(),(myYmin-P1.Y())*D.Z()/D.Y()+P1.Z(), | |
787 | P2.X(),(myYmin-P2.Y())*D.Z()/D.Y()+P2.Z())) | |
788 | return Standard_False; | |
789 | ||
790 | if(!IsSegmentOut(myXmin, myZmin, myXmax, myZmax, | |
791 | P1.X(),(myYmax-P1.Y())*D.Z()/D.Y()+P1.Z(), | |
792 | P2.X(),(myYmax-P2.Y())*D.Z()/D.Y()+P2.Z())) | |
793 | return Standard_False; | |
794 | ||
795 | if(!IsSegmentOut(myXmin, myYmin, myXmax, myYmax, | |
796 | P1.X(),(myZmin-P1.Z())*D.Y()/D.Z()+P1.Y(), | |
797 | P2.X(),(myZmin-P2.Z())*D.Y()/D.Z()+P2.Y())) | |
798 | return Standard_False; | |
799 | ||
800 | if(!IsSegmentOut(myXmin, myYmin, myXmax, myYmax, | |
801 | P1.X(),(myZmax-P1.Z())*D.Y()/D.Z()+P1.Y(), | |
802 | P2.X(),(myZmax-P2.Z())*D.Y()/D.Z()+P2.Y())) | |
803 | return Standard_False; | |
804 | ||
805 | return Standard_True; | |
806 | }//if(D.X() == 0) | |
807 | ||
808 | if(Abs(D.Y()) < eps) | |
809 | { | |
810 | if(!IsSegmentOut(myYmin, myZmin, myYmax, myZmax, | |
811 | P1.Y(),(myXmin-P1.X())*D.Z()/D.X()+P1.Z(), | |
812 | P2.Y(),(myXmin-P2.X())*D.Z()/D.X()+P2.Z())) | |
813 | return Standard_False; | |
814 | ||
815 | if(!IsSegmentOut(myYmin, myZmin, myYmax, myZmax, | |
816 | P1.Y(),(myXmax-P1.X())*D.Z()/D.X()+P1.Z(), | |
817 | P2.Y(),(myXmax-P2.X())*D.Z()/D.X()+P2.Z())) | |
818 | return Standard_False; | |
819 | ||
820 | if(!IsSegmentOut(myYmin, myXmin, myYmax, myXmax, | |
821 | P1.Y(),(myZmin-P1.Z())*D.X()/D.Z()+P1.X(), | |
822 | P2.Y(),(myZmin-P2.Z())*D.X()/D.Z()+P2.X())) | |
823 | return Standard_False; | |
824 | ||
825 | if(!IsSegmentOut(myYmin, myXmin, myYmax, myXmax, | |
826 | P1.Y(),(myZmax-P1.Z())*D.X()/D.Z()+P1.X(), | |
827 | P2.Y(),(myZmax-P2.Z())*D.X()/D.Z()+P2.X())) | |
828 | return Standard_False; | |
829 | ||
830 | return Standard_True; | |
831 | }//if(D.Y() == 0) | |
832 | ||
833 | if(Abs(D.Z()) < eps) | |
834 | { | |
835 | if(!IsSegmentOut(myZmin, myXmin, myZmax, myXmax, | |
836 | P1.Z(),(myYmax-P1.Y())*D.X()/D.Y()+P1.X(), | |
837 | P2.Z(),(myYmax-P2.Y())*D.X()/D.Y()+P2.X())) | |
838 | return Standard_False; | |
839 | ||
840 | if(!IsSegmentOut(myZmin, myXmin, myZmax, myXmax, | |
841 | P1.Z(),(myYmin-P1.Y())*D.X()/D.Y()+P1.X(), | |
842 | P2.Z(),(myYmin-P2.Y())*D.X()/D.Y()+P2.X())) | |
843 | return Standard_False; | |
844 | ||
845 | if(!IsSegmentOut(myZmin, myYmin, myZmax, myYmax, | |
846 | P1.Z(),(myXmax-P1.X())*D.Y()/D.X()+P1.Y(), | |
847 | P2.Z(),(myXmax-P2.X())*D.Y()/D.X()+P2.Y())) | |
848 | return Standard_False; | |
849 | ||
850 | if(!IsSegmentOut(myZmin, myYmin, myZmax, myYmax, | |
851 | P1.Z(),(myXmin-P1.X())*D.Y()/D.X()+P1.Y(), | |
852 | P2.Z(),(myXmin-P2.X())*D.Y()/D.X()+P2.Y())) | |
853 | return Standard_False; | |
854 | ||
855 | return Standard_True; | |
856 | }//if(D.Z() == 0) | |
857 | ||
858 | if(!IsSegmentOut(myXmin,myZmin,myXmax,myZmax, | |
859 | (myYmin - P1.Y())/D.Y()*D.X() + P1.X(), | |
860 | (myYmin - P1.Y())/D.Y()*D.Z() + P1.Z(), | |
861 | (myYmin - P2.Y())/D.Y()*D.X() + P2.X(), | |
862 | (myYmin - P2.Y())/D.Y()*D.Z() + P2.Z())) | |
863 | return Standard_False; | |
864 | ||
865 | if(!IsSegmentOut(myXmin,myZmin,myXmax,myZmax, | |
866 | (myYmax - P1.Y())/D.Y()*D.X() + P1.X(), | |
867 | (myYmax - P1.Y())/D.Y()*D.Z() + P1.Z(), | |
868 | (myYmax - P2.Y())/D.Y()*D.X() + P2.X(), | |
869 | (myYmax - P2.Y())/D.Y()*D.Z() + P2.Z())) | |
870 | return Standard_False; | |
871 | ||
872 | if(!IsSegmentOut(myXmin,myYmin,myXmax,myYmax, | |
873 | (myZmin - P1.Z())/D.Z()*D.X() + P1.X(), | |
874 | (myZmin - P1.Z())/D.Z()*D.Y() + P1.Y(), | |
875 | (myZmin - P2.Z())/D.Z()*D.X() + P2.X(), | |
876 | (myZmin - P2.Z())/D.Z()*D.Y() + P2.Y())) | |
877 | return Standard_False; | |
878 | ||
879 | if(!IsSegmentOut(myXmin,myYmin,myXmax,myYmax, | |
880 | (myZmax - P1.Z())/D.Z()*D.X() + P1.X(), | |
881 | (myZmax - P1.Z())/D.Z()*D.Y() + P1.Y(), | |
882 | (myZmax - P2.Z())/D.Z()*D.X() + P2.X(), | |
883 | (myZmax - P2.Z())/D.Z()*D.Y() + P2.Y())) | |
884 | return Standard_False; | |
885 | ||
886 | if(!IsSegmentOut(myZmin,myYmin,myZmax,myYmax, | |
887 | (myXmin - P1.X())/D.X()*D.Z() + P1.Z(), | |
888 | (myXmin - P1.X())/D.X()*D.Y() + P1.Y(), | |
889 | (myXmin - P2.X())/D.X()*D.Z() + P2.Z(), | |
890 | (myXmin - P2.X())/D.X()*D.Y() + P2.Y())) | |
891 | return Standard_False; | |
892 | ||
893 | if(!IsSegmentOut(myZmin,myYmin,myZmax,myYmax, | |
894 | (myXmax - P1.X())/D.X()*D.Z() + P1.Z(), | |
895 | (myXmax - P1.X())/D.X()*D.Y() + P1.Y(), | |
896 | (myXmax - P2.X())/D.X()*D.Z() + P2.Z(), | |
897 | (myXmax - P2.X())/D.X()*D.Y() + P2.Y())) | |
898 | return Standard_False; | |
899 | ||
900 | return Standard_True; | |
901 | ||
902 | } | |
903 | ||
904 | //======================================================================= | |
905 | //function : Distance | |
906 | //purpose : computes the minimum distance between two boxes | |
907 | //======================================================================= | |
908 | ||
909 | static Standard_Real DistMini2Box( const Standard_Real r1min, const Standard_Real r1max, const Standard_Real r2min, const Standard_Real r2max) | |
910 | { Standard_Real r1, r2; | |
911 | ||
912 | r1 = Square(r1min - r2max); | |
913 | r2 = Square(r1max - r2min); | |
914 | return (Min( r1, r2 )); | |
915 | } | |
916 | ||
917 | ||
918 | ||
919 | Standard_Real Bnd_Box::Distance(const Bnd_Box& Other) const | |
920 | { Standard_Real xminB1, yminB1, zminB1, xmaxB1, ymaxB1, zmaxB1; | |
921 | Standard_Real xminB2, yminB2, zminB2, xmaxB2, ymaxB2, zmaxB2; | |
922 | Standard_Real dist_x, dist_y, dist_z, dist_t; | |
923 | ||
924 | Get( xminB1, yminB1, zminB1, xmaxB1, ymaxB1, zmaxB1); | |
925 | Other.Get( xminB2, yminB2, zminB2, xmaxB2, ymaxB2, zmaxB2); | |
926 | ||
927 | if ( ((xminB1<= xminB2)&&( xminB2 <= xmaxB1)) || ((xminB2<= xminB1)&&( xminB1 <= xmaxB2)) ) | |
928 | { dist_x=0; } | |
929 | else { dist_x= DistMini2Box(xminB1, xmaxB1, xminB2, xmaxB2);} | |
930 | if ( ((yminB1<= yminB2)&&( yminB2 <= ymaxB1)) || ((yminB2<= yminB1)&&( yminB1 <= ymaxB2)) ) | |
931 | { dist_y=0; } | |
932 | else { dist_y= DistMini2Box(yminB1, ymaxB1, yminB2, ymaxB2);} | |
933 | if ( ((zminB1<= zminB2)&&( zminB2 <= zmaxB1)) || ((zminB2<= zminB1)&&( zminB1 <= zmaxB2)) ) | |
934 | { dist_z=0; } | |
935 | else { dist_z= DistMini2Box(zminB1, zmaxB1, zminB2, zmaxB2);} | |
936 | dist_t = dist_x+ dist_y+ dist_z; | |
937 | return( Sqrt ( dist_t)); | |
938 | } | |
939 | ||
940 | //======================================================================= | |
941 | //function : Dump | |
942 | //purpose : | |
943 | //======================================================================= | |
944 | ||
945 | void Bnd_Box::Dump () const | |
946 | { | |
04232180 | 947 | std::cout << "Box3D : "; |
948 | if (IsVoid()) std::cout << "Void"; | |
949 | else if (IsWhole()) std::cout << "Whole"; | |
7fd59977 | 950 | else { |
04232180 | 951 | std::cout << "\n Xmin : "; |
952 | if (IsOpenXmin()) std::cout << "Infinite"; | |
953 | else std::cout << Xmin; | |
954 | std::cout << "\n Xmax : "; | |
955 | if (IsOpenXmax()) std::cout << "Infinite"; | |
956 | else std::cout << Xmax; | |
957 | std::cout << "\n Ymin : "; | |
958 | if (IsOpenYmin()) std::cout << "Infinite"; | |
959 | else std::cout << Ymin; | |
960 | std::cout << "\n Ymax : "; | |
961 | if (IsOpenYmax()) std::cout << "Infinite"; | |
962 | else std::cout << Ymax; | |
963 | std::cout << "\n Zmin : "; | |
964 | if (IsOpenZmin()) std::cout << "Infinite"; | |
965 | else std::cout << Zmin; | |
966 | std::cout << "\n Zmax : "; | |
967 | if (IsOpenZmax()) std::cout << "Infinite"; | |
968 | else std::cout << Zmax; | |
7fd59977 | 969 | } |
04232180 | 970 | std::cout << "\n Gap : " << Gap; |
971 | std::cout << "\n"; | |
7fd59977 | 972 | } |
0904aa63 | 973 | |
974 | //======================================================================= | |
975 | //function : DumpJson | |
976 | //purpose : | |
977 | //======================================================================= | |
978 | void Bnd_Box::DumpJson (Standard_OStream& theOStream, const Standard_Integer) const | |
979 | { | |
3de0f784 | 980 | OCCT_DUMP_CLASS_BEGIN (theOStream, Bnd_Box); |
0904aa63 | 981 | |
3de0f784 | 982 | OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "CornerMin", 3, Xmin, Ymin, Zmin) |
983 | OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "CornerMax", 3, Xmax, Ymax, Zmax) | |
0904aa63 | 984 | |
3de0f784 | 985 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, Gap); |
986 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, Flags); | |
0904aa63 | 987 | } |