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