0030232: Visualization, StdPrs_BndBox - support Bnd_OBB in addition to Bnd_Box
[occt.git] / src / Bnd / Bnd_OBB.hxx
1 // Created by: Eugeny MALTCHIKOV
2 // Copyright (c) 2017 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #ifndef _Bnd_OBB_HeaderFile
16 #define _Bnd_OBB_HeaderFile
17
18 #include <Standard.hxx>
19 #include <Standard_DefineAlloc.hxx>
20 #include <Standard_Handle.hxx>
21 #include <Standard_Real.hxx>
22 #include <Standard_Boolean.hxx>
23
24 #include <Bnd_Box.hxx>
25 #include <gp_Ax3.hxx>
26 #include <gp_Dir.hxx>
27 #include <gp_Pnt.hxx>
28 #include <gp_XYZ.hxx>
29 #include <TColgp_Array1OfPnt.hxx>
30 #include <TColStd_Array1OfReal.hxx>
31
32 //! The class describes the Oriented Bounding Box (OBB),
33 //! much tighter enclosing volume for the shape than the
34 //! Axis Aligned Bounding Box (AABB).
35 //! The OBB is defined by a center of the box, the axes and the halves
36 //! of its three dimensions.
37 //! The OBB can be used more effectively than AABB as a rejection mechanism
38 //! for non-interfering objects.
39 class Bnd_OBB
40 {
41 public:
42
43   DEFINE_STANDARD_ALLOC
44
45   //! Empty constructor
46   Bnd_OBB() :myIsAABox(Standard_False)
47   {
48     myHDims[0] = myHDims[1] = myHDims[2] = -1.0;
49   }
50
51   //! Constructor taking all defining parameters
52   Bnd_OBB(const gp_Pnt& theCenter,
53           const gp_Dir& theXDirection,
54           const gp_Dir& theYDirection,
55           const gp_Dir& theZDirection,
56           const Standard_Real theHXSize,
57           const Standard_Real theHYSize,
58           const Standard_Real theHZSize) :myCenter (theCenter.XYZ()),
59                                           myIsAABox(Standard_False)
60   {
61     myAxes[0] = theXDirection.XYZ();
62     myAxes[1] = theYDirection.XYZ();
63     myAxes[2] = theZDirection.XYZ();
64
65     Standard_ASSERT_VOID(theHXSize >= 0.0, "Negative value of X-size");
66     Standard_ASSERT_VOID(theHYSize >= 0.0, "Negative value of Y-size");
67     Standard_ASSERT_VOID(theHZSize >= 0.0, "Negative value of Z-size");
68     
69     myHDims[0] = theHXSize;
70     myHDims[1] = theHYSize;
71     myHDims[2] = theHZSize;
72   }
73
74   //! Constructor to create OBB from AABB.
75   Bnd_OBB(const Bnd_Box& theBox) : myIsAABox(Standard_True)
76   {
77     if (theBox.IsVoid())
78     {
79       myHDims[0] = myHDims[1] = myHDims[2] = -1.0;
80       myIsAABox = Standard_False;
81       return;
82     }
83
84     Standard_Real aX1, aY1, aZ1, aX2, aY2, aZ2;
85     theBox.Get(aX1, aY1, aZ1, aX2, aY2, aZ2);
86
87     myAxes[0].SetCoord(1.0, 0.0, 0.0);
88     myAxes[1].SetCoord(0.0, 1.0, 0.0);
89     myAxes[2].SetCoord(0.0, 0.0, 1.0);
90
91     myHDims[0] = 0.5*(aX2 - aX1);
92     myHDims[1] = 0.5*(aY2 - aY1);
93     myHDims[2] = 0.5*(aZ2 - aZ1);
94
95     myCenter.SetCoord(0.5*(aX2 + aX1), 0.5*(aY2 + aY1), 0.5*(aZ2 + aZ1));
96   }
97
98   //! Created new OBB covering every point in theListOfPoints.
99   //! Tolerance of every such point is set by *theListOfTolerances array.
100   //! If this array is not void (not null-pointer) then the resulted Bnd_OBB
101   //! will be enlarged using tolerances of points lying on the box surface.
102   Standard_EXPORT void ReBuild(const TColgp_Array1OfPnt& theListOfPoints,
103                                const TColStd_Array1OfReal *theListOfTolerances = 0);
104
105   //! Sets the center of OBB
106   void SetCenter(const gp_Pnt& theCenter)
107   {
108     myCenter = theCenter.XYZ();
109   }
110
111     //! Sets the X component of OBB - direction and size
112   void SetXComponent(const gp_Dir& theXDirection,
113                      const Standard_Real theHXSize)
114   {
115     Standard_ASSERT_VOID(theHXSize >= 0.0, "Negative value of X-size");
116
117     myAxes[0] = theXDirection.XYZ();
118     myHDims[0] = theHXSize;
119   }
120
121   //! Sets the Y component of OBB - direction and size
122   void SetYComponent(const gp_Dir& theYDirection,
123                      const Standard_Real theHYSize)
124   {
125     Standard_ASSERT_VOID(theHYSize >= 0.0, "Negative value of Y-size");
126
127     myAxes[1] = theYDirection.XYZ();
128     myHDims[1] = theHYSize;
129   }
130
131   //! Sets the Z component of OBB - direction and size
132   void SetZComponent(const gp_Dir& theZDirection,
133                      const Standard_Real theHZSize)
134   {
135     Standard_ASSERT_VOID(theHZSize >= 0.0, "Negative value of Z-size");
136
137     myAxes[2] = theZDirection.XYZ();
138     myHDims[2] = theHZSize;
139   }
140
141   //! Returns the local coordinates system of this oriented box.
142   //! So that applying it to axis-aligned box ((-XHSize, -YHSize, -ZHSize), (XHSize, YHSize, ZHSize)) will produce this oriented box.
143   //! @code
144   //!   gp_Trsf aLoc;
145   //!   aLoc.SetTransformation (theOBB.Position(), gp::XOY());
146   //! @endcode
147   gp_Ax3 Position() const { return gp_Ax3 (myCenter, ZDirection(), XDirection()); }
148
149   //! Returns the center of OBB
150   const gp_XYZ& Center() const
151   {
152     return myCenter;
153   }
154
155   //! Returns the X Direction of OBB
156   const gp_XYZ& XDirection() const
157   {
158     return myAxes[0];
159   }
160
161   //! Returns the Y Direction of OBB
162   const gp_XYZ& YDirection() const
163   {
164     return myAxes[1];
165   }
166
167   //! Returns the Z Direction of OBB
168   const gp_XYZ& ZDirection() const
169   {
170     return myAxes[2];
171   }
172
173   //! Returns the X Dimension of OBB
174   Standard_Real XHSize() const
175   {
176     return myHDims[0];
177   }
178
179   //! Returns the Y Dimension of OBB
180   Standard_Real YHSize() const
181   {
182     return myHDims[1];
183   }
184
185   //! Returns the Z Dimension of OBB
186   Standard_Real ZHSize() const
187   {
188     return myHDims[2];
189   }
190
191   //! Checks if the box is empty.
192   Standard_Boolean IsVoid() const
193   {
194     return ((myHDims[0] < 0.0) || (myHDims[1] < 0.0) || (myHDims[2] < 0.0));
195   }
196
197   //! Clears this box
198   void SetVoid()
199   {
200     myHDims[0] = myHDims[1] = myHDims[2] = -1.0;
201     myCenter = myAxes[0] = myAxes[1] = myAxes[2] = gp_XYZ();
202     myIsAABox = Standard_False;
203   }
204
205   //! Sets the flag for axes aligned box
206   void SetAABox(const Standard_Boolean& theFlag)
207   {
208     myIsAABox = theFlag;
209   }
210
211   //! Returns TRUE if the box is axes aligned
212   Standard_Boolean IsAABox() const
213   {
214     return myIsAABox;
215   }
216
217   //! Enlarges the box with the given value
218   void Enlarge(const Standard_Real theGapAdd)
219   {
220     const Standard_Real aGap = Abs(theGapAdd);
221     myHDims[0] += aGap;
222     myHDims[1] += aGap;
223     myHDims[2] += aGap;
224   }
225
226   //! Returns the array of vertices in <this>.
227   //! The local coordinate of the vertex depending on the
228   //! index of the array are follow:
229   //! Index == 0: (-XHSize(), -YHSize(), -ZHSize())
230   //! Index == 1: ( XHSize(), -YHSize(), -ZHSize())
231   //! Index == 2: (-XHSize(),  YHSize(), -ZHSize())
232   //! Index == 3: ( XHSize(),  YHSize(), -ZHSize())
233   //! Index == 4: (-XHSize(), -YHSize(),  ZHSize())
234   //! Index == 5: ( XHSize(), -YHSize(),  ZHSize())
235   //! Index == 6: (-XHSize(),  YHSize(),  ZHSize())
236   //! Index == 7: ( XHSize(),  YHSize(),  ZHSize()).
237   Standard_Boolean GetVertex(gp_Pnt theP[8]) const
238   {
239     if(IsVoid())
240       return Standard_False;
241
242     theP[0].SetXYZ(myCenter - myHDims[0]*myAxes[0] - myHDims[1]*myAxes[1] - myHDims[2]*myAxes[2]);
243     theP[1].SetXYZ(myCenter + myHDims[0]*myAxes[0] - myHDims[1]*myAxes[1] - myHDims[2]*myAxes[2]);
244     theP[2].SetXYZ(myCenter - myHDims[0]*myAxes[0] + myHDims[1]*myAxes[1] - myHDims[2]*myAxes[2]);
245     theP[3].SetXYZ(myCenter + myHDims[0]*myAxes[0] + myHDims[1]*myAxes[1] - myHDims[2]*myAxes[2]);
246     theP[4].SetXYZ(myCenter - myHDims[0]*myAxes[0] - myHDims[1]*myAxes[1] + myHDims[2]*myAxes[2]);
247     theP[5].SetXYZ(myCenter + myHDims[0]*myAxes[0] - myHDims[1]*myAxes[1] + myHDims[2]*myAxes[2]);
248     theP[6].SetXYZ(myCenter - myHDims[0]*myAxes[0] + myHDims[1]*myAxes[1] + myHDims[2]*myAxes[2]);
249     theP[7].SetXYZ(myCenter + myHDims[0]*myAxes[0] + myHDims[1]*myAxes[1] + myHDims[2]*myAxes[2]);
250
251     return Standard_True;
252   }
253
254   //! Returns square diagonal of this box
255   Standard_Real SquareExtent() const
256   {
257     return (4.0*myHDims[0] * myHDims[0] + 
258             myHDims[1] * myHDims[1] +
259             myHDims[1] * myHDims[1]);
260   }
261
262   //! Check if the box do not interfere the other box.
263   Standard_EXPORT Standard_Boolean IsOut(const Bnd_OBB& theOther) const;
264
265   //! Check if the point is inside of <this>.
266   Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt& theP) const;
267
268   //! Check if the theOther is completely inside *this.
269   Standard_EXPORT Standard_Boolean IsCompletelyInside(const Bnd_OBB& theOther) const;
270
271   //! Rebuilds this in order to include all previous objects
272   //! (which it was created from) and theOther.
273   Standard_EXPORT void Add(const Bnd_OBB& theOther);
274
275   //! Rebuilds this in order to include all previous objects
276   //! (which it was created from) and theP.
277   Standard_EXPORT void Add(const gp_Pnt& theP);
278
279 protected:
280
281     void ProcessOnePoint(const gp_Pnt& theP)
282     {
283       myIsAABox = Standard_True;
284       myHDims[0] = myHDims[1] = myHDims[2] = 0.0;
285       myAxes[0].SetCoord(1.0, 0.0, 0.0);
286       myAxes[1].SetCoord(0.0, 1.0, 0.0);
287       myAxes[2].SetCoord(0.0, 0.0, 1.0);
288       myCenter = theP.XYZ();
289     }
290
291 private:
292
293   //! Center of the OBB
294   gp_XYZ myCenter;
295
296   //! Directions of the box's axes
297   //! (all vectors are already normalized)
298   gp_XYZ myAxes[3];
299
300   //! Half-size dimensions of the OBB
301   Standard_Real myHDims[3];
302
303   //! To be set if the OBB is axis aligned box;
304   Standard_Boolean myIsAABox;
305 };
306
307 #endif