1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #if !defined(ON_BOUNDING_BOX_INC_)
18 #define ON_BOUNDING_BOX_INC_
19 
20 ////////////////////////////////////////////////////////////////
21 //
22 //   ON_BoundingBox  - axis aligned bounding box
23 //
24 
25 class ON_CLASS ON_BoundingBox
26 {
27 public:
28   static const ON_BoundingBox EmptyBoundingBox; // ((1.0,0,0,0,0),(-1.0,0.0,0.0))
29 
30   ON_BoundingBox(); // creates EmptyBox
31 
32 	ON_BoundingBox(
33     const ON_3dPoint&, // min corner of axis aligned bounding box
34     const ON_3dPoint&  // max corner of axis aligned bounding box
35     );
36   ~ON_BoundingBox();
37 
38 
39   // temporary - use ON_ClippingRegion - this function will be removed soon.
40   int IsVisible(
41     const ON_Xform& bbox2c
42     ) const;
43 
44   void Destroy(); // invalidates bounding box
45 
46   // operator[] returns min if index <= 0 and max if indes >= 1
47   ON_3dPoint& operator[](int);
48   const ON_3dPoint& operator[](int) const;
49 
50   ON_3dPoint Min() const;
51   ON_3dPoint Max() const;
52   ON_3dVector Diagonal() const; // max corner - min corner
53   ON_3dPoint Center() const;
54   ON_3dPoint Corner( // 8 corners of box
55     int, // x_index   0 = Min().x, 1 = Max().x
56     int, // y_index   0 = Min().y, 1 = Max().y
57     int  // z_index   0 = Min().z, 1 = Max().z
58     ) const;
59   bool GetCorners(
60     ON_3dPointArray& box_corners // returns list of 8 corner points
61     ) const;
62   bool GetCorners(
63     ON_3dPoint box_corners[8] // returns list of 8 corner points
64     ) const;
65 
66   /*
67   Parameters:
68     edges[] - out
69       12 edge lines. If the bounding box has no height, width or depth,
70       then the corresponding edges will have the same "from" and "to"
71       points.
72   Returns:
73     If the bounding box is valid, then true is returned and
74     12 line segments, some possibly a single point, are returned.
75     Otherwise false is returned and 12 line segments with "from"
76     and "to" points set to ON_3dPoint::UnsetPoint are returned.
77   */
78   bool GetEdges(
79     ON_Line edges[12]  // returns list of 12 edge segments
80     ) const;
81 
82   bool IsValid() const; // empty boxes are not valid
83 
84   void Dump(class ON_TextLog&) const;
85 
86   /*
87   Description:
88     Test a bounding box to see if it is degenerate (flat)
89     in one or more directions.
90   Parameters:
91     tolerance - [in] Distances <= tolerance will be considered
92         to be zero.  If tolerance is negative (default), then
93         a scale invarient tolerance is used.
94   Returns:
95     @untitled table
96     0     box is not degenerate
97     1     box is a rectangle (degenerate in one direction)
98     2     box is a line (degenerate in two directions)
99     3     box is a point (degenerate in three directions)
100     4     box is not valid
101   */
102   int IsDegenerate(
103     double tolerance = ON_UNSET_VALUE
104     ) const;
105 
106 
107   //////////
108   // ON_BoundingBox::Transform() updates the bounding box
109   // to be the smallest axis aligned bounding box that contains
110   // the transform of the eight corner points of the input
111   // bounding box.
112   bool Transform( const ON_Xform& );
113 
114   double Tolerance() const; // rough guess at a tolerance to use for comparing
115                             // objects in this bounding box
116 
117 
118   // All of these Set() functions set or expand a box to enclose the points in the arguments
119   // If bGrowBox is true, the existing box is expanded, otherwise it is only set to the current point list
120   bool Set(
121     int dim,
122     int is_rat,
123     int count,
124     int stride,
125     const double* point_array,
126     int bGrowBox = false
127     );
128 
129   bool Set(
130     const ON_3dPoint& point,
131     int bGrowBox = false
132     );
133 
134   bool Set(
135     const ON_2dPoint& point,
136     int bGrowBox = false
137     );
138 
139   bool Set(
140     const ON_SimpleArray<ON_4dPoint>& point_array,
141     int bGrowBox = false
142     );
143 
144   bool Set(
145     const ON_SimpleArray<ON_3dPoint>& point_array,
146     int bGrowBox = false
147     );
148 
149   bool Set(
150     const ON_SimpleArray<ON_2dPoint>& point_array,
151     int bGrowBox = false
152     );
153 
154   bool Set(
155     int dim,
156     int is_rat,
157     int count,
158     int stride,
159     const float* point_array,
160     int bGrowBox = false
161     );
162 
163   bool Set(
164     const ON_3fPoint& point,
165     int bGrowBox = false
166     );
167 
168   bool Set(
169     const ON_2fPoint& point,
170     int bGrowBox = false
171     );
172 
173   bool Set(
174     const ON_SimpleArray<ON_4fPoint>& point_array,
175     int bGrowBox = false
176     );
177 
178   bool Set(
179     const ON_SimpleArray<ON_3fPoint>& point_array,
180     int bGrowBox = false
181     );
182 
183   bool Set(
184     const ON_SimpleArray<ON_2fPoint>& point_array,
185     int bGrowBox = false
186     );
187 
188 	bool IsPointIn(
189          const ON_3dPoint& test_point, // point to test
190          int bStrictlyIn = false
191                    // true to test for strict ( min < point < max )
192                    // false to test for (min <= point <= max)
193                    //
194          ) const;
195 
196   //////////
197   // Point on or in the box that is closest to test_point.
198   // If test_point is in or on the box, the test_point is returned.
199   ON_3dPoint ClosestPoint(
200     const ON_3dPoint& test_point
201     ) const;
202 
203 
204   /*
205   Description:
206     Quickly find a lower bound on the distance
207     between the point and this bounding box.
208   Parameters:
209     P - [in]
210   Returns:
211     A distance that is less than or equal to the shortest
212     distance from the line to this bounding box.
213     Put another way, if Q is any point in this bounding box,
214     then P.DistanceTo(Q) >= MinimumDistanceTo(bbox).
215   */
216   double MinimumDistanceTo( const ON_3dPoint& P ) const;
217 
218   /*
219   Description:
220     Quickly find an upper bound on the distance
221     between the point and this bounding box.
222   Parameters:
223     P - [in]
224   Returns:
225     A distance that is greater than or equal to the
226     longest distance from the point P to this bounding box.
227     Put another way, if Q is any point in this bounding box,
228     then P.DistanceTo(Q) <= MaximumDistanceTo(bbox).
229   */
230   double MaximumDistanceTo( const ON_3dPoint& P ) const;
231 
232 
233   /*
234   Description:
235     Quickly find a lower bound on the distance
236     between this and the other bounding box.
237   Parameters:
238     other - [in]
239   Returns:
240     A distance that is less than or equal to the shortest
241     distance between the bounding boxes.
242     Put another way, if Q is any point in this bounding box
243     and P is any point in the other bounding box,
244     then P.DistanceTo(Q) >= MinimumDistanceTo(bbox).
245   */
246   double MinimumDistanceTo( const ON_BoundingBox& other ) const;
247 
248   /*
249   Description:
250     Quickly find an upper bound on the distance
251     between this and the other bounding box.
252   Parameters:
253     other - [in]
254   Returns:
255     A distance that is greater than or equal to the longest
256     distance between the bounding boxes.
257     Put another way, if Q is any point in this bounding box
258     and P is any point in the other bounding box,
259     then P.DistanceTo(Q) <= MaximumDistanceTo(bbox).
260   */
261   double MaximumDistanceTo( const ON_BoundingBox& other ) const;
262 
263   /*
264   Description:
265     Quickly find a lower bound on the distance
266     between the line segment and this bounding box.
267   Parameters:
268     line - [in]
269   Returns:
270     A distance that is less than or equal to the shortest
271     distance from the line to this bounding box.
272     Put another way, if Q is any point on line
273     and P is any point in this bounding box, then
274     P.DistanceTo(Q) >= MinimumDistanceTo(bbox).
275   */
276   double MinimumDistanceTo( const ON_Line& line ) const;
277 
278   /*
279   Description:
280     Quickly find a tight lower bound on the distance
281     between the plane and this bounding box.
282   Parameters:
283     plane - [in]
284   Returns:
285     The minimum distance between a point on the plane
286     and a point on the bounding box.
287   See Also:
288     ON_PlaneEquation::MimimumValueAt
289     ON_PlaneEquation::MaximumValueAt
290   */
291   double MinimumDistanceTo( const ON_Plane& plane ) const;
292   double MinimumDistanceTo( const ON_PlaneEquation& plane_equation ) const;
293 
294   /*
295   Description:
296     Quickly find an upper bound on the distance
297     between the line segment and this bounding box.
298   Parameters:
299     line - [in]
300   Returns:
301     A distance that is greater than or equal to the
302     longest distance from the line to this bounding box.
303     Put another way, if Q is any point on the line
304     and P is any point in this bounding box, then
305     P.DistanceTo(Q) <= MaximumDistanceTo(bbox).
306   */
307   double MaximumDistanceTo( const ON_Line& line ) const;
308 
309   /*
310   Description:
311     Quickly find a tight upper bound on the distance
312     between the plane and this bounding box.
313   Parameters:
314     plane - [in]
315   Returns:
316     A distance that is equal to the longest distance from
317     the plane to this bounding box.  Put another way,
318     if Q is any point on the plane and P is any point
319     in this bounding box, then
320     P.DistanceTo(Q) <= MaximumDistanceTo(bbox) and there
321     is at least one point on the bounding box where the
322     distance is equal to the returned value.
323   See Also:
324     ON_PlaneEquation::MaximumValueAt
325   */
326   double MaximumDistanceTo( const ON_Plane& plane ) const;
327   double MaximumDistanceTo( const ON_PlaneEquation& plane_equation ) const;
328 
329 
330   /*
331   Description:
332     Quickly determine if the shortest distance from
333     the point P to the bounding box is greater than d.
334   Parameters:
335     d - [in] distance (> 0.0)
336     P - [in]
337   Returns:
338     True if if the shortest distance from the point P
339     to the bounding box is greater than d.
340   */
341   bool IsFartherThan( double d, const ON_3dPoint& P ) const;
342 
343   /*
344   Description:
345     Quickly determine if the shortest distance from the line
346     to the bounding box is greater than d.
347   Parameters:
348     d - [in] distance (> 0.0)
349     line - [in]
350   Returns:
351     True if the shortest distance from the line
352     to the bounding box is greater than d. It is not the
353     case that false means that the shortest distance
354     is less than or equal to d.
355   */
356   bool IsFartherThan( double d, const ON_Line& line ) const;
357 
358   /*
359   Description:
360     Quickly determine if the shortest distance from the plane
361     to the bounding box is greater than d.
362   Parameters:
363     d - [in] distance (> 0.0)
364     plane - [in]
365   Returns:
366     True if the shortest distance from the plane
367     to the bounding box is greater than d, and false
368     if the shortest distance is less than or equal to d.
369   */
370   bool IsFartherThan( double d, const ON_Plane& plane ) const;
371 
372   /*
373   Description:
374     Quickly determine if the shortest distance from the plane
375     to the bounding box is greater than d.
376   Parameters:
377     d - [in] distance (> 0.0)
378     plane_equation - [in] (the first three coefficients
379                            are assumed to be a unit vector.
380                            If not, adjust your d accordingly.)
381   Returns:
382     True if the shortest distance from the plane
383     to the bounding box is greater than d, and false
384     if the shortest distance is less than or equal to d.
385   */
386   bool IsFartherThan( double d, const ON_PlaneEquation& plane_equation ) const;
387 
388   /*
389   Description:
390     Quickly determine if the shortest distance this bounding
391     box to another bounding box is greater than d.
392   Parameters:
393     d - [in] distance (> 0.0)
394     other - [in] other bounding box
395   Returns:
396     True if if the shortest distance from this bounding
397     box to the other bounding box is greater than d.
398   */
399   bool IsFartherThan( double d, const ON_BoundingBox& other ) const;
400 
401 
402   // Description:
403   //   Get point in a bounding box that is closest to a line
404   //   segment.
405   // Parameters:
406   //   line - [in] line segment
407   //   box_point - [out] point in box that is closest to line
408   //       segment point at t0.
409   //   t0 - [out] parameter of point on line that is closest to
410   //       the box.
411   //   t1 - [out] parameter of point on line that is closest to
412   //       the box.
413   // Returns:
414   //   3 success - line segments intersects box in a segment
415   //               from line(t0) to line(t1) (t0 < t1)
416   //   2 success - line segments intersects box in a single point
417   //               at line(t0) (t0==t1)
418   //   1 success - line segment does not intersect box.  Closest
419   //               point on the line is at line(t0) (t0==t1)
420   //   0 failure - box is invalid.
421   // Remarks:
422   //   The box is treated as a solid box.  If the intersection
423   //   of the line segment, then 3 is returned.
424   int GetClosestPoint(
425     const ON_Line&, // line
426     ON_3dPoint&,    // box_point
427     double*,        // t0
428     double*         // t1
429     ) const;
430 
431   //////////
432   // Get points on bounding boxes that are closest to each other.
433   // If the boxes intersect, then the point at the centroid of the
434   // intersection is returned for both points.
435   bool GetClosestPoint(
436          const ON_BoundingBox&, // "other" bounding box
437          ON_3dPoint&, // point on "this" box that is closest to "other" box
438          ON_3dPoint&  // point on "other" box that is closest to "this" box
439          )  const;
440 
441   //////////
442   // Point on the box that is farthest from the test_point.
443   ON_3dPoint FarPoint(
444     const ON_3dPoint& // test_point
445     ) const;
446 
447   //////////
448   // Get points on bounding boxes that are farthest from each other.
449   bool GetFarPoint(
450          const ON_BoundingBox&, // "other" bounding box
451          ON_3dPoint&, // point on "this" box that is farthest from "other" box
452          ON_3dPoint&  // point on "other" box that is farthest from "this" box
453          )  const;
454 
455   /*
456   Description:
457     Intersect this with other_bbox and save intersection in this.
458   Parameters:
459     other_bbox - [in]
460   Returns:
461     True if this-intesect-other_bbox is a non-empty valid bounding box
462     and this is set.  False if the intersection is empty, in which case
463     "this" is set to an invalid bounding box.
464   Remarks:
465     If "this" or other_bbox is invalid, they are treated as
466     the empty set, and false is returned.
467   */
468   bool Intersection(
469          const ON_BoundingBox& other_bbox
470          );
471 
472   /*
473   Description:
474     Set "this" to the intersection of bbox_A and bbox_B.
475   Parameters:
476     bbox_A - [in]
477     bbox_B - [in]
478   Returns:
479     True if the "this" is a non-empty valid bounding box.
480     False if the intersection is empty, in which case
481     "this" is set to an invalid bounding box.
482   Remarks:
483     If bbox_A or bbox_B is invalid, they are treated as
484     the empty set, and false is returned.
485   */
486   bool Intersection( // this = intersection of two args
487          const ON_BoundingBox& bbox_A,
488          const ON_BoundingBox& bbox_B
489          );
490 
491 	bool Intersection(				//Returns true when intersect is non-empty.
492 				 const ON_Line&,		//Infinite Line segment to intersect with
493 				 double* =NULL ,			// t0  parameter of first intersection point
494 				 double* =NULL       // t1  parameter of last intersection point (t0<=t1)
495 				 ) const;
496 
497   /*
498   Description:
499     Test a box to see if it is contained in this box.
500   Parameters:
501     other - [in] box to test
502     bProperSubSet - [in] if true, then the test is for a proper inclusion.
503   Returns:
504     If bProperSubSet is false, then the result is true when
505 			this->m_min[i] <= other.m_min[i] and other.m_max[i] <= this->m_max[i].
506 			for i=0,1 and 2.
507     If bProperSubSet is true, then the result is true when
508 			the above condition is true and at least one of the inequalities is strict.
509   */
510   bool Includes(
511     const ON_BoundingBox& other,
512     bool bProperSubSet = false
513     ) const;
514 
515 	double Volume() const;
516 
517   double Area() const;
518 
519   // Union() returns true if union is not empty.
520   // Invalid boxes are treated as the empty set.
521   bool Union( // this = this union arg
522          const ON_BoundingBox&
523          );
524 
525   bool Union( // this = union of two args
526          const ON_BoundingBox&,
527          const ON_BoundingBox&
528          );
529 
530   /*
531   Description:
532     Test to see if "this" and other_bbox are disjoint (do not intersect).
533   Parameters:
534     other_bbox - [in]
535   Returns:
536     True if "this" and other_bbox are disjoint.
537   Remarks:
538     If "this" or other_bbox is invalid, then true is returned.
539   */
540   bool IsDisjoint(
541     const ON_BoundingBox& other_bbox
542     ) const;
543 
544   bool SwapCoordinates( int, int );
545 
546   ON_3dPoint m_min;
547   ON_3dPoint m_max;
548 };
549 
550 #if defined(ON_DLL_TEMPLATE)
551 
552 // This stuff is here because of a limitation in the way Microsoft
553 // handles templates and DLLs.  See Microsoft's knowledge base
554 // article ID Q168958 for details.
555 #pragma warning( push )
556 #pragma warning( disable : 4231 )
557 ON_DLL_TEMPLATE template class ON_CLASS ON_SimpleArray<ON_BoundingBox>;
558 #pragma warning( pop )
559 
560 #endif
561 
562 /*
563 Description:
564   Get a tight bounding box that contains the points.
565 Parameters:
566  dim - [in] (>=1)
567  is_rat - [in] true if points are rational
568  count - [in] number of points
569  stride - [in] stride between points
570  point_list - [in]
571  bbox - [in/out]
572  bGrowBox - [in] (default = false)
573    If the input bbox is valid and bGrowBox is true,
574    then the output bbox is the union of the input
575    bbox and the bounding box of the point list.
576  xform - [in] (default = NULL)
577    If not null, the bounding box of the transformed
578    points is calculated.  The points are not modified.
579 Returns:
580   True if the output bbox is valid.
581 */
582 ON_DECL
583 bool ON_GetPointListBoundingBox(
584     int dim,
585     int is_rat,
586     int count,
587     int stride,
588     const double* point_list,
589     ON_BoundingBox& bbox,
590     int bGrowBox = false,
591     const ON_Xform* xform = 0
592     );
593 
594 ON_DECL
595 bool ON_GetPointListBoundingBox(
596     int dim,
597     int is_rat,
598     int count,
599     int stride,
600     const float* point_list,
601     ON_BoundingBox& bbox,
602     int bGrowBox = false,
603     const ON_Xform* xform = 0
604     );
605 
606 ON_DECL
607 bool ON_GetPointListBoundingBox(
608     int dim,
609     int is_rat,
610     int count,
611     int stride,
612     const double* point_list,
613     double* boxmin,       // min[dim]
614     double* boxmax,       // max[dim]
615     int bGrowBox
616     );
617 
618 ON_DECL
619 ON_BoundingBox ON_PointListBoundingBox(
620     int dim,
621     int is_rat,
622     int count,
623     int stride,
624     const double* point_list
625     );
626 
627 ON_DECL
628 bool ON_GetPointListBoundingBox(
629     int dim,
630     int is_rat,
631     int count,
632     int stride,
633     const float* point_list,
634     float* boxmin,       // min[dim]
635     float* boxmax,       // max[dim]
636     int bGrowBox
637     );
638 
639 ON_DECL
640 ON_BoundingBox ON_PointListBoundingBox( // low level workhorse function
641     int dim,
642     int is_rat,
643     int count,
644     int stride,
645     const float* point_list
646     );
647 
648 ON_DECL
649 bool ON_GetPointGridBoundingBox(
650         int dim,
651         int is_rat,
652         int point_count0, int point_count1,
653         int point_stride0, int point_stride1,
654         const double* point_grid,
655         double* boxmin,       // min[dim]
656         double* boxmax,       // max[dim]
657         int bGrowBox
658     );
659 
660 ON_DECL
661 ON_BoundingBox ON_PointGridBoundingBox(
662         int dim,
663         int is_rat,
664         int point_count0, int point_count1,
665         int point_stride0, int point_stride1,
666         const double* point_grid
667     );
668 
669 ON_DECL
670 double ON_BoundingBoxTolerance(
671         int dim,
672         const double* bboxmin,
673         const double* bboxmax
674         );
675 
676 /*
677 Description:
678   Determine if an object is too large or too far
679   from the origin for single precision coordinates
680   to be useful.
681 Parameters:
682   bbox - [in]
683     Bounding box of an object with single precision
684     coordinates.  An ON_Mesh is an example of an
685     object with single precision coordinates.
686   xform - [out]
687     If this function returns false and xform is not
688     null, then the identity transform is returned.
689     If this function returns true and xform is not
690     null, then the transform moves the region
691     contained in bbox to a location where single
692     precision coordinates will have enough
693     information for the object to be useful.
694 Returns:
695   true:
696     The region contained in bbox is too large
697     or too far from the origin for single
698     precision coordinates to be useful.
699   false:
700     A single precision object contained in bbox
701     will be satisfactory for common calculations.
702 */
703 ON_DECL
704 bool ON_BeyondSinglePrecision( const ON_BoundingBox& bbox, ON_Xform* xform );
705 
706 ON_DECL
707 bool ON_WorldBBoxIsInTightBBox(
708           const ON_BoundingBox& tight_bbox,
709           const ON_BoundingBox& world_bbox,
710           const ON_Xform* xform
711           );
712 
713 #endif
714