VTK  9.4.20241219
vtkBlockSortHelper.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2// SPDX-License-Identifier: BSD-3-Clause
8#ifndef vtkBlockSortHelper_h
9#define vtkBlockSortHelper_h
10
11#include "vtkCamera.h"
12#include "vtkDataSet.h"
13#include "vtkMatrix4x4.h"
14#include "vtkNew.h"
15#include "vtkRenderer.h"
16#include "vtkVector.h"
17
18#include <vector>
19
21{
22VTK_ABI_NAMESPACE_BEGIN
23
24template <typename T>
25inline void GetBounds(T a, double bds[6])
26{
27 a.GetBounds(bds);
28}
29
30template <>
31inline void GetBounds(vtkDataSet* first, double bds[6])
32{
33 first->GetBounds(bds);
34}
35
42template <typename T>
44{
48
49 //----------------------------------------------------------------------------
51 {
52 vtkCamera* cam = ren->GetActiveCamera();
53 this->CameraIsParallel = (cam->GetParallelProjection() != 0);
54
55 double camWorldPos[4];
56 cam->GetPosition(camWorldPos);
57 camWorldPos[3] = 1.0;
58
59 double camWorldFocalPoint[4];
60 cam->GetFocalPoint(camWorldFocalPoint);
61 camWorldFocalPoint[3] = 1.0;
62
63 // Transform the camera position to the volume (dataset) coordinate system.
64 vtkNew<vtkMatrix4x4> InverseVolumeMatrix;
65 InverseVolumeMatrix->DeepCopy(volMatrix);
66 InverseVolumeMatrix->Invert();
67 InverseVolumeMatrix->MultiplyPoint(camWorldPos, camWorldPos);
68 InverseVolumeMatrix->MultiplyPoint(camWorldFocalPoint, camWorldFocalPoint);
69
70 this->CameraPosition = vtkVector3d(camWorldPos[0], camWorldPos[1], camWorldPos[2]);
71 this->CameraPosition = this->CameraPosition / vtkVector3d(camWorldPos[3]);
72
73 vtkVector3d camFP(camWorldFocalPoint[0], camWorldFocalPoint[1], camWorldFocalPoint[2]);
74 camFP = camFP / vtkVector3d(camWorldFocalPoint[3]);
75
76 this->CameraViewDirection = camFP - this->CameraPosition;
77 }
78
79 //----------------------------------------------------------------------------
80 // camPos is used when is_parallel is false, else viewdirection is used.
81 // thus a valid camPos is only needed if is_parallel is false, and a valid viewdirection
82 // is only needed if is_parallel is true.
83 BackToFront(const vtkVector3d& camPos, const vtkVector3d& viewdirection, bool is_parallel)
84 : CameraPosition(camPos)
85 , CameraViewDirection(viewdirection)
86 , CameraIsParallel(is_parallel)
87 {
88 }
89
90 // -1 if first is closer than second
91 // 0 if unknown
92 // 1 if second is farther than first
93 template <typename TT>
94 inline int CompareOrderWithUncertainty(TT& first, TT& second)
95 {
96 double abounds[6], bbounds[6];
97 vtkBlockSortHelper::GetBounds<TT>(first, abounds);
98 vtkBlockSortHelper::GetBounds<TT>(second, bbounds);
99 return CompareBoundsOrderWithUncertainty(abounds, bbounds);
100 }
101
102 // -1 if first is closer than second
103 // 0 if unknown
104 // 1 if second is farther than first
105 inline int CompareBoundsOrderWithUncertainty(const double abounds[6], const double bbounds[6])
106 {
107 double bboundsP[6];
108 double aboundsP[6];
109 for (int i = 0; i < 6; ++i)
110 {
111 int low = 2 * (i / 2);
112 bboundsP[i] = bbounds[i];
113 if (bboundsP[i] < abounds[low])
114 {
115 bboundsP[i] = abounds[low];
116 }
117 if (bboundsP[i] > abounds[low + 1])
118 {
119 bboundsP[i] = abounds[low + 1];
120 }
121 aboundsP[i] = abounds[i];
122 if (aboundsP[i] < bbounds[low])
123 {
124 aboundsP[i] = bbounds[low];
125 }
126 if (aboundsP[i] > bbounds[low + 1])
127 {
128 aboundsP[i] = bbounds[low + 1];
129 }
130 }
131
132 int dims = 0;
133 int degenDims = 0;
134 int degenAxes[3];
135 int dimSize[3];
136 for (int i = 0; i < 6; i += 2)
137 {
138 if (aboundsP[i] != aboundsP[i + 1])
139 {
140 dimSize[dims] = aboundsP[i + 1] - aboundsP[i];
141 dims++;
142 }
143 else
144 {
145 degenAxes[degenDims] = i / 2;
146 degenDims++;
147 }
148 }
149
150 // overlapping volumes?
151 // in that case find the two largest dimensions
152 // geneally this should not happen
153 if (dims == 3)
154 {
155 if (dimSize[0] < dimSize[1])
156 {
157 if (dimSize[0] < dimSize[2])
158 {
159 degenAxes[0] = 0;
160 }
161 else
162 {
163 degenAxes[0] = 2;
164 }
165 }
166 else
167 {
168 if (dimSize[1] < dimSize[2])
169 {
170 degenAxes[0] = 1;
171 }
172 else
173 {
174 degenAxes[0] = 2;
175 }
176 }
177 dims = 2;
178 degenDims = 1;
179 }
180
181 // compute the direction from a to b
182 double atobdir[3] = { bbounds[0] + bbounds[1] - abounds[0] - abounds[1],
183 bbounds[2] + bbounds[3] - abounds[2] - abounds[3],
184 bbounds[4] + bbounds[5] - abounds[4] - abounds[5] };
185 double atoblength = vtkMath::Normalize(atobdir);
186
187 // no comment on blocks that do not touch
188 if (fabs(aboundsP[degenAxes[0] * 2] - bboundsP[degenAxes[0] * 2]) > 0.01 * atoblength)
189 {
190 return 0;
191 }
192
193 // compute the camera direction
194 vtkVector3d dir;
195 if (this->CameraIsParallel)
196 {
197 dir = this->CameraViewDirection;
198 }
199 else
200 {
201 // compute a point for the half space plane
202 vtkVector3d planePoint(0.25 * (aboundsP[0] + aboundsP[1] + bboundsP[0] + bboundsP[1]),
203 0.25 * (aboundsP[2] + aboundsP[3] + bboundsP[2] + bboundsP[3]),
204 0.25 * (aboundsP[4] + aboundsP[5] + bboundsP[4] + bboundsP[5]));
205 dir = planePoint - this->CameraPosition;
206 }
207 dir.Normalize();
208
209 // planar interface
210 if (dims == 2)
211 {
212 double plane[3] = { 0, 0, 0 };
213 plane[degenAxes[0]] = 1.0;
214 // dot product with camera direction
215 double dot = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
216 if (dot == 0)
217 {
218 return 0;
219 }
220 // figure out what side we are on
221 double side = plane[0] * atobdir[0] + plane[1] * atobdir[1] + plane[2] * atobdir[2];
222 return (dot * side < 0 ? 1 : -1);
223 }
224
225 return 0;
226 }
227};
228
229#ifdef MB_DEBUG
230template <class RandomIt>
231class gnode
232{
233public:
234 RandomIt Value;
235 bool Visited = false;
236 std::vector<gnode<RandomIt>*> Closer;
237};
238
239template <class RandomIt>
240bool operator==(gnode<RandomIt> const& lhs, gnode<RandomIt> const& rhs)
241{
242 return lhs.Value == rhs.Value && lhs.Closer == rhs.Closer;
243}
244
245template <class RandomIt>
246bool findCycle(gnode<RandomIt>& start, std::vector<gnode<RandomIt>>& graph,
247 std::vector<gnode<RandomIt>>& active, std::vector<gnode<RandomIt>>& loop)
248{
249 if (start.Visited)
250 {
251 return false;
252 }
253
254 // add the current node to active list
255 active.push_back(start);
256
257 // traverse the closer nodes one by one depth first
258 for (auto& close : start.Closer)
259 {
260 if (close->Visited)
261 {
262 continue;
263 }
264
265 // is the node already in the active list? if so we have a loop
266 for (auto ait = active.begin(); ait != active.end(); ++ait)
267 {
268 if (ait->Value == close->Value)
269 {
270 loop.push_back(*ait);
271 return true;
272 }
273 }
274 // otherwise recurse
275 if (findCycle(*close, graph, active, loop))
276 {
277 // a loop was detected, build the loop output
278 loop.push_back(*close);
279 return true;
280 }
281 }
282
283 active.erase(std::find(active.begin(), active.end(), start));
284 start.Visited = true;
285 return false;
286}
287#endif
288
289template <class RandomIt, typename T>
290inline void Sort(RandomIt bitr, RandomIt eitr, BackToFront<T>& me)
291{
292 auto start = bitr;
293
294 // brute force for testing
295
296 std::vector<typename RandomIt::value_type> working;
297 std::vector<typename RandomIt::value_type> result;
298 working.assign(bitr, eitr);
299 size_t numNodes = working.size();
300
301#ifdef MB_DEBUG
302 // check for any short loops and debug
303 for (auto it = working.begin(); it != working.end(); ++it)
304 {
305 auto it2 = it;
306 it2++;
307 for (; it2 != working.end(); ++it2)
308 {
309 int comp1 = me.CompareOrderWithUncertainty(*it, *it2);
310 int comp2 = me.CompareOrderWithUncertainty(*it2, *it);
311 if (comp1 * comp2 > 0)
312 {
313 me.CompareOrderWithUncertainty(*it, *it2);
314 me.CompareOrderWithUncertainty(*it2, *it);
315 }
316 }
317 }
318
319 // build the graph
320 std::vector<gnode<RandomIt>> graph;
321 for (auto it = working.begin(); it != working.end(); ++it)
322 {
323 gnode<RandomIt> anode;
324 anode.Value = it;
325 graph.push_back(anode);
326 }
327 for (auto& git : graph)
328 {
329 for (auto& next : graph)
330 {
331 if (git.Value != next.Value && me.CompareOrderWithUncertainty(*git.Value, *next.Value) > 0)
332 {
333 git.Closer.push_back(&next);
334 }
335 }
336 }
337
338 // graph constructed, now look for a loop
339 std::vector<gnode<RandomIt>> active;
340 std::vector<gnode<RandomIt>> loop;
341 for (auto& gval : graph)
342 {
343 loop.clear();
344 if (findCycle(gval, graph, active, loop))
345 {
347 dir.Normalize();
348 vtkGenericWarningMacro("found a loop cam dir: " << dir[0] << " " << dir[1] << " " << dir[2]);
349 for (auto& lval : loop)
350 {
351 double bnds[6];
352 vtkBlockSortHelper::GetBounds((*lval.Value), bnds);
353 vtkGenericWarningMacro(<< bnds[0] << " " << bnds[1] << " " << bnds[2] << " " << bnds[3]
354 << " " << bnds[4] << " " << bnds[5]);
355 }
356 }
357 }
358#endif
359
360 // loop over items and find the first that is not in front of any others
361 for (auto it = working.begin(); it != working.end();)
362 {
363 auto it2 = working.begin();
364 for (; it2 != working.end(); ++it2)
365 {
366 // if another block is in front of this block then this is not the
367 // closest block
368 if (it != it2 && me.CompareOrderWithUncertainty(*it, *it2) > 0)
369 {
370 // not a winner
371 break;
372 }
373 }
374 if (it2 == working.end())
375 {
376 // found a winner, add it to the results, remove from the working set and then restart
377 result.push_back(*it);
378 working.erase(it);
379 it = working.begin();
380 }
381 else
382 {
383 ++it;
384 }
385 }
386
387 if (result.size() != numNodes)
388 {
389 vtkGenericWarningMacro("sorting failed");
390 }
391
392 // copy results to original container
393 std::reverse_copy(result.begin(), result.end(), start);
394};
395VTK_ABI_NAMESPACE_END
396}
397
398#endif // vtkBlockSortHelper_h
399// VTK-HeaderTest-Exclude: vtkBlockSortHelper.h
a virtual camera for 3D rendering
Definition vtkCamera.h:151
virtual double * GetFocalPoint()
Set/Get the focal of the camera in world coordinates.
virtual double * GetPosition()
Set/Get the position of the camera in world coordinates.
virtual vtkTypeBool GetParallelProjection()
Set/Get the value of the ParallelProjection instance variable.
abstract class to specify dataset behavior
Definition vtkDataSet.h:165
double * GetBounds()
Return a pointer to the geometry bounding box in the form (xmin,xmax, ymin,ymax, zmin,...
static float Normalize(float v[3])
Normalize (in place) a 3-vector.
Definition vtkMath.h:1915
represent and manipulate 4x4 transformation matrices
Allocate and hold a VTK object.
Definition vtkNew.h:167
abstract specification for renderers
vtkCamera * GetActiveCamera()
Get the current camera.
double Normalize()
Normalize the vector in place.
Definition vtkVector.h:106
Collection of comparison functions for std::sort.
void Sort(RandomIt bitr, RandomIt eitr, BackToFront< T > &me)
void GetBounds(T a, double bds[6])
@ loop
Definition vtkX3D.h:407
operator() for back-to-front sorting.
int CompareOrderWithUncertainty(TT &first, TT &second)
int CompareBoundsOrderWithUncertainty(const double abounds[6], const double bbounds[6])
BackToFront(vtkRenderer *ren, vtkMatrix4x4 *volMatrix)
BackToFront(const vtkVector3d &camPos, const vtkVector3d &viewdirection, bool is_parallel)
bool VTKCOMMONCORE_EXPORT operator==(const std::string &a, const vtkStringToken &b)