d325cb7f |
1 | // Copyright (c) 2011-2019 OPEN CASCADE SAS |
c5751993 |
2 | // |
3 | // This file is part of Open CASCADE Technology software library. |
4 | // |
0a36ca0a |
5 | // This library is free software; you can redistribute it and/or modify it under |
6 | // the terms of the GNU Lesser General Public License version 2.1 as published |
c5751993 |
7 | // by the Free Software Foundation, with special exception defined in the file |
8 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
9 | // distribution for complete text of the license and disclaimer of any warranty. |
10 | // |
11 | // Alternatively, this file may be used under the terms of Open CASCADE |
12 | // commercial license or contractual agreement. |
13 | |
d325cb7f |
14 | #include <Graphic3d_Layer.hxx> |
a1954302 |
15 | |
d325cb7f |
16 | #include <Graphic3d_CStructure.hxx> |
17 | #include <Graphic3d_CullingTool.hxx> |
c5751993 |
18 | |
d325cb7f |
19 | IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Layer, Standard_Transient) |
f5b72419 |
20 | |
a1954302 |
21 | // ======================================================================= |
d325cb7f |
22 | // function : Graphic3d_Layer |
a1954302 |
23 | // purpose : |
24 | // ======================================================================= |
1c728f2d |
25 | Graphic3d_Layer::Graphic3d_Layer (Graphic3d_ZLayerId theId, |
26 | Standard_Integer theNbPriorities, |
d325cb7f |
27 | const Handle(Select3D_BVHBuilder3d)& theBuilder) |
50d06d8f |
28 | : myArray (0, theNbPriorities - 1), |
29 | myNbStructures (0), |
15669413 |
30 | myNbStructuresNotCulled (0), |
1c728f2d |
31 | myLayerId (theId), |
f5b72419 |
32 | myBVHPrimitivesTrsfPers (theBuilder), |
a1954302 |
33 | myBVHIsLeftChildQueuedFirst (Standard_True), |
15669413 |
34 | myIsBVHPrimitivesNeedsReset (Standard_False) |
c5751993 |
35 | { |
50d06d8f |
36 | myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true; |
c5751993 |
37 | } |
38 | |
a1954302 |
39 | // ======================================================================= |
d325cb7f |
40 | // function : ~Graphic3d_Layer |
a1954302 |
41 | // purpose : |
42 | // ======================================================================= |
d325cb7f |
43 | Graphic3d_Layer::~Graphic3d_Layer() |
a1954302 |
44 | { |
45 | // |
46 | } |
47 | |
48 | // ======================================================================= |
49 | // function : Add |
50 | // purpose : |
51 | // ======================================================================= |
d325cb7f |
52 | void Graphic3d_Layer::Add (const Graphic3d_CStructure* theStruct, |
53 | Standard_Integer thePriority, |
54 | Standard_Boolean isForChangePriority) |
a1954302 |
55 | { |
56 | const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1); |
57 | if (theStruct == NULL) |
58 | { |
59 | return; |
60 | } |
61 | |
9f112210 |
62 | myArray (anIndex).Add (theStruct); |
a1954302 |
63 | if (theStruct->IsAlwaysRendered()) |
64 | { |
65 | theStruct->MarkAsNotCulled(); |
3fe9ce0e |
66 | if (!isForChangePriority) |
67 | { |
68 | myAlwaysRenderedMap.Add (theStruct); |
69 | } |
a1954302 |
70 | } |
71 | else if (!isForChangePriority) |
72 | { |
778cd667 |
73 | if (theStruct->TransformPersistence().IsNull()) |
825aa485 |
74 | { |
75 | myBVHPrimitives.Add (theStruct); |
76 | } |
77 | else |
78 | { |
79 | myBVHPrimitivesTrsfPers.Add (theStruct); |
80 | } |
a1954302 |
81 | } |
82 | ++myNbStructures; |
83 | } |
84 | |
85 | // ======================================================================= |
86 | // function : Remove |
87 | // purpose : |
88 | // ======================================================================= |
d325cb7f |
89 | bool Graphic3d_Layer::Remove (const Graphic3d_CStructure* theStruct, |
90 | Standard_Integer& thePriority, |
91 | Standard_Boolean isForChangePriority) |
a1954302 |
92 | { |
93 | if (theStruct == NULL) |
94 | { |
95 | thePriority = -1; |
96 | return false; |
97 | } |
98 | |
99 | const Standard_Integer aNbPriorities = myArray.Length(); |
100 | for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) |
101 | { |
d325cb7f |
102 | Graphic3d_IndexedMapOfStructure& aStructures = myArray (aPriorityIter); |
9f112210 |
103 | const Standard_Integer anIndex = aStructures.FindIndex (theStruct); |
d325cb7f |
104 | if (anIndex == 0) |
a1954302 |
105 | { |
d325cb7f |
106 | continue; |
107 | } |
108 | |
109 | aStructures.Swap (anIndex, aStructures.Size()); |
110 | aStructures.RemoveLast(); |
9f112210 |
111 | |
d325cb7f |
112 | if (!isForChangePriority) |
113 | { |
114 | Standard_Boolean isAlwaysRend = theStruct->IsAlwaysRendered(); |
115 | if (!isAlwaysRend) |
a1954302 |
116 | { |
d325cb7f |
117 | if (!myBVHPrimitives.Remove (theStruct)) |
825aa485 |
118 | { |
d325cb7f |
119 | if (!myBVHPrimitivesTrsfPers.Remove (theStruct)) |
3fe9ce0e |
120 | { |
d325cb7f |
121 | isAlwaysRend = Standard_True; |
3fe9ce0e |
122 | } |
123 | } |
d325cb7f |
124 | } |
125 | if (isAlwaysRend) |
126 | { |
127 | const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct); |
128 | if (anIndex2 != 0) |
3fe9ce0e |
129 | { |
d325cb7f |
130 | myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2); |
131 | myAlwaysRenderedMap.RemoveLast(); |
825aa485 |
132 | } |
a1954302 |
133 | } |
134 | } |
d325cb7f |
135 | --myNbStructures; |
136 | thePriority = aPriorityIter; |
137 | return true; |
a1954302 |
138 | } |
139 | |
140 | thePriority = -1; |
141 | return false; |
142 | } |
143 | |
144 | // ======================================================================= |
145 | // function : InvalidateBVHData |
146 | // purpose : |
147 | // ======================================================================= |
d325cb7f |
148 | void Graphic3d_Layer::InvalidateBVHData() |
a1954302 |
149 | { |
150 | myIsBVHPrimitivesNeedsReset = Standard_True; |
151 | } |
152 | |
3fe9ce0e |
153 | //! Calculate a finite bounding box of infinite object as its middle point. |
7c3ef2f7 |
154 | inline Graphic3d_BndBox3d centerOfinfiniteBndBox (const Graphic3d_BndBox3d& theBndBox) |
3fe9ce0e |
155 | { |
156 | // bounding borders of infinite line has been calculated as own point in center of this line |
7c3ef2f7 |
157 | const Graphic3d_Vec3d aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin(); |
158 | return aDiagVec.SquareModulus() >= 500000.0 * 500000.0 |
159 | ? Graphic3d_BndBox3d ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5) |
160 | : Graphic3d_BndBox3d(); |
3fe9ce0e |
161 | } |
162 | |
163 | //! Return true if at least one vertex coordinate out of float range. |
7c3ef2f7 |
164 | inline bool isInfiniteBndBox (const Graphic3d_BndBox3d& theBndBox) |
3fe9ce0e |
165 | { |
166 | return Abs (theBndBox.CornerMax().x()) >= ShortRealLast() |
167 | || Abs (theBndBox.CornerMax().y()) >= ShortRealLast() |
168 | || Abs (theBndBox.CornerMax().z()) >= ShortRealLast() |
169 | || Abs (theBndBox.CornerMin().x()) >= ShortRealLast() |
170 | || Abs (theBndBox.CornerMin().y()) >= ShortRealLast() |
171 | || Abs (theBndBox.CornerMin().z()) >= ShortRealLast(); |
172 | } |
173 | |
4e993e4d |
174 | //! Extend bounding box with another box. |
175 | static void addBox3dToBndBox (Bnd_Box& theResBox, |
176 | const Graphic3d_BndBox3d& theBox) |
177 | { |
178 | // skip too big boxes to prevent float overflow at camera parameters calculation |
179 | if (theBox.IsValid() && !isInfiniteBndBox (theBox)) |
180 | { |
181 | theResBox.Add (gp_Pnt (theBox.CornerMin().x(), theBox.CornerMin().y(), theBox.CornerMin().z())); |
182 | theResBox.Add (gp_Pnt (theBox.CornerMax().x(), theBox.CornerMax().y(), theBox.CornerMax().z())); |
183 | } |
184 | } |
185 | |
a1954302 |
186 | // ======================================================================= |
50d06d8f |
187 | // function : BoundingBox |
188 | // purpose : |
189 | // ======================================================================= |
d325cb7f |
190 | Bnd_Box Graphic3d_Layer::BoundingBox (Standard_Integer theViewId, |
191 | const Handle(Graphic3d_Camera)& theCamera, |
192 | Standard_Integer theWindowWidth, |
193 | Standard_Integer theWindowHeight, |
194 | Standard_Boolean theToIncludeAuxiliary) const |
50d06d8f |
195 | { |
150ed3d5 |
196 | updateBVH(); |
197 | |
3fe9ce0e |
198 | const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1; |
7c3ef2f7 |
199 | const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix(); |
200 | const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix(); |
50d06d8f |
201 | if (myIsBoundingBoxNeedsReset[aBoxId]) |
202 | { |
203 | // Recompute layer bounding box |
7c3ef2f7 |
204 | myBoundingBox[aBoxId].SetVoid(); |
50d06d8f |
205 | |
d325cb7f |
206 | for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
50d06d8f |
207 | { |
d325cb7f |
208 | const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
209 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
50d06d8f |
210 | { |
d325cb7f |
211 | const Graphic3d_CStructure* aStructure = aStructIter.Value(); |
3fe9ce0e |
212 | if (!aStructure->IsVisible (theViewId)) |
50d06d8f |
213 | { |
214 | continue; |
215 | } |
216 | |
217 | // "FitAll" operation ignores object with transform persistence parameter |
218 | // but adds transform persistence point in a bounding box of layer (only zoom pers. objects). |
778cd667 |
219 | if (!aStructure->TransformPersistence().IsNull()) |
50d06d8f |
220 | { |
3fe9ce0e |
221 | if (!theToIncludeAuxiliary |
778cd667 |
222 | && aStructure->TransformPersistence()->IsZoomOrRotate()) |
50d06d8f |
223 | { |
778cd667 |
224 | const gp_Pnt anAnchor = aStructure->TransformPersistence()->AnchorPoint(); |
7c3ef2f7 |
225 | myBoundingBox[aBoxId].Add (anAnchor); |
50d06d8f |
226 | continue; |
227 | } |
228 | // Panning and 2d persistence apply changes to projection or/and its translation components. |
229 | // It makes them incompatible with z-fitting algorithm. Ignored by now. |
3fe9ce0e |
230 | else if (!theToIncludeAuxiliary |
778cd667 |
231 | || aStructure->TransformPersistence()->IsTrihedronOr2d()) |
50d06d8f |
232 | { |
233 | continue; |
234 | } |
235 | } |
236 | |
4e993e4d |
237 | if (!theToIncludeAuxiliary |
238 | && aStructure->HasGroupTransformPersistence()) |
239 | { |
240 | // add per-group transform-persistence point in a bounding box |
241 | for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (aStructure->Groups()); aGroupIter.More(); aGroupIter.Next()) |
242 | { |
243 | const Handle(Graphic3d_Group)& aGroup = aGroupIter.Value(); |
244 | if (!aGroup->TransformPersistence().IsNull() |
245 | && aGroup->TransformPersistence()->IsZoomOrRotate()) |
246 | { |
247 | const gp_Pnt anAnchor = aGroup->TransformPersistence()->AnchorPoint(); |
248 | myBoundingBox[aBoxId].Add (anAnchor); |
249 | } |
250 | } |
251 | } |
252 | |
7c3ef2f7 |
253 | Graphic3d_BndBox3d aBox = aStructure->BoundingBox(); |
3fe9ce0e |
254 | if (!aBox.IsValid()) |
255 | { |
256 | continue; |
257 | } |
50d06d8f |
258 | |
259 | if (aStructure->IsInfinite |
3fe9ce0e |
260 | && !theToIncludeAuxiliary) |
50d06d8f |
261 | { |
3fe9ce0e |
262 | // include center of infinite object |
263 | aBox = centerOfinfiniteBndBox (aBox); |
50d06d8f |
264 | } |
265 | |
778cd667 |
266 | if (!aStructure->TransformPersistence().IsNull()) |
50d06d8f |
267 | { |
778cd667 |
268 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); |
50d06d8f |
269 | } |
4e993e4d |
270 | addBox3dToBndBox (myBoundingBox[aBoxId], aBox); |
50d06d8f |
271 | } |
272 | } |
273 | |
274 | myIsBoundingBoxNeedsReset[aBoxId] = false; |
275 | } |
276 | |
7c3ef2f7 |
277 | Bnd_Box aResBox = myBoundingBox[aBoxId]; |
3fe9ce0e |
278 | if (!theToIncludeAuxiliary |
279 | || myAlwaysRenderedMap.IsEmpty()) |
280 | { |
7c3ef2f7 |
281 | return aResBox; |
3fe9ce0e |
282 | } |
283 | |
284 | // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit |
d325cb7f |
285 | for (NCollection_IndexedMap<const Graphic3d_CStructure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next()) |
3fe9ce0e |
286 | { |
d325cb7f |
287 | const Graphic3d_CStructure* aStructure = aStructIter.Value(); |
3fe9ce0e |
288 | if (!aStructure->IsVisible (theViewId)) |
289 | { |
290 | continue; |
291 | } |
4e993e4d |
292 | |
293 | // handle per-group transformation persistence specifically |
294 | if (aStructure->HasGroupTransformPersistence()) |
3fe9ce0e |
295 | { |
4e993e4d |
296 | for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (aStructure->Groups()); aGroupIter.More(); aGroupIter.Next()) |
297 | { |
298 | const Handle(Graphic3d_Group)& aGroup = aGroupIter.Value(); |
299 | const Graphic3d_BndBox4f& aBoxF = aGroup->BoundingBox(); |
300 | if (aGroup->TransformPersistence().IsNull() |
301 | || !aBoxF.IsValid()) |
302 | { |
303 | continue; |
304 | } |
305 | |
306 | Graphic3d_BndBox3d aBoxCopy (Graphic3d_Vec3d (aBoxF.CornerMin().xyz()), |
307 | Graphic3d_Vec3d (aBoxF.CornerMax().xyz())); |
308 | aGroup->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBoxCopy); |
309 | addBox3dToBndBox (aResBox, aBoxCopy); |
310 | } |
3fe9ce0e |
311 | } |
312 | |
4e993e4d |
313 | const Graphic3d_BndBox3d& aStructBox = aStructure->BoundingBox(); |
314 | if (!aStructBox.IsValid() |
315 | || aStructure->TransformPersistence().IsNull() |
316 | || !aStructure->TransformPersistence()->IsTrihedronOr2d()) |
3fe9ce0e |
317 | { |
318 | continue; |
319 | } |
320 | |
4e993e4d |
321 | Graphic3d_BndBox3d aBoxCopy = aStructBox; |
322 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBoxCopy); |
323 | addBox3dToBndBox (aResBox, aBoxCopy); |
3fe9ce0e |
324 | } |
325 | |
326 | return aResBox; |
50d06d8f |
327 | } |
328 | |
329 | // ======================================================================= |
330 | // function : considerZoomPersistenceObjects |
331 | // purpose : |
332 | // ======================================================================= |
d325cb7f |
333 | Standard_Real Graphic3d_Layer::considerZoomPersistenceObjects (Standard_Integer theViewId, |
334 | const Handle(Graphic3d_Camera)& theCamera, |
335 | Standard_Integer theWindowWidth, |
336 | Standard_Integer theWindowHeight) const |
50d06d8f |
337 | { |
338 | if (NbOfTransformPersistenceObjects() == 0) |
339 | { |
340 | return 1.0; |
341 | } |
342 | |
7c3ef2f7 |
343 | const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix(); |
344 | const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix(); |
50d06d8f |
345 | Standard_Real aMaxCoef = -std::numeric_limits<double>::max(); |
346 | |
d325cb7f |
347 | for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
50d06d8f |
348 | { |
d325cb7f |
349 | const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
350 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
50d06d8f |
351 | { |
d325cb7f |
352 | const Graphic3d_CStructure* aStructure = aStructIter.Value(); |
3fe9ce0e |
353 | if (!aStructure->IsVisible (theViewId) |
778cd667 |
354 | || aStructure->TransformPersistence().IsNull() |
355 | || !aStructure->TransformPersistence()->IsZoomOrRotate()) |
50d06d8f |
356 | { |
357 | continue; |
358 | } |
359 | |
7c3ef2f7 |
360 | Graphic3d_BndBox3d aBox = aStructure->BoundingBox(); |
3fe9ce0e |
361 | if (!aBox.IsValid()) |
50d06d8f |
362 | { |
363 | continue; |
364 | } |
365 | |
778cd667 |
366 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); |
50d06d8f |
367 | |
7c3ef2f7 |
368 | const BVH_Vec3d& aCornerMin = aBox.CornerMin(); |
369 | const BVH_Vec3d& aCornerMax = aBox.CornerMax(); |
50d06d8f |
370 | const Standard_Integer aNbOfPoints = 8; |
371 | const gp_Pnt aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()), |
372 | gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()), |
373 | gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()), |
374 | gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()), |
375 | gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()), |
376 | gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()), |
377 | gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()), |
378 | gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) }; |
379 | gp_Pnt aConvertedPoints[aNbOfPoints]; |
380 | Standard_Real aConvertedMinX = std::numeric_limits<double>::max(); |
381 | Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max(); |
382 | Standard_Real aConvertedMinY = std::numeric_limits<double>::max(); |
383 | Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max(); |
384 | for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx) |
385 | { |
386 | aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]); |
387 | |
388 | aConvertedMinX = Min (aConvertedMinX, aConvertedPoints[anIdx].X()); |
389 | aConvertedMaxX = Max (aConvertedMaxX, aConvertedPoints[anIdx].X()); |
390 | |
391 | aConvertedMinY = Min (aConvertedMinY, aConvertedPoints[anIdx].Y()); |
392 | aConvertedMaxY = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y()); |
393 | } |
394 | |
395 | const Standard_Boolean isBigObject = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0) // width of zoom pers. object greater than width of window |
396 | || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window |
397 | const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0) |
398 | && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0) |
399 | && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0) |
400 | && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0); |
401 | if (isBigObject || isAlreadyInScreen) |
402 | { |
403 | continue; |
404 | } |
405 | |
778cd667 |
406 | const gp_Pnt aTPPoint = aStructure->TransformPersistence()->AnchorPoint(); |
50d06d8f |
407 | gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint); |
408 | aConvertedTPPoint.SetZ (0.0); |
409 | |
410 | if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion()) |
411 | { |
412 | continue; |
413 | } |
414 | |
415 | Standard_Real aShiftX = 0.0; |
416 | if (aConvertedMinX < -1.0) |
417 | { |
418 | aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX)); |
419 | } |
420 | else if (aConvertedMaxX > 1.0) |
421 | { |
422 | aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0)); |
423 | } |
424 | |
425 | Standard_Real aShiftY = 0.0; |
426 | if (aConvertedMinY < -1.0) |
427 | { |
428 | aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY)); |
429 | } |
430 | else if (aConvertedMaxY > 1.0) |
431 | { |
432 | aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0)); |
433 | } |
434 | |
435 | const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX; |
436 | const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY; |
437 | if (aDifX > Precision::Confusion()) |
438 | { |
439 | aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX); |
440 | } |
441 | if (aDifY > Precision::Confusion()) |
442 | { |
443 | aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY); |
444 | } |
445 | } |
446 | } |
447 | |
448 | return (aMaxCoef > 0.0) ? aMaxCoef : 1.0; |
449 | } |
450 | |
a1954302 |
451 | // ======================================================================= |
3fe9ce0e |
452 | // function : updateBVH |
a1954302 |
453 | // purpose : |
454 | // ======================================================================= |
d325cb7f |
455 | void Graphic3d_Layer::updateBVH() const |
a1954302 |
456 | { |
3fe9ce0e |
457 | if (!myIsBVHPrimitivesNeedsReset) |
458 | { |
459 | return; |
460 | } |
461 | |
462 | myBVHPrimitives.Clear(); |
463 | myBVHPrimitivesTrsfPers.Clear(); |
150ed3d5 |
464 | myAlwaysRenderedMap.Clear(); |
3fe9ce0e |
465 | myIsBVHPrimitivesNeedsReset = Standard_False; |
d325cb7f |
466 | for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
a1954302 |
467 | { |
d325cb7f |
468 | const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
469 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
825aa485 |
470 | { |
d325cb7f |
471 | const Graphic3d_CStructure* aStruct = aStructIter.Value(); |
3fe9ce0e |
472 | if (aStruct->IsAlwaysRendered()) |
825aa485 |
473 | { |
150ed3d5 |
474 | aStruct->MarkAsNotCulled(); |
475 | myAlwaysRenderedMap.Add (aStruct); |
3fe9ce0e |
476 | } |
778cd667 |
477 | else if (aStruct->TransformPersistence().IsNull()) |
3fe9ce0e |
478 | { |
479 | myBVHPrimitives.Add (aStruct); |
480 | } |
481 | else |
482 | { |
483 | myBVHPrimitivesTrsfPers.Add (aStruct); |
825aa485 |
484 | } |
485 | } |
a1954302 |
486 | } |
3fe9ce0e |
487 | } |
488 | |
9ad4ff93 |
489 | namespace |
490 | { |
491 | //! This structure describes the node in BVH |
492 | struct NodeInStack |
493 | { |
494 | NodeInStack (Standard_Integer theId = 0, |
495 | Standard_Boolean theIsFullInside = false) : Id (theId), IsFullInside (theIsFullInside) {} |
496 | |
497 | Standard_Integer Id; //!< node identifier |
498 | Standard_Boolean IsFullInside; //!< if the node is completely inside |
499 | }; |
500 | } |
501 | |
3fe9ce0e |
502 | // ======================================================================= |
2b8832bb |
503 | // function : UpdateCulling |
3fe9ce0e |
504 | // purpose : |
505 | // ======================================================================= |
d325cb7f |
506 | void Graphic3d_Layer::UpdateCulling (Standard_Integer theViewId, |
507 | const Graphic3d_CullingTool& theSelector, |
508 | const Graphic3d_RenderingParams::FrustumCulling theFrustumCullingState) |
3fe9ce0e |
509 | { |
510 | updateBVH(); |
a1954302 |
511 | |
15669413 |
512 | myNbStructuresNotCulled = myNbStructures; |
0e3025bc |
513 | if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_NoUpdate) |
a1954302 |
514 | { |
d325cb7f |
515 | Standard_Boolean toTraverse = (theFrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On); |
516 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitives.Structures()); aStructIter.More(); aStructIter.Next()) |
0e3025bc |
517 | { |
d325cb7f |
518 | const Graphic3d_CStructure* aStruct = aStructIter.Value(); |
0e3025bc |
519 | aStruct->SetCulled (toTraverse); |
520 | } |
d325cb7f |
521 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitivesTrsfPers.Structures()); aStructIter.More(); aStructIter.Next()) |
0e3025bc |
522 | { |
d325cb7f |
523 | const Graphic3d_CStructure* aStruct = aStructIter.Value(); |
0e3025bc |
524 | aStruct->SetCulled (toTraverse); |
525 | } |
a1954302 |
526 | } |
a1954302 |
527 | |
0e3025bc |
528 | if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_On) |
2b8832bb |
529 | { |
530 | return; |
531 | } |
532 | if (myBVHPrimitives .Size() == 0 |
533 | && myBVHPrimitivesTrsfPers.Size() == 0) |
534 | { |
535 | return; |
536 | } |
537 | |
15669413 |
538 | myNbStructuresNotCulled = myAlwaysRenderedMap.Extent(); |
d325cb7f |
539 | Graphic3d_CullingTool::CullingContext aCullCtx; |
2b8832bb |
540 | theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance()); |
541 | theSelector.SetCullingSize (aCullCtx, myLayerSettings.CullingSize()); |
825aa485 |
542 | for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx) |
a1954302 |
543 | { |
825aa485 |
544 | const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1; |
2b8832bb |
545 | opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree; |
825aa485 |
546 | if (isTrsfPers) |
a1954302 |
547 | { |
825aa485 |
548 | if (myBVHPrimitivesTrsfPers.Size() == 0) |
825aa485 |
549 | continue; |
97f937cc |
550 | |
d325cb7f |
551 | const Graphic3d_Mat4d& aProjection = theSelector.ProjectionMatrix(); |
552 | const Graphic3d_Mat4d& aWorldView = theSelector.WorldViewMatrix(); |
825aa485 |
553 | const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState(); |
91d96372 |
554 | const Standard_Integer aViewportWidth = theSelector.ViewportWidth(); |
555 | const Standard_Integer aViewportHeight = theSelector.ViewportHeight(); |
556 | |
3fe9ce0e |
557 | aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState); |
825aa485 |
558 | } |
559 | else |
560 | { |
561 | if (myBVHPrimitives.Size() == 0) |
825aa485 |
562 | continue; |
97f937cc |
563 | |
825aa485 |
564 | aBVHTree = myBVHPrimitives.BVH(); |
565 | } |
566 | |
9ad4ff93 |
567 | const bool toCheckFullInside = true; |
568 | NodeInStack aNode (0, toCheckFullInside); // a root node |
569 | if (theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0), toCheckFullInside ? &aNode.IsFullInside : NULL)) |
825aa485 |
570 | { |
571 | continue; |
572 | } |
573 | |
9ad4ff93 |
574 | NodeInStack aStack[BVH_Constants_MaxTreeDepth]; |
825aa485 |
575 | Standard_Integer aHead = -1; |
576 | for (;;) |
577 | { |
9ad4ff93 |
578 | if (!aBVHTree->IsOuter (aNode.Id)) |
a1954302 |
579 | { |
9ad4ff93 |
580 | NodeInStack aLeft (aBVHTree->Child<0> (aNode.Id), toCheckFullInside); |
581 | NodeInStack aRight(aBVHTree->Child<1> (aNode.Id), toCheckFullInside); |
582 | bool isLeftChildIn = true, isRightChildIn = true; |
583 | if (aNode.IsFullInside) |
584 | { |
585 | // small size should be always checked |
586 | isLeftChildIn = !theSelector.IsTooSmall (aCullCtx, aBVHTree->MinPoint (aLeft.Id), aBVHTree->MaxPoint (aLeft.Id)); |
587 | isRightChildIn = !theSelector.IsTooSmall (aCullCtx, aBVHTree->MinPoint (aRight.Id), aBVHTree->MaxPoint (aRight.Id)); |
588 | } |
589 | else |
590 | { |
591 | isLeftChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aLeft.Id), aBVHTree->MaxPoint (aLeft.Id), toCheckFullInside ? &aLeft.IsFullInside : NULL); |
592 | if (!isLeftChildIn) |
593 | { |
594 | aLeft.IsFullInside = false; |
595 | } |
596 | |
597 | isRightChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aRight.Id), aBVHTree->MaxPoint (aRight.Id), toCheckFullInside ? &aRight.IsFullInside : NULL); |
598 | if (!isRightChildIn) |
599 | { |
600 | aRight.IsFullInside = false; |
601 | } |
602 | } |
603 | |
825aa485 |
604 | if (isLeftChildIn |
605 | && isRightChildIn) |
606 | { |
9ad4ff93 |
607 | aNode = myBVHIsLeftChildQueuedFirst ? aLeft : aRight; |
608 | aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRight : aLeft; |
825aa485 |
609 | myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst; |
610 | } |
611 | else if (isLeftChildIn |
612 | || isRightChildIn) |
613 | { |
9ad4ff93 |
614 | aNode = isLeftChildIn ? aLeft : aRight; |
825aa485 |
615 | } |
616 | else |
617 | { |
618 | if (aHead < 0) |
619 | { |
620 | break; |
621 | } |
622 | |
623 | aNode = aStack[aHead--]; |
624 | } |
a1954302 |
625 | } |
626 | else |
627 | { |
9ad4ff93 |
628 | const Standard_Integer aStartIdx = aBVHTree->BegPrimitive (aNode.Id); |
629 | const Standard_Integer anEndIdx = aBVHTree->EndPrimitive (aNode.Id); |
a2803f37 |
630 | for (Standard_Integer anIdx = aStartIdx; anIdx <= anEndIdx; ++anIdx) |
5dc0517d |
631 | { |
a2803f37 |
632 | const Graphic3d_CStructure* aStruct = isTrsfPers |
633 | ? myBVHPrimitivesTrsfPers.GetStructureById (anIdx) |
634 | : myBVHPrimitives.GetStructureById (anIdx); |
635 | if (aStruct->IsVisible (theViewId)) |
636 | { |
637 | aStruct->MarkAsNotCulled(); |
638 | ++myNbStructuresNotCulled; |
639 | } |
5dc0517d |
640 | } |
a1954302 |
641 | if (aHead < 0) |
642 | { |
825aa485 |
643 | break; |
a1954302 |
644 | } |
645 | |
14a35e5d |
646 | aNode = aStack[aHead--]; |
a1954302 |
647 | } |
648 | } |
a1954302 |
649 | } |
650 | } |
651 | |
652 | // ======================================================================= |
653 | // function : Append |
654 | // purpose : |
655 | // ======================================================================= |
d325cb7f |
656 | Standard_Boolean Graphic3d_Layer::Append (const Graphic3d_Layer& theOther) |
a1954302 |
657 | { |
658 | // the source priority list shouldn't have more priorities |
659 | const Standard_Integer aNbPriorities = theOther.NbPriorities(); |
660 | if (aNbPriorities > NbPriorities()) |
661 | { |
662 | return Standard_False; |
663 | } |
664 | |
665 | // add all structures to destination priority list |
666 | for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) |
667 | { |
d325cb7f |
668 | const Graphic3d_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter); |
669 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
a1954302 |
670 | { |
7c3ef2f7 |
671 | Add (aStructIter.Value(), aPriorityIter); |
a1954302 |
672 | } |
673 | } |
674 | |
675 | return Standard_True; |
676 | } |
677 | |
7c3ef2f7 |
678 | //======================================================================= |
679 | //function : SetLayerSettings |
680 | //purpose : |
681 | //======================================================================= |
d325cb7f |
682 | void Graphic3d_Layer::SetLayerSettings (const Graphic3d_ZLayerSettings& theSettings) |
7c3ef2f7 |
683 | { |
684 | const Standard_Boolean toUpdateTrsf = !myLayerSettings.Origin().IsEqual (theSettings.Origin(), gp::Resolution()); |
685 | myLayerSettings = theSettings; |
d325cb7f |
686 | if (!toUpdateTrsf) |
7c3ef2f7 |
687 | { |
d325cb7f |
688 | return; |
7c3ef2f7 |
689 | } |
690 | |
d325cb7f |
691 | for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
83da37b1 |
692 | { |
d325cb7f |
693 | Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.ChangeValue(); |
694 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
695 | { |
696 | Graphic3d_CStructure* aStructure = const_cast<Graphic3d_CStructure* >(aStructIter.Value()); |
697 | aStructure->updateLayerTransformation(); |
698 | } |
83da37b1 |
699 | } |
c5751993 |
700 | } |
bc73b006 |
701 | |
702 | // ======================================================================= |
703 | // function : DumpJson |
704 | // purpose : |
705 | // ======================================================================= |
706 | void Graphic3d_Layer::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const |
707 | { |
708 | OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream) |
709 | |
710 | OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, this) |
711 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLayerId) |
712 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbStructures) |
713 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbStructuresNotCulled) |
714 | |
715 | const Standard_Integer aNbPriorities = myArray.Length(); |
716 | for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) |
717 | { |
718 | const Graphic3d_IndexedMapOfStructure& aStructures = myArray (aPriorityIter); |
719 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
720 | { |
721 | const Graphic3d_CStructure* aStructure = aStructIter.Value(); |
722 | OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, aStructure) |
723 | } |
724 | } |
725 | |
726 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myLayerSettings) |
727 | |
728 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myBVHIsLeftChildQueuedFirst) |
729 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBVHPrimitivesNeedsReset) |
730 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBoundingBoxNeedsReset[0]) |
731 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBoundingBoxNeedsReset[1]) |
732 | |
733 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBoundingBox[0]) |
734 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBoundingBox[1]) |
735 | } |