1 | // =================================================================== |
---|
2 | // $Id: $ |
---|
3 | // |
---|
4 | // ktbai.cpp |
---|
5 | // The classes for building up CKTB tree by statistical optimization. |
---|
6 | // The bounding boxes of the all objects are sorted along all |
---|
7 | // axes (x,y,z) in the array-based structure by radix sort algorithm. |
---|
8 | // |
---|
9 | // REPLACEMENT_STRING |
---|
10 | // |
---|
11 | // Copyright by Vlastimil Havran, 2007 - email to "vhavran AT seznam.cz" |
---|
12 | // Initial coding by Vlasta Havran, 2005. |
---|
13 | |
---|
14 | // standard headers |
---|
15 | #include <algorithm> |
---|
16 | #include <iostream> |
---|
17 | #include <string> |
---|
18 | |
---|
19 | // GOLEM headers |
---|
20 | #include "ktbai.h" |
---|
21 | #include "timer.h" |
---|
22 | #include "Environment.h" |
---|
23 | |
---|
24 | //#define _DEBUG |
---|
25 | |
---|
26 | #define AVOIDCHECKLIST |
---|
27 | |
---|
28 | #define _USE_OPTIMIZE_DIVIDE_AX |
---|
29 | |
---|
30 | // Note that the RADIX SORT does not work properly with -mtune=pentium3 for GCC.4.0 !!!! |
---|
31 | // Note that the RADIX SORT does not work properly with -mtune=pentium4 for GCC.3.4 !!!! |
---|
32 | // The reason is unknown, probably the bug in compiler |
---|
33 | |
---|
34 | namespace GtpVisibilityPreprocessor { |
---|
35 | |
---|
36 | // for testing accuracy of setting position from the ideal position |
---|
37 | //#define _RANDOMIZE_POSITION |
---|
38 | |
---|
39 | |
---|
40 | // This is epsilon for randomization |
---|
41 | static |
---|
42 | float randomEps = 0.0f; // By max 5 percent = 0.05 |
---|
43 | |
---|
44 | static void |
---|
45 | RandomizePosition(float &value, float vmin, float vmax) |
---|
46 | { |
---|
47 | assert(vmax > vmin); |
---|
48 | assert( ((value >= vmin) && (value <= vmax) ) ); |
---|
49 | |
---|
50 | // copy the value |
---|
51 | const float origvalue = value; |
---|
52 | float offset = 0.f; |
---|
53 | |
---|
54 | #define _RND_OFFSET |
---|
55 | #ifdef _RND_OFFSET |
---|
56 | const int maxCount = 10; |
---|
57 | int count = 0; |
---|
58 | do { |
---|
59 | if (count > maxCount) { |
---|
60 | value = origvalue; |
---|
61 | break; |
---|
62 | } |
---|
63 | offset = -(vmax - vmin) * randomEps/2.0f; |
---|
64 | offset += randomEps * RandomValue(vmin,vmax); |
---|
65 | value = origvalue + offset; |
---|
66 | count++; |
---|
67 | } |
---|
68 | while (! ((value > vmin) && (value < vmax)) ); |
---|
69 | #else |
---|
70 | offset = (vmax - vmin) * randomEps/2.0f; |
---|
71 | if (RandomValue(0.f, 1.f) < 0.5f) |
---|
72 | offset = -offset; |
---|
73 | value = origvalue + offset; |
---|
74 | if ( (value < vmin) || (value > vmax) ) |
---|
75 | value = origvalue - offset; |
---|
76 | //cout << "offset = " << 100.0f * offset / (vmax-vmin) << "\n"; |
---|
77 | #endif |
---|
78 | |
---|
79 | float epsShift = 1e-5; |
---|
80 | if ( (value <= (vmin + (vmax-vmin) * epsShift)) || |
---|
81 | (value >= (vmax - (vmax-vmin) * epsShift)) ) { |
---|
82 | value = origvalue; |
---|
83 | } |
---|
84 | |
---|
85 | assert( ((value >= vmin) && (value <= vmax) ) ); |
---|
86 | |
---|
87 | return; |
---|
88 | } |
---|
89 | |
---|
90 | // ------------------------------------------------ |
---|
91 | // for debugging cost function in the scene |
---|
92 | //#define _DEBUG_COSTFUNCTION |
---|
93 | #ifdef _DEBUG_COSTFUNCTION |
---|
94 | |
---|
95 | const int indexToFindSS = 0; |
---|
96 | |
---|
97 | static CFileIO ffcost; |
---|
98 | static int costEvalCnt; |
---|
99 | static int costCntObjects; |
---|
100 | static int costIndexDebug; |
---|
101 | static string fnameCost; |
---|
102 | static float maxCost; |
---|
103 | static float minCost; |
---|
104 | static float maxPos; |
---|
105 | static float minPos; |
---|
106 | static float minPosAxis; |
---|
107 | static float maxPosAxis; |
---|
108 | static bool _alreadyDebugged = false; |
---|
109 | static bool _streamOpened = false; |
---|
110 | |
---|
111 | static void |
---|
112 | InitCostStream(int indexDebug, int cntObjects, |
---|
113 | float minx, float maxx) |
---|
114 | { |
---|
115 | maxCost = -INFINITY; |
---|
116 | minCost = INFINITY; |
---|
117 | costEvalCnt = 0; |
---|
118 | costIndexDebug = indexDebug; |
---|
119 | costCntObjects = cntObjects; |
---|
120 | minPosAxis = minx; |
---|
121 | maxPosAxis = maxx; |
---|
122 | |
---|
123 | // and init the stream - rewrite |
---|
124 | string name = "debugcostfile" |
---|
125 | //Environment::GetSingleton()->GetBoolValue("OutputFileName", name); |
---|
126 | char lns[100]; |
---|
127 | sprintf(lns, "%05d.res", indexDebug); |
---|
128 | ChangeFilenameExtension(name, string(lns), fnameCost); |
---|
129 | |
---|
130 | ffcost.SetFilename(fnameCost.c_str()); |
---|
131 | if (ffcost.OpenInMode(CFileIO::EE_Mode_w)) { |
---|
132 | cerr << "Opening of stream failed" << endl; |
---|
133 | abort();; |
---|
134 | } |
---|
135 | cout << "Saving debug to " << fnameCost << endl; |
---|
136 | ffcost.WriteChars("\n"); |
---|
137 | sprintf(lns, "#CntObjects = %d\n", costCntObjects); |
---|
138 | ffcost.WriteChars(lns); |
---|
139 | sprintf(lns, "#IndexToDebug = %d\n", costIndexDebug); |
---|
140 | ffcost.WriteChars(lns); |
---|
141 | ffcost.WriteChars("#File "); |
---|
142 | ffcost.WriteChars(fnameCost.c_str()); |
---|
143 | ffcost.WriteChars("\n"); |
---|
144 | ffcost.WriteChars("#==============================================\n"); |
---|
145 | |
---|
146 | cout << "#---------------------------------------" << endl; |
---|
147 | _streamOpened = true; |
---|
148 | } |
---|
149 | |
---|
150 | static void |
---|
151 | CloseCostStream() |
---|
152 | { |
---|
153 | if (_streamOpened) { |
---|
154 | char lns[255]; |
---|
155 | ffcost.WriteChars("#==============================================\n"); |
---|
156 | ffcost.WriteChars("#EndOfFile\n"); |
---|
157 | sprintf(lns, "#minCost = %8.6f minPos = %8.6f\n", minCost, minPos); |
---|
158 | ffcost.WriteChars(lns); |
---|
159 | sprintf(lns, "#maxCost = %8.6f maxPos = %8.6f\n", maxCost, maxPos); |
---|
160 | ffcost.WriteChars(lns); |
---|
161 | sprintf(lns, "#ratioMin/Max = %6.5f\n", |
---|
162 | minCost/maxCost); |
---|
163 | ffcost.WriteChars(lns); |
---|
164 | sprintf(lns, "#CntEval = %d\n", costEvalCnt); |
---|
165 | ffcost.WriteChars(lns); |
---|
166 | sprintf(lns, "#CntObjects = %d\n", costCntObjects); |
---|
167 | ffcost.WriteChars(lns); |
---|
168 | sprintf(lns, "#IndexToDebug = %d\n", costIndexDebug); |
---|
169 | ffcost.WriteChars(lns); |
---|
170 | sprintf(lns, "#MinPosAxis = %8.6f maxPosAxis = %8.6f\n", minPosAxis, maxPosAxis); |
---|
171 | ffcost.WriteChars(lns); |
---|
172 | ffcost.WriteChars("#File "); |
---|
173 | ffcost.WriteChars(fnameCost.c_str()); |
---|
174 | ffcost.WriteChars("\n"); |
---|
175 | ffcost.Close(); |
---|
176 | //cout << "#=======================================" << endl; |
---|
177 | _streamOpened = false; |
---|
178 | _alreadyDebugged = true; |
---|
179 | // Temporarily |
---|
180 | exit(0); |
---|
181 | } |
---|
182 | } |
---|
183 | |
---|
184 | static void |
---|
185 | ReportCostStream(float pos, float cost) |
---|
186 | { |
---|
187 | // Here we normalize a position to the interval <0-1> |
---|
188 | float posn = (pos - minPosAxis)/(maxPosAxis - minPosAxis); |
---|
189 | |
---|
190 | if (_streamOpened) { |
---|
191 | costEvalCnt++; |
---|
192 | if (cost < minCost) { |
---|
193 | minCost = cost; |
---|
194 | minPos = pos; |
---|
195 | } |
---|
196 | if (cost > maxCost) { |
---|
197 | maxCost = cost; |
---|
198 | maxPos = pos; |
---|
199 | } |
---|
200 | char lns[255]; |
---|
201 | sprintf(lns, "%8.6f %8.6f\n", posn, cost); |
---|
202 | //cout << lns << endl; |
---|
203 | ffcost.WriteChars(lns); |
---|
204 | } |
---|
205 | } |
---|
206 | #endif // _DEBUG_COSTFUNCTION |
---|
207 | |
---|
208 | //---------------------------------------------------------------- |
---|
209 | //---------- Implementation of CKTB tree with irregular ----------- |
---|
210 | //---------- placed splitting planes ----------------------------- |
---|
211 | //---------------------------------------------------------------- |
---|
212 | |
---|
213 | // default constructor |
---|
214 | CKTBABuildUp::CKTBABuildUp() |
---|
215 | { |
---|
216 | // verbose is set |
---|
217 | verbose = true; |
---|
218 | |
---|
219 | // Maximum depth of the tree is set and stack is allocated |
---|
220 | maxTreeDepth = MAX_HEIGHT; |
---|
221 | stackDepth = maxTreeDepth + 2; |
---|
222 | stackID = new GALIGN16 SInputData[stackDepth]; |
---|
223 | assert(stackID); |
---|
224 | stackIndex = 0; |
---|
225 | return; |
---|
226 | } |
---|
227 | |
---|
228 | // destructor |
---|
229 | CKTBABuildUp::~CKTBABuildUp() |
---|
230 | { |
---|
231 | delete [] stackID; |
---|
232 | stackID = 0; |
---|
233 | } |
---|
234 | |
---|
235 | void |
---|
236 | CKTBABuildUp::ProvideID(ostream &app) |
---|
237 | { |
---|
238 | bool tempvar; |
---|
239 | |
---|
240 | Environment::GetSingleton()->GetBoolValue("BSP.splitclip", tempvar); |
---|
241 | if (tempvar) |
---|
242 | app << "#BSP.splitClip \t\tChange of bboxes(splitclip) " |
---|
243 | << "dis/en\n" << tempvar << "\n"; |
---|
244 | Environment::GetSingleton()->GetBoolValue("BSP.emptyCut", tempvar); |
---|
245 | app << "#BSP.emptyCut\t\tLate cutting off empty space in leaves" |
---|
246 | << " dis/en\n" << tempvar << "\n"; |
---|
247 | |
---|
248 | if (tempvar) { |
---|
249 | app << "#BSP.absMaxAllowedDepth\tMaximum abs depth for empty cutting\n"; |
---|
250 | app << absMaxAllowedDepth << "\n"; |
---|
251 | app << "#BSP.maxEmptyCutDepth\tMaximum allowed depth for late cutting" |
---|
252 | << "(0-6)\n"; |
---|
253 | app << maxEmptyCutDepth << "\n"; |
---|
254 | } |
---|
255 | |
---|
256 | string termCrit; |
---|
257 | Environment::GetSingleton()->GetStringValue("BSP.termCrit", termCrit); |
---|
258 | app << "#BSP.termCrit\t\tTermination criteria to build up BSP tree\n"; |
---|
259 | app << termCrit << "\n"; |
---|
260 | |
---|
261 | maxCountTrials = 0; |
---|
262 | if ( (!termCrit.compare("auto")) && |
---|
263 | (!termCrit.compare("auto2")) ) { |
---|
264 | // everything except auto settings, when depth is determined |
---|
265 | // It should be reported for adhoc and possibly others |
---|
266 | Environment::GetSingleton()->GetIntValue("BSP.maxDepthAllowed", |
---|
267 | maxDepthAllowed); |
---|
268 | Environment::GetSingleton()->GetIntValue("BSP.maxListLength", |
---|
269 | maxListLength); |
---|
270 | app << "#MaxDepth (Dmax)\tMaximal allowed depth of the BSP tree\n"; |
---|
271 | app << maxDepthAllowed << "\n"; |
---|
272 | app << "#MaxListLength (Noilf)\tMaximal number of solids in one cell\n"; |
---|
273 | app << maxListLength << "\n"; |
---|
274 | // maximum number of trials to further subdivide |
---|
275 | maxCountTrials = (int)(1.0 + 0.2 * (float)maxDepthAllowed); |
---|
276 | if (maxCountTrials < 3) |
---|
277 | maxCountTrials = 3; |
---|
278 | } |
---|
279 | else { |
---|
280 | if (!termCrit.compare("auto2") ) { |
---|
281 | Environment::GetSingleton()->GetIntValue("BSP.maxListLength", |
---|
282 | maxListLength); |
---|
283 | app << "#MaxDepth (Dmax)\tMaximal allowed depth of the BSP tree\n"; |
---|
284 | } |
---|
285 | } |
---|
286 | |
---|
287 | float eCt, eCi, eCd; |
---|
288 | Environment::GetSingleton()->GetFloatValue("BSP.decisionCost", eCd); |
---|
289 | Environment::GetSingleton()->GetFloatValue("BSP.intersectionCost", eCi); |
---|
290 | Environment::GetSingleton()->GetFloatValue("BSP.traversalCost", eCt); |
---|
291 | |
---|
292 | // Ci should no be changed from 1.0, only Cd and Ct should be changed |
---|
293 | app << "#SetBSP.(Cd, Ci, Ct) \tDecision, Intersection, "; |
---|
294 | app << "and Traversal costs\n"; |
---|
295 | app << " ( " << eCd << ", " << eCi << " ," << eCt << " )\n"; |
---|
296 | |
---|
297 | return; |
---|
298 | } |
---|
299 | |
---|
300 | // ------------------------------------------------------- |
---|
301 | // the next two axes for a given one |
---|
302 | const CKTBAxes::Axes |
---|
303 | CKTBABuildUp::oaxes[3][2]= |
---|
304 | {{CKTBAxes::EE_Y_axis, CKTBAxes::EE_Z_axis}, |
---|
305 | {CKTBAxes::EE_Z_axis, CKTBAxes::EE_X_axis}, |
---|
306 | {CKTBAxes::EE_X_axis, CKTBAxes::EE_Y_axis}}; |
---|
307 | |
---|
308 | // ------------------------------------------------------- |
---|
309 | // compare function passed to quicksort |
---|
310 | int |
---|
311 | CKTBABuildUp::Compare(const SItem *p, const SItem *q) |
---|
312 | { |
---|
313 | register float pv = p->pos; |
---|
314 | register float qv = q->pos; |
---|
315 | |
---|
316 | if (pv < qv) |
---|
317 | return 1; |
---|
318 | else |
---|
319 | if (pv > qv) |
---|
320 | return -1; |
---|
321 | else |
---|
322 | // the coordinates are equal |
---|
323 | if ( (p->IsRightBoundary()) && |
---|
324 | (q->IsLeftBoundary()) ) |
---|
325 | return 1; // right_boundary < left_boundary |
---|
326 | else |
---|
327 | if ( (p->IsLeftBoundary()) && |
---|
328 | (q->IsRightBoundary()) ) |
---|
329 | return -1; // left_boundary > right_boundary |
---|
330 | |
---|
331 | return 0; // coordinates are equal, the same value and type |
---|
332 | } |
---|
333 | |
---|
334 | // -------------------------------------------- |
---|
335 | // This is sorting using quicksort |
---|
336 | void |
---|
337 | CKTBABuildUp::SortOneAxis(SItemVec &itemvec, int cnt, int * const stack) |
---|
338 | { |
---|
339 | // the pointer to the stack |
---|
340 | int stackUk = 0; |
---|
341 | // setting initial beg and end index for the whole array |
---|
342 | stack[++stackUk] = 0; |
---|
343 | stack[++stackUk] = cnt - 1; |
---|
344 | SItem auxSwap; |
---|
345 | int e, b, i, j; |
---|
346 | |
---|
347 | while ( stackUk !=0 ) { |
---|
348 | // retrieving indeces from the stack |
---|
349 | j = e = stack[stackUk--]; // begin and end in the array |
---|
350 | i = b = stack[stackUk--]; // auxiliary indeces |
---|
351 | |
---|
352 | // selecting pivot .. in the best case median |
---|
353 | SItem X = itemvec[(i+j) / 2]; |
---|
354 | do { |
---|
355 | while (Compare(&(itemvec[i]), &X) > 0) |
---|
356 | i++; // find the array[i] > array[x]=pivot |
---|
357 | while (Compare(&(itemvec[j]), &X) < 0) |
---|
358 | j--; // find the array[j] < array[x]=pivot |
---|
359 | if (i < j) { // swap the elements |
---|
360 | auxSwap = itemvec[i]; |
---|
361 | itemvec[i] = itemvec[j]; |
---|
362 | itemvec[j] = auxSwap; |
---|
363 | i++; j--; |
---|
364 | } |
---|
365 | else |
---|
366 | if (i == j) { |
---|
367 | i++; |
---|
368 | j--; |
---|
369 | } |
---|
370 | } |
---|
371 | while (i <= j); |
---|
372 | // Now all the elements on the left are smaller than pivot and |
---|
373 | // all the right are larger than pivot |
---|
374 | #if 0 |
---|
375 | #ifdef _DEBUG |
---|
376 | int t; |
---|
377 | for (t = b; t < j; t++) { |
---|
378 | if (X.pos < itemvec[t].pos) { |
---|
379 | cout << "Problem 1 for t = " << t << endl; |
---|
380 | cout << "X->pos = " << X.pos << "a[t]= " << itemvec[t].pos << endl; |
---|
381 | } |
---|
382 | } |
---|
383 | for (t = i; t < e; t++) { |
---|
384 | if (X.pos > itemvec[t].pos) { |
---|
385 | cout << "Problem 2 for t = " << t << endl; |
---|
386 | cout << "X->pos = " << X.pos << "a[t]= " << itemvec[t].pos << endl; |
---|
387 | } |
---|
388 | } |
---|
389 | #endif |
---|
390 | #endif |
---|
391 | if (b < j) { // go to the left |
---|
392 | stack[++stackUk] = b; |
---|
393 | stack[++stackUk] = j; |
---|
394 | } |
---|
395 | if (i < e) { // go to the right |
---|
396 | stack[++stackUk] = i; |
---|
397 | stack[++stackUk] = e; |
---|
398 | } |
---|
399 | // Just a check |
---|
400 | assert(stackUk <= cnt); |
---|
401 | } // while (stackUk) |
---|
402 | |
---|
403 | return; |
---|
404 | } |
---|
405 | |
---|
406 | void |
---|
407 | CKTBABuildUp::CopyToAuxArray(const SItemVec &bounds, SItemVecRadix &aux) |
---|
408 | { |
---|
409 | // assume that both arrays are of the same size |
---|
410 | assert(bounds.size() <= aux.capacity()); |
---|
411 | |
---|
412 | #if 1 |
---|
413 | // source iterator |
---|
414 | SItemVec::const_iterator src = bounds.begin(); |
---|
415 | for (SItemVecRadix::iterator it = aux.begin(); |
---|
416 | it != aux.end(); |
---|
417 | it++, src++) |
---|
418 | { |
---|
419 | *it = *src; // copy one elem |
---|
420 | } |
---|
421 | #else |
---|
422 | // Attempt for vectorization |
---|
423 | int i; |
---|
424 | const int cnt = aux.size(); |
---|
425 | for (i = 0; i < cnt; i++) { |
---|
426 | aux[i] = bounds[i]; |
---|
427 | } |
---|
428 | #endif |
---|
429 | |
---|
430 | return; |
---|
431 | } |
---|
432 | |
---|
433 | // ----------------------------------------------------------------- |
---|
434 | // The first pass of radix sort setting the links |
---|
435 | void |
---|
436 | CKTBABuildUp::RadixPassHoffset11(SItemVecRadix &bounds, int bit, |
---|
437 | SRadix *rb, float offset, |
---|
438 | SItemRadix **start) |
---|
439 | { |
---|
440 | // preparing the hash table |
---|
441 | memset(rb, 0, sizeof(SRadix) * RXBUFS30); |
---|
442 | |
---|
443 | SItemRadix *p; |
---|
444 | SItemRadix *q; |
---|
445 | //SRadix *r; |
---|
446 | |
---|
447 | // linearly process the input array |
---|
448 | //for (SItemVecRadix::iterator it = bounds.begin(); it != bounds.end(); it++) |
---|
449 | const int cnt = bounds.size(); |
---|
450 | for (int i = 0; i < cnt; i++) |
---|
451 | { |
---|
452 | // Take the element linearly from the array |
---|
453 | //p = &(*it); |
---|
454 | p = &(bounds[i]); |
---|
455 | |
---|
456 | // add offset to get positive value to be sorted |
---|
457 | p->pos += offset; |
---|
458 | assert(p->pos >= 0.f); |
---|
459 | |
---|
460 | // compute the index of the bucket |
---|
461 | unsigned int *val = (unsigned int*)&(p->pos); |
---|
462 | unsigned int bucket = (( (*val) >> bit) & (RXBUFS30 - 1)); |
---|
463 | assert( bucket < RXBUFS30 ); |
---|
464 | // compute the address of correct bucket |
---|
465 | //r = rb + bucket; |
---|
466 | if (!rb[bucket].beg) { |
---|
467 | rb[bucket].end = rb[bucket].beg = p; // inserting into empty cell, mark begin |
---|
468 | p->next = 0; // new item is the end of chain |
---|
469 | } |
---|
470 | else { |
---|
471 | // if the end of bounding box |
---|
472 | if (p->IsRightBoundary()) { |
---|
473 | // right boundary - store item at the beginning of the group |
---|
474 | p->next = rb[bucket].beg; |
---|
475 | rb[bucket].beg = p; |
---|
476 | } |
---|
477 | else { |
---|
478 | // left boundary - store item at the end of the group |
---|
479 | p->next = 0; // it is the end elem |
---|
480 | rb[bucket].end->next = p; // chain last item to new item |
---|
481 | rb[bucket].end = p; |
---|
482 | } |
---|
483 | } |
---|
484 | } // for all input data |
---|
485 | |
---|
486 | // append groups together |
---|
487 | // q used as start item |
---|
488 | SItemRadix **fset = &q; |
---|
489 | |
---|
490 | for(int j = 0; j < RXBUFS30; j++) { |
---|
491 | // only used elements |
---|
492 | if (rb[j].beg) { |
---|
493 | *fset = rb[j].beg; // store pointer to the next group |
---|
494 | fset = &(rb[j].end->next); // prepare group's end for update |
---|
495 | } |
---|
496 | } // for all buckets |
---|
497 | |
---|
498 | *start = q; |
---|
499 | return; |
---|
500 | } |
---|
501 | |
---|
502 | // radix sort pass starting with 'bit' over 'axis', using buckets in 'rb' |
---|
503 | void |
---|
504 | CKTBABuildUp::RadixPass11(SItemRadix **start, int cnt, int bit, SRadix *rb) |
---|
505 | { |
---|
506 | // preparing the hash table |
---|
507 | memset(rb, 0, sizeof(SRadix) * RXBUFS30); |
---|
508 | |
---|
509 | // list grouping |
---|
510 | SItemRadix *p = *start; |
---|
511 | SItemRadix *q; |
---|
512 | //SRadix *r; |
---|
513 | |
---|
514 | // process the items using links |
---|
515 | for (int i = 0; i < cnt; i++) { |
---|
516 | assert(p); |
---|
517 | unsigned int *val = (unsigned int*)&(p->pos); |
---|
518 | unsigned int bucket = (( (*val) >> bit) & (RXBUFS30 - 1)); |
---|
519 | assert(bucket < RXBUFS30); |
---|
520 | //r = rb + bucket; |
---|
521 | if (!rb[bucket].beg) |
---|
522 | rb[bucket].beg = p; // inserting into empty cell, mark begin |
---|
523 | else |
---|
524 | rb[bucket].end->next = p; // chain last item to new item |
---|
525 | |
---|
526 | rb[bucket].end = p; // update the end of group |
---|
527 | q = p->next; // save the next position |
---|
528 | p->next = 0; // new item is the end of chain |
---|
529 | p = q; |
---|
530 | } // for all items |
---|
531 | |
---|
532 | // append groups together |
---|
533 | //r = rb; |
---|
534 | // q used as start item |
---|
535 | SItemRadix **fset = &q; |
---|
536 | |
---|
537 | for(int j = 0; j < RXBUFS30; j++) |
---|
538 | // only used elements |
---|
539 | if (rb[j].beg) { |
---|
540 | *fset = rb[j].beg; // store pointer to the next group |
---|
541 | fset = &(rb[j].end->next); // prepare group's end for update |
---|
542 | } |
---|
543 | |
---|
544 | *start = q; |
---|
545 | return; |
---|
546 | } |
---|
547 | |
---|
548 | // radix sort pass starting with 'bit' over 'axis', using buckets in 'rb' |
---|
549 | void |
---|
550 | CKTBABuildUp::RadixPassOffset10(SItemRadix **start, int cnt, int bit, |
---|
551 | SRadix *rb, float offset) |
---|
552 | { |
---|
553 | // preparing the hash table |
---|
554 | memset(rb, 0, sizeof(SRadix) * RXBUFS30_2); |
---|
555 | |
---|
556 | // list grouping |
---|
557 | SItemRadix *p = *start; |
---|
558 | SItemRadix *q; |
---|
559 | //SRadix *r; |
---|
560 | |
---|
561 | // process the items using links |
---|
562 | for (int i = 0; i < cnt; i++) { |
---|
563 | assert(p); |
---|
564 | unsigned int *val = (unsigned int*)&(p->pos); |
---|
565 | unsigned int bucket = (( (*val) >> bit) & (RXBUFS30_2 - 1)); |
---|
566 | assert(bucket < RXBUFS30_2); |
---|
567 | //r = rb + bucket; |
---|
568 | if (!(rb[bucket].beg)) { |
---|
569 | rb[bucket].beg = p; // inserting into empty cell, mark begin |
---|
570 | } |
---|
571 | else { |
---|
572 | rb[bucket].end->next = p; // chain last item to new item |
---|
573 | } |
---|
574 | |
---|
575 | rb[bucket].end = p; // update the end of group |
---|
576 | |
---|
577 | // Compute the correct value back, using the offset for the |
---|
578 | // first pass |
---|
579 | p->pos -= offset; |
---|
580 | |
---|
581 | // go to the next item |
---|
582 | q = p->next; // save the next position |
---|
583 | p->next = 0; // new item is the end of chain |
---|
584 | p = q; // take the next item |
---|
585 | } // for all items |
---|
586 | |
---|
587 | // append groups together and set bidirectional links |
---|
588 | //r = rb; |
---|
589 | SItemRadix *prev = 0; |
---|
590 | for (int j = 0; j < RXBUFS30_2; j++) { |
---|
591 | if (rb[j].beg) { |
---|
592 | if (prev) { |
---|
593 | // set forward link |
---|
594 | prev->next = rb[j].beg; |
---|
595 | } |
---|
596 | prev = rb[j].end; |
---|
597 | } |
---|
598 | } // for i |
---|
599 | |
---|
600 | // Find the first item in the list |
---|
601 | //r = rb; |
---|
602 | for (int k = 0; k < RXBUFS30_2; k++) { |
---|
603 | if (rb[k].beg) { |
---|
604 | // find the beginning of the chain |
---|
605 | *start = rb[k].beg; |
---|
606 | break; |
---|
607 | } |
---|
608 | } // for |
---|
609 | |
---|
610 | return; |
---|
611 | } |
---|
612 | |
---|
613 | void |
---|
614 | CKTBABuildUp::CopyFromAuxArray(SItemRadix *sorted, SItemVec &bounds) |
---|
615 | { |
---|
616 | // source iterator |
---|
617 | SItemRadix *src = sorted; |
---|
618 | //for (SItemVec::iterator it = bounds.begin(); it != bounds.end(); it++) |
---|
619 | |
---|
620 | int i; |
---|
621 | const int cnt = bounds.size(); |
---|
622 | for (i = 0; i < cnt; i++) |
---|
623 | { |
---|
624 | bounds[i] = *src; // copy one elem, forgetting the pointer 'next' |
---|
625 | src = src->next; |
---|
626 | } |
---|
627 | |
---|
628 | return; |
---|
629 | } |
---|
630 | |
---|
631 | |
---|
632 | // --------------------------------------------------------------- |
---|
633 | // sort the boundaries of objects' bounding boxes along all 3 axes |
---|
634 | void |
---|
635 | CKTBABuildUp::SortAxes(SInputData *data) |
---|
636 | { |
---|
637 | // Note that cnt is the number of boundaries = odd number |
---|
638 | assert(data); |
---|
639 | assert(data->count); |
---|
640 | |
---|
641 | CTimer timer; |
---|
642 | timer.Start(); |
---|
643 | |
---|
644 | // the number of boundaries |
---|
645 | int cnt = 2*data->count; |
---|
646 | |
---|
647 | if (!_useRadixSort) { |
---|
648 | cout << "Sorting by quicksort " << flush; |
---|
649 | #if 1 |
---|
650 | // this is the worst case allocation !!! |
---|
651 | int *stackQuickSort = new GALIGN16 int [cnt+1]; |
---|
652 | if (stackQuickSort == NULL) { |
---|
653 | cerr << " ktbai.cpp: quicksort allocation failed\n"; |
---|
654 | exit(3);; |
---|
655 | } |
---|
656 | cout << " Qsort, sizeof(SItem)=" << sizeof(SItem) |
---|
657 | << " size(vec[0])= " << sizeof(data->xvec[0]) << endl; |
---|
658 | assert(cnt == data->xvec->size()); |
---|
659 | assert(cnt == data->yvec->size()); |
---|
660 | assert(cnt == data->zvec->size()); |
---|
661 | // Sort all three axis by Quicksort |
---|
662 | //cout << "Sort x" << endl; |
---|
663 | SortOneAxis(*(data->xvec), data->xvec->size(), stackQuickSort); |
---|
664 | //cout << "Check x" << endl; |
---|
665 | Check1List(data->xvec, 0, data->xvec->size()/2); |
---|
666 | //cout << "Sort y" << endl; |
---|
667 | SortOneAxis(*(data->yvec), data->yvec->size(), stackQuickSort); |
---|
668 | //cout << "Check y" << endl; |
---|
669 | Check1List(data->yvec, 0, data->yvec->size()/2); |
---|
670 | //cout << "Sort z" << endl; |
---|
671 | SortOneAxis(*(data->zvec), data->zvec->size(), stackQuickSort); |
---|
672 | //cout << "Check z" << endl; |
---|
673 | Check1List(data->zvec, 0, data->zvec->size()/2); |
---|
674 | |
---|
675 | // delete the data |
---|
676 | delete [] stackQuickSort; |
---|
677 | #endif |
---|
678 | #if 0 |
---|
679 | sort(data->xvec->begin(), data->xvec->end()); |
---|
680 | sort(data->yvec->begin(), data->yvec->end()); |
---|
681 | sort(data->zvec->begin(), data->zvec->end()); |
---|
682 | #endif |
---|
683 | #if 0 |
---|
684 | qsort(&(data->xvec[0]), data->xvec->size(), sizeof(data->xvec[0]), |
---|
685 | (int(*)(const void*, const void*))(&Compare)); |
---|
686 | Check1List(data->xvec, 0, data->xvec->size()/2); |
---|
687 | |
---|
688 | qsort(&(data->yvec[0]), data->yvec->size(), sizeof(data->yvec[0]), |
---|
689 | (int(*)(const void*, const void*))(&Compare)); |
---|
690 | qsort(&(data->zvec[0]), data->zvec->size(), sizeof(data->zvec[0]), |
---|
691 | (int(*)(const void*, const void*))(&Compare)); |
---|
692 | #endif |
---|
693 | } |
---|
694 | else { |
---|
695 | // ----------------------------------------------- |
---|
696 | // Implementation by RadixSort with 3 passes, faster by 30% or so |
---|
697 | // than 4-passes RadixSort, see ktbi.cpp |
---|
698 | cout << "Sorting by radixsort3 " << flush; |
---|
699 | SRadix *rb = new GALIGN16 SRadix[RXBUFS30]; |
---|
700 | assert(rb); |
---|
701 | // the auxiliary array for sorting |
---|
702 | SItemVecRadix *aux = new GALIGN16 SItemVecRadix(); |
---|
703 | assert(aux); |
---|
704 | aux->resize(cnt); |
---|
705 | // change axis |
---|
706 | for(int i = 0; i < 3; i++) { |
---|
707 | // Offset to get only positive values to be sorted |
---|
708 | float offset = -(wBbox.Min(i)); |
---|
709 | // Get a single array of bounds |
---|
710 | SItemVec *bounds = data->GetItemVec(i); |
---|
711 | assert(bounds); |
---|
712 | // sort 3 times using 10 bits in one pass |
---|
713 | CopyToAuxArray(*bounds, *aux); |
---|
714 | // take the first elem and start radix sort |
---|
715 | SItemRadix *start = 0; |
---|
716 | // first pass: bits 0-10 |
---|
717 | RadixPassHoffset11(*aux, RXBITS30 * 0, rb, offset, &start); |
---|
718 | // second pass: bits 11-21 |
---|
719 | RadixPass11(&start, cnt, RXBITS30 * 1, rb); |
---|
720 | // third pass: bits 22-31 (bit 32 is sign) |
---|
721 | RadixPassOffset10(&start, cnt, RXBITS30 * 2, rb, offset); |
---|
722 | // Copy the sorted data back to the array, forgetting pointer 'next' |
---|
723 | CopyFromAuxArray(start, *bounds); |
---|
724 | } |
---|
725 | // delete aux array |
---|
726 | delete aux; |
---|
727 | delete [] rb; |
---|
728 | // end of radix sort |
---|
729 | } |
---|
730 | |
---|
731 | timer.Stop(); |
---|
732 | // ------------------------------------------ |
---|
733 | cout << " finished in " << timer.UserTime() << " [s] - user time " << endl; |
---|
734 | |
---|
735 | #ifdef _DEBUG |
---|
736 | // check if the lists are correctly sorted .. in debug |
---|
737 | // DEBUG << "SortAxis check\n" << flush; |
---|
738 | Check3List(data); |
---|
739 | #endif |
---|
740 | |
---|
741 | return; |
---|
742 | } |
---|
743 | |
---|
744 | // test if the lists are correctly sorted |
---|
745 | void |
---|
746 | CKTBABuildUp::Check3List(SInputData *data) |
---|
747 | { |
---|
748 | #ifndef AVOIDCHECKLIST |
---|
749 | #ifdef _DEBUG |
---|
750 | assert(data); |
---|
751 | if (data->xvec->size() != (unsigned int)data->count*2) { |
---|
752 | cerr << "The number of X boundaries does not match" << endl; |
---|
753 | abort();; |
---|
754 | } |
---|
755 | if (data->yvec->size() != (unsigned int)data->count*2) { |
---|
756 | cerr << "The number of Y boundaries does not match" << endl; |
---|
757 | abort();; |
---|
758 | } |
---|
759 | if (data->zvec->size() != (unsigned int)data->count*2) { |
---|
760 | cerr << "The number of Z boundaries does not match" << endl; |
---|
761 | abort();; |
---|
762 | } |
---|
763 | Check1List(data, 0, data->count); |
---|
764 | Check1List(data, 1, data->count); |
---|
765 | Check1List(data, 2, data->count); |
---|
766 | #endif // _DEBUG |
---|
767 | #endif // AVOIDCHECKLIST |
---|
768 | return; |
---|
769 | } |
---|
770 | |
---|
771 | // test if one list is correctly sorted |
---|
772 | void |
---|
773 | CKTBABuildUp::Check1List(SInputData *data, int axis, int countExpected) |
---|
774 | { |
---|
775 | #ifndef AVOIDCHECKLIST |
---|
776 | #ifdef _DEBUG |
---|
777 | assert((axis >= 0) && (axis < 3)); |
---|
778 | SItemVec *vec = data->GetItemVec(axis); |
---|
779 | assert(vec); |
---|
780 | if (countExpected) |
---|
781 | Check1List(vec, axis, countExpected); |
---|
782 | else { |
---|
783 | if (vec->size() > 0) { |
---|
784 | cerr << "The array of objects should be of zero size"<<endl; |
---|
785 | abort();; |
---|
786 | } |
---|
787 | } |
---|
788 | #endif // _DEBUG |
---|
789 | #endif // AVOIDCHECKLIST |
---|
790 | } |
---|
791 | |
---|
792 | // test if one list is correctly sorted |
---|
793 | void |
---|
794 | CKTBABuildUp::Check1List(SItemVec *vec, int axis, int countExpected) |
---|
795 | { |
---|
796 | #ifndef AVOIDCHECKLIST |
---|
797 | #ifdef _DEBUG |
---|
798 | int cntl,cntr; // the number of left/right boundaries |
---|
799 | |
---|
800 | // DEBUG << "Check1List starting\n"; |
---|
801 | cntl = 0; // the number of left boundaries |
---|
802 | cntr = 0; // the number of right boundaries |
---|
803 | int cntDups = 0; // the number of duplications for current position |
---|
804 | |
---|
805 | // the position to check |
---|
806 | SItemVec::iterator prev = vec->begin(); |
---|
807 | |
---|
808 | // DEBUG << p->value[i] << "\n"; |
---|
809 | if ( (*prev).IsLeftBoundary()) { |
---|
810 | cntl++; |
---|
811 | cntDups++; |
---|
812 | } |
---|
813 | else { |
---|
814 | cntr++; |
---|
815 | cntDups--; |
---|
816 | } |
---|
817 | // the next item |
---|
818 | SItemVec::iterator it = vec->begin(); |
---|
819 | it++; |
---|
820 | // start from the second item |
---|
821 | int index = 1; |
---|
822 | bool firstDupsProb = false; |
---|
823 | for ( ; it != vec->end(); it++, prev++, index++) |
---|
824 | { |
---|
825 | const SItem &p = *it; |
---|
826 | |
---|
827 | if (p.obj->ToBeRemoved()) { |
---|
828 | cout << "Object to be removed, obj = " |
---|
829 | << p.obj << " -- it should not happen" << endl; |
---|
830 | } |
---|
831 | |
---|
832 | // DEBUG << p->value[i] << "\n"; |
---|
833 | if (p.IsLeftBoundary()) { |
---|
834 | cntl++; |
---|
835 | cntDups++; |
---|
836 | } |
---|
837 | else { |
---|
838 | cntr++; |
---|
839 | cntDups--; |
---|
840 | } |
---|
841 | |
---|
842 | if (cntDups < 0) { |
---|
843 | cerr << "The array is sorted in wrong way, cntDups = " |
---|
844 | << cntDups << " index= " << index << " indexMax=" |
---|
845 | << countExpected*2 << endl; |
---|
846 | if (!firstDupsProb) { |
---|
847 | int imin = index-3; |
---|
848 | if (imin < 0) imin = 0; |
---|
849 | int imax = index+3; |
---|
850 | if (imax > countExpected*2) imax = countExpected*2; |
---|
851 | for (int i = imin; i < imax; i++) { |
---|
852 | cout << "i= " << i << " pos = " << (*vec)[i].pos; |
---|
853 | if ((*vec)[i].IsLeftBoundary()) |
---|
854 | cout << " L "; |
---|
855 | else |
---|
856 | cout << " R "; |
---|
857 | cout << (*vec)[i].obj << endl; |
---|
858 | } |
---|
859 | } |
---|
860 | firstDupsProb = true; |
---|
861 | } |
---|
862 | |
---|
863 | if ( (*prev).pos > p.pos) { |
---|
864 | cerr << "The array is for axis=" <<(int)axis<<" incorrectly sorted\n"; |
---|
865 | cerr << "prevPos = " << (*prev).pos << " curr->pos=" |
---|
866 | << p.pos << "\n"; |
---|
867 | abort();; |
---|
868 | } |
---|
869 | else { |
---|
870 | if ( ((*prev).pos == p.pos) && |
---|
871 | ( (*prev).IsLeftBoundary()) && |
---|
872 | ( (*it).IsRightBoundary()) ) { |
---|
873 | if (countExpected > 1) { |
---|
874 | cerr << "The right and left boundary are incorrectly sorted, axis = " |
---|
875 | << axis << "\n"; |
---|
876 | int i = 0; |
---|
877 | for (SItemVec::iterator itt = vec->begin(); itt != vec->end(); itt++, i++) |
---|
878 | { |
---|
879 | cout << i << " = "; |
---|
880 | if ((*itt).IsLeftBoundary()) |
---|
881 | cout << "L"; else cout << "R"; |
---|
882 | cout << " obj = " << (*itt).obj << " pos = " << (*itt).pos << endl; |
---|
883 | } |
---|
884 | } // if more than one object |
---|
885 | } |
---|
886 | } |
---|
887 | } // for all items |
---|
888 | |
---|
889 | if (cntl != cntr) { |
---|
890 | cerr << "The #left boundaries <> #right boundaries\n"; |
---|
891 | cerr << " #left boundaries= " << cntl << " #right boundaries= " |
---|
892 | << cntr << " axis= " << (int)axis << "\n"; |
---|
893 | abort();; |
---|
894 | } |
---|
895 | |
---|
896 | if (countExpected > 0) { |
---|
897 | if (cntl != countExpected) { |
---|
898 | cerr << "The number of found left boundaries = " << cntl |
---|
899 | << " does not equal to expected count = " << countExpected << endl; |
---|
900 | } |
---|
901 | if (cntr != countExpected) { |
---|
902 | cerr << "The number of found right boundaries = " << cntr |
---|
903 | << " does not equal to expected count = " << countExpected << endl; |
---|
904 | } |
---|
905 | } // if checking of count is allowed |
---|
906 | |
---|
907 | cerr << flush; |
---|
908 | #endif // _DEBUG |
---|
909 | #endif // AVOIDCHECKLIST |
---|
910 | } |
---|
911 | |
---|
912 | // Init required parameters |
---|
913 | void |
---|
914 | CKTBABuildUp::InitReqPref(SReqPrefParams *pars) |
---|
915 | { |
---|
916 | // nothing is obligatory as default |
---|
917 | pars->reqPosition = Limits::Infinity; |
---|
918 | pars->reqAxis = CKTBAxes::EE_Leaf; |
---|
919 | pars->useReqAxis = false; |
---|
920 | |
---|
921 | // the values for automatic termination criteria, since it was |
---|
922 | // not subdivided |
---|
923 | pars->ratioLast = 1000.0; |
---|
924 | pars->ratioLastButOne = 1000.0; |
---|
925 | pars->failedSubDivCount = 0; |
---|
926 | |
---|
927 | Environment::GetSingleton()->GetIntValue("BSP.axisSelectionAlg", |
---|
928 | _algorithmForAxisSelection); |
---|
929 | if (_algorithmForAxisSelection != 0) { |
---|
930 | // The axis as prefered one - testing all 3 axes. Start |
---|
931 | // from the axis cutting the longest side of the box |
---|
932 | pars->reqAxis = (CKTBAxes::Axes)(wBbox.Diagonal().DrivingAxis()); |
---|
933 | } |
---|
934 | |
---|
935 | return; |
---|
936 | } |
---|
937 | |
---|
938 | // creates all the auxiliary structures for building up CKTB tree |
---|
939 | CKTBABuildUp::SInputData* |
---|
940 | CKTBABuildUp::Init(ObjectContainer *objlist, const AxisAlignedBox3 &box) |
---|
941 | { |
---|
942 | #ifdef _RANDOMIZE_POSITION |
---|
943 | //world->_environment.GetFloat("SetBSP.randomizePosition.Eps", randomEps); |
---|
944 | #endif // _RANDOMIZE_POSITION |
---|
945 | |
---|
946 | #ifdef _KTB_CONSTR_STATS |
---|
947 | _stats_interiorCount = 0; |
---|
948 | _stats_bboxCount = 0; |
---|
949 | _stats_leafNodeCount = 0; |
---|
950 | _stats_emptyLeftNodeCount = 0; |
---|
951 | // Aggregate statistics |
---|
952 | _maxDepth = 0; |
---|
953 | _sumLeafDepth = 0; |
---|
954 | _sumFullLeafDepth = 0; |
---|
955 | _sumObjectRefCount = 0; |
---|
956 | _maxObjectRefInLeaf = 0; |
---|
957 | // surface areas |
---|
958 | _sumSurfaceAreaLeaves = 0.f; |
---|
959 | _sumSurfaceAreaMULcntLeaves = 0.f; |
---|
960 | _sumSurfaceAreaInteriorNodes = 0.f; |
---|
961 | #endif |
---|
962 | // If to print out the tree during contruction |
---|
963 | Environment::GetSingleton()->GetBoolValue("BSP.printCuts", _printCuts); |
---|
964 | |
---|
965 | // if to cut off empty space in postprocessing and how it is performed |
---|
966 | Environment::GetSingleton()->GetBoolValue("BSP.emptyCut", cutEmptySpace); |
---|
967 | Environment::GetSingleton()->GetBoolValue("BSP.useRadixSort", _useRadixSort); |
---|
968 | Environment::GetSingleton()->GetIntValue("BSP.absMaxAllowedDepth", |
---|
969 | absMaxAllowedDepth); |
---|
970 | Environment::GetSingleton()->GetIntValue("BSP.maxEmptyCutDepth", |
---|
971 | maxEmptyCutDepth); |
---|
972 | Environment::GetSingleton()->GetIntValue("BSP.algAutoTermination", |
---|
973 | algorithmAutoTermination); |
---|
974 | Environment::GetSingleton()->GetFloatValue("BSP.biasFreeCuts", |
---|
975 | biasFreeCuts); |
---|
976 | #ifdef _BIDIRLISTS |
---|
977 | // if to clip the bounding boxes |
---|
978 | Environment::GetSingleton()->GetBoolValue("BSP.splitclip", splitClip); |
---|
979 | #else |
---|
980 | // Without bidirectional list we cannot make split clipping |
---|
981 | splitClip = false; |
---|
982 | #endif // _BIDIRLISTS |
---|
983 | |
---|
984 | // if to make tagging lists inside the tree |
---|
985 | Environment::GetSingleton()->GetBoolValue("BSP.minBoxes.use", |
---|
986 | makeMinBoxes); |
---|
987 | Environment::GetSingleton()->GetBoolValue("BSP.minBoxes.tight", |
---|
988 | makeTightMinBoxes); |
---|
989 | Environment::GetSingleton()->GetIntValue("BSP.minBoxes.minObjects", |
---|
990 | minObjectsToCreateMinBox); |
---|
991 | Environment::GetSingleton()->GetIntValue("BSP.minBoxes.minDepthDistance", |
---|
992 | minDepthDistanceBetweenMinBoxes); |
---|
993 | Environment::GetSingleton()->GetFloatValue("BSP.minBoxes.minSA2ratio", |
---|
994 | minSA2ratioMinBoxes); |
---|
995 | |
---|
996 | // How many items can be allocated at once |
---|
997 | int maxItemsAtOnce = 1; |
---|
998 | if (makeMinBoxes) { |
---|
999 | #ifdef _KTB8Bytes |
---|
1000 | // We need to allocate for boxes the memory in a row |
---|
1001 | maxItemsAtOnce = 5; // 8x5=40 = 16+24; |
---|
1002 | #else |
---|
1003 | maxItemsAtOnce = 4; // 12x4=48 = 24+24; |
---|
1004 | #endif // _KTB8Bytes |
---|
1005 | assert(minObjectsToCreateMinBox >= 1); |
---|
1006 | assert(minDepthDistanceBetweenMinBoxes >= 0); |
---|
1007 | assert(minDepthDistanceBetweenMinBoxes <= 50); |
---|
1008 | } |
---|
1009 | |
---|
1010 | // Initiate the allocator |
---|
1011 | InitAux(0, MAX_HEIGHT - 1, maxItemsAtOnce); |
---|
1012 | |
---|
1013 | // since six planes are enough to cull empty space from leaves |
---|
1014 | if ( (maxEmptyCutDepth < 0) || |
---|
1015 | (maxEmptyCutDepth > 6) ) { |
---|
1016 | cerr << "BSP.maxEmptyCutDepth = " << maxEmptyCutDepth |
---|
1017 | << " must be in range <0,6>\n"; |
---|
1018 | abort();; |
---|
1019 | } |
---|
1020 | |
---|
1021 | wBbox.Convert(box); // the box of the whole scene |
---|
1022 | boxSize = box.Diagonal(); // the size of the box along the axes |
---|
1023 | |
---|
1024 | wholeBoxArea = wBbox.SA2(); // the half of the surface area of the box |
---|
1025 | |
---|
1026 | // the array of bounding boxes and duplications to the objects |
---|
1027 | int objlistcnt = objlist->size(); |
---|
1028 | |
---|
1029 | // Here create the auxiliary array |
---|
1030 | //solidArray.reserve(objlistcnt); |
---|
1031 | // $$JB - crashed below |
---|
1032 | solidArray.resize(objlistcnt); |
---|
1033 | |
---|
1034 | // Here create the first entry of boundaries for all objects |
---|
1035 | SInputData* data = AllocNewData(); |
---|
1036 | // set the box |
---|
1037 | data->box = wBbox; |
---|
1038 | // which algorithm to use for break-ax |
---|
1039 | #if 1 |
---|
1040 | data->algorithmBreakAx = 0; // position based |
---|
1041 | #else |
---|
1042 | data->algorithmBreakAx = 1; // pointer based |
---|
1043 | #endif |
---|
1044 | |
---|
1045 | #ifdef _RANDOMIZE_POSITION |
---|
1046 | data->algorithmBreakAx = 0; // position based |
---|
1047 | #endif |
---|
1048 | |
---|
1049 | resetFlagsForBreakAx = true; |
---|
1050 | |
---|
1051 | assert(objlistcnt > 0); |
---|
1052 | |
---|
1053 | // allocate the array of boundaries for all 3 axes |
---|
1054 | data->Alloc(data->count*2); |
---|
1055 | // set the number of objects |
---|
1056 | data->count = objlistcnt; |
---|
1057 | int i = 0; |
---|
1058 | // cout << data->xvec->size() << " " << data->count*2 << endl; |
---|
1059 | // create the list of bounding boxes |
---|
1060 | for (ObjectContainer::iterator scr = objlist->begin(); |
---|
1061 | scr != objlist->end(); scr++, i++) { |
---|
1062 | // set the object |
---|
1063 | solidArray[i].obj = *scr; |
---|
1064 | solidArray[i].flags = 0; |
---|
1065 | SSolid *solid = &(solidArray[i]); |
---|
1066 | // create bounding box of the object |
---|
1067 | SBBox abox; |
---|
1068 | abox.Convert((*scr)->GetBox()); |
---|
1069 | // copy the boundaries to the arrays |
---|
1070 | // max boundaries as first because of stable quicksort |
---|
1071 | SItem itemX; |
---|
1072 | itemX.pos = abox.Min(0); |
---|
1073 | itemX.obj = solid; |
---|
1074 | itemX.axis = 0; |
---|
1075 | itemX.SetLeftBoundary(); |
---|
1076 | data->xvec->push_back(itemX); |
---|
1077 | |
---|
1078 | SItem itemY; |
---|
1079 | itemY.pos = abox.Min(1); |
---|
1080 | itemY.obj = solid; |
---|
1081 | itemY.axis = 1; |
---|
1082 | itemY.SetLeftBoundary(); |
---|
1083 | data->yvec->push_back(itemY); |
---|
1084 | |
---|
1085 | SItem itemZ; |
---|
1086 | itemZ.pos = abox.Min(2); |
---|
1087 | itemZ.obj = solid; |
---|
1088 | itemZ.axis = 2; |
---|
1089 | itemZ.SetLeftBoundary(); |
---|
1090 | data->zvec->push_back(itemZ); |
---|
1091 | |
---|
1092 | // max boundaries |
---|
1093 | itemX.pos = abox.Max(0); |
---|
1094 | itemX.SetRightBoundary(); |
---|
1095 | data->xvec->push_back(itemX); |
---|
1096 | |
---|
1097 | itemY.pos = abox.Max(1); |
---|
1098 | itemY.SetRightBoundary(); |
---|
1099 | data->yvec->push_back(itemY); |
---|
1100 | |
---|
1101 | itemZ.pos = abox.Max(2); |
---|
1102 | itemZ.SetRightBoundary(); |
---|
1103 | data->zvec->push_back(itemZ); |
---|
1104 | } // for all objects |
---|
1105 | |
---|
1106 | // cout << data->xvec->size() << " " << data->count*2 << endl; |
---|
1107 | |
---|
1108 | assert(data->xvec->size() == (unsigned int)data->count*2); |
---|
1109 | data->xvec->resize(data->count*2); |
---|
1110 | assert(data->yvec->size() == (unsigned int)data->count*2); |
---|
1111 | data->yvec->resize(data->count*2); |
---|
1112 | assert(data->zvec->size() == (unsigned int)data->count*2); |
---|
1113 | data->zvec->resize(data->count*2); |
---|
1114 | |
---|
1115 | // If to use radix sort or quicksort |
---|
1116 | //_useRadixSort = true; |
---|
1117 | // Note that quicksort does not work for some reason !! 27/12/2005 |
---|
1118 | //_useRadixSort = false; |
---|
1119 | |
---|
1120 | // sort all the bounding boxes along the axes |
---|
1121 | if ((initcnt = objlist->size()) != 0) |
---|
1122 | SortAxes(data); |
---|
1123 | |
---|
1124 | // The statistics init |
---|
1125 | cntDuplicate = 0; |
---|
1126 | |
---|
1127 | // Init the parameters from the environment file |
---|
1128 | InitReqPref(&(data->pars)); |
---|
1129 | |
---|
1130 | // Init the termination criteria |
---|
1131 | string termCrit; |
---|
1132 | Environment::GetSingleton()->GetStringValue("BSP.termCrit", termCrit); |
---|
1133 | |
---|
1134 | maxCountTrials = 0; |
---|
1135 | if (!termCrit.compare("adhoc")) { |
---|
1136 | // termination criteria are the max depth of the hierarchy, number |
---|
1137 | // of primitives |
---|
1138 | data->modeSubDiv = EE_SUBDIVADHOC; |
---|
1139 | Environment::GetSingleton()->GetIntValue("BSP.maxListLength", |
---|
1140 | maxListLength); |
---|
1141 | Environment::GetSingleton()->GetIntValue("BSP.maxDepthAllowed", |
---|
1142 | maxDepthAllowed); |
---|
1143 | } |
---|
1144 | else { |
---|
1145 | if ( (!termCrit.compare("auto")) || |
---|
1146 | (!termCrit.compare("auto2")) ) { |
---|
1147 | // automatic termination criteria are used, everything is computed |
---|
1148 | // automatically from number of objects etc. |
---|
1149 | int estHeight = (int)(log((float)initcnt)/log((float)2.0) + 0.9); |
---|
1150 | // cout << "EstHeight=" << estHeight << endl; |
---|
1151 | maxDepthAllowed = (int)((float)estHeight * 1.2f + 2.0f); |
---|
1152 | |
---|
1153 | // maximum number of trials to further subdivide |
---|
1154 | maxCountTrials = (int)(1.0 + 0.2 * (float)maxDepthAllowed); |
---|
1155 | if (maxCountTrials < 3) |
---|
1156 | maxCountTrials = 3; |
---|
1157 | |
---|
1158 | // for 'auto2' we specify the length of the object list by hand |
---|
1159 | if (!termCrit.compare("auto2")) |
---|
1160 | Environment::GetSingleton()->GetIntValue("BSP.maxListLength", |
---|
1161 | maxListLength); |
---|
1162 | else |
---|
1163 | // for 'auto' we set the length of the object list that is supposed |
---|
1164 | // to be the best for ray shooting |
---|
1165 | maxListLength = 1; |
---|
1166 | |
---|
1167 | if (verbose) { |
---|
1168 | cout << "TERMCRIT:maximum height of a leaf set to " |
---|
1169 | << maxDepthAllowed << "\n"; |
---|
1170 | cout << "TERMCRIT:maximum number of objects in leaf set to " |
---|
1171 | << maxListLength << "\n" ; |
---|
1172 | } |
---|
1173 | // set the mode to be recognized |
---|
1174 | data->modeSubDiv = EE_SUBDIVAUTOMATIC; |
---|
1175 | } |
---|
1176 | else { |
---|
1177 | cerr << " unknown termination criteria for BSP tree\n"; |
---|
1178 | cerr << "It was specified: " << termCrit << "\n"; |
---|
1179 | cerr << "Allowed types = auto, auto2, adhoc" << endl; |
---|
1180 | exit(3);; |
---|
1181 | } |
---|
1182 | } |
---|
1183 | |
---|
1184 | // for some evaluation it is necessary to determine the following costs |
---|
1185 | Environment::GetSingleton()->GetFloatValue("BSP.traversalCost", Ct); |
---|
1186 | Environment::GetSingleton()->GetFloatValue("BSP.intersectionCost", Ci); |
---|
1187 | if (verbose) |
---|
1188 | cout << "Ct=" << Ct << " Ci=" << Ci << "\n"; |
---|
1189 | |
---|
1190 | if (cutEmptySpace) { |
---|
1191 | // correct the maximum abs depth, when late cutting is allowed |
---|
1192 | if (absMaxAllowedDepth < maxDepthAllowed) |
---|
1193 | absMaxAllowedDepth = maxDepthAllowed; |
---|
1194 | if (absMaxAllowedDepth > (maxDepthAllowed + maxEmptyCutDepth) ) |
---|
1195 | absMaxAllowedDepth = maxDepthAllowed + maxEmptyCutDepth; |
---|
1196 | if (absMaxAllowedDepth >= MAX_HEIGHT) { |
---|
1197 | absMaxAllowedDepth = MAX_HEIGHT; |
---|
1198 | maxDepthAllowed = MAX_HEIGHT - maxEmptyCutDepth; |
---|
1199 | } |
---|
1200 | |
---|
1201 | if (verbose) { |
---|
1202 | cout << "Cutting off empty spaces ON\n"; |
---|
1203 | cout << "BSP.absMaxAllowedDepth = " << absMaxAllowedDepth << "\n"; |
---|
1204 | cout << "BSP.maxEmptyCutDepth = " << maxEmptyCutDepth << endl; |
---|
1205 | } |
---|
1206 | } |
---|
1207 | else { |
---|
1208 | if (maxDepthAllowed >= MAX_HEIGHT) |
---|
1209 | maxDepthAllowed = MAX_HEIGHT - 1; |
---|
1210 | } |
---|
1211 | |
---|
1212 | if (verbose) |
---|
1213 | cout << "MaxListLength = " << maxListLength << endl; |
---|
1214 | |
---|
1215 | return data; |
---|
1216 | } |
---|
1217 | |
---|
1218 | // interface function for building up CKTB tree |
---|
1219 | SKTBNodeT* |
---|
1220 | CKTBABuildUp::BuildUp(ObjectContainer &objlist, |
---|
1221 | const AxisAlignedBox3 &box, |
---|
1222 | bool verboseF) |
---|
1223 | { |
---|
1224 | // check the number of objects |
---|
1225 | if (objlist.size() == 0) |
---|
1226 | return 0; // nothing |
---|
1227 | |
---|
1228 | // --------------------------------------------------- |
---|
1229 | // Rewriting the triangles to the just wrappers to save |
---|
1230 | // the memory during building!!!! |
---|
1231 | bool useWrappers = false; |
---|
1232 | if (useWrappers) { |
---|
1233 | cout << "WARNING: using only wrappers, not objects to save the memory!" |
---|
1234 | << endl; |
---|
1235 | cout << "Size of(AxisAlignedBox3Intersectable) = " << sizeof(AxisAlignedBox3Intersectable) << endl; |
---|
1236 | cout << "Size of(TriangleIntersectable) = " << sizeof(TriangleIntersectable) << endl; |
---|
1237 | for (ObjectContainer::iterator it = objlist.begin(); |
---|
1238 | it != objlist.end(); it++) { |
---|
1239 | // take the triangle |
---|
1240 | Intersectable *i = *it; |
---|
1241 | // store the properties to new variables |
---|
1242 | AxisAlignedBox3 b = i->GetBox(); |
---|
1243 | int mId = i->mId; |
---|
1244 | // delete the triangle |
---|
1245 | delete i; |
---|
1246 | // create the wrapper with the same box as triangle |
---|
1247 | AxisAlignedBox3Intersectable *a = new AxisAlignedBox3Intersectable(b); |
---|
1248 | a->mId = mId; |
---|
1249 | // and put it back to the list of objects |
---|
1250 | *it = a; |
---|
1251 | } // for |
---|
1252 | cout << "Rewriting to wrappers is finished!" << endl; |
---|
1253 | } // if |
---|
1254 | // --------------------------------------------------- |
---|
1255 | |
---|
1256 | // cerr<<"hh44"<<endl; |
---|
1257 | // initialize the whole box of the kd-tree and sort |
---|
1258 | // the boundary entries |
---|
1259 | SInputData *d = Init(&objlist, box); |
---|
1260 | |
---|
1261 | //cerr<<"hh45"<<endl; |
---|
1262 | |
---|
1263 | // copy verbose to be used consistenly further on |
---|
1264 | this->verbose = verboseF; |
---|
1265 | |
---|
1266 | if (verbose) |
---|
1267 | cout << "Building up KTB tree for " << objlist.size() |
---|
1268 | << " objects." << endl << flush; |
---|
1269 | |
---|
1270 | // Initialization of the first value to insert the min boxes |
---|
1271 | d->lastMinBoxSA2 = box.SurfaceArea() * 10000.f; |
---|
1272 | d->lastDepthForMinBoxes = -20; // for root you always put the node |
---|
1273 | d->lastMinBoxNode = 0; |
---|
1274 | |
---|
1275 | // ----------------------------------------------- |
---|
1276 | // Start to build the tree |
---|
1277 | if ( (cutEmptySpace) && |
---|
1278 | (initcnt <= maxListLength)) { |
---|
1279 | // only cutting off empty space for initial leaf |
---|
1280 | d->modeSubDiv = EE_SUBDIVCUTEMPTY; |
---|
1281 | root = SubDiv(d); |
---|
1282 | } |
---|
1283 | else { |
---|
1284 | // normal subdivision scheme, creating whole tree |
---|
1285 | root = SubDiv(d); |
---|
1286 | } |
---|
1287 | |
---|
1288 | #ifdef _DEBUG |
---|
1289 | if (GetDepth() != 0) { |
---|
1290 | cerr << "Using depth value does not work correctly, depth = " |
---|
1291 | << GetDepth() << endl; |
---|
1292 | } |
---|
1293 | #endif |
---|
1294 | assert(root); |
---|
1295 | |
---|
1296 | // ---------------------------------------------------- |
---|
1297 | // Deallocate all auxiliary data |
---|
1298 | DeleteAuxiliaryData(); |
---|
1299 | |
---|
1300 | // delete the temporary data array |
---|
1301 | solidArray.resize(0); |
---|
1302 | |
---|
1303 | // the pointer to the root node |
---|
1304 | return GetRootNode(); |
---|
1305 | } |
---|
1306 | |
---|
1307 | int |
---|
1308 | CKTBABuildUp::UpdateEvaluation(float &eval, const float &newEval) |
---|
1309 | { |
---|
1310 | if (newEval < eval) { |
---|
1311 | eval = newEval; |
---|
1312 | return 1; // updated |
---|
1313 | } |
---|
1314 | return 0; // not updated |
---|
1315 | } |
---|
1316 | |
---|
1317 | // recursive function for subdividing the CKTB tree into two |
---|
1318 | // halves .. creates one node of CKTB tree |
---|
1319 | // list .. list of boundaries, count .. number of objects in current node |
---|
1320 | // bb .. current bounding box of node, (pars,reqGlobAxis, modeSubDiv) .. cut pref. |
---|
1321 | SKTBNodeT* |
---|
1322 | CKTBABuildUp::SubDiv(SInputData *d) |
---|
1323 | { |
---|
1324 | #ifdef _DEBUG |
---|
1325 | Check3List(d); |
---|
1326 | #endif |
---|
1327 | |
---|
1328 | #if 0 |
---|
1329 | static int index = 0; |
---|
1330 | cout << "SubDiv index = " << index << endl; |
---|
1331 | const int indexToFind = 13916; |
---|
1332 | if (index == indexToFind) { |
---|
1333 | cout << " IndexToFind = " << indexToFind << endl; |
---|
1334 | cout << " You should start debug" << endl; |
---|
1335 | } |
---|
1336 | index++; |
---|
1337 | #endif |
---|
1338 | |
---|
1339 | // This is the node to return from this function |
---|
1340 | SKTBNodeT *nodeToReturn = 0; |
---|
1341 | |
---|
1342 | // if to make the interior node extended by the box here |
---|
1343 | makeMinBoxHere = false; |
---|
1344 | |
---|
1345 | // ----------------------------------------------------- |
---|
1346 | if (makeMinBoxes) { |
---|
1347 | #if 1 |
---|
1348 | if ( (d->count >= minObjectsToCreateMinBox) && |
---|
1349 | (GetDepth() - d->lastDepthForMinBoxes >= minDepthDistanceBetweenMinBoxes) ) { |
---|
1350 | makeMinBoxHere = true; |
---|
1351 | d->lastDepthForMinBoxes = GetDepth(); |
---|
1352 | d->lastMinBoxSA2 = d->box.SA2(); |
---|
1353 | } |
---|
1354 | #endif |
---|
1355 | #if 0 |
---|
1356 | if (d->count >= minObjectsToCreateMinBox) { |
---|
1357 | if ( (d->lastMinBoxSA2 >= d->box.SA2() * minSA2ratioMinBoxes) && |
---|
1358 | (GetDepth() - d->lastDepthForMinBoxes >= minDepthDistanceBetweenMinBoxes) ) { |
---|
1359 | makeMinBoxHere = true; |
---|
1360 | d->lastDepthForMinBoxes = GetDepth(); |
---|
1361 | d->lastMinBoxSA2 = d->box.SA2(); |
---|
1362 | } |
---|
1363 | } |
---|
1364 | #endif |
---|
1365 | #if 0 |
---|
1366 | if ( (d->count >= minObjectsToCreateMinBox) && |
---|
1367 | (GetDepth() % minDepthDistanceBetweenMinBoxes == 0) ) { |
---|
1368 | makeMinBoxHere = true; |
---|
1369 | d->lastDepthForMinBoxes = GetDepth(); |
---|
1370 | d->lastMinBoxSA2 = d->box.SA2(); |
---|
1371 | } |
---|
1372 | #endif |
---|
1373 | } |
---|
1374 | |
---|
1375 | if ( (makeMinBoxHere) && (makeTightMinBoxes) ) { |
---|
1376 | // In case we should make the box of the current |
---|
1377 | // interior node and this should be tight, we have |
---|
1378 | // to first compute its extent before splitting |
---|
1379 | SBBox tightbox; |
---|
1380 | GetTightBox(*d, tightbox); |
---|
1381 | // Here we decrease the box to the minimum size |
---|
1382 | d->box = tightbox; |
---|
1383 | } |
---|
1384 | |
---|
1385 | // ------------------------------------------------------------------ |
---|
1386 | // if we are forced to make subdivision at given point |
---|
1387 | if (d->pars.reqPosition != Limits::Infinity) { |
---|
1388 | // this code preceeds switch(mode) since 2-level evaluation |
---|
1389 | d->position = d->pars.reqPosition; |
---|
1390 | d->axis = d->pars.reqAxis; |
---|
1391 | // next subdivison will not be forced |
---|
1392 | d->pars.reqPosition = Limits::Infinity; |
---|
1393 | d->pars.reqAxis = CKTBAxes::EE_Leaf; |
---|
1394 | IncDepth(); |
---|
1395 | SKTBNodeT* n = MakeOneCut(d); |
---|
1396 | if (!nodeToReturn) |
---|
1397 | nodeToReturn = n; |
---|
1398 | DecDepth(); |
---|
1399 | return nodeToReturn; |
---|
1400 | } |
---|
1401 | |
---|
1402 | // ------------------------------------------------------------------------- |
---|
1403 | // determine between subdivision modes - different termination criteria |
---|
1404 | switch (d->modeSubDiv) { // subdivision mode |
---|
1405 | case EE_SUBDIVCUTEMPTY: { // cutting off empty space |
---|
1406 | if ((GetDepth() >= absMaxAllowedDepth) || |
---|
1407 | (GetDepth() >= (startEmptyCutDepth + maxEmptyCutDepth)) || |
---|
1408 | (d->count == 0) ) { |
---|
1409 | SKTBNodeT* n = MakeLeaf(d); |
---|
1410 | if (!nodeToReturn) |
---|
1411 | nodeToReturn = n; |
---|
1412 | // cout << "LEC\n"; |
---|
1413 | return nodeToReturn; |
---|
1414 | } |
---|
1415 | // to require the axis has no meaning in cutting off |
---|
1416 | d->pars.reqAxis = d->axis = CKTBAxes::EE_Leaf; |
---|
1417 | break; |
---|
1418 | } |
---|
1419 | // both adhoc, clustering and automatic termination criteria |
---|
1420 | case EE_SUBDIVADHOC: |
---|
1421 | case EE_SUBDIVAUTOMATIC: { |
---|
1422 | // automatic termination criteria are used in this phase as |
---|
1423 | // the absolute threshold similarly to SUBDIVADHOC mode |
---|
1424 | if ( (GetDepth() >= maxDepthAllowed) || |
---|
1425 | (d->count <= maxListLength)) { |
---|
1426 | SKTBNodeT* n = MakeLeaf(d); |
---|
1427 | if (!nodeToReturn) |
---|
1428 | nodeToReturn = n; |
---|
1429 | // cout << "LLA\n"; |
---|
1430 | return nodeToReturn; |
---|
1431 | } |
---|
1432 | break; |
---|
1433 | } |
---|
1434 | default: { |
---|
1435 | cerr << " unknown subdivision mode in ibsp.cpp\n"; |
---|
1436 | abort();; |
---|
1437 | } |
---|
1438 | } // switch(modeSubDiv) |
---|
1439 | |
---|
1440 | // the axis where splitting should be done |
---|
1441 | CKTBAxes::Axes axis = CKTBAxes::EE_Leaf; |
---|
1442 | d->twoSplits = -1; |
---|
1443 | d->bestCost = WorstEvaluation() * 0.5f; |
---|
1444 | d->position = MAXFLOAT; |
---|
1445 | d->cntThickness = 0; |
---|
1446 | |
---|
1447 | // which calls should be used, standard or optimized |
---|
1448 | #if 1 |
---|
1449 | #define CallGetSplitPlaneX GetSplitPlaneOpt2 |
---|
1450 | #define CallGetSplitPlaneY GetSplitPlaneOpt2 |
---|
1451 | #define CallGetSplitPlaneZ GetSplitPlaneOpt2 |
---|
1452 | #endif |
---|
1453 | #if 0 |
---|
1454 | // This does not work for unknown reason... VH 2006/01/08 |
---|
1455 | #define CallGetSplitPlaneX GetSplitPlaneOpt3 |
---|
1456 | #define CallGetSplitPlaneY GetSplitPlaneOpt3 |
---|
1457 | #define CallGetSplitPlaneZ GetSplitPlaneOpt3 |
---|
1458 | #endif |
---|
1459 | #if 0 |
---|
1460 | #define CallGetSplitPlaneX GetSplitPlaneOptUnroll4 |
---|
1461 | #define CallGetSplitPlaneY GetSplitPlaneOptUnroll4 |
---|
1462 | #define CallGetSplitPlaneZ GetSplitPlaneOptUnroll4 |
---|
1463 | #endif |
---|
1464 | |
---|
1465 | // if the axis is required in pars structure for some reasons |
---|
1466 | if (d->pars.useReqAxis) { |
---|
1467 | axis = d->pars.reqAxis; |
---|
1468 | // The next subdivision is not prescribed |
---|
1469 | d->pars.useReqAxis = false; |
---|
1470 | switch(axis) { |
---|
1471 | case CKTBAxes::EE_X_axis : { |
---|
1472 | state.InitXaxis(d->count, d->box); // init |
---|
1473 | CallGetSplitPlaneX(d->xvec, 0); // evaluate |
---|
1474 | break; |
---|
1475 | } |
---|
1476 | case CKTBAxes::EE_Y_axis : { |
---|
1477 | state.InitYaxis(d->count, d->box); // init |
---|
1478 | CallGetSplitPlaneY(d->yvec, 1); // evaluate |
---|
1479 | break; |
---|
1480 | } |
---|
1481 | case CKTBAxes::EE_Z_axis : { |
---|
1482 | state.InitZaxis(d->count, d->box); // init |
---|
1483 | CallGetSplitPlaneZ(d->zvec, 2); // evaluate |
---|
1484 | break; |
---|
1485 | } |
---|
1486 | default: { |
---|
1487 | cerr << "No other option is allowed here" << endl; |
---|
1488 | abort();; |
---|
1489 | } |
---|
1490 | } |
---|
1491 | // compute the cost, normalized by surface area |
---|
1492 | state.NormalizeCostBySA2(); |
---|
1493 | d->bestCost /= state.areaWholeSA2; |
---|
1494 | if (UpdateEvaluation(d->bestCost, state.bestCost)) { |
---|
1495 | // Compute correct position to be used for splitting |
---|
1496 | d->position = (*(state.bestIterator)).pos; |
---|
1497 | d->bestIterator = state.bestIterator; |
---|
1498 | d->twoSplits = state.bestTwoSplits; // one or two splitting planes planed |
---|
1499 | d->cntThickness = state.bestThickness; |
---|
1500 | if (d->twoSplits > 1) { |
---|
1501 | SItemVec::iterator it = state.bestIterator; it++; |
---|
1502 | if (it != d->GetItemVec(axis)->end()) |
---|
1503 | d->position2 = (*it).pos; |
---|
1504 | else |
---|
1505 | d->position2 = state.box.Max(axis); |
---|
1506 | } |
---|
1507 | } |
---|
1508 | } |
---|
1509 | else { |
---|
1510 | int algorithmForAxisSel = _algorithmForAxisSelection; |
---|
1511 | if (d->modeSubDiv == EE_SUBDIVCUTEMPTY) |
---|
1512 | algorithmForAxisSel = 0; |
---|
1513 | |
---|
1514 | // only a single axis will be tested |
---|
1515 | bool useSingleAxis = true; |
---|
1516 | |
---|
1517 | // the required axis is by global function .. e.g. cyclic change x, y, z |
---|
1518 | switch (algorithmForAxisSel) { |
---|
1519 | case 0: { |
---|
1520 | // all three axis will be used, starting from x, y, z |
---|
1521 | useSingleAxis = false; |
---|
1522 | break; |
---|
1523 | } |
---|
1524 | case 1: { |
---|
1525 | // cyclic order of axes, x, y, z, x, y.... |
---|
1526 | axis = d->pars.reqAxis; |
---|
1527 | // compute the axis for the next subdivision step |
---|
1528 | d->pars.reqAxis = oaxes[axis][0]; |
---|
1529 | break; |
---|
1530 | } |
---|
1531 | case 2 : { |
---|
1532 | // The next time will be determined the same way |
---|
1533 | axis = (CKTBAxes::Axes)(d->box.Diagonal().DrivingAxis()); |
---|
1534 | break; |
---|
1535 | } |
---|
1536 | case 3 : { |
---|
1537 | float p = RandomValue(0.0f, 1.0f); |
---|
1538 | const float thresholdAxisP = 0.8f; |
---|
1539 | if (p < thresholdAxisP) { |
---|
1540 | axis = (CKTBAxes::Axes)(d->box.Diagonal().DrivingAxis()); |
---|
1541 | } |
---|
1542 | else { |
---|
1543 | // Use the axis prescribed from previous step |
---|
1544 | axis = d->pars.reqAxis; |
---|
1545 | } |
---|
1546 | // for the next time, different axis |
---|
1547 | d->pars.reqAxis = oaxes[axis][0]; |
---|
1548 | break; |
---|
1549 | } |
---|
1550 | case 4 : { |
---|
1551 | float p = RandomValue(0.0f, 1.0f); |
---|
1552 | const float thresholdAxisP = 0.3f; |
---|
1553 | if (p < thresholdAxisP) { |
---|
1554 | axis = (CKTBAxes::Axes)(d->box.Diagonal().DrivingAxis()); |
---|
1555 | } |
---|
1556 | else { |
---|
1557 | // Use the axis prescribed from previous step |
---|
1558 | axis = d->pars.reqAxis; |
---|
1559 | } |
---|
1560 | // for the next time, different axis |
---|
1561 | d->pars.reqAxis = oaxes[axis][0]; |
---|
1562 | break; |
---|
1563 | } |
---|
1564 | case 5 : { |
---|
1565 | float p = RandomValue(0.0f, 1.0f); |
---|
1566 | const float thresholdAxisP = 0.2f; |
---|
1567 | d->pars.reqAxis = (CKTBAxes::Axes)-1; |
---|
1568 | if (p < thresholdAxisP) { |
---|
1569 | axis = (CKTBAxes::Axes)(d->box.Diagonal().DrivingAxis()); |
---|
1570 | // for the next time, different axis |
---|
1571 | } |
---|
1572 | else { |
---|
1573 | // Use the axis for which cost model gets minimum, |
---|
1574 | // compute it for all axes x, y, z |
---|
1575 | useSingleAxis = false; |
---|
1576 | } |
---|
1577 | break; |
---|
1578 | } |
---|
1579 | default: { |
---|
1580 | cerr << "Selection algorithm = " << algorithmForAxisSel |
---|
1581 | << " for axis is not implemented" << endl; |
---|
1582 | abort();; |
---|
1583 | } |
---|
1584 | } // switch |
---|
1585 | |
---|
1586 | // How the algorithm is used |
---|
1587 | if (useSingleAxis) { |
---|
1588 | // ------------------------------------------- |
---|
1589 | // Compute subdivision only for one axis |
---|
1590 | switch(axis) { |
---|
1591 | case CKTBAxes::EE_X_axis : { |
---|
1592 | state.InitXaxis(d->count, d->box); // init |
---|
1593 | CallGetSplitPlaneX(d->xvec, 0); // evaluate |
---|
1594 | break; |
---|
1595 | } |
---|
1596 | case CKTBAxes::EE_Y_axis : { |
---|
1597 | state.InitYaxis(d->count, d->box); // init |
---|
1598 | CallGetSplitPlaneY(d->yvec, 1); // evaluate |
---|
1599 | break; |
---|
1600 | } |
---|
1601 | case CKTBAxes::EE_Z_axis : { |
---|
1602 | state.InitZaxis(d->count, d->box); // init |
---|
1603 | CallGetSplitPlaneZ(d->zvec, 2); // evaluate |
---|
1604 | break; |
---|
1605 | } |
---|
1606 | //case CKTBAxes::EE_Leaf : { |
---|
1607 | //goto MAKE_LEAF; |
---|
1608 | //} |
---|
1609 | default: { |
---|
1610 | cerr << "Selection algorithm = " << algorithmForAxisSel |
---|
1611 | << " for axis = " << axis <<" is not implemented" << endl; |
---|
1612 | abort();; |
---|
1613 | } |
---|
1614 | } |
---|
1615 | state.NormalizeCostBySA2(); |
---|
1616 | d->bestCost /= state.areaWholeSA2; |
---|
1617 | if (UpdateEvaluation(d->bestCost, state.bestCost)) { |
---|
1618 | // Compute correct position to be used for splitting |
---|
1619 | d->position = (*(state.bestIterator)).pos; |
---|
1620 | d->bestIterator = state.bestIterator; |
---|
1621 | d->twoSplits = state.bestTwoSplits; // one or two splitting planes planed |
---|
1622 | d->cntThickness = state.bestThickness; |
---|
1623 | if (d->twoSplits > 1) { |
---|
1624 | SItemVec::iterator it = state.bestIterator; it++; |
---|
1625 | if (it != d->GetItemVec(axis)->end()) |
---|
1626 | d->position2 = (*it).pos; |
---|
1627 | else |
---|
1628 | d->position2 = state.box.Max(axis); |
---|
1629 | } |
---|
1630 | } |
---|
1631 | } |
---|
1632 | else { |
---|
1633 | // no axis is required, we can pickup any we like. We test all three axis |
---|
1634 | // and we pickup the minimum cost for all three axes. |
---|
1635 | state.InitXaxis(d->count, d->box); // init for x axis |
---|
1636 | CallGetSplitPlaneX(d->xvec, 0); // evaluate for x axis |
---|
1637 | if (UpdateEvaluation(d->bestCost, state.bestCost)) { |
---|
1638 | axis = CKTBAxes::EE_X_axis; // the x-axis should be used |
---|
1639 | // Compute correct position to be used for splitting |
---|
1640 | d->bestCost = state.bestCost; |
---|
1641 | d->position = (*(state.bestIterator)).pos; |
---|
1642 | d->bestIterator = state.bestIterator; |
---|
1643 | d->twoSplits = state.bestTwoSplits; // one or two splitting planes planed |
---|
1644 | d->cntThickness = state.bestThickness; |
---|
1645 | if (d->twoSplits > 1) { |
---|
1646 | SItemVec::iterator it = state.bestIterator; |
---|
1647 | it++; |
---|
1648 | if (it != d->xvec->end()) |
---|
1649 | d->position2 = (*it).pos; |
---|
1650 | else |
---|
1651 | d->position2 = state.box.Max().x; |
---|
1652 | } |
---|
1653 | } |
---|
1654 | // ----------------------- |
---|
1655 | // now test for y axis |
---|
1656 | state.ReinitYaxis(d->count, d->box); // init for x axis |
---|
1657 | //state.InitYaxis(d->count, d->box); // init for x axis |
---|
1658 | CallGetSplitPlaneY(d->yvec, 1); // evaluate for x axis |
---|
1659 | if (UpdateEvaluation(d->bestCost, state.bestCost)) { |
---|
1660 | axis = CKTBAxes::EE_Y_axis; // the y-axis should be used |
---|
1661 | // Compute correct position to be used for splitting |
---|
1662 | d->position = (*(state.bestIterator)).pos; |
---|
1663 | d->bestIterator = state.bestIterator; |
---|
1664 | d->twoSplits = state.bestTwoSplits; // one or two splitting planes planed |
---|
1665 | d->cntThickness = state.bestThickness; |
---|
1666 | if (d->twoSplits > 1) { |
---|
1667 | SItemVec::iterator it = state.bestIterator; |
---|
1668 | it++; |
---|
1669 | if (it != d->yvec->end()) |
---|
1670 | d->position2 = (*it).pos; |
---|
1671 | else |
---|
1672 | d->position2 = state.box.Max().y; |
---|
1673 | } |
---|
1674 | } |
---|
1675 | // ----------------------- |
---|
1676 | // now test for z axis |
---|
1677 | state.ReinitZaxis(d->count, d->box); // init for x axis |
---|
1678 | //state.InitZaxis(d->count, d->box); // init for x axis |
---|
1679 | CallGetSplitPlaneZ(d->zvec, 2); // evaluate for x axis |
---|
1680 | if (UpdateEvaluation(d->bestCost, state.bestCost)) { |
---|
1681 | axis = CKTBAxes::EE_Z_axis; // the z-axis should be used |
---|
1682 | // Compute correct position to be used for splitting |
---|
1683 | d->position = (*(state.bestIterator)).pos; |
---|
1684 | d->bestIterator = state.bestIterator; |
---|
1685 | d->twoSplits = state.bestTwoSplits; // one or two splitting planes planed |
---|
1686 | d->cntThickness = state.bestThickness; |
---|
1687 | if (d->twoSplits > 1) { |
---|
1688 | SItemVec::iterator it = state.bestIterator; |
---|
1689 | it++; |
---|
1690 | if (it != d->zvec->end()) |
---|
1691 | d->position2 = (*it).pos; |
---|
1692 | else |
---|
1693 | d->position2 = state.box.Max().z; |
---|
1694 | } |
---|
1695 | } |
---|
1696 | // Now we have to renormalize the cost for purpose of termination the building |
---|
1697 | d->bestCost /= state.areaWholeSA2; |
---|
1698 | } // arbitrary order of axes |
---|
1699 | } // for which axis to compute surface area heuristics |
---|
1700 | |
---|
1701 | // ---------------------------------------------------------- |
---|
1702 | // when automatic termination criteria should be used |
---|
1703 | if (d->modeSubDiv == EE_SUBDIVAUTOMATIC) { |
---|
1704 | bool stopSubdivision = false; |
---|
1705 | float ratio; |
---|
1706 | // which algorithm to use for automatic termination criteria |
---|
1707 | switch (algorithmAutoTermination) { |
---|
1708 | // -------------------------------------------------- |
---|
1709 | case 0: { // This is described in my thesis. |
---|
1710 | // This is the cost of unsubdivided node |
---|
1711 | float leafCost = (float)(d->count); |
---|
1712 | ratio = d->bestCost / leafCost; |
---|
1713 | const float minRatio = 0.75; |
---|
1714 | if (ratio > minRatio) |
---|
1715 | stopSubdivision = true; |
---|
1716 | break; |
---|
1717 | } |
---|
1718 | // -------------------------------------------------- |
---|
1719 | case 1: { |
---|
1720 | // This is the cost of unsubdivided node, with uniformly distributed |
---|
1721 | // objects and the spatial median subdivision, without any object straddling |
---|
1722 | // the splitting plane. In some sense ideal setting for uniform distribution. |
---|
1723 | Vector3 s = d->box.Diagonal(); |
---|
1724 | // Taking the widest side of the object to be subdivided |
---|
1725 | int diagAxis = s.DrivingAxis(); |
---|
1726 | // Half of the width |
---|
1727 | // ---------------------- |
---|
1728 | float w2 = s[diagAxis] * 0.5; |
---|
1729 | float t = s[oaxes[diagAxis][0]]; |
---|
1730 | float h = s[oaxes[diagAxis][1]]; |
---|
1731 | float sah2 = w2*(t+h) + h*t; // half of the surface area of a child |
---|
1732 | // This is the cost for case when the node is subdivided in the half and |
---|
1733 | // the half of the object is on the left and half of the objects on the right |
---|
1734 | // This is not the best cost possible !!! |
---|
1735 | // = float subdividedCost = 2 * (sah2/state.areaWholeSA2 * count/2); |
---|
1736 | float subdividedCost = sah2/state.areaWholeSA2 * (float)(d->count); |
---|
1737 | ratio = d->bestCost / subdividedCost; |
---|
1738 | // This is the max ratio allowed for splitting node subdivision |
---|
1739 | |
---|
1740 | // The computed ratio = 1.0 corresponds to 'ideal case', so the threshold |
---|
1741 | // must be higher than 1.0 ! |
---|
1742 | const float minRatio = 1.1; |
---|
1743 | if (ratio > minRatio) |
---|
1744 | stopSubdivision = true; |
---|
1745 | break; |
---|
1746 | } |
---|
1747 | default : { |
---|
1748 | cerr << "Uknown algorithm for automatic termination criteria = " |
---|
1749 | << algorithmAutoTermination << endl; |
---|
1750 | } |
---|
1751 | |
---|
1752 | } // switch |
---|
1753 | |
---|
1754 | //cout << "R=" << ratio << " "; |
---|
1755 | if (stopSubdivision) { |
---|
1756 | // cout << "F" << pars.failedSubDivCount << " "; |
---|
1757 | // when small improvement by the subdivision is reached |
---|
1758 | d->pars.failedSubDivCount++; |
---|
1759 | if (d->pars.failedSubDivCount > maxCountTrials) { |
---|
1760 | // make leaf and finish with this KD-tree branch |
---|
1761 | // cout << "L, cnt=" << count << " ,d=" << GetDepth()() |
---|
1762 | // << " ,c=" << bestQ << " ,rat=" << ratio << "\n"; |
---|
1763 | // possibly cut empty space before leaf is created |
---|
1764 | if (cutEmptySpace) { |
---|
1765 | // setting initial depth if empty space cutting |
---|
1766 | startEmptyCutDepth = GetDepth(); |
---|
1767 | IncDepth(); |
---|
1768 | d->modeSubDiv = EE_SUBDIVCUTEMPTY; |
---|
1769 | // create the leaf first, with late empty cutting |
---|
1770 | SKTBNodeT *n = SubDiv(d); |
---|
1771 | if (!nodeToReturn) |
---|
1772 | nodeToReturn = n; |
---|
1773 | DecDepth(); |
---|
1774 | return nodeToReturn; // and finish by constructing a leaf |
---|
1775 | } |
---|
1776 | |
---|
1777 | // make leaf and finish |
---|
1778 | SKTBNodeT *n = MakeLeaf(d); |
---|
1779 | if (!nodeToReturn) |
---|
1780 | nodeToReturn = n; |
---|
1781 | return nodeToReturn; |
---|
1782 | } |
---|
1783 | } |
---|
1784 | |
---|
1785 | // Do not stop subdivision now |
---|
1786 | |
---|
1787 | // update the progress in the parameters |
---|
1788 | d->pars.ratioLastButOne = d->pars.ratioLast; |
---|
1789 | d->pars.ratioLast = ratio; |
---|
1790 | |
---|
1791 | // assure that axis is defined, if finding the |
---|
1792 | // splitting plane has failed |
---|
1793 | if ( (axis == CKTBAxes::EE_Leaf) || |
---|
1794 | (d->position == MAXFLOAT) ) { |
---|
1795 | // compute the spatial median for arbitrary axis |
---|
1796 | axis = (CKTBAxes::Axes)int(RandomValue(0.f, 2.98f)); |
---|
1797 | // set position based algorithm for the next cut and children |
---|
1798 | d->algorithmBreakAx = 0; |
---|
1799 | resetFlagsForBreakAx = true; |
---|
1800 | d->position = (d->box.Min(axis) + d->box.Max(axis)) * 0.5f; |
---|
1801 | d->twoSplits = 1; |
---|
1802 | } |
---|
1803 | } // subdivision automatic |
---|
1804 | |
---|
1805 | // ----------------------------------------------- |
---|
1806 | // We have evaluated surface area heuristics above |
---|
1807 | // if no winner for subdivision exists, make a leaf |
---|
1808 | if ( (axis == CKTBAxes::EE_Leaf) || |
---|
1809 | (d->position == MAXFLOAT) ) |
---|
1810 | { |
---|
1811 | //cerr << "This shall not happen" << endl; |
---|
1812 | SKTBNodeT *n = MakeLeaf(d); |
---|
1813 | if (!nodeToReturn) |
---|
1814 | nodeToReturn = n; |
---|
1815 | // cout << "LL\n"; |
---|
1816 | return nodeToReturn; |
---|
1817 | } |
---|
1818 | |
---|
1819 | if (verbose) { |
---|
1820 | #ifdef _DEBUG |
---|
1821 | |
---|
1822 | //#define _KTBPRINTCUTS |
---|
1823 | #ifndef _KTBPRINTCUTS |
---|
1824 | if (GetDepth() == 0) |
---|
1825 | #else |
---|
1826 | if (_printCuts) |
---|
1827 | #endif |
---|
1828 | { |
---|
1829 | cout << "position: " << d->position << ", axis: " |
---|
1830 | << (int)axis << ", depth=" << GetDepth() << ", box:" << endl; |
---|
1831 | Describe(d->box, cout, 0); |
---|
1832 | cout << endl; |
---|
1833 | } |
---|
1834 | #endif // _DEBUG |
---|
1835 | } |
---|
1836 | |
---|
1837 | #ifdef _DEBUG |
---|
1838 | if (d->twoSplits == -1) { |
---|
1839 | cerr << "Some problem in implementation" << endl; |
---|
1840 | abort();; |
---|
1841 | } |
---|
1842 | #endif |
---|
1843 | |
---|
1844 | // copy the parameters to use for splitting |
---|
1845 | d->axis = axis; |
---|
1846 | |
---|
1847 | if (d->twoSplits == 1) { |
---|
1848 | // create interior node with two successors |
---|
1849 | // case (1) |
---|
1850 | // DEBUG << "case 1 \n"; |
---|
1851 | // Make easy cut, using one position |
---|
1852 | IncDepth(); |
---|
1853 | SKTBNodeT* n = MakeOneCut(d); |
---|
1854 | if (!nodeToReturn) |
---|
1855 | nodeToReturn = n; |
---|
1856 | DecDepth(); |
---|
1857 | return nodeToReturn; |
---|
1858 | } |
---|
1859 | |
---|
1860 | #if 1 |
---|
1861 | cerr << "Unexpected use in this implementation" << endl; |
---|
1862 | cerr << "ABORTING " << endl; |
---|
1863 | abort();; |
---|
1864 | #endif |
---|
1865 | |
---|
1866 | // case case |
---|
1867 | // (2) or (3) structure must be created |
---|
1868 | // O O # |
---|
1869 | // / \ / \ # |
---|
1870 | // L RI LI R # |
---|
1871 | // / \ / \ # |
---|
1872 | // RL RR LL LR # |
---|
1873 | |
---|
1874 | #ifdef _DEBUG |
---|
1875 | if ( (d->box.Min()[axis] >= d->position) || |
---|
1876 | (d->position >= d->position2) || |
---|
1877 | (d->position2 >= d->box.Max()[axis]) ) { |
---|
1878 | cerr << " the case 2 or 3 is defined incorrectly\n"; |
---|
1879 | abort();; |
---|
1880 | } |
---|
1881 | #endif |
---|
1882 | |
---|
1883 | // To be reworked !!! |
---|
1884 | abort();; |
---|
1885 | if (d->twoSplits == 2) { |
---|
1886 | // ----------------------------------------- |
---|
1887 | // case (2) |
---|
1888 | // DEBUG << "case 2 \n"; |
---|
1889 | |
---|
1890 | // make L part, linked in DFS order |
---|
1891 | int cntLeft = 1; |
---|
1892 | int cntRight = 0; |
---|
1893 | IncDepth(); |
---|
1894 | SKTBNodeT *n = MakeOneCut(d); |
---|
1895 | if (!nodeToReturn) |
---|
1896 | nodeToReturn = n; |
---|
1897 | |
---|
1898 | // make RI part, linked to the left node explictly |
---|
1899 | SBBox rbb = d->box; // the bounding box |
---|
1900 | rbb.Reduce(axis, 1, d->position); |
---|
1901 | d->box = rbb; |
---|
1902 | d->pars.reqAxis = axis; |
---|
1903 | d->pars.reqPosition = d->position2; |
---|
1904 | SKTBNodeT *n2 = SubDiv(d); |
---|
1905 | DecDepth(); |
---|
1906 | //Link the node |
---|
1907 | SetInteriorNodeLinks(n, 0, n2); |
---|
1908 | return nodeToReturn; |
---|
1909 | } |
---|
1910 | |
---|
1911 | // ----------------------------------------- |
---|
1912 | // case (3) ????????????????? I am not sure if this is correct implementation !!! VH |
---|
1913 | // DEBUG << "case 3 \n"; |
---|
1914 | |
---|
1915 | // make LI part |
---|
1916 | SBBox lbb = d->box; // the bounding box |
---|
1917 | lbb.Reduce(axis, 0, d->position2); |
---|
1918 | int cntLeft = 0; |
---|
1919 | int cntRight = 1; |
---|
1920 | d->box = lbb; |
---|
1921 | d->position = d->position2; |
---|
1922 | d->axis = axis; |
---|
1923 | // the next subdivision step for R part |
---|
1924 | d->pars.reqAxis = axis; |
---|
1925 | d->pars.reqPosition = d->position; |
---|
1926 | |
---|
1927 | IncDepth(); |
---|
1928 | SKTBNodeT *nl = SubDiv(d); |
---|
1929 | if (!nodeToReturn) |
---|
1930 | nodeToReturn = nl; |
---|
1931 | |
---|
1932 | // make R part |
---|
1933 | SKTBNodeT *n = MakeOneCut(d); |
---|
1934 | DecDepth(); |
---|
1935 | SetInteriorNodeLinks(nl, 0, n); |
---|
1936 | // return left node, linked in DFS order to the previous one |
---|
1937 | return nodeToReturn; |
---|
1938 | } |
---|
1939 | |
---|
1940 | // makes cutting on the given position on given axis |
---|
1941 | // at value position, bb is the bounding box of current node, |
---|
1942 | // count is the number of objects in the node |
---|
1943 | // flags LeftF and RightF declares if to continue down after the recursion |
---|
1944 | SKTBNodeT * |
---|
1945 | CKTBABuildUp::MakeOneCut(SInputData *d) |
---|
1946 | { |
---|
1947 | // for testing accuracy of setting position from the ideal position |
---|
1948 | #ifdef _RANDOMIZE_POSITION |
---|
1949 | assert(d->algorithmBreakAx == 0); // position based |
---|
1950 | RandomizePosition(d->position, d->box.Min(d->axis), d->box.Max(d->axis)); |
---|
1951 | #endif //_RANDOMIZE_POSITION |
---|
1952 | |
---|
1953 | #ifdef _DEBUG |
---|
1954 | assert(d->position >= d->box.Min(d->axis)); |
---|
1955 | assert(d->position <= d->box.Max(d->axis)); |
---|
1956 | #endif |
---|
1957 | |
---|
1958 | SKTBNodeT *nodeToReturn = 0; |
---|
1959 | |
---|
1960 | #ifdef _KTB_CONSTR_STATS |
---|
1961 | // surface area of the interior nodes to be subdivided |
---|
1962 | _sumSurfaceAreaInteriorNodes += d->box.SA2(); |
---|
1963 | #endif // _KTB_CONSTR_STATS |
---|
1964 | |
---|
1965 | if (splitClip) { |
---|
1966 | // empty object list to store the pointers to the split objects |
---|
1967 | ObjectContainer objlist; |
---|
1968 | cerr << "Not yet handled" << endl; |
---|
1969 | abort();; |
---|
1970 | } |
---|
1971 | |
---|
1972 | #if 0 |
---|
1973 | // check if the lists are correctly sorted .. in debug |
---|
1974 | static int index = 0; |
---|
1975 | #if 1 |
---|
1976 | cout << "MakeOneCut index = " << index << " .. check axis = " |
---|
1977 | << d->axis << " count = " << d->count |
---|
1978 | << " depth = " << GetDepth() << endl; |
---|
1979 | const int indexToFind = 3743; |
---|
1980 | if (index == indexToFind) { |
---|
1981 | |
---|
1982 | cout << "Debug should start " << endl; |
---|
1983 | cout << "index = indexToFind" << endl; |
---|
1984 | } |
---|
1985 | #endif |
---|
1986 | index++; |
---|
1987 | #endif |
---|
1988 | |
---|
1989 | #ifdef _DEBUG |
---|
1990 | // We do not know the number of boundaries |
---|
1991 | Check3List(d); |
---|
1992 | #endif |
---|
1993 | |
---|
1994 | //#define _VYPIS |
---|
1995 | #ifdef _VYPIS |
---|
1996 | DEBUG << "START: Subdivision at pos=" |
---|
1997 | << position << " axis = " << axis << "\n"; |
---|
1998 | PrintOut(axis, 1, list+axis, sec+axis, Limits::Infinity); |
---|
1999 | #endif |
---|
2000 | |
---|
2001 | // axis .. the axis perpendicular to splitting plane positioned at position |
---|
2002 | // break active axis = split the list into two pieces |
---|
2003 | // list[axis] .. start of the first list in axis direction .. input |
---|
2004 | // second[axis] .. start of the second list in axis direction .. output |
---|
2005 | // objlist .. the list of objects that are duplicated |
---|
2006 | #ifdef _DEBUG |
---|
2007 | Check1List(d, d->axis, d->count); |
---|
2008 | //cout << "Axis = " << axis << endl; |
---|
2009 | #endif |
---|
2010 | |
---|
2011 | // We have to allocate a new node for right child |
---|
2012 | SInputData* rightData = AllocNewData(2*d->count); |
---|
2013 | // Copy the basic data from parent |
---|
2014 | rightData->CopyBasicData(d); |
---|
2015 | |
---|
2016 | // The number of objects for left children and right children |
---|
2017 | int cntL, cntR; |
---|
2018 | |
---|
2019 | //#ifdef _DEBUG |
---|
2020 | #if 1 |
---|
2021 | if (d->cntThickness < 0) { |
---|
2022 | cerr << "Problem, d->cntThickness = " << d->cntThickness << endl; |
---|
2023 | abort();; |
---|
2024 | } |
---|
2025 | #endif |
---|
2026 | |
---|
2027 | // Correct for cutting off empty space and many left |
---|
2028 | // boundaries on the splitting plane. |
---|
2029 | SItemVec *vec = d->GetItemVec(d->axis); |
---|
2030 | |
---|
2031 | if (d->algorithmBreakAx) { |
---|
2032 | // Use pointer-based break-ax algorithm |
---|
2033 | if (d->bestIterator == vec->begin()) { |
---|
2034 | assert(d->cntThickness == 0); |
---|
2035 | d->bestIterator--; |
---|
2036 | } |
---|
2037 | else { |
---|
2038 | if (d->count > 1) { |
---|
2039 | int origThickness = d->cntThickness; |
---|
2040 | SItemVec::iterator origIterator = d->bestIterator; |
---|
2041 | SItemVec::iterator it = d->bestIterator; |
---|
2042 | int caseBreak = 0; |
---|
2043 | if ((*(it)).IsLeftBoundary()) { |
---|
2044 | float pos = d->position; |
---|
2045 | it--; |
---|
2046 | int ir = 1; |
---|
2047 | assert(it != vec->begin()-1); |
---|
2048 | for ( ; true; ) { |
---|
2049 | if ( (*(it)).pos < pos) { |
---|
2050 | caseBreak = 0; |
---|
2051 | d->bestIterator = it; |
---|
2052 | if (ir > 1) |
---|
2053 | d->cntThickness -= ir; |
---|
2054 | break; |
---|
2055 | } |
---|
2056 | if (it == vec->begin()) { |
---|
2057 | // cutting off, #objects on the left = 0 |
---|
2058 | d->cntThickness = 0; |
---|
2059 | it--; |
---|
2060 | d->bestIterator = it; |
---|
2061 | caseBreak = 1; |
---|
2062 | break; |
---|
2063 | } |
---|
2064 | if ((*(it)).IsRightBoundary()) { |
---|
2065 | d->bestIterator = it; |
---|
2066 | if (ir > 1) |
---|
2067 | d->cntThickness -= ir; |
---|
2068 | caseBreak = 2; |
---|
2069 | break; |
---|
2070 | } |
---|
2071 | it--; |
---|
2072 | ir++; |
---|
2073 | } // for |
---|
2074 | #ifdef _DEBUG |
---|
2075 | if (d->cntThickness < 0) { |
---|
2076 | cerr << "Problem, d->cntThickness = " << d->cntThickness << endl; |
---|
2077 | cerr << " origThickness = " << origThickness << " Depth = " |
---|
2078 | << GetDepth() << endl; |
---|
2079 | for (SItemVec::iterator iq = it; iq != origIterator; iq++) { |
---|
2080 | cout << " pos = " << (*iq).pos; |
---|
2081 | if ((*iq).IsLeftBoundary()) |
---|
2082 | cout << " L "; |
---|
2083 | else |
---|
2084 | cout << " R "; |
---|
2085 | cout << (*iq).obj << endl; |
---|
2086 | } // for |
---|
2087 | cout << "AAAA" << endl; |
---|
2088 | abort();; |
---|
2089 | } |
---|
2090 | #endif |
---|
2091 | } // if left boundary |
---|
2092 | } // if d->count > 1 |
---|
2093 | } // if d->vec is not the beginning of the list |
---|
2094 | } // pointer based break-ax algorithm |
---|
2095 | |
---|
2096 | #if 0 |
---|
2097 | DEBUG << "MakeOneCut cntL = " << cntL << " cntR = " << cntR << endl; |
---|
2098 | #endif |
---|
2099 | |
---|
2100 | // Here is the breaking the arrays into two arrays, compute the number |
---|
2101 | // of objects on the left and on the right of the splitting plane |
---|
2102 | int dCountTagging = 0; |
---|
2103 | // Use either |
---|
2104 | if (d->algorithmBreakAx == 0) |
---|
2105 | BreakAxPosition(d, d->axis, rightData, cntL, cntR); |
---|
2106 | else |
---|
2107 | BreakAx(d, d->axis, rightData, cntL, cntR); |
---|
2108 | |
---|
2109 | #ifdef _DEBUG |
---|
2110 | // the number of objects on the left and on the right |
---|
2111 | int cntL_B = cntL; |
---|
2112 | int cntR_B = cntR; |
---|
2113 | #if 0 |
---|
2114 | cout << "B - Count*2 = " << d->count*2 |
---|
2115 | << " countSum = " << cntL_B + cntR_B |
---|
2116 | << " CntL_B = " << cntL_B |
---|
2117 | << " cntR_B = " << cntR_B << endl; |
---|
2118 | #endif |
---|
2119 | //Check1List(alist, axis, cntL_B, true, position); |
---|
2120 | Check1List(d, d->axis, cntL_B); |
---|
2121 | Check1List(rightData, d->axis, cntR_B); |
---|
2122 | // cout << "AxisNext = " << oax0 << endl; |
---|
2123 | #endif |
---|
2124 | |
---|
2125 | // DEBUG << "THE CHECK at DEPTH=" << GetDepth() << endl; |
---|
2126 | |
---|
2127 | #ifdef _VYPIS |
---|
2128 | DEBUG << "After Break at pos=" |
---|
2129 | << position << " axis = " << axis << "\n"; |
---|
2130 | PrintOut(d, axis, d->position); |
---|
2131 | #endif |
---|
2132 | |
---|
2133 | #ifdef _VYPIS |
---|
2134 | DEBUG << "BEFORE oax0\n"; |
---|
2135 | PrintOut(d, oax0, Limits::Infinity); |
---|
2136 | #endif |
---|
2137 | |
---|
2138 | // -------------------------------------------------- |
---|
2139 | // break other two axes |
---|
2140 | CKTBAxes::Axes oax0 = oaxes[d->axis][0]; |
---|
2141 | #ifdef _DEBUG |
---|
2142 | Check1List(d, oax0, d->count); |
---|
2143 | #endif |
---|
2144 | |
---|
2145 | SItemVec *vecc = d->GetItemVec(oax0); |
---|
2146 | if (vecc->size() != 2 * d->count) { |
---|
2147 | cout << "AAAA 1" << endl; |
---|
2148 | } |
---|
2149 | |
---|
2150 | // Here break the list in the next axis |
---|
2151 | #ifdef _USE_OPTIMIZE_DIVIDE_AX |
---|
2152 | DivideAx_I_opt(d, oax0, rightData, cntL, cntR); |
---|
2153 | #else |
---|
2154 | DivideAx_I(d, oax0, rightData, cntL, cntR); |
---|
2155 | #endif |
---|
2156 | |
---|
2157 | if (vecc->size() != 2 * cntL) { |
---|
2158 | cout << "AAAA 3" << endl; |
---|
2159 | } |
---|
2160 | if (rightData->GetItemVec(oax0)->size() != 2 * cntR) { |
---|
2161 | cout << "AAAA 4" << endl; |
---|
2162 | cout << "cntR * 2 = " << 2 * cntR << endl; |
---|
2163 | cout << "vecSize = " << rightData->GetItemVec(oax0)->size() << endl; |
---|
2164 | } |
---|
2165 | |
---|
2166 | #ifdef _DEBUG |
---|
2167 | // the number of objects on the left and on the right |
---|
2168 | int cntL_I = cntL; |
---|
2169 | int cntR_I = cntR; |
---|
2170 | #if 0 |
---|
2171 | cout << "I - Count*2 = " << count*2 |
---|
2172 | << " countSum = " << cntL_I + cntR_I |
---|
2173 | << " CntL_B = " << cntL_I |
---|
2174 | << " cntR_B = " << cntR_I << endl; |
---|
2175 | #endif |
---|
2176 | |
---|
2177 | if (cntL_I != cntL_B) { |
---|
2178 | cerr << "FirstList - Problem with DivideAx_I, cntL_B = " << cntL_B |
---|
2179 | << " and cntL_I = " << cntL_I << endl; |
---|
2180 | } |
---|
2181 | if (cntR_I != cntR_B) { |
---|
2182 | cerr << "SecondList = Problem with DivideAx_I, cntR_B = " << cntR_B |
---|
2183 | << " and cntR_I = " << cntR_I << endl; |
---|
2184 | } |
---|
2185 | |
---|
2186 | Check1List(d, oax0, cntL_B); |
---|
2187 | Check1List(rightData, oax0, cntR_B); |
---|
2188 | |
---|
2189 | //cout << "AxisNextNext = " << oax1 << endl; |
---|
2190 | |
---|
2191 | #endif |
---|
2192 | |
---|
2193 | #ifdef _VYPIS |
---|
2194 | DEBUG << "AFTER DivideAx oax0\n"; |
---|
2195 | PrintOut(oax0, 3, alist + oax0, sec+oax0, 0); |
---|
2196 | #endif |
---|
2197 | |
---|
2198 | #ifdef _VYPIS |
---|
2199 | DEBUG << "BEFORE oax1\n"; |
---|
2200 | PrintOut(oax1, 1, alist + oax1, sec+oax1, Limits::Infinity); |
---|
2201 | #endif |
---|
2202 | |
---|
2203 | // Her break the list in the next next axis |
---|
2204 | CKTBAxes::Axes oax1 = oaxes[d->axis][1]; |
---|
2205 | |
---|
2206 | SItemVec *vec2 = d->GetItemVec(oax1); |
---|
2207 | if (vec2->size() != 2 * d->count) { |
---|
2208 | cout << "BBBB 1" << endl; |
---|
2209 | } |
---|
2210 | |
---|
2211 | #ifdef _USE_OPTIMIZE_DIVIDE_AX |
---|
2212 | DivideAx_II_opt(d, oax1, rightData, cntL, cntR); |
---|
2213 | #else |
---|
2214 | DivideAx_II(d, oax1, rightData, cntL, cntR); |
---|
2215 | #endif |
---|
2216 | |
---|
2217 | if (vec2->size() != 2 * cntL) { |
---|
2218 | cout << "BBBB 3" << endl; |
---|
2219 | cout << "cntL * 2 = " << 2 * cntL << endl; |
---|
2220 | cout << "vec2size = " << vec2->size() << endl; |
---|
2221 | } |
---|
2222 | if (rightData->GetItemVec(oax1)->size() != 2 * cntR) { |
---|
2223 | cout << "BBBB 4" << endl; |
---|
2224 | cout << "cntR * 2 = " << 2 * cntR << endl; |
---|
2225 | cout << "vecSize = " << rightData->GetItemVec(oax1)->size() << endl; |
---|
2226 | } |
---|
2227 | |
---|
2228 | #ifdef _DEBUG |
---|
2229 | int cntL_II = cntL; |
---|
2230 | int cntR_II = cntR; |
---|
2231 | #if 0 |
---|
2232 | cout << "II - Count*2 = " << count*2 |
---|
2233 | << " countSum = " << cntL_II + cntR_II |
---|
2234 | << " CntL_B = " << cntL_II |
---|
2235 | << " cntR_B = " << cntR_II << endl; |
---|
2236 | #endif |
---|
2237 | if (cntL_II != cntL_B) { |
---|
2238 | cerr << "FirstList - Problem with DivideAx_II, cntL_B = " << cntL_B |
---|
2239 | << " and cntL_I = " << cntL_I |
---|
2240 | << " and cntL_II = " << cntL_II << endl; |
---|
2241 | } |
---|
2242 | if (cntR_II != cntR_B) { |
---|
2243 | cerr << "Second List - Problem with DivideAx_II, cntR_B = " << cntR_B |
---|
2244 | << " and cntR_I = " << cntR_I |
---|
2245 | << " and cntR_II = " << cntR_II << endl; |
---|
2246 | } |
---|
2247 | |
---|
2248 | Check1List(d, oax1, cntL_B); |
---|
2249 | Check1List(rightData, oax1, cntR_B); |
---|
2250 | |
---|
2251 | if ( (cntL_I != cntL_II) || |
---|
2252 | (cntR_I != cntR_II) ) { |
---|
2253 | cout << "Problem with dividing axis II: cntL_I = " << cntL_I |
---|
2254 | << " cntL_II = " << cntL_II |
---|
2255 | << " cntR_I = " << cntR_I |
---|
2256 | << " cntR_II = " << cntR_II << endl; |
---|
2257 | } |
---|
2258 | #endif |
---|
2259 | |
---|
2260 | #ifdef _VYPIS |
---|
2261 | DEBUG << "AFTER DivideAx oax1\n"; |
---|
2262 | PrintOut(oax1, 3, alist + oax1, sec+oax1, position); |
---|
2263 | #endif |
---|
2264 | |
---|
2265 | // Allocate the representation of the interior node |
---|
2266 | SKTBNodeT *node = 0; |
---|
2267 | |
---|
2268 | if (makeMinBoxHere) { |
---|
2269 | // ------------------------------------------------------- |
---|
2270 | // interior node with the box |
---|
2271 | node = AllocInteriorNodeWithBox(// interior node data |
---|
2272 | d->axis, d->position, cntL, cntR, |
---|
2273 | // box data |
---|
2274 | d->box, d->lastMinBoxNode, d->lastDepthForMinBoxes); |
---|
2275 | |
---|
2276 | //cout << "depth = " << GetDepth() << " node = " << node |
---|
2277 | // << " lastMinBoxNode = " << d->lastMinBoxNode << endl; |
---|
2278 | |
---|
2279 | d->lastMinBoxNode = node; // we have to remember the last node |
---|
2280 | rightData->lastMinBoxNode = node; |
---|
2281 | makeMinBoxHere = false; // reset for the next time |
---|
2282 | } |
---|
2283 | else |
---|
2284 | // normal interior node (=without box) |
---|
2285 | node = AllocInteriorNode(d->axis, d->position, cntL, cntR); |
---|
2286 | |
---|
2287 | #ifdef _DEBUG |
---|
2288 | if (!node) { |
---|
2289 | cerr << "Allocation of Interior Node failed.\n"; |
---|
2290 | abort();; |
---|
2291 | } |
---|
2292 | #endif // _DEBUG |
---|
2293 | // set the node to be returned |
---|
2294 | if (!nodeToReturn) |
---|
2295 | nodeToReturn = nodeToLink; |
---|
2296 | assert(node); |
---|
2297 | assert(nodeToReturn); |
---|
2298 | |
---|
2299 | #if 0 |
---|
2300 | // If we make split clipping, then we want to reduce the boxes for |
---|
2301 | // the objects straddling the splitting plane now. |
---|
2302 | if ((splitClip) && (objlist.ListCount() > 0 )) { |
---|
2303 | // if the objects are split by splitting plane |
---|
2304 | //DEBUG << "Reduces box ax=" << axis << " position=" |
---|
2305 | // << position << "#split_objs=" << objlist.ListCount() << "\n" << flush; |
---|
2306 | ReduceBBoxes(d, d->axis, rightData, d->position); |
---|
2307 | } |
---|
2308 | #endif |
---|
2309 | |
---|
2310 | // --------------------------------------------- |
---|
2311 | // initialize the left bounding box 'bb' |
---|
2312 | d->box.Reduce(d->axis, 0, d->position); |
---|
2313 | |
---|
2314 | // initialize the right bounding box 'rbb' |
---|
2315 | rightData->box.Reduce(d->axis, 1, d->position); |
---|
2316 | |
---|
2317 | // Set correct number of objects |
---|
2318 | d->count = cntL; |
---|
2319 | rightData->count = cntR; |
---|
2320 | |
---|
2321 | // The children nodes to be created |
---|
2322 | SKTBNodeT *nodeL=0, *nodeR=0; |
---|
2323 | |
---|
2324 | // Recurse to the left child |
---|
2325 | if (d->makeSubdivisionLeft) { |
---|
2326 | // subdivide branches |
---|
2327 | ESubdivMode modeLeft = d->modeSubDiv ; |
---|
2328 | if ( (cutEmptySpace) && |
---|
2329 | (modeLeft != EE_SUBDIVCUTEMPTY) && |
---|
2330 | (d->count <= maxListLength) ) { |
---|
2331 | // setting initial depth if empty space cutting |
---|
2332 | startEmptyCutDepth = GetDepth(); |
---|
2333 | d->modeSubDiv = EE_SUBDIVCUTEMPTY; |
---|
2334 | } |
---|
2335 | // DEBUG << "Left cnt= " << (cnt[0] >> 1) << " depth= " |
---|
2336 | // << GetDepth() << "\n"; |
---|
2337 | nodeL = SubDiv(d); |
---|
2338 | } |
---|
2339 | |
---|
2340 | // Recurse to the right child |
---|
2341 | if (rightData->makeSubdivisionRight) { |
---|
2342 | ESubdivMode modeRight = d->modeSubDiv ; |
---|
2343 | if ( (cutEmptySpace) && |
---|
2344 | (modeRight != EE_SUBDIVCUTEMPTY) && |
---|
2345 | (rightData->count <= maxListLength) ) { |
---|
2346 | // setting initial depth if empty space cutting |
---|
2347 | startEmptyCutDepth = GetDepth(); |
---|
2348 | rightData->modeSubDiv = EE_SUBDIVCUTEMPTY; |
---|
2349 | } |
---|
2350 | // DEBUG << "Right cnt= " << (cnt[1] >> 1) << " depth= " |
---|
2351 | // << GetDepth() << "\n"; |
---|
2352 | nodeR = SubDiv(rightData); |
---|
2353 | |
---|
2354 | } |
---|
2355 | |
---|
2356 | // Free the data to be reused further on |
---|
2357 | FreeLastData(); |
---|
2358 | |
---|
2359 | // Set the node pointers to the children for created node |
---|
2360 | SetInteriorNodeLinks(node, nodeL, nodeR); |
---|
2361 | |
---|
2362 | return nodeToReturn; // return the node |
---|
2363 | } |
---|
2364 | |
---|
2365 | // returns a box enclosing all the objects in the node |
---|
2366 | void |
---|
2367 | CKTBABuildUp::GetTightBox(const SInputData &i, SBBox &tbox) |
---|
2368 | { |
---|
2369 | // Index to the last boundary |
---|
2370 | int cnt = 2*i.count-1; |
---|
2371 | |
---|
2372 | tbox.MinX() = (*(i.xvec))[0].pos; |
---|
2373 | tbox.MinY() = (*(i.yvec))[0].pos; |
---|
2374 | tbox.MinZ() = (*(i.zvec))[0].pos; |
---|
2375 | tbox.MaxX() = (*(i.xvec))[cnt].pos; |
---|
2376 | tbox.MaxY() = (*(i.yvec))[cnt].pos; |
---|
2377 | tbox.MaxZ() = (*(i.zvec))[cnt].pos; |
---|
2378 | |
---|
2379 | assert(tbox.MinX() >= i.box.MinX()); |
---|
2380 | assert(tbox.MaxX() <= i.box.MaxX()); |
---|
2381 | assert(tbox.MinY() >= i.box.MinY()); |
---|
2382 | assert(tbox.MaxY() <= i.box.MaxY()); |
---|
2383 | assert(tbox.MinZ() >= i.box.MinZ()); |
---|
2384 | assert(tbox.MaxZ() <= i.box.MaxZ()); |
---|
2385 | } |
---|
2386 | |
---|
2387 | |
---|
2388 | // returns a box enclosing all the objects in the node |
---|
2389 | int |
---|
2390 | CKTBABuildUp::GetEBox(const SInputData &i, SBBox &tbox) |
---|
2391 | { |
---|
2392 | // LEFT BOX |
---|
2393 | // initialization |
---|
2394 | |
---|
2395 | // Index to the last boundary |
---|
2396 | int cnt = 2*i.count-1; |
---|
2397 | int changed = 0; // number of planes, that are changed by bounding box |
---|
2398 | |
---|
2399 | float xMin = (*(i.xvec))[0].pos; |
---|
2400 | changed = (xMin > i.box.Min(0)) ? changed+1 : changed; |
---|
2401 | float xMax = (*(i.xvec))[cnt].pos; |
---|
2402 | changed = (xMax < i.box.Max(0)) ? changed+1 : changed; |
---|
2403 | |
---|
2404 | float yMin = (*(i.yvec))[0].pos; |
---|
2405 | changed = (yMin > i.box.Min(1)) ? changed+1 : changed; |
---|
2406 | float yMax = (*(i.yvec))[cnt].pos; |
---|
2407 | changed = (yMax < i.box.Max(1)) ? changed+1 : changed; |
---|
2408 | |
---|
2409 | float zMin = (*(i.zvec))[0].pos; |
---|
2410 | changed = (zMin > i.box.Min(2)) ? changed+1 : changed; |
---|
2411 | float zMax = (*(i.zvec))[cnt].pos; |
---|
2412 | changed = (zMax < i.box.Max(2)) ? changed+1 : changed; |
---|
2413 | |
---|
2414 | // Set the bounding (reduced) box |
---|
2415 | tbox.Min() = Vector3(xMin, yMin, zMin); |
---|
2416 | tbox.Max() = Vector3(xMax, yMax, zMax); |
---|
2417 | |
---|
2418 | // Return the number of bounding splitting planes with respect to original box |
---|
2419 | return changed; |
---|
2420 | } |
---|
2421 | |
---|
2422 | |
---|
2423 | // This is only for debugging purposes, to be removed! |
---|
2424 | static |
---|
2425 | CKTBABuildUp::SSolid* objtf = (CKTBABuildUp::SSolid*)0x0; |
---|
2426 | |
---|
2427 | // removes the objects specified in "tagobjlist" from boundary "list" |
---|
2428 | // it supposes the "tagobjlist" is ordered in the left boundary order |
---|
2429 | // in CKTBAxes::EE_X_axis. |
---|
2430 | void |
---|
2431 | CKTBABuildUp::RemoveObjects(SItemVec *vec, int cntObjects) |
---|
2432 | { |
---|
2433 | assert(vec); |
---|
2434 | assert(cntObjects); |
---|
2435 | |
---|
2436 | // number of removed left boundaries |
---|
2437 | int cnt = 0; |
---|
2438 | |
---|
2439 | SItemVec::iterator curr; |
---|
2440 | #ifdef _DEBUG |
---|
2441 | int cnt2 = 0; |
---|
2442 | for (curr = vec->begin(); curr != vec->end(); curr++) |
---|
2443 | { |
---|
2444 | if (curr->obj->ToBeRemoved()) { |
---|
2445 | //cout << cnt2 << " " << curr - vec->begin() << endl; |
---|
2446 | cnt2++; |
---|
2447 | } |
---|
2448 | //if (curr->obj == objtf) |
---|
2449 | // cout << "Index found cnt2 = " << cnt2 << endl; |
---|
2450 | } // for |
---|
2451 | if (cnt2 != 2*cntObjects) { |
---|
2452 | cerr << "Some problem with data marking" << endl; |
---|
2453 | abort();; |
---|
2454 | } |
---|
2455 | #endif |
---|
2456 | |
---|
2457 | // Find the first boundary |
---|
2458 | for (curr = vec->begin(); curr != vec->end(); curr++) |
---|
2459 | { |
---|
2460 | //if (curr->obj == objtf) |
---|
2461 | //cout << "2 Index found cnt2 = " << cnt2 << endl; |
---|
2462 | |
---|
2463 | if (curr->obj->ToBeRemoved()) { |
---|
2464 | cnt++; // the number of removed boundaries |
---|
2465 | assert(curr->IsLeftBoundary()); |
---|
2466 | //cout << cnt << " objToRemove=" << curr->obj << endl; |
---|
2467 | break; |
---|
2468 | } |
---|
2469 | } |
---|
2470 | // the first element to be overwritten |
---|
2471 | SItemVec::iterator it = curr; |
---|
2472 | curr++; |
---|
2473 | |
---|
2474 | for ( ; curr != vec->end(); curr++) { |
---|
2475 | //if (curr->obj == objtf) { |
---|
2476 | // cout << "3 Index found cnt2 = " << cnt2 << endl; |
---|
2477 | |
---|
2478 | if (curr->obj->ToBeRemoved()) { |
---|
2479 | cnt++; // the number of removed boundaries |
---|
2480 | //cout << cnt << " " << curr->obj << endl; |
---|
2481 | if (cnt == cntObjects*2) { |
---|
2482 | curr++; |
---|
2483 | break; |
---|
2484 | } |
---|
2485 | } |
---|
2486 | else { |
---|
2487 | // copy the element to the right place |
---|
2488 | *it = *curr; |
---|
2489 | it++; |
---|
2490 | } |
---|
2491 | } // for |
---|
2492 | |
---|
2493 | #ifdef _DEBUG |
---|
2494 | if (cnt != 2*cntObjects) { |
---|
2495 | cerr << "Problem with removing objects implementation" << endl; |
---|
2496 | abort();; |
---|
2497 | } |
---|
2498 | #endif |
---|
2499 | |
---|
2500 | // copy the rest of the list to the right place |
---|
2501 | for ( ; curr != vec->end(); curr++, it++) |
---|
2502 | { |
---|
2503 | //if (curr->obj == objtf) { |
---|
2504 | // cout << "4 Index found cnt2 = " << cnt2 << endl; |
---|
2505 | |
---|
2506 | // copy the element to the right place |
---|
2507 | *it = *curr; |
---|
2508 | } |
---|
2509 | |
---|
2510 | // resize the vector correctly |
---|
2511 | int oldSize = vec->size(); |
---|
2512 | assert(oldSize >= cnt); |
---|
2513 | if (oldSize == cnt) |
---|
2514 | vec->erase(vec->begin(), vec->end()); |
---|
2515 | else |
---|
2516 | vec->resize(oldSize - cnt); |
---|
2517 | assert(vec->size() % 2 == 0); |
---|
2518 | assert(vec->size() == oldSize - cnt); |
---|
2519 | |
---|
2520 | #ifdef _DEBUG |
---|
2521 | for (curr = vec->begin(); curr != vec->end(); curr++) |
---|
2522 | { |
---|
2523 | if (curr->obj->ToBeRemoved()) { |
---|
2524 | cerr << "Implementation bug" << endl; |
---|
2525 | abort();; |
---|
2526 | } // if left boundary |
---|
2527 | } // for |
---|
2528 | #endif |
---|
2529 | |
---|
2530 | //cout << "size = " << vec->size() << endl; |
---|
2531 | |
---|
2532 | return; |
---|
2533 | } |
---|
2534 | |
---|
2535 | // removes the objects specified in "tagobjlist" from boundary "list" |
---|
2536 | // it supposes the "tagobjlist" is ordered in the left boundary order |
---|
2537 | // in CKTBAxes::EE_X_axis. |
---|
2538 | void |
---|
2539 | CKTBABuildUp::RemoveObjectsReset(SItemVec *vec, int cntObjects) |
---|
2540 | { |
---|
2541 | assert(vec); |
---|
2542 | assert(cntObjects); |
---|
2543 | |
---|
2544 | // number of removed left boundaries |
---|
2545 | int cnt = 0; |
---|
2546 | SItemVec::iterator curr; |
---|
2547 | |
---|
2548 | #ifdef _DEBUG |
---|
2549 | int cnt2 = 0; |
---|
2550 | for (curr = vec->begin(); curr != vec->end(); curr++) |
---|
2551 | { |
---|
2552 | if (curr->obj->ToBeRemoved()) { |
---|
2553 | //cout << cnt2 << " " << curr - vec->begin() << endl; |
---|
2554 | cnt2++; |
---|
2555 | } |
---|
2556 | } // for |
---|
2557 | if (cnt2 != 2*cntObjects) { |
---|
2558 | cerr << "Some problem with data marking" << endl; |
---|
2559 | abort();; |
---|
2560 | } |
---|
2561 | #endif |
---|
2562 | |
---|
2563 | // Find the first boundary |
---|
2564 | for (curr = vec->begin(); curr != vec->end(); curr++) |
---|
2565 | { |
---|
2566 | if (curr->obj->ToBeRemoved()) { |
---|
2567 | cnt++; // the number of removed boundaries |
---|
2568 | assert(curr->IsLeftBoundary()); |
---|
2569 | curr++; |
---|
2570 | break; |
---|
2571 | } |
---|
2572 | } |
---|
2573 | SItemVec::iterator it = curr; |
---|
2574 | it--; // the first element to be overwritten |
---|
2575 | |
---|
2576 | for ( ; curr != vec->end(); curr++) { |
---|
2577 | if (curr->obj->ToBeRemoved()) { |
---|
2578 | cnt++; // the number of removed boundaries |
---|
2579 | if (curr->IsRightBoundary()) { |
---|
2580 | curr->obj->ResetFlags(); |
---|
2581 | assert(curr->obj->flags == 0); |
---|
2582 | } |
---|
2583 | if (cnt == cntObjects*2) { |
---|
2584 | curr++; |
---|
2585 | break; |
---|
2586 | } |
---|
2587 | } |
---|
2588 | else { |
---|
2589 | // copy the element to the right place |
---|
2590 | *it = *curr; |
---|
2591 | it++; |
---|
2592 | } |
---|
2593 | } // for |
---|
2594 | |
---|
2595 | #ifdef _DEBUG |
---|
2596 | if (cnt != 2*cntObjects) { |
---|
2597 | cerr << "Problem with removing objects implementation" << endl; |
---|
2598 | abort();; |
---|
2599 | } |
---|
2600 | #endif |
---|
2601 | |
---|
2602 | // copy the rest of the list to the right place |
---|
2603 | for ( ; curr != vec->end(); curr++, it++) |
---|
2604 | { |
---|
2605 | // copy the element to the right place |
---|
2606 | *it = *curr; |
---|
2607 | } |
---|
2608 | |
---|
2609 | // resize the vector correctly |
---|
2610 | int oldSize = vec->size(); |
---|
2611 | assert(oldSize >= cnt); |
---|
2612 | if (oldSize == cnt) |
---|
2613 | vec->erase(vec->begin(), vec->end()); |
---|
2614 | else |
---|
2615 | vec->resize(oldSize - cnt); |
---|
2616 | assert(vec->size() % 2 == 0); |
---|
2617 | assert(vec->size() == oldSize - cnt); |
---|
2618 | |
---|
2619 | #ifdef _DEBUG |
---|
2620 | for (curr = vec->begin(); curr != vec->end(); curr++) |
---|
2621 | { |
---|
2622 | if (curr->obj->ToBeRemoved()) { |
---|
2623 | cerr << "Implementation bug" << endl; |
---|
2624 | abort();; |
---|
2625 | } // if left boundary |
---|
2626 | } // for |
---|
2627 | #endif |
---|
2628 | |
---|
2629 | //cout << "size = " << vec->size() << endl; |
---|
2630 | |
---|
2631 | return; |
---|
2632 | } |
---|
2633 | |
---|
2634 | |
---|
2635 | // make the full leaf from current node |
---|
2636 | SKTBNodeT* |
---|
2637 | CKTBABuildUp::MakeLeaf(SInputData *d) |
---|
2638 | { |
---|
2639 | #ifdef _KTBPRINTCUTS |
---|
2640 | cout << " Creating leaf, depth = " << GetDepth() |
---|
2641 | << " cntObjs = " << count << endl; |
---|
2642 | //exit(3); |
---|
2643 | #endif |
---|
2644 | |
---|
2645 | #ifdef _KTB_CONSTR_STATS |
---|
2646 | // update the statistics |
---|
2647 | float sa2bb; |
---|
2648 | _sumSurfaceAreaLeaves += (sa2bb = d->box.SA2()); |
---|
2649 | _sumSurfaceAreaMULcntLeaves += ((float)d->count * sa2bb); |
---|
2650 | #endif // _KTB_CONSTR_STATS |
---|
2651 | |
---|
2652 | // ------------------------------------------------------ |
---|
2653 | // The version with allocating empty leaves. This makes |
---|
2654 | // sense since in DFS order it works correctly |
---|
2655 | SKTBNodeT *node = AllocLeaf(d->count); |
---|
2656 | |
---|
2657 | if (d->count > 0) { |
---|
2658 | // copy the list of objects |
---|
2659 | ObjectContainer *objlist = NULL; |
---|
2660 | objlist = new ObjectContainer; |
---|
2661 | |
---|
2662 | SItemVec *vec = d->GetItemVec(0); |
---|
2663 | SItemVec::iterator curr; |
---|
2664 | for (curr = vec->begin(); curr != vec->end(); curr++) { |
---|
2665 | if ( (*curr).IsLeftBoundary()) // skip all right boundaries |
---|
2666 | objlist->push_back( (*curr).obj->obj); |
---|
2667 | } |
---|
2668 | |
---|
2669 | assert(objlist->size() != 0); |
---|
2670 | // Do not delete the object list, it is used as allocated above |
---|
2671 | SetFullLeaf(node, objlist); |
---|
2672 | } |
---|
2673 | |
---|
2674 | // We assume that the allocation of the single leaf cannot |
---|
2675 | // fail, since this one shall be the last in the sequence. |
---|
2676 | assert(node == nodeToLink); |
---|
2677 | |
---|
2678 | // Return the node to be used in the linking |
---|
2679 | return nodeToLink; |
---|
2680 | } |
---|
2681 | |
---|
2682 | // split the list along the required axis |
---|
2683 | // first is the begin of the SItem list, axis is the axis, where |
---|
2684 | // to split, val is the splitting value in integer notation. |
---|
2685 | // The output of the function are two lists, first and second |
---|
2686 | // Optionally, objlist store the objects that straddle the splitting plane |
---|
2687 | void |
---|
2688 | CKTBABuildUp::BreakAx(SInputData *d, int axis, |
---|
2689 | SInputData *rightData, |
---|
2690 | int &cntLout, int &cntRout) |
---|
2691 | { |
---|
2692 | // the number of object boundaries for left array |
---|
2693 | int cntLeft = (d->bestIterator) - d->GetItemVec(axis)->begin() + 1; |
---|
2694 | assert(cntLeft >= 0); |
---|
2695 | assert(cntLeft <= 2*d->count); |
---|
2696 | // the number of object boundaries for right array |
---|
2697 | int cntRight = d->count*2 - cntLeft; |
---|
2698 | assert(cntRight >= 0); |
---|
2699 | assert(cntRight <= 2*d->count); |
---|
2700 | assert(d->cntThickness >= 0); |
---|
2701 | cntLeft += d->cntThickness; // duplicated boundaries for left array |
---|
2702 | cntRight += d->cntThickness; // duplicated boundaries for right array |
---|
2703 | assert(cntLeft + cntRight == (d->count + d->cntThickness) * 2); |
---|
2704 | |
---|
2705 | #ifdef _DEBUG |
---|
2706 | if ( (cntLeft % 2 != 0) || |
---|
2707 | (cntRight % 2 != 0) ) { |
---|
2708 | int i = 0; |
---|
2709 | SItemVec *vec = d->GetItemVec(axis); |
---|
2710 | cout << "d->count = " << d->count ; |
---|
2711 | cout << "cntLeft = " << cntLeft << " cntRight" << cntRight << endl; |
---|
2712 | cout << "bestIterator = " << (int)(d->bestIterator - vec->begin()); |
---|
2713 | cout << " cntThickness= " << d->cntThickness << " position=" << d->position << endl; |
---|
2714 | for (SItemVec::iterator itt = vec->begin(); itt != vec->end(); itt++, i++) |
---|
2715 | { |
---|
2716 | cout << i << " = "; |
---|
2717 | if ((*itt).IsLeftBoundary()) |
---|
2718 | cout << "L"; else cout << "R"; |
---|
2719 | cout << " obj = " << (*itt).obj << " pos = " << (*itt).pos << endl; |
---|
2720 | } |
---|
2721 | abort();; |
---|
2722 | } |
---|
2723 | #endif |
---|
2724 | |
---|
2725 | // A special case, right list is empty |
---|
2726 | if (cntRight == 0) { |
---|
2727 | assert(d->cntThickness == 0); |
---|
2728 | rightData->Alloc(0); |
---|
2729 | rightData->count = 0; |
---|
2730 | // The final setting of number of objects |
---|
2731 | cntLout = cntLeft / 2; |
---|
2732 | cntRout = cntRight / 2; |
---|
2733 | return; // nothing to do |
---|
2734 | } |
---|
2735 | |
---|
2736 | // We have some problem that is difficult to detect, when tagging objects |
---|
2737 | // are allowed, the flags are not always reset to zero in some cases. |
---|
2738 | // VH 2/1/2006. The flags are always left boundaries (=1). |
---|
2739 | // Therefore here it is a hack to assure that the flags are definitely zero. |
---|
2740 | if (resetFlagsForBreakAx) { |
---|
2741 | SItemVec *vecd = d->GetItemVec(axis); |
---|
2742 | for (SItemVec::iterator itt = vecd->begin(); itt != vecd->end(); itt++) { |
---|
2743 | (*itt).obj->ResetFlags(); |
---|
2744 | } // for |
---|
2745 | } // if |
---|
2746 | |
---|
2747 | #ifdef _DEBUG |
---|
2748 | SItemVec *vecd = d->GetItemVec(axis); |
---|
2749 | for (SItemVec::iterator itt = vecd->begin(); itt != vecd->end(); itt++) { |
---|
2750 | if ((*itt).obj->Flags() != 0) { |
---|
2751 | cout << "Init ERROR 1 in original list, flags = " |
---|
2752 | << (*itt).obj->Flags() << " obj = " << (void*)((*itt).obj) << endl; |
---|
2753 | } |
---|
2754 | } // for |
---|
2755 | #endif // _DEBUG |
---|
2756 | |
---|
2757 | assert(cntRight > 0); |
---|
2758 | |
---|
2759 | // Allocate the appropriate size for right array, for all 3 axes |
---|
2760 | rightData->Alloc(cntRight); |
---|
2761 | |
---|
2762 | // First find create all left boundaries for right array |
---|
2763 | SItem boundary; // create left boundary |
---|
2764 | SItemVec *vecRight = rightData->GetItemVec(axis); |
---|
2765 | |
---|
2766 | #define _USE_PUSHBACK |
---|
2767 | #ifdef _USE_PUSHBACK |
---|
2768 | vecRight->resize(0); |
---|
2769 | #else |
---|
2770 | vecRight->resize(cntRight); |
---|
2771 | #endif |
---|
2772 | if (d->cntThickness) { |
---|
2773 | boundary.pos = d->position; |
---|
2774 | boundary.axis = axis; |
---|
2775 | boundary.SetLeftBoundary(); |
---|
2776 | #ifdef _USE_PUSHBACK |
---|
2777 | int i; |
---|
2778 | for (i = 0; i < d->cntThickness; i++) { |
---|
2779 | vecRight->push_back(boundary); // Note that the objects pointed to are not set !!! |
---|
2780 | } // for i; |
---|
2781 | #else |
---|
2782 | for (int i = 0; i < d->cntThickness; i++) { |
---|
2783 | (*vecRight)[i] = boundary; // Note that the objects pointed to are not set !!! |
---|
2784 | } // for i; |
---|
2785 | #endif |
---|
2786 | } |
---|
2787 | const SItemVec::iterator itendLeft = d->bestIterator + 1; |
---|
2788 | SItemVec *vec = d->GetItemVec(axis); |
---|
2789 | SItemVec::iterator it; |
---|
2790 | //int cntSetLeft = 0; |
---|
2791 | for (it = vec->begin(); it != itendLeft; it++) { |
---|
2792 | // Mark all the items to be in the first list |
---|
2793 | (*it).obj->SetInFirstList(); |
---|
2794 | //cntSetLeft++; |
---|
2795 | } // for |
---|
2796 | // The boundaries that belong definitely to the second list |
---|
2797 | //int cntSetRight = 0; |
---|
2798 | #ifdef _USE_PUSHBACK |
---|
2799 | const SItemVec::iterator itend = vec->end(); |
---|
2800 | for (; it != itend; it++) { |
---|
2801 | // Mark all the items to be in the second list |
---|
2802 | (*it).obj->SetInSecondList(); |
---|
2803 | // and copy the item to the right array |
---|
2804 | vecRight->push_back(*it); |
---|
2805 | //cntSetRight++; |
---|
2806 | } // for |
---|
2807 | #else |
---|
2808 | const int imax = vec->end() - (d->bestIterator + 1); |
---|
2809 | int ir = d->cntThickness; |
---|
2810 | for (int i = 0; i < imax; i++) { |
---|
2811 | (*it).obj->SetInSecondList(); |
---|
2812 | // and copy the item to the right array |
---|
2813 | (*vecRight)[ir] = (*it); |
---|
2814 | ir++; it++; |
---|
2815 | } |
---|
2816 | assert(ir == cntRight); |
---|
2817 | #endif |
---|
2818 | |
---|
2819 | #ifdef _DEBUG |
---|
2820 | if (vecRight->size() != cntRight) { |
---|
2821 | cerr << "Implementation problem vecRight->size() = " |
---|
2822 | << vecRight->size() << " cntRight = " << cntRight |
---|
2823 | << " d->cntThickness = " << d->cntThickness << endl; |
---|
2824 | abort();; |
---|
2825 | } |
---|
2826 | #endif |
---|
2827 | // Only check, if right boundary is set correctly |
---|
2828 | assert(vecRight->size() == cntRight); |
---|
2829 | |
---|
2830 | if (d->cntThickness) { |
---|
2831 | // Now go only through the items on the left side of the splitting plane |
---|
2832 | SItemVec::iterator itR = vecRight->begin(); // to set left boundaries in right array |
---|
2833 | SItemVec::iterator itL = itendLeft; // to set new right boundaries in left array |
---|
2834 | boundary.SetRightBoundary(); |
---|
2835 | #ifdef _USE_PUSHBACK |
---|
2836 | for (it = vec->begin(); it != itendLeft; it++) { |
---|
2837 | if ((*it).obj->InBothLists()) { |
---|
2838 | // set new right boundaries in left array |
---|
2839 | (*itL) = boundary; |
---|
2840 | (*itL).obj = (*it).obj; // set the right object |
---|
2841 | itL++; |
---|
2842 | // and set new left boundary in right array, only object is set |
---|
2843 | (*itR).obj = (*it).obj; |
---|
2844 | itR++; |
---|
2845 | } |
---|
2846 | } // for |
---|
2847 | #else |
---|
2848 | int imax = itendLeft - vec->begin(); |
---|
2849 | int i; |
---|
2850 | for (i = 0; i < imax ; i++) { |
---|
2851 | if ((*vec)[i].obj->InBothLists()) { |
---|
2852 | // set new right boundaries in left array |
---|
2853 | (*itL) = boundary; |
---|
2854 | (*itL).obj = (*vec)[i].obj; // set the right object |
---|
2855 | itL++; |
---|
2856 | // and set new left boundary in right array, only object is set |
---|
2857 | (*itR).obj = (*vec)[i].obj; |
---|
2858 | itR++; |
---|
2859 | } |
---|
2860 | } // for |
---|
2861 | #endif |
---|
2862 | #ifdef _DEBUG |
---|
2863 | int sizeL = itL - vec->begin(); |
---|
2864 | assert(sizeL == cntLeft); |
---|
2865 | int sizeR = itR - vecRight->begin(); |
---|
2866 | assert(sizeR == d->cntThickness); |
---|
2867 | #endif |
---|
2868 | } |
---|
2869 | #ifdef _DEBUG |
---|
2870 | else { |
---|
2871 | vec->resize(cntLeft); |
---|
2872 | assert(d->cntThickness == 0); |
---|
2873 | int cntLL = 0; |
---|
2874 | int cntRR = 0; |
---|
2875 | for (it = vec->begin(); it != vec->end(); it++) { |
---|
2876 | if ((*it).obj->InBothLists()) { |
---|
2877 | cntLL++; |
---|
2878 | cout << "ERROR in left list " << cntLL << endl; |
---|
2879 | } |
---|
2880 | } // for |
---|
2881 | for (it = vecRight->begin(); it != vecRight->end(); it++) { |
---|
2882 | if ((*it).obj->InBothLists()) { |
---|
2883 | cntRR++; |
---|
2884 | cout << "ERROR in right list " << cntRR << endl; |
---|
2885 | } |
---|
2886 | } // for |
---|
2887 | } |
---|
2888 | #endif // _DEBUG |
---|
2889 | |
---|
2890 | // The boundary on the left, unused items are not used |
---|
2891 | vec->resize(cntLeft); |
---|
2892 | |
---|
2893 | // The final setting of size |
---|
2894 | cntLout = cntLeft / 2; |
---|
2895 | cntRout = cntRight / 2; |
---|
2896 | |
---|
2897 | return; |
---|
2898 | } |
---|
2899 | |
---|
2900 | |
---|
2901 | void |
---|
2902 | CKTBABuildUp::BreakAxPosition(SInputData *d, int axis, |
---|
2903 | SInputData *rightData, |
---|
2904 | int &cntLout, int &cntRout) |
---|
2905 | { |
---|
2906 | // the number of object boundaries for left array is not known |
---|
2907 | int cntLeft = 0; |
---|
2908 | int cntRight = 0; |
---|
2909 | d->cntThickness = 0; |
---|
2910 | const float positionToDecide = d->position; |
---|
2911 | |
---|
2912 | // We have some problem that is difficult to detect, when tagging objects |
---|
2913 | // are allowed, the flags are not always reset to zero in some cases. |
---|
2914 | // VH 2/1/2006. The flags are always left boundaries (=1). |
---|
2915 | // Therefore here it is a hack to assure that the flags are definitely zero. |
---|
2916 | if (resetFlagsForBreakAx) { |
---|
2917 | SItemVec *vecd = d->GetItemVec(axis); |
---|
2918 | for (SItemVec::iterator itt = vecd->begin(); itt != vecd->end(); itt++) { |
---|
2919 | (*itt).obj->ResetFlags(); |
---|
2920 | } // for |
---|
2921 | } // if |
---|
2922 | |
---|
2923 | #ifdef _DEBUG |
---|
2924 | SItemVec *vecd = d->GetItemVec(axis); |
---|
2925 | for (SItemVec::iterator itt = vecd->begin(); itt != vecd->end(); itt++) { |
---|
2926 | if ((*itt).obj->Flags() != 0) { |
---|
2927 | cout << "Init ERROR 2 in original list, flags = " |
---|
2928 | << (*itt).obj->Flags() << " obj = " << (void*)((*itt).obj) << endl; |
---|
2929 | } |
---|
2930 | } // for |
---|
2931 | #endif // _DEBUG |
---|
2932 | |
---|
2933 | // Allocate the appropriate size for right array, for all 3 axes |
---|
2934 | // This is only estimated at this algorithm. |
---|
2935 | int estimatedSize = (int)(0.6f * (float)d->count); |
---|
2936 | if (estimatedSize < 10) |
---|
2937 | estimatedSize = 10; |
---|
2938 | rightData->Alloc(estimatedSize * 2); |
---|
2939 | |
---|
2940 | // First find create all left boundaries for right array |
---|
2941 | SItemVec *vecRight = rightData->GetItemVec(axis); |
---|
2942 | |
---|
2943 | // Resize to 0 to start from the beginning |
---|
2944 | vecRight->resize(0); |
---|
2945 | SItemVec *vec = d->GetItemVec(axis); |
---|
2946 | SItemVec::iterator it; |
---|
2947 | const SItemVec::iterator itEnd = vec->end(); |
---|
2948 | for (it = vec->begin(); it != itEnd; it++) { |
---|
2949 | const float &pos = (*it).pos; |
---|
2950 | if (pos < positionToDecide) { |
---|
2951 | cntLeft++; |
---|
2952 | // Mark the item to be in the first list |
---|
2953 | (*it).obj->SetInFirstList(); |
---|
2954 | } |
---|
2955 | else { |
---|
2956 | if (pos > positionToDecide) { |
---|
2957 | // It belongs to the right list |
---|
2958 | break; |
---|
2959 | } |
---|
2960 | else { |
---|
2961 | // pos == positionToDecide |
---|
2962 | if ((*it).IsRightBoundary()) { |
---|
2963 | // it belongs to the left list |
---|
2964 | cntLeft++; |
---|
2965 | (*it).obj->SetInFirstList(); |
---|
2966 | } |
---|
2967 | else { |
---|
2968 | // this is the left boundary |
---|
2969 | // it belongs already to the right list |
---|
2970 | break; |
---|
2971 | } |
---|
2972 | } |
---|
2973 | } |
---|
2974 | } // for it |
---|
2975 | |
---|
2976 | // Remember the position of the iterator, where right |
---|
2977 | // list has to start |
---|
2978 | SItemVec::iterator itStart = it; |
---|
2979 | int cntDups = 0; |
---|
2980 | SItem boundary; |
---|
2981 | |
---|
2982 | // create left boundaries for right list |
---|
2983 | boundary.pos = d->position; |
---|
2984 | boundary.axis = axis; |
---|
2985 | boundary.SetLeftBoundary(); |
---|
2986 | for (; it != itEnd; it++) { |
---|
2987 | assert((*it).pos >= positionToDecide); |
---|
2988 | // Mark all the items to be in the second list |
---|
2989 | if ((*it).obj->InFirstList()) { |
---|
2990 | // and copy the newly created boundary to the right array |
---|
2991 | boundary.obj = (*it).obj; |
---|
2992 | vecRight->push_back(boundary); |
---|
2993 | cntDups++; |
---|
2994 | cntRight++; |
---|
2995 | } |
---|
2996 | } // for |
---|
2997 | |
---|
2998 | // Now go through the right part of the list again |
---|
2999 | // and copy the rest of the list to the right list |
---|
3000 | for (it = itStart; it != itEnd; it++) { |
---|
3001 | (*it).obj->SetInSecondList(); |
---|
3002 | assert((*it).pos >= positionToDecide); |
---|
3003 | vecRight->push_back((*it)); |
---|
3004 | cntRight++; |
---|
3005 | } // for |
---|
3006 | |
---|
3007 | // in final pass create the new boundaries for the left list |
---|
3008 | int i; |
---|
3009 | SItemVec::iterator srcIt = vecRight->begin(); |
---|
3010 | for (it = itStart, i = 0 ; i < cntDups; it++, srcIt++, i++) { |
---|
3011 | cntLeft++; |
---|
3012 | // first copy the boundary from the beginning of the right list |
---|
3013 | *it = *srcIt; |
---|
3014 | // then set the right boundary in copied item |
---|
3015 | (*it).SetRightBoundary(); |
---|
3016 | assert( (*srcIt).IsLeftBoundary()); |
---|
3017 | } // for it |
---|
3018 | |
---|
3019 | // The boundary on the left, unused items are not used |
---|
3020 | vec->resize(cntLeft); |
---|
3021 | assert(cntLeft % 2 == 0); |
---|
3022 | assert(cntRight % 2 == 0); |
---|
3023 | assert(cntLeft+cntRight == 2*(d->count+cntDups)); |
---|
3024 | |
---|
3025 | // The final setting of size |
---|
3026 | cntLout = cntLeft / 2; |
---|
3027 | cntRout = cntRight / 2; |
---|
3028 | // Set correctly also the number of objects |
---|
3029 | d->cntThickness = cntDups; |
---|
3030 | |
---|
3031 | #ifdef _DEBUG |
---|
3032 | SItemVec *vecdL = d->GetItemVec(axis); |
---|
3033 | int cntL = 0; int cntL_LB = 0; int cntL_RB = 0; int cntL_LR = 0; |
---|
3034 | for (SItemVec::iterator itl = vecdL->begin(); itl != vecdL->end(); itl++) { |
---|
3035 | if ((*itl).obj->InBothLists()) |
---|
3036 | cntL_LR++; |
---|
3037 | if ((*itl).IsLeftBoundary()) cntL_LB++; |
---|
3038 | if ((*itl).IsRightBoundary()) cntL_RB++; |
---|
3039 | cntL++; |
---|
3040 | } // for |
---|
3041 | SItemVec *vecdR = rightData->GetItemVec(axis); |
---|
3042 | int cntR = 0; int cntR_LB = 0; int cntR_RB = 0; int cntR_LR = 0; |
---|
3043 | for (SItemVec::iterator itr = vecdR->begin(); itr != vecdR->end(); itr++) { |
---|
3044 | if ((*itr).obj->InBothLists()) |
---|
3045 | cntR_LR++; |
---|
3046 | if ((*itr).IsLeftBoundary()) cntR_LB++; |
---|
3047 | if ((*itr).IsRightBoundary()) cntR_RB++; |
---|
3048 | cntR++; |
---|
3049 | } // for |
---|
3050 | assert(cntL_LR == cntR_LR); |
---|
3051 | assert(cntL_LB == cntL_RB); |
---|
3052 | assert(cntR_LB == cntR_RB); |
---|
3053 | #endif |
---|
3054 | |
---|
3055 | return; |
---|
3056 | } |
---|
3057 | |
---|
3058 | #if 0 |
---|
3059 | // This below was an attempt to do it differently in Vienna, Dec 2007. |
---|
3060 | // VH |
---|
3061 | |
---|
3062 | // --------------------------------------------------------- |
---|
3063 | // split the list along the required axis |
---|
3064 | // first is the begin of the SItem list, axis is the axis, where |
---|
3065 | // to split, val is the splitting value in integer notation. |
---|
3066 | // The output of the function are two lists, first and second |
---|
3067 | // Optionally, objlist store the objects that straddle the splitting plane |
---|
3068 | void |
---|
3069 | CKTBABuildUp::BreakAxPosition(SInputData *d, int axis, |
---|
3070 | SInputData *rightData, |
---|
3071 | int &cntLout, int &cntRout) |
---|
3072 | { |
---|
3073 | // the number of object boundaries for left array is not known |
---|
3074 | int cntLeft = 0; |
---|
3075 | int cntRight = 0; |
---|
3076 | d->cntThickness = 0; |
---|
3077 | const float positionToDecide = d->position; |
---|
3078 | |
---|
3079 | // We have some problem that is difficult to detect, when tagging objects |
---|
3080 | // are allowed, the flags are not always reset to zero in some cases. |
---|
3081 | // VH 2/1/2006. The flags are always left boundaries (=1). |
---|
3082 | // Therefore here it is a hack to assure that the flags are definitely zero. |
---|
3083 | if (resetFlagsForBreakAx) { |
---|
3084 | SItemVec *vecd = d->GetItemVec(axis); |
---|
3085 | for (SItemVec::iterator itt = vecd->begin(); itt != vecd->end(); itt++) { |
---|
3086 | (*itt).obj->ResetFlags(); |
---|
3087 | } // for |
---|
3088 | } // if |
---|
3089 | |
---|
3090 | #ifdef _DEBUG |
---|
3091 | SItemVec *vecd = d->GetItemVec(axis); |
---|
3092 | for (SItemVec::iterator itt = vecd->begin(); itt != vecd->end(); itt++) { |
---|
3093 | if ((*itt).obj->Flags() != 0) { |
---|
3094 | cout << "Init ERROR 2 in original list, flags = " |
---|
3095 | << (*itt).obj->Flags() << " obj = " << (void*)((*itt).obj) << endl; |
---|
3096 | } |
---|
3097 | } // for |
---|
3098 | #endif // _DEBUG |
---|
3099 | |
---|
3100 | // Allocate the appropriate size for right array, for all 3 axes |
---|
3101 | // This is only estimated at this algorithm. |
---|
3102 | int estimatedSize = (int)(0.6f * (float)d->count); |
---|
3103 | if (estimatedSize < 10) |
---|
3104 | estimatedSize = 10; |
---|
3105 | assert(estimatedSize > 0); |
---|
3106 | rightData->Alloc(estimatedSize * 2); |
---|
3107 | |
---|
3108 | // First find create all left boundaries for right array |
---|
3109 | SItemVec *vecRight = rightData->GetItemVec(axis); |
---|
3110 | |
---|
3111 | // Resize to 0 to start from the beginning |
---|
3112 | vecRight->resize(0); |
---|
3113 | SItemVec *vec = d->GetItemVec(axis); |
---|
3114 | SItemVec::iterator it; |
---|
3115 | SItemVec::iterator itLeft; |
---|
3116 | const SItemVec::iterator itEnd = vec->end(); |
---|
3117 | bool foundBoundary = false; |
---|
3118 | for (it = vec->begin(); it != itEnd; it++) { |
---|
3119 | const float &pos = (*it).pos; |
---|
3120 | if (pos < positionToDecide) { |
---|
3121 | cntLeft++; |
---|
3122 | // Mark the item to be in the first list |
---|
3123 | (*it).obj->SetInFirstList(); |
---|
3124 | } |
---|
3125 | else { |
---|
3126 | if (pos > positionToDecide) { |
---|
3127 | cntRight++; |
---|
3128 | (*it).obj->SetInSecondList(); |
---|
3129 | if (!foundBoundary) { |
---|
3130 | foundBoundary = true; |
---|
3131 | itLeft = it; |
---|
3132 | } |
---|
3133 | // It belongs to the right list |
---|
3134 | } |
---|
3135 | else { |
---|
3136 | // pos == positionToDecide |
---|
3137 | if ((*it).IsRightBoundary()) { |
---|
3138 | // it belongs to the left list |
---|
3139 | cntLeft++; |
---|
3140 | (*it).obj->SetInFirstList(); |
---|
3141 | } |
---|
3142 | else { |
---|
3143 | // this is the left boundary |
---|
3144 | // it belongs already to the right list |
---|
3145 | cntRight++; |
---|
3146 | (*it).obj->SetInSecondList(); |
---|
3147 | if (!foundBoundary) { |
---|
3148 | foundBoundary = true; |
---|
3149 | itLeft = it; |
---|
3150 | } |
---|
3151 | } |
---|
3152 | } |
---|
3153 | } |
---|
3154 | } // for it |
---|
3155 | |
---|
3156 | // Remember the position of the iterator, where right |
---|
3157 | // list has to start |
---|
3158 | SItem boundary; |
---|
3159 | int cntDups = 0; |
---|
3160 | cntLeft = 0; |
---|
3161 | cntRight = 0; |
---|
3162 | |
---|
3163 | // create left boundaries for right list |
---|
3164 | boundary.pos = d->position; |
---|
3165 | boundary.axis = axis; |
---|
3166 | boundary.SetLeftBoundary(); |
---|
3167 | for (it = itLeft; it != itEnd; it++) { |
---|
3168 | assert((*it).pos >= positionToDecide); |
---|
3169 | // Mark all the items to be in the second list |
---|
3170 | if ((*it).obj->InFirstList()) { |
---|
3171 | // and copy the newly created boundary to the right array |
---|
3172 | boundary.obj = (*it).obj; |
---|
3173 | vecRight->push_back(boundary); |
---|
3174 | cntDups++; |
---|
3175 | cntRight++; |
---|
3176 | } |
---|
3177 | } // for |
---|
3178 | |
---|
3179 | // Now go through the right part of the list again |
---|
3180 | // and copy the rest of the list to the right list |
---|
3181 | for (it = vec->begin(); it != itEnd; it++) { |
---|
3182 | const float &pos = (*it).pos; |
---|
3183 | if (pos < positionToDecide) { |
---|
3184 | // we copy the boundary to the left list |
---|
3185 | *itLeft = *it; |
---|
3186 | itLeft++; |
---|
3187 | cntLeft++; |
---|
3188 | } |
---|
3189 | if (pos > positionToDecide) { |
---|
3190 | // we copy the boundary to the right list |
---|
3191 | vecRight->push_back(*it); |
---|
3192 | cntRight++; |
---|
3193 | } |
---|
3194 | else { |
---|
3195 | if (pos == positionToDecide) { |
---|
3196 | if ((*it).obj->InBothLists()) { |
---|
3197 | if ((*it).IsRightBoundary()) { |
---|
3198 | // right boundary is added to the right as |
---|
3199 | // we already created left boundaries |
---|
3200 | vecRight->push_back(*it); |
---|
3201 | cntRight++; |
---|
3202 | } |
---|
3203 | else { |
---|
3204 | // we copy the left boundary to the left list |
---|
3205 | *itLeft = *it; |
---|
3206 | itLeft++; |
---|
3207 | cntLeft++; |
---|
3208 | } |
---|
3209 | } |
---|
3210 | else { |
---|
3211 | // This boundary belongs to only a single list |
---|
3212 | if ((*it).obj->InFirstList()) { |
---|
3213 | // we copy this boundary to the left list |
---|
3214 | *itLeft = *it; |
---|
3215 | itLeft++; |
---|
3216 | cntLeft++; |
---|
3217 | } |
---|
3218 | else |
---|
3219 | if ((*it).obj->InSecondList()) { |
---|
3220 | // we copy this boundary to the right list |
---|
3221 | vecRight->push_back(*it); |
---|
3222 | cntRight++; |
---|
3223 | } |
---|
3224 | } |
---|
3225 | } |
---|
3226 | } |
---|
3227 | } // for |
---|
3228 | |
---|
3229 | |
---|
3230 | // in final pass create the new boundaries for the left list |
---|
3231 | int i; |
---|
3232 | SItemVec::iterator srcIt = vecRight->begin(); |
---|
3233 | for (it = itLeft, i = 0 ; i < cntDups; it++, srcIt++, i++) { |
---|
3234 | cntLeft++; |
---|
3235 | // first copy the boundary from the beginning of the right list |
---|
3236 | assert( (*srcIt).IsLeftBoundary()); |
---|
3237 | *it = *srcIt; |
---|
3238 | // then set the right boundary in copied item |
---|
3239 | (*it).SetRightBoundary(); |
---|
3240 | assert( (*it).IsRightBoundary()); |
---|
3241 | } // for it |
---|
3242 | |
---|
3243 | // The boundary on the left, unused items are not used |
---|
3244 | vec->resize(cntLeft); |
---|
3245 | assert(cntLeft % 2 == 0); |
---|
3246 | assert(cntRight % 2 == 0); |
---|
3247 | assert(cntLeft+cntRight == 2*(d->count+cntDups)); |
---|
3248 | |
---|
3249 | // The final setting of size |
---|
3250 | cntLout = cntLeft / 2; |
---|
3251 | cntRout = cntRight / 2; |
---|
3252 | // Set correctly also the number of objects |
---|
3253 | d->cntThickness = cntDups; |
---|
3254 | |
---|
3255 | #ifdef _DEBUG |
---|
3256 | SItemVec *vecdL = d->GetItemVec(axis); |
---|
3257 | int cntL = 0; int cntL_LB = 0; int cntL_RB = 0; int cntL_LR = 0; |
---|
3258 | for (SItemVec::iterator itl = vecdL->begin(); itl != vecdL->end(); itl++) { |
---|
3259 | if ((*itl).obj->InBothLists()) |
---|
3260 | cntL_LR++; |
---|
3261 | if ((*itl).IsLeftBoundary()) cntL_LB++; |
---|
3262 | if ((*itl).IsRightBoundary()) cntL_RB++; |
---|
3263 | cntL++; |
---|
3264 | } // for |
---|
3265 | SItemVec *vecdR = rightData->GetItemVec(axis); |
---|
3266 | int cntR = 0; int cntR_LB = 0; int cntR_RB = 0; int cntR_LR = 0; |
---|
3267 | for (SItemVec::iterator itr = vecdR->begin(); itr != vecdR->end(); itr++) { |
---|
3268 | if ((*itr).obj->InBothLists()) |
---|
3269 | cntR_LR++; |
---|
3270 | if ((*itr).IsLeftBoundary()) cntR_LB++; |
---|
3271 | if ((*itr).IsRightBoundary()) cntR_RB++; |
---|
3272 | cntR++; |
---|
3273 | } // for |
---|
3274 | assert(vecdL->size() == 2 * cntLout); |
---|
3275 | assert(vecdR->size() == 2 * cntRout); |
---|
3276 | assert(vecdL->size() == cntL_LB + cntL_RB); |
---|
3277 | assert(vecdR->size() == cntR_LB + cntR_RB); |
---|
3278 | assert(cntL_LR == cntR_LR); |
---|
3279 | assert(cntL_LB == cntL_RB); |
---|
3280 | assert(cntR_LB == cntR_RB); |
---|
3281 | #endif |
---|
3282 | |
---|
3283 | return; |
---|
3284 | } |
---|
3285 | #endif |
---|
3286 | |
---|
3287 | // ------------------------------------------------------------------ |
---|
3288 | // break the given list of SItem into two parts by reference axis |
---|
3289 | // and reference value, the output is in the first and second SItem |
---|
3290 | void |
---|
3291 | CKTBABuildUp::DivideAx_I(SInputData *d, int axis, |
---|
3292 | SInputData *rightData, |
---|
3293 | int &cntLout, int &cntRout) |
---|
3294 | { |
---|
3295 | // First check, if this is not only singular case |
---|
3296 | if (cntRout == 0) { |
---|
3297 | assert(d->cntThickness == 0); |
---|
3298 | return; // nothing to do |
---|
3299 | } |
---|
3300 | |
---|
3301 | // the number of found boundaries on the left and on the right |
---|
3302 | int cntLeft = 0; |
---|
3303 | int cntRight = 0; |
---|
3304 | |
---|
3305 | // vector for left and right part |
---|
3306 | SItemVec *vec = d->GetItemVec(axis); |
---|
3307 | #ifdef _DEBUG |
---|
3308 | if (d->cntThickness == 0) { |
---|
3309 | SItemVec::iterator it; |
---|
3310 | for (it = vec->begin(); it != vec->end(); it++) { |
---|
3311 | if ((*it).obj->InBothLists()) { |
---|
3312 | cout << "ERROR in left 3 list" << endl; |
---|
3313 | } |
---|
3314 | if ((*it).obj->flags > 3) { |
---|
3315 | cout << "Problem with 4 flags = " << (*it).obj->flags << endl; |
---|
3316 | } |
---|
3317 | } // for |
---|
3318 | } |
---|
3319 | #endif // _DEBUG |
---|
3320 | |
---|
3321 | assert(vec->size() == d->count*2); |
---|
3322 | SItemVec *vecRight = rightData->GetItemVec(axis); |
---|
3323 | vecRight->resize(0); |
---|
3324 | |
---|
3325 | // Now go through source list |
---|
3326 | SItemVec::iterator itDest = vec->begin(); |
---|
3327 | SItemVec::iterator itSrc = vec->begin(); |
---|
3328 | // traverse all boundaries, belonging only to the left part |
---|
3329 | int i = 0; |
---|
3330 | const int imax = d->count*2; |
---|
3331 | for (; i != imax; itSrc++, i++) { |
---|
3332 | // Check if the item belongs to the second list |
---|
3333 | if ((*itSrc).obj->InSecondList()) { |
---|
3334 | break; // we can copy the |
---|
3335 | } |
---|
3336 | // Check if the item belongs to the first list |
---|
3337 | if ((*itSrc).obj->InFirstList()) { |
---|
3338 | // copy the content to the first list |
---|
3339 | // Note that *itDest = *itSrc is not necessary, since itDest = itSrc |
---|
3340 | cntLeft++; |
---|
3341 | } |
---|
3342 | } // for |
---|
3343 | |
---|
3344 | // for newly copied object in the next step |
---|
3345 | itDest = itSrc; |
---|
3346 | |
---|
3347 | // the boundaries can belong to both parts |
---|
3348 | for (; i != imax; itSrc++, i++) { |
---|
3349 | // Check if the item belongs to the second list |
---|
3350 | if ((*itSrc).obj->InSecondList()) { |
---|
3351 | vecRight->push_back((*itSrc)); |
---|
3352 | cntRight++; |
---|
3353 | } |
---|
3354 | // Check if the item belongs to the first list |
---|
3355 | if ((*itSrc).obj->InFirstList()) { |
---|
3356 | // copy the content to the first list |
---|
3357 | *itDest = *itSrc; |
---|
3358 | itDest++; // and move the iterator |
---|
3359 | cntLeft++; |
---|
3360 | } |
---|
3361 | } // for |
---|
3362 | |
---|
3363 | assert(cntLeft % 2 == 0); |
---|
3364 | assert(cntRight % 2 == 0); |
---|
3365 | assert(cntLeft == 2 * cntLout); |
---|
3366 | assert(cntRight == 2 * cntRout); |
---|
3367 | |
---|
3368 | vec->resize(cntLeft); |
---|
3369 | |
---|
3370 | return; |
---|
3371 | } |
---|
3372 | |
---|
3373 | // break the given list of SItem into two parts by reference axis |
---|
3374 | // and reference value, the output is in the first and second SItem |
---|
3375 | void |
---|
3376 | CKTBABuildUp::DivideAx_II(SInputData *d, int axis, |
---|
3377 | SInputData *rightData, |
---|
3378 | int &cntLout, int &cntRout) |
---|
3379 | { |
---|
3380 | // First check, if this is not only singular case |
---|
3381 | if (cntRout == 0) { |
---|
3382 | assert(d->cntThickness == 0); |
---|
3383 | return; // nothing to do |
---|
3384 | } |
---|
3385 | |
---|
3386 | // the number of found boundaries on the left and on the right |
---|
3387 | int cntLeft = 0; |
---|
3388 | int cntRight = 0; |
---|
3389 | |
---|
3390 | // vector for left and right part |
---|
3391 | SItemVec *vec = d->GetItemVec(axis); |
---|
3392 | #ifdef _DEBUG |
---|
3393 | if (d->cntThickness == 0) { |
---|
3394 | SItemVec::iterator it; |
---|
3395 | for (it = vec->begin(); it != vec->end(); it++) { |
---|
3396 | if ((*it).obj->InBothLists()) { |
---|
3397 | cout << "ERROR in left list" << endl; |
---|
3398 | } |
---|
3399 | if ((*it).obj->flags > 3) { |
---|
3400 | cout << "Problem with flags = " << (*it).obj->flags << endl; |
---|
3401 | } |
---|
3402 | } // for |
---|
3403 | } |
---|
3404 | #endif // _DEBUG |
---|
3405 | |
---|
3406 | assert(vec->size() == d->count*2); |
---|
3407 | SItemVec *vecRight = rightData->GetItemVec(axis); |
---|
3408 | vecRight->resize(0); |
---|
3409 | |
---|
3410 | // Now go through the source list |
---|
3411 | SItemVec::iterator itDest = vec->begin(); |
---|
3412 | SItemVec::iterator itSrc = vec->begin(); |
---|
3413 | // traverse all boundaries, belonging only to the left part |
---|
3414 | int i = 0; |
---|
3415 | const int imax = d->count*2; |
---|
3416 | for (; i != imax; itSrc++, i++) { |
---|
3417 | // Check if the item belongs to the second list |
---|
3418 | if ((*itSrc).obj->InSecondList()) { |
---|
3419 | break; // we can copy the |
---|
3420 | } |
---|
3421 | // Check if the item belongs to the first list |
---|
3422 | if ((*itSrc).obj->InFirstList()) { |
---|
3423 | // copy the content to the first list |
---|
3424 | // Note that *itDest = *itSrc is not necessary, since itDest = itSrc |
---|
3425 | cntLeft++; |
---|
3426 | } |
---|
3427 | // Reset flags for the next subdivision step |
---|
3428 | if ((*itSrc).IsRightBoundary()) |
---|
3429 | (*itSrc).obj->ResetFlags(); |
---|
3430 | } // for |
---|
3431 | |
---|
3432 | // for newly copied object in the next step |
---|
3433 | itDest = itSrc; |
---|
3434 | |
---|
3435 | // !!!!!!!!!!!!!! |
---|
3436 | // for newly copied object in the next step |
---|
3437 | itDest = itSrc; |
---|
3438 | |
---|
3439 | // the boundaries can belong to both parts |
---|
3440 | for (; i != imax; itSrc++, i++) { |
---|
3441 | //if ((*itSrc).obj == objtf) { |
---|
3442 | // cout << "DivideAxII - obj found2 , i = " << i << endl; |
---|
3443 | |
---|
3444 | // Reset flags for the next subdivision step |
---|
3445 | if ((*itSrc).IsRightBoundary()) { |
---|
3446 | // This is the right boundary, we have to reset flags |
---|
3447 | bool inFirstList = (*itSrc).obj->InFirstList(); |
---|
3448 | bool inSecondList = (*itSrc).obj->InSecondList(); |
---|
3449 | (*itSrc).obj->ResetFlags(); |
---|
3450 | if (inSecondList) { |
---|
3451 | cntRight++; |
---|
3452 | vecRight->push_back((*itSrc)); |
---|
3453 | } |
---|
3454 | |
---|
3455 | // Check if the item belongs to the first list |
---|
3456 | if (inFirstList) { |
---|
3457 | cntLeft++; |
---|
3458 | // copy the content to the first list |
---|
3459 | *itDest = *itSrc; |
---|
3460 | itDest++; // and move the iterator |
---|
3461 | } |
---|
3462 | } |
---|
3463 | else { // left boundary |
---|
3464 | // Check if the item belongs to the second list |
---|
3465 | if ((*itSrc).obj->InSecondList()) { |
---|
3466 | cntRight++; |
---|
3467 | vecRight->push_back((*itSrc)); |
---|
3468 | } |
---|
3469 | // Check if the item belongs to the first list |
---|
3470 | if ((*itSrc).obj->InFirstList()) { |
---|
3471 | cntLeft++; |
---|
3472 | // copy the content to the first list |
---|
3473 | *itDest = *itSrc; |
---|
3474 | itDest++; // and move the iterator |
---|
3475 | } |
---|
3476 | } // end of left boundary |
---|
3477 | } // for |
---|
3478 | |
---|
3479 | assert(cntLeft % 2 == 0); |
---|
3480 | assert(cntRight % 2 == 0); |
---|
3481 | assert(cntLeft == 2 * cntLout); |
---|
3482 | assert(cntRight == 2 * cntRout); |
---|
3483 | vec->resize(cntLeft); |
---|
3484 | |
---|
3485 | #ifdef _DEBUG |
---|
3486 | for (SItemVec::iterator itt = vec->begin(); itt != vec->end(); itt++) { |
---|
3487 | if ((*itt).obj->Flags() != 0) { |
---|
3488 | cout << "DivideAxII ERROR 1 in final left list, flags = " |
---|
3489 | << (*itt).obj->Flags() << " obj = " << (void*)((*itt).obj) << endl; |
---|
3490 | abort();; |
---|
3491 | } |
---|
3492 | } // for |
---|
3493 | for (SItemVec::iterator itt = vecRight->begin(); itt != vecRight->end(); itt++) { |
---|
3494 | if ((*itt).obj->Flags() != 0) { |
---|
3495 | cout << "DivideAxII ERROR 1 in final right list, flags = " |
---|
3496 | << (*itt).obj->Flags() << " obj = " << (void*)((*itt).obj) << endl; |
---|
3497 | abort();; |
---|
3498 | } |
---|
3499 | } // for |
---|
3500 | #endif // _DEBUG |
---|
3501 | |
---|
3502 | return; |
---|
3503 | } |
---|
3504 | |
---|
3505 | |
---|
3506 | // break the given list of SItem into two parts by reference axis |
---|
3507 | // and reference value, the output is in the first and second SItem |
---|
3508 | void |
---|
3509 | CKTBABuildUp::DivideAx_I_opt(SInputData *d, int axis, |
---|
3510 | SInputData *rightData, |
---|
3511 | int cntLout, int cntRout) |
---|
3512 | { |
---|
3513 | // First check, if this is not only singular case |
---|
3514 | if (cntRout == 0) { |
---|
3515 | assert(d->cntThickness == 0); |
---|
3516 | return; // nothing to do |
---|
3517 | } |
---|
3518 | |
---|
3519 | // vector for left and right part |
---|
3520 | SItemVec *vec = d->GetItemVec(axis); |
---|
3521 | |
---|
3522 | #ifdef _DEBUG |
---|
3523 | if (vec->size() != d->count*2) { |
---|
3524 | cout << "vec->size() = " << vec->size() |
---|
3525 | << " d->count*2 = " << d->count*2 << endl; |
---|
3526 | } |
---|
3527 | |
---|
3528 | if (d->cntThickness == 0) { |
---|
3529 | SItemVec::iterator it; |
---|
3530 | for (it = vec->begin(); it != vec->end(); it++) { |
---|
3531 | if ((*it).obj->InBothLists()) { |
---|
3532 | cout << "ERROR in left list" << endl; |
---|
3533 | } |
---|
3534 | if ((*it).obj->flags > 3) { |
---|
3535 | cout << "Problem with flags = " << (*it).obj->flags << endl; |
---|
3536 | } |
---|
3537 | } // for |
---|
3538 | } |
---|
3539 | #endif // _DEBUG |
---|
3540 | |
---|
3541 | assert(vec->size() == d->count*2); |
---|
3542 | SItemVec *vecRight = rightData->GetItemVec(axis); |
---|
3543 | vecRight->resize(0); |
---|
3544 | |
---|
3545 | // Now go through source list |
---|
3546 | SItemVec::iterator itDest = vec->begin(); |
---|
3547 | SItemVec::iterator itSrc = vec->begin(); |
---|
3548 | #if 1 |
---|
3549 | if (vec->size() != d->count * 2) { |
---|
3550 | cout << "Something wrong HERE vec->size=" |
---|
3551 | << vec->size() << " d->count*2 = " |
---|
3552 | << d->count*2 << endl; |
---|
3553 | abort(); |
---|
3554 | } |
---|
3555 | #endif |
---|
3556 | |
---|
3557 | // traverse all boundaries, belonging only to the left part |
---|
3558 | int i = 0; |
---|
3559 | const int imax = d->count*2; |
---|
3560 | for (; i != imax; itSrc++, i++) { |
---|
3561 | // Check if the item belongs to the second list |
---|
3562 | if ((*itSrc).obj->InSecondList()) { |
---|
3563 | break; // we can copy the |
---|
3564 | } |
---|
3565 | } // for |
---|
3566 | |
---|
3567 | // for newly copied object in the next step |
---|
3568 | itDest = itSrc; |
---|
3569 | |
---|
3570 | // the boundaries can belong to both parts |
---|
3571 | for (; i != imax; itSrc++, i++) { |
---|
3572 | SItem &itt = *itSrc; |
---|
3573 | // Check if the item belongs to the second list |
---|
3574 | if (itt.obj->InSecondList()) { |
---|
3575 | // and first copy the right boundary to a new list |
---|
3576 | vecRight->push_back((*itSrc)); |
---|
3577 | } |
---|
3578 | // Check if the item belongs to the first list |
---|
3579 | if (itt.obj->InFirstList()) { |
---|
3580 | // copy the content to the first list |
---|
3581 | *itDest = *itSrc; |
---|
3582 | itDest++; // and move the iterator |
---|
3583 | } |
---|
3584 | } // for |
---|
3585 | |
---|
3586 | // Shorten the left array by resizing |
---|
3587 | vec->resize(cntLout*2); |
---|
3588 | assert(vecRight->size() == cntRout*2); |
---|
3589 | |
---|
3590 | return; |
---|
3591 | } |
---|
3592 | |
---|
3593 | // break the given list of SItem into two parts by reference axis |
---|
3594 | // and reference value, the output is in the first and second SItem |
---|
3595 | void |
---|
3596 | CKTBABuildUp::DivideAx_II_opt(SInputData *d, int axis, |
---|
3597 | SInputData *rightData, |
---|
3598 | int cntLout, int cntRout) |
---|
3599 | { |
---|
3600 | // First check, if this is not only singular case |
---|
3601 | if (cntRout == 0) { |
---|
3602 | assert(d->cntThickness == 0); |
---|
3603 | return; // nothing to do |
---|
3604 | } |
---|
3605 | |
---|
3606 | // vector for left and right part |
---|
3607 | SItemVec *vec = d->GetItemVec(axis); |
---|
3608 | assert(vec->size() == d->count*2); |
---|
3609 | #ifdef _DEBUG |
---|
3610 | if (d->cntThickness == 0) { |
---|
3611 | SItemVec::iterator it; |
---|
3612 | for (it = vec->begin(); it != vec->end(); it++) { |
---|
3613 | if ((*it).obj->InBothLists()) { |
---|
3614 | cout << "ERROR in left list" << endl; |
---|
3615 | } |
---|
3616 | if ((*it).obj->flags > 3) { |
---|
3617 | cout << "Problem with flags = " << (*it).obj->flags << endl; |
---|
3618 | } |
---|
3619 | } // for |
---|
3620 | } |
---|
3621 | { |
---|
3622 | SItemVec::iterator ittt; |
---|
3623 | for (ittt = vec->begin(); ittt != vec->end(); ittt++) { |
---|
3624 | if ((*ittt).obj->ToBeRemoved()) { |
---|
3625 | cout << "ERROR - to be removed in the left list" << endl; |
---|
3626 | } |
---|
3627 | } |
---|
3628 | } |
---|
3629 | #endif // _DEBUG |
---|
3630 | |
---|
3631 | assert(vec->size() == d->count*2); |
---|
3632 | SItemVec *vecRight = rightData->GetItemVec(axis); |
---|
3633 | vecRight->resize(0); |
---|
3634 | |
---|
3635 | // Now go through the source list |
---|
3636 | SItemVec::iterator itDest = vec->begin(); |
---|
3637 | SItemVec::iterator itSrc = vec->begin(); |
---|
3638 | #if 1 |
---|
3639 | if (vec->size() != d->count * 2) { |
---|
3640 | cout << "Something wrong HERE II vec->size=" |
---|
3641 | << vec->size() << " d->count*2 = " |
---|
3642 | << d->count*2 << endl; |
---|
3643 | abort(); |
---|
3644 | } |
---|
3645 | #endif |
---|
3646 | // traverse all boundaries, belonging only to the left part |
---|
3647 | int i = 0; |
---|
3648 | const int imax = d->count*2; |
---|
3649 | for (; i != imax; itSrc++, i++) { |
---|
3650 | //if ((*itSrc).obj == objtf) { |
---|
3651 | // cout << "DivideAxII - obj found1 , i = " << i << endl; |
---|
3652 | |
---|
3653 | // Check if the item belongs to the second list |
---|
3654 | if ((*itSrc).obj->InSecondList()) { |
---|
3655 | break; // we can copy the |
---|
3656 | } |
---|
3657 | // Reset flags for the next subdivision step |
---|
3658 | if ((*itSrc).IsRightBoundary()) |
---|
3659 | (*itSrc).obj->ResetFlags(); |
---|
3660 | } // for |
---|
3661 | |
---|
3662 | // for newly copied object in the next step |
---|
3663 | itDest = itSrc; |
---|
3664 | |
---|
3665 | // the boundaries can belong to both parts |
---|
3666 | for (; i != imax; itSrc++, i++) { |
---|
3667 | //if ((*itSrc).obj == objtf) { |
---|
3668 | // cout << "DivideAxII - obj found2 , i = " << i << endl; |
---|
3669 | |
---|
3670 | bool inFirstList = (*itSrc).obj->InFirstList(); |
---|
3671 | bool inSecondList = (*itSrc).obj->InSecondList(); |
---|
3672 | |
---|
3673 | // Reset flags for the next subdivision step |
---|
3674 | if ((*itSrc).IsRightBoundary()) { |
---|
3675 | // This is the right boundary, we have to reset flags |
---|
3676 | if (inSecondList) |
---|
3677 | vecRight->push_back((*itSrc)); |
---|
3678 | // Check if the item belongs to the first list |
---|
3679 | if (inFirstList) { |
---|
3680 | // copy the content to the first list |
---|
3681 | *itDest = *itSrc; |
---|
3682 | itDest++; // and move the iterator |
---|
3683 | } |
---|
3684 | } |
---|
3685 | else { // left boundary |
---|
3686 | // Check if the item belongs to the second list |
---|
3687 | if (inSecondList) { |
---|
3688 | vecRight->push_back((*itSrc)); |
---|
3689 | } |
---|
3690 | // Check if the item belongs to the first list |
---|
3691 | if (inFirstList) { |
---|
3692 | // copy the content to the first list |
---|
3693 | *itDest = *itSrc; |
---|
3694 | itDest++; // and move the iterator |
---|
3695 | } |
---|
3696 | } // end of left boundary |
---|
3697 | } // for |
---|
3698 | |
---|
3699 | // Shorten the left array by resizing |
---|
3700 | vec->resize(cntLout*2); |
---|
3701 | assert(vecRight->size() == cntRout*2); |
---|
3702 | |
---|
3703 | #if 0 |
---|
3704 | #ifdef _DEBUG |
---|
3705 | for (SItemVec::iterator itt2 = vec->begin(); itt2 != vec->end(); itt2++) { |
---|
3706 | if ((*itt2).obj->Flags() != 0) { |
---|
3707 | cout << "DivideAxII ERROR 1 in final left list, flags = " |
---|
3708 | << (*itt2).obj->Flags() << " obj = " |
---|
3709 | << (void*)((*itt2).obj) << endl; |
---|
3710 | abort();; |
---|
3711 | } |
---|
3712 | } // for |
---|
3713 | for (SItemVec::iterator itt3 = vecRight->begin(); itt3 != vecRight->end(); itt3++) { |
---|
3714 | if ((*itt3).obj->Flags() != 0) { |
---|
3715 | cout << "DivideAxII ERROR 1 in final right list, flags = " |
---|
3716 | << (*itt3).obj->Flags() << " obj = " |
---|
3717 | << (void*)((*itt3).obj) << endl; |
---|
3718 | abort();; |
---|
3719 | } |
---|
3720 | } // for |
---|
3721 | #endif // _DEBUG |
---|
3722 | #endif |
---|
3723 | |
---|
3724 | return; |
---|
3725 | } |
---|
3726 | |
---|
3727 | #ifdef _VYPIS |
---|
3728 | void |
---|
3729 | CKTBABuildUp::PrintOut(CKTBAxes::Axes axis, int stat, SItem **first, |
---|
3730 | SItem **second, float /*position*/) |
---|
3731 | { |
---|
3732 | #if 1 |
---|
3733 | int cnt = 0; |
---|
3734 | SItem *t = *first; |
---|
3735 | if (stat & 1) { |
---|
3736 | DEBUG << "----FIRST--- axis=" << (int)axis << "\n"; |
---|
3737 | while (t != NULL) { |
---|
3738 | #define _VYP |
---|
3739 | |
---|
3740 | #ifdef _VYP |
---|
3741 | float v = t->value[axis]; |
---|
3742 | DEBUGW << "curr=" << t |
---|
3743 | #ifdef _BIDIRLISTS |
---|
3744 | << " prev=" << t->prev[axis] |
---|
3745 | #endif |
---|
3746 | << " next=" |
---|
3747 | << t->next[axis] << " val=" << v |
---|
3748 | << " " << (t->IsRightBoundary() ? 1 : 0); |
---|
3749 | if (t->IsRightBoundary()) |
---|
3750 | DEBUGW << " obj= " << t->obj; |
---|
3751 | else |
---|
3752 | DEBUGW << " pair= " << t->pairF; |
---|
3753 | |
---|
3754 | DEBUGW << endl; |
---|
3755 | #endif // _VYP |
---|
3756 | t = t->next[axis]; |
---|
3757 | cnt++; |
---|
3758 | } |
---|
3759 | |
---|
3760 | DEBUG<< "FIRST cnt= " << cnt <<"\n" << flush; |
---|
3761 | } |
---|
3762 | |
---|
3763 | if (stat & 2) { |
---|
3764 | // the right list |
---|
3765 | t = *second; |
---|
3766 | cnt = 0; |
---|
3767 | DEBUG << "----SECOND-----\n"; |
---|
3768 | while (t != NULL) { |
---|
3769 | #ifdef _VYP |
---|
3770 | float v = t->value[axis]; |
---|
3771 | DEBUGW << "curr=" << t |
---|
3772 | #ifdef _BIDIRLISTS |
---|
3773 | << " prev=" << t->prev[axis] |
---|
3774 | #endif |
---|
3775 | << " next=" |
---|
3776 | << t->next[axis] << " val=" << v |
---|
3777 | << " " << ((t->IsRightBoundary()) ? 1 : 0); |
---|
3778 | if (t->IsRightBoundary()) |
---|
3779 | DEBUGW << " obj= " << t->obj; |
---|
3780 | else |
---|
3781 | DEBUGW << " pair= " << t->pairF; |
---|
3782 | DEBUGW << "\n" << flush; |
---|
3783 | #endif // _VYP |
---|
3784 | t = t->next[axis]; |
---|
3785 | cnt++; |
---|
3786 | } |
---|
3787 | DEBUGW << "SECOND cnt= " << cnt <<"\n" << flush; |
---|
3788 | } |
---|
3789 | #endif |
---|
3790 | } |
---|
3791 | #endif // _VYPIS |
---|
3792 | |
---|
3793 | // -------------------------------------------------------------------- |
---|
3794 | // class CKTBABuildUp::CTestAx |
---|
3795 | |
---|
3796 | // The initialization for the first axis to be tested, this time *****Z axis******* |
---|
3797 | void |
---|
3798 | CKTBABuildUp::SSplitState::InitXaxis(int cnt, const SBBox &boxN) |
---|
3799 | { |
---|
3800 | // initialize the variables, mainly for surface area estimates |
---|
3801 | cntAll = cnt; // the number of all objects in the bounding box |
---|
3802 | cntLeft = 0; // the count of bounding boxes on the left |
---|
3803 | cntRight = cnt; // the count of bounding boxes on the right |
---|
3804 | thickness = 0; // the count of bounding boxes straddling the splitting plane |
---|
3805 | axis = CKTBAxes::EE_X_axis; // the axis, where the splitting is proposed |
---|
3806 | box = boxN; // the box, that is subdivided |
---|
3807 | //int topAxis = 1; // axis that is considered in top .. depth |
---|
3808 | //int frontAxis = 2; // axis that is considered in front .. height |
---|
3809 | // the size of bounding box along the axis to be split |
---|
3810 | width = box.Max().x - box.Min().x; |
---|
3811 | // and along two other axes |
---|
3812 | topw = box.Max().y - box.Min().y; |
---|
3813 | frontw = box.Max().z - box.Min().z; |
---|
3814 | // surface area of the splitting plane .. one face !! |
---|
3815 | areaSplitPlane = topw * frontw; |
---|
3816 | // the sum of length of the boxes not to be subdivided |
---|
3817 | areaSumLength = topw + frontw; |
---|
3818 | // The surface are of the whole box |
---|
3819 | areaWholeSA2 = width * areaSumLength + areaSplitPlane; |
---|
3820 | // initial evaluation .. the worst cost |
---|
3821 | bestCost = WorstEvaluation(); |
---|
3822 | } |
---|
3823 | |
---|
3824 | // The initialization for the first axis to be tested, this time *****Y axis******* |
---|
3825 | // This can be run independently. |
---|
3826 | void |
---|
3827 | CKTBABuildUp::SSplitState::InitYaxis(int cnt, const SBBox &boxN) |
---|
3828 | { |
---|
3829 | // initialize the variables, mainly for surface area estimates |
---|
3830 | cntAll = cnt; // the number of all objects in the bounding box |
---|
3831 | cntLeft = 0; // the count of bounding boxes on the left |
---|
3832 | cntRight = cnt; // the count of bounding boxes on the right |
---|
3833 | thickness = 0; // the count of bounding boxes straddling the splitting plane |
---|
3834 | axis = CKTBAxes::EE_Y_axis; // the axis, where the splitting is proposed |
---|
3835 | box = boxN; // the box, that is subdivided |
---|
3836 | //int frontAxis = oaxes[axis][0]; // axis that is considered in front .. height - x-axis |
---|
3837 | //int topAxis = oaxes[axis][1]; // axis that is considered in top .. depth - y-axis |
---|
3838 | // the size along the second axis - height |
---|
3839 | frontw = box.Max().x - box.Min().x; |
---|
3840 | // the size of bounding box along the axis to be split - width |
---|
3841 | width = box.Max().y - box.Min().y; |
---|
3842 | // The size along third axis - depth |
---|
3843 | topw = box.Max().z - box.Min().z; |
---|
3844 | // surface area of the splitting plane .. one face !! |
---|
3845 | areaSplitPlane = topw * frontw; |
---|
3846 | // the sum of length of the boxes not to be subdivided |
---|
3847 | areaSumLength = topw + frontw; |
---|
3848 | areaWholeSA2 = width * areaSumLength + areaSplitPlane; |
---|
3849 | // initial evaluation .. the worst cost |
---|
3850 | bestCost = WorstEvaluation(); |
---|
3851 | } |
---|
3852 | |
---|
3853 | // The initialization for the first axis to be tested, this time *****Z axis******* |
---|
3854 | // This can be run independently. |
---|
3855 | void |
---|
3856 | CKTBABuildUp::SSplitState::InitZaxis(int cnt, const SBBox &boxN) |
---|
3857 | { |
---|
3858 | // initialize the variables, mainly for surface area estimates |
---|
3859 | cntAll = cnt; // the number of all objects in the bounding box |
---|
3860 | cntLeft = 0; // the count of bounding boxes on the left |
---|
3861 | cntRight = cnt; // the count of bounding boxes on the right |
---|
3862 | thickness = 0; // the count of bounding boxes straddling the splitting plane |
---|
3863 | axis = CKTBAxes::EE_Z_axis; // the axis, where the splitting is proposed |
---|
3864 | box = boxN; // the box, that is subdivided |
---|
3865 | //int frontAxis = oaxes[axis][1]; // axis that is considered in front .. height - x axis |
---|
3866 | //int topAxis = oaxes[axis][0]; // axis that is considered in top .. depth - y axis |
---|
3867 | // The size along third axis - depth |
---|
3868 | topw = box.Max().x - box.Min().x; |
---|
3869 | // the size along the second axis - height |
---|
3870 | frontw = box.Max().y - box.Min().y; |
---|
3871 | // the size of bounding box along the axis to be split - width |
---|
3872 | width = box.Max().z - box.Min().z; |
---|
3873 | // surface area of the splitting plane .. one face !! |
---|
3874 | areaSplitPlane = topw * frontw; |
---|
3875 | // the sum of length of the boxes not to be subdivided |
---|
3876 | areaSumLength = topw + frontw; |
---|
3877 | areaWholeSA2 = width * areaSumLength + areaSplitPlane; |
---|
3878 | // initial evaluation .. the worst cost |
---|
3879 | bestCost = WorstEvaluation(); |
---|
3880 | } |
---|
3881 | |
---|
3882 | // -------------------------------------------------------------------- |
---|
3883 | // The initialization for the first axis to be tested, use only in case |
---|
3884 | // when all 3 axes are tested. It can be called only when InitXaxis was called before !!!! |
---|
3885 | void |
---|
3886 | CKTBABuildUp::SSplitState::ReinitYaxis(int cnt, const SBBox &boxN) |
---|
3887 | { |
---|
3888 | // initialize the variables, mainly for surface area estimates |
---|
3889 | assert(cntAll == cnt); // the number of all objects in the bounding box |
---|
3890 | cntLeft = 0; // the count of bounding boxes on the left |
---|
3891 | cntRight = cnt; // the count of bounding boxes on the right |
---|
3892 | thickness = 0; // the count of bounding boxes straddling the splitting plane |
---|
3893 | axis = CKTBAxes::EE_Y_axis; // the axis, where the splitting is proposed |
---|
3894 | //int topAxis = 2; // axis that is considered in top .. depth |
---|
3895 | //int frontAxis = 0; // axis that is considered in front .. height |
---|
3896 | // Swap the width, height, and depth |
---|
3897 | float tS = width; |
---|
3898 | // the size of bounding box along the axis to be split |
---|
3899 | width = topw; |
---|
3900 | // and along two other axes |
---|
3901 | topw = frontw; |
---|
3902 | frontw = tS; // copy the temporary variable |
---|
3903 | // surface area of the splitting plane .. one face !! |
---|
3904 | areaSplitPlane = topw * frontw; |
---|
3905 | // the sum of length of the boxes not to be subdivided |
---|
3906 | areaSumLength = topw + frontw; |
---|
3907 | //assert(areaWholeSA2 == width * SumLength + areaSplitPlane); |
---|
3908 | } |
---|
3909 | |
---|
3910 | // The initialization for the first axis to be tested, use only in case |
---|
3911 | // when all 3 axes are tested. It can be called only when ReinitYaxis was called before !!! |
---|
3912 | void |
---|
3913 | CKTBABuildUp::SSplitState::ReinitZaxis(int cnt, const SBBox &boxN) |
---|
3914 | { |
---|
3915 | // initialize the variables, mainly for surface area estimates |
---|
3916 | assert(cntAll == cnt); // the number of all objects in the bounding box |
---|
3917 | cntLeft = 0; // the count of bounding boxes on the left |
---|
3918 | cntRight = cnt; // the count of bounding boxes on the right |
---|
3919 | thickness = 0; // the count of bounding boxes straddling the splitting plane |
---|
3920 | axis = CKTBAxes::EE_Z_axis; // the axis, where the splitting is proposed |
---|
3921 | // Swap the width, height, and depth |
---|
3922 | float tS = width; |
---|
3923 | // the size of bounding box along the axis to be split |
---|
3924 | width = topw; |
---|
3925 | // and along two other axes |
---|
3926 | topw = frontw; |
---|
3927 | frontw = tS; // copy the temporary variable |
---|
3928 | // surface area of the splitting plane .. one face !! |
---|
3929 | areaSplitPlane = topw * frontw; |
---|
3930 | // the sum of length of the boxes not to be subdivided |
---|
3931 | areaSumLength = topw + frontw; |
---|
3932 | //assert(areaWholeSA2 == width * stateSumLength + areaSplitPlane); |
---|
3933 | } |
---|
3934 | |
---|
3935 | // This is the computation of the cost using surface area heuristics |
---|
3936 | // using LINEAR EXTIMATE |
---|
3937 | void |
---|
3938 | CKTBABuildUp::EvaluateCost(SSplitState &state) |
---|
3939 | { |
---|
3940 | // the surface area of the bounding box for the left child |
---|
3941 | assert(state.position > -1e-9); |
---|
3942 | float areaLeft = state.position * state.areaSumLength + state.areaSplitPlane; |
---|
3943 | |
---|
3944 | // the surface area of the right bounding box for the right child |
---|
3945 | assert(state.width - state.position > -1e-9); |
---|
3946 | float areaRight = (state.width - state.position) * state.areaSumLength + |
---|
3947 | state.areaSplitPlane; |
---|
3948 | |
---|
3949 | // computation of the cost .. smaller is better |
---|
3950 | float cost = areaLeft * state.cntLeft + areaRight * state.cntRight; |
---|
3951 | |
---|
3952 | #ifdef _DEBUG_COSTFUNCTION |
---|
3953 | // Put there normalized position and cost also normalized somehow |
---|
3954 | ReportCostStream(state.position / state.width, |
---|
3955 | cost / (state.areaWholeSA2 * state.cntAll)); |
---|
3956 | #endif |
---|
3957 | |
---|
3958 | // This normalization is not in fact necessary here |
---|
3959 | //cost //= state.areaWholeSA2; |
---|
3960 | if (cost < state.bestCost) { |
---|
3961 | state.bestCost = cost; |
---|
3962 | // The iterator pointing to the best boundary |
---|
3963 | state.bestIterator = state.it; |
---|
3964 | // The number of objects whose boundaries are duplicated |
---|
3965 | state.bestThickness = state.thickness; |
---|
3966 | } |
---|
3967 | return; |
---|
3968 | } |
---|
3969 | |
---|
3970 | // This is the computation of the cost using surface area heuristics |
---|
3971 | void |
---|
3972 | CKTBABuildUp::EvaluateCostFreeCut(SSplitState &state) |
---|
3973 | { |
---|
3974 | // This is assumed to work for free cut (no object intersected) |
---|
3975 | assert(state.thickness == 0); |
---|
3976 | |
---|
3977 | // the surface area of the bounding box for the left child |
---|
3978 | assert(state.position > -1e-9); |
---|
3979 | float areaLeft = state.position * state.areaSumLength + state.areaSplitPlane; |
---|
3980 | |
---|
3981 | // the surface area of the right bounding box for the right child |
---|
3982 | assert(state.width - state.position > -1e-9); |
---|
3983 | float areaRight = (state.width - state.position) * state.areaSumLength + |
---|
3984 | state.areaSplitPlane; |
---|
3985 | |
---|
3986 | // computation of the cost .. smaller is better |
---|
3987 | float cost = biasFreeCuts *(areaLeft * state.cntLeft + areaRight * state.cntRight); |
---|
3988 | |
---|
3989 | #ifdef _DEBUG_COSTFUNCTION |
---|
3990 | // Put there normalized position and cost also normalized somehow |
---|
3991 | ReportCostStream(state.position / state.width, |
---|
3992 | cost / (state.areaWholeSA2 * state.cntAll)); |
---|
3993 | #endif |
---|
3994 | |
---|
3995 | // This normalization is not in fact necessary here |
---|
3996 | //cost //= state.areaWholeSA2; |
---|
3997 | if (cost < state.bestCost) { |
---|
3998 | state.bestCost = cost; |
---|
3999 | // The iterator pointing to the best boundary |
---|
4000 | state.bestIterator = state.it; |
---|
4001 | // The number of objects whose boundaries are duplicated |
---|
4002 | state.bestThickness = 0; |
---|
4003 | } |
---|
4004 | return; |
---|
4005 | } |
---|
4006 | |
---|
4007 | // ------------------------------------------------------------------------------- |
---|
4008 | // TRIAL TO IMPROVE for a given X-axis search for the best splitting plane position. |
---|
4009 | // Starts from start item, the rest of the information is set to 'state' variable. |
---|
4010 | void |
---|
4011 | CKTBABuildUp::GetSplitPlaneOpt(SItemVec *vec, int axisToTest) |
---|
4012 | { |
---|
4013 | #ifdef _DEBUG |
---|
4014 | if ((vec == NULL) || (vec->size() == 0)) { |
---|
4015 | cerr << "Trying to subdivide some node without an object" << endl; |
---|
4016 | abort();; |
---|
4017 | } |
---|
4018 | #endif // _DEBUG |
---|
4019 | |
---|
4020 | #if 0 |
---|
4021 | static int index = 0; |
---|
4022 | cout << "index = " << index << endl; |
---|
4023 | const int indexToFind = 8; |
---|
4024 | if (index == indexToFind) { |
---|
4025 | cout << "Index found = " << index << endl; |
---|
4026 | } |
---|
4027 | index++; |
---|
4028 | #endif |
---|
4029 | |
---|
4030 | // some necessary space is required to cut off |
---|
4031 | const float eps = 1.0e-6 * state.width; |
---|
4032 | const float MinPosition = state.box.Min(axisToTest); |
---|
4033 | const float MaxPosition = state.box.Max(axisToTest); |
---|
4034 | //float MinPositionAccept = MinPosition + eps; |
---|
4035 | //float MaxPositionAccept = MaxPosition - eps; |
---|
4036 | |
---|
4037 | // wherefrom to start |
---|
4038 | SItemVec::iterator curr = vec->begin(); |
---|
4039 | SItemVec::iterator next = vec->begin() + 1; |
---|
4040 | // Set the type of splitting by this function, which is in this case |
---|
4041 | // not overwritten in Evaluate() function |
---|
4042 | state.bestTwoSplits = 1; |
---|
4043 | float val = (*curr).pos; |
---|
4044 | float nval; |
---|
4045 | float pval = val; |
---|
4046 | |
---|
4047 | // Evaluate the first possible position, cutting off empty |
---|
4048 | // space on the left of the splitting plane |
---|
4049 | state.position = val - MinPosition; |
---|
4050 | if (state.position > 0.f) { |
---|
4051 | state.position2 = next->pos - MinPosition; |
---|
4052 | state.it = curr; |
---|
4053 | // Here evaluate the cost of surface area heuristics |
---|
4054 | EvaluateCostFreeCut(state); |
---|
4055 | } |
---|
4056 | |
---|
4057 | //-------------------- TEST LOOP --------------------------------------- |
---|
4058 | // make evaluation for each splitting position |
---|
4059 | const int imax = vec->size()-1; |
---|
4060 | int ii; |
---|
4061 | for (ii = 0; ii < imax; ii++) |
---|
4062 | { |
---|
4063 | nval = next->pos; |
---|
4064 | |
---|
4065 | #if 0 |
---|
4066 | if (axisToTest == 2) { |
---|
4067 | if ((val > 0.866) && (val < 0.870)) { |
---|
4068 | cout << "val = " << val; |
---|
4069 | cout << " nval = " << nval; |
---|
4070 | if (curr->IsRightBoundary()) |
---|
4071 | cout << " R "; |
---|
4072 | else |
---|
4073 | cout << " L "; |
---|
4074 | cout << " thickness = " << state.thickness << endl; |
---|
4075 | |
---|
4076 | } |
---|
4077 | } |
---|
4078 | #endif |
---|
4079 | // update left box and rightbox properties |
---|
4080 | if (curr->IsRightBoundary()) { // we are on the right boundary of an object |
---|
4081 | state.cntRight--; |
---|
4082 | state.thickness--; |
---|
4083 | // Check possibly the position |
---|
4084 | if ( (val != nval) || |
---|
4085 | ((curr->IsRightBoundary()) && (next->IsLeftBoundary())) ) |
---|
4086 | { |
---|
4087 | state.position = val - MinPosition; |
---|
4088 | state.position2 = nval - MinPosition; |
---|
4089 | state.it = curr; |
---|
4090 | // Here evaluate the cost of surface area heuristics |
---|
4091 | EvaluateCost(state); |
---|
4092 | } |
---|
4093 | } |
---|
4094 | else { |
---|
4095 | // the left boundary .. enter the object from left |
---|
4096 | |
---|
4097 | // Check possibly the position |
---|
4098 | if ( (pval != val) |
---|
4099 | // || ((curr->IsRightBoundary()) && (next->IsLeftBoundary())) |
---|
4100 | ) |
---|
4101 | { |
---|
4102 | state.position = val - MinPosition; |
---|
4103 | state.position2 = nval - MinPosition; |
---|
4104 | state.it = curr; |
---|
4105 | // Here evaluate the cost of surface area heuristics |
---|
4106 | EvaluateCost(state); |
---|
4107 | } |
---|
4108 | |
---|
4109 | state.cntLeft++; |
---|
4110 | state.thickness++; |
---|
4111 | } |
---|
4112 | |
---|
4113 | curr = next; // pointer to the boundary |
---|
4114 | next++; |
---|
4115 | pval = val; |
---|
4116 | val = nval; // value of splitting plane |
---|
4117 | } // while |
---|
4118 | |
---|
4119 | //cout << "i = " << i << endl; |
---|
4120 | |
---|
4121 | assert(state.cntLeft == state.cntAll); |
---|
4122 | state.cntRight--; |
---|
4123 | assert(state.cntRight == 0); |
---|
4124 | state.thickness--; |
---|
4125 | assert(state.thickness == 0); |
---|
4126 | |
---|
4127 | // Evaluate last possible position |
---|
4128 | state.position = val - MinPosition; |
---|
4129 | if (state.position < MaxPosition) { |
---|
4130 | state.position2 = state.width; |
---|
4131 | state.it = curr; |
---|
4132 | // Here evaluate the cost of surface area heuristics |
---|
4133 | EvaluateCostFreeCut(state); |
---|
4134 | } |
---|
4135 | |
---|
4136 | // In this case the best result is kept in 'state' variable |
---|
4137 | return; |
---|
4138 | } // CTestAx::GetSplitPlaneOpt (for X, Y, Z) |
---|
4139 | |
---|
4140 | // ------------------------------------------------------------------------------- |
---|
4141 | // TRIAL TO IMPROVE for a given X/Y/Z-axis search for the best splitting plane position. |
---|
4142 | // Starts from start item, the rest of the information is set to 'state' variable. |
---|
4143 | void |
---|
4144 | CKTBABuildUp::GetSplitPlaneOpt2(SItemVec *vec, int axisToTest) |
---|
4145 | { |
---|
4146 | #ifdef _DEBUG |
---|
4147 | if ((vec == NULL) || (vec->size() == 0)) { |
---|
4148 | cerr << "Trying to subdivide some node without an object" << endl; |
---|
4149 | abort();; |
---|
4150 | } |
---|
4151 | #endif // _DEBUG |
---|
4152 | |
---|
4153 | // some necessary space is required to cut off |
---|
4154 | const float eps = 1.0e-6 * state.width; |
---|
4155 | const float MinPosition = state.box.Min(axisToTest); |
---|
4156 | const float MaxPosition = state.box.Max(axisToTest); |
---|
4157 | //float MinPositionAccept = MinPosition + eps; |
---|
4158 | //float MaxPositionAccept = MaxPosition - eps; |
---|
4159 | |
---|
4160 | // wherefrom to start |
---|
4161 | SItemVec::iterator curr = vec->begin(); |
---|
4162 | SItemVec::iterator next = vec->begin() + 1; |
---|
4163 | // Set the type of splitting by this function, which is in this case |
---|
4164 | // not overwritten in Evaluate() function |
---|
4165 | state.bestTwoSplits = 1; |
---|
4166 | state.thickness = 0; |
---|
4167 | float val = (*curr).pos; |
---|
4168 | float nval; |
---|
4169 | float pval = val; |
---|
4170 | |
---|
4171 | //#if 1 |
---|
4172 | #ifdef _DEBUG_COSTFUNCTION |
---|
4173 | static int indexToFind = 0; |
---|
4174 | static int indexSS = 0; |
---|
4175 | if ( (indexSS == indexToFindSS) && |
---|
4176 | (!_alreadyDebugged)) { |
---|
4177 | cout << "Debugging cost function, index = " << indexSS << endl; |
---|
4178 | InitCostStream(indexSS, state.cntAll, |
---|
4179 | (val-state.box.Min(axisToTest))/state.width, |
---|
4180 | //(val-MinPosition)/state.width, |
---|
4181 | //(MinPosition)/state.width, |
---|
4182 | (state.box.Max(axisToTest)-MinPosition)/state.width); |
---|
4183 | } |
---|
4184 | indexSS++; |
---|
4185 | #endif |
---|
4186 | |
---|
4187 | // Evaluate the first possible position, cutting off empty |
---|
4188 | // space on the left of the splitting plane |
---|
4189 | state.position = val - MinPosition; |
---|
4190 | if (state.position > 0.f) { |
---|
4191 | state.position2 = next->pos - MinPosition; |
---|
4192 | state.it = curr; |
---|
4193 | // Here evaluate the cost of surface area heuristics |
---|
4194 | EvaluateCostFreeCut(state); |
---|
4195 | } |
---|
4196 | |
---|
4197 | //-------------------- TEST LOOP --------------------------------------- |
---|
4198 | // make evaluation for each splitting position |
---|
4199 | const int imax = vec->size()-1; |
---|
4200 | int ii; |
---|
4201 | for (ii = 1; ii <= imax; ii++) |
---|
4202 | { |
---|
4203 | nval = (*vec)[ii].pos; |
---|
4204 | // update left box and rightbox properties |
---|
4205 | if (curr->IsRightBoundary()) { |
---|
4206 | // the right boundary of an object |
---|
4207 | state.cntRight--; |
---|
4208 | state.thickness--; |
---|
4209 | |
---|
4210 | // Check possibly the position |
---|
4211 | if ( (val != nval) || |
---|
4212 | ((curr->IsRightBoundary()) && (next->IsLeftBoundary())) ) |
---|
4213 | { |
---|
4214 | if (state.thickness >= 0) { |
---|
4215 | state.position = val - MinPosition; |
---|
4216 | state.position2 = nval - MinPosition; |
---|
4217 | state.it = curr; |
---|
4218 | // Here evaluate the cost of surface area heuristics |
---|
4219 | EvaluateCost(state); |
---|
4220 | } |
---|
4221 | } |
---|
4222 | } |
---|
4223 | else { |
---|
4224 | // the left boundary .. enter the object from left |
---|
4225 | |
---|
4226 | // Check possibly the position |
---|
4227 | if (pval != val) |
---|
4228 | { |
---|
4229 | if (state.thickness >= 0) { |
---|
4230 | state.position = val - MinPosition; |
---|
4231 | state.position2 = nval - MinPosition; |
---|
4232 | state.it = curr; |
---|
4233 | // Here evaluate the cost of surface area heuristics |
---|
4234 | EvaluateCost(state); |
---|
4235 | } |
---|
4236 | } |
---|
4237 | state.cntLeft++; |
---|
4238 | state.thickness++; |
---|
4239 | } |
---|
4240 | |
---|
4241 | curr = next; // pointer to the boundary |
---|
4242 | pval = val; |
---|
4243 | val = nval; // value of splitting plane |
---|
4244 | next++; |
---|
4245 | } // while |
---|
4246 | |
---|
4247 | //cout << "i = " << i << endl; |
---|
4248 | |
---|
4249 | assert(state.cntLeft == state.cntAll); |
---|
4250 | state.cntRight--; |
---|
4251 | assert(state.cntRight == 0); |
---|
4252 | state.thickness--; |
---|
4253 | assert(state.thickness == 0); |
---|
4254 | |
---|
4255 | #if 0 |
---|
4256 | if (state.thickness < 0) { |
---|
4257 | cout << "SSSomething wrong happened here at end\n" << endl; |
---|
4258 | } |
---|
4259 | #endif |
---|
4260 | |
---|
4261 | #ifdef _DEBUG |
---|
4262 | if (curr != vec->end()-1) { |
---|
4263 | cerr << "Implementation bug in pointers" << endl; |
---|
4264 | cout << "curr = " << curr - vec->begin() |
---|
4265 | << " vec->end()-1 = " << vec->end()-1 - vec->begin() << endl; |
---|
4266 | abort();; |
---|
4267 | } |
---|
4268 | #endif |
---|
4269 | |
---|
4270 | // Evaluate last possible position |
---|
4271 | state.position = val - MinPosition; |
---|
4272 | if (state.position < MaxPosition) { |
---|
4273 | state.position2 = state.width; |
---|
4274 | state.it = curr; |
---|
4275 | // Here evaluate the cost of surface area heuristics |
---|
4276 | EvaluateCostFreeCut(state); |
---|
4277 | } |
---|
4278 | |
---|
4279 | #ifdef _DEBUG_COSTFUNCTION |
---|
4280 | CloseCostStream(); |
---|
4281 | #endif |
---|
4282 | |
---|
4283 | // In this case the best result is kept in 'state' variable |
---|
4284 | return; |
---|
4285 | } // CTestAx::GetSplitPlaneOpt (for X, Y, Z) |
---|
4286 | |
---|
4287 | // ------------------------------------------------------------------------------- |
---|
4288 | // TRIAL TO IMPROVE for a given X/Y/Z-axis search for the best splitting plane position. |
---|
4289 | // Using unrolling possibly understandable for inteligent compiler. |
---|
4290 | // Starts from start item, the rest of the information is set to 'state' variable. |
---|
4291 | void |
---|
4292 | CKTBABuildUp::GetSplitPlaneOpt3(SItemVec *vec, int axisToTest) |
---|
4293 | { |
---|
4294 | #ifdef _DEBUG |
---|
4295 | if ((vec == NULL) || (vec->size() == 0)) { |
---|
4296 | cerr << "Trying to subdivide some node without an object" << endl; |
---|
4297 | abort();; |
---|
4298 | } |
---|
4299 | #endif // _DEBUG |
---|
4300 | |
---|
4301 | #if 0 |
---|
4302 | static int index = 0; |
---|
4303 | cout << "index = " << index << endl; |
---|
4304 | const int indexToFind = 27; |
---|
4305 | if (index == indexToFind) { |
---|
4306 | cout << "Index found = " << index << endl; |
---|
4307 | } |
---|
4308 | index++; |
---|
4309 | #endif |
---|
4310 | |
---|
4311 | // some necessary space is required to cut off |
---|
4312 | const float eps = 1.0e-6 * state.width; |
---|
4313 | const float MinPosition = state.box.Min(axisToTest); |
---|
4314 | const float MaxPosition = state.box.Max(axisToTest); |
---|
4315 | //float MinPositionAccept = MinPosition + eps; |
---|
4316 | //float MaxPositionAccept = MaxPosition - eps; |
---|
4317 | |
---|
4318 | // wherefrom to start |
---|
4319 | SItemVec::iterator curr = vec->begin(); |
---|
4320 | SItemVec::iterator next = vec->begin() + 1; |
---|
4321 | // Set the type of splitting by this function, which is in this case |
---|
4322 | // not overwritten in Evaluate() function |
---|
4323 | state.bestTwoSplits = 1; |
---|
4324 | float val = (*curr).pos; |
---|
4325 | // value at previous and next position |
---|
4326 | float pval, nval; |
---|
4327 | pval = MinPosition; |
---|
4328 | |
---|
4329 | // Evaluate the first possible position, cutting off empty |
---|
4330 | // space on the left of the splitting plane |
---|
4331 | state.position = val - MinPosition; |
---|
4332 | // The first boundary must be left |
---|
4333 | assert(curr->IsLeftBoundary()); |
---|
4334 | if (state.position > 0.f) { |
---|
4335 | state.position2 = next->pos - MinPosition; |
---|
4336 | state.it = curr; |
---|
4337 | // Here evaluate the cost of surface area heuristics |
---|
4338 | EvaluateCostFreeCut(state); |
---|
4339 | } // ------------------------------ |
---|
4340 | // Update for the next iteration |
---|
4341 | state.cntLeft++; |
---|
4342 | state.thickness++; |
---|
4343 | pval = val; |
---|
4344 | |
---|
4345 | //-------------------- TEST LOOP --------------------------------------- |
---|
4346 | // make evaluation for each splitting position, minus the first and |
---|
4347 | // the last one |
---|
4348 | int imax = vec->size()-2; |
---|
4349 | // Setting unrolling |
---|
4350 | const int MaxUNROLL = 4; |
---|
4351 | const int loops = imax / MaxUNROLL; |
---|
4352 | const int remainder = imax % MaxUNROLL; |
---|
4353 | // There is some bug, when using this version, the boundaries are |
---|
4354 | // incorrectly sorted. |
---|
4355 | assert(remainder < MaxUNROLL); |
---|
4356 | int ii = 1; |
---|
4357 | if (loops > 0) { |
---|
4358 | // The outer loop |
---|
4359 | for (int l = 0; l < loops; l++, ii += MaxUNROLL) |
---|
4360 | { |
---|
4361 | // This has to be unrolled by compiler such as Intel Compiler or GCC4.1 |
---|
4362 | // The number of loops is known in advance ! |
---|
4363 | for (int qq = 0; qq < MaxUNROLL; qq++) |
---|
4364 | { |
---|
4365 | curr = vec->begin() + ii + qq; |
---|
4366 | next = curr + 1; |
---|
4367 | #if 1 |
---|
4368 | val = (*curr).pos; |
---|
4369 | nval = (*next).pos; |
---|
4370 | #else |
---|
4371 | val = (*vec)[ii+qq].pos; |
---|
4372 | nval = (*vec)[ii+qq+1].pos; |
---|
4373 | #endif |
---|
4374 | |
---|
4375 | // update left box and rightbox properties |
---|
4376 | if (curr->IsRightBoundary()){// we are on the right boundary of an object |
---|
4377 | state.cntRight--; |
---|
4378 | state.thickness--; |
---|
4379 | // Check possibly the position |
---|
4380 | if ( (val != nval) || |
---|
4381 | ((curr->IsRightBoundary()) && (next->IsLeftBoundary())) ) |
---|
4382 | { |
---|
4383 | state.position = val - MinPosition; |
---|
4384 | state.position2 = nval - MinPosition; |
---|
4385 | state.it = curr; |
---|
4386 | // Here evaluate the cost of surface area heuristics |
---|
4387 | EvaluateCost(state); |
---|
4388 | // It does make sense to change boundary value |
---|
4389 | pval = (*vec)[ii+qq].pos; |
---|
4390 | } |
---|
4391 | } |
---|
4392 | else { |
---|
4393 | // the left boundary .. enter the object from left |
---|
4394 | |
---|
4395 | // Check possibly the position |
---|
4396 | if (pval != val) |
---|
4397 | { |
---|
4398 | state.position = val - MinPosition; |
---|
4399 | state.position2 = nval - MinPosition; |
---|
4400 | state.it = curr; |
---|
4401 | // Here evaluate the cost of surface area heuristics |
---|
4402 | EvaluateCost(state); |
---|
4403 | // It makes sense to change boundary value |
---|
4404 | pval = (*vec)[ii+qq].pos; |
---|
4405 | } |
---|
4406 | state.cntLeft++; |
---|
4407 | state.thickness++; |
---|
4408 | } // left or right boundary |
---|
4409 | } // for qq |
---|
4410 | } // for ii |
---|
4411 | |
---|
4412 | // Set the correct pointer for the next iteration |
---|
4413 | curr = next; next++; |
---|
4414 | pval = val; |
---|
4415 | } |
---|
4416 | else { |
---|
4417 | //cout << "No loop" << endl; |
---|
4418 | pval = val; |
---|
4419 | curr = next; |
---|
4420 | next++; |
---|
4421 | } |
---|
4422 | |
---|
4423 | // The rest of the loop |
---|
4424 | if (ii <= imax) { |
---|
4425 | // Set the correct pointer |
---|
4426 | for ( ;ii <= imax; ii++) { |
---|
4427 | nval = curr->pos; |
---|
4428 | // update left box and rightbox properties |
---|
4429 | if (curr->IsRightBoundary()) { // we are on the right boundary of an object |
---|
4430 | state.cntRight--; |
---|
4431 | state.thickness--; |
---|
4432 | // Check possibly the position |
---|
4433 | if ( (val != nval) || |
---|
4434 | ((curr->IsRightBoundary()) && (next->IsLeftBoundary())) ) |
---|
4435 | { |
---|
4436 | state.position = val - MinPosition; |
---|
4437 | state.position2 = nval - MinPosition; |
---|
4438 | state.it = curr; |
---|
4439 | // Here evaluate the cost of surface area heuristics |
---|
4440 | EvaluateCost(state); |
---|
4441 | } |
---|
4442 | } |
---|
4443 | else { |
---|
4444 | // the left boundary .. enter the object from left |
---|
4445 | |
---|
4446 | // Check possibly the position |
---|
4447 | if (pval != val) |
---|
4448 | { |
---|
4449 | state.position = val - MinPosition; |
---|
4450 | state.position2 = nval - MinPosition; |
---|
4451 | state.it = curr; |
---|
4452 | // Here evaluate the cost of surface area heuristics |
---|
4453 | EvaluateCost(state); |
---|
4454 | } |
---|
4455 | state.cntLeft++; |
---|
4456 | state.thickness++; |
---|
4457 | } // if right/left boundary |
---|
4458 | |
---|
4459 | curr = next; // pointer to the boundary |
---|
4460 | pval = val; |
---|
4461 | val = nval; // value of splitting plane |
---|
4462 | next++; |
---|
4463 | } // for qq |
---|
4464 | |
---|
4465 | // For the last evaluation |
---|
4466 | } |
---|
4467 | else { |
---|
4468 | if (!loops) { |
---|
4469 | curr = next; |
---|
4470 | val = nval; |
---|
4471 | } |
---|
4472 | } |
---|
4473 | |
---|
4474 | //cout << "i = " << i << endl; |
---|
4475 | |
---|
4476 | #ifdef _DEBUG |
---|
4477 | if (curr != vec->end()-1) { |
---|
4478 | cerr << "Implementation bug in pointers" << endl; |
---|
4479 | cout << "curr = " << curr - vec->begin() |
---|
4480 | << "vec->end()-1 = " << vec->end()-1 - vec->begin() << endl; |
---|
4481 | abort();; |
---|
4482 | } |
---|
4483 | #endif |
---|
4484 | |
---|
4485 | assert(state.cntLeft == state.cntAll); |
---|
4486 | state.cntRight--; |
---|
4487 | assert(state.cntRight == 0); |
---|
4488 | state.thickness--; |
---|
4489 | assert(state.thickness == 0); |
---|
4490 | |
---|
4491 | // Evaluate last possible position |
---|
4492 | state.position = val - MinPosition; |
---|
4493 | if (state.position < MaxPosition) { |
---|
4494 | state.position2 = state.width; |
---|
4495 | state.it = curr; |
---|
4496 | // Here evaluate the cost of surface area heuristics |
---|
4497 | EvaluateCostFreeCut(state); |
---|
4498 | } |
---|
4499 | |
---|
4500 | // In this case the best result is kept in 'state' variable |
---|
4501 | return; |
---|
4502 | } // CTestAx::GetSplitPlaneOpt3 (for X, Y, Z) |
---|
4503 | |
---|
4504 | #if 0 |
---|
4505 | // Here is some bug, that is clearly visible for tree.nff !! The resulting |
---|
4506 | // tree is much less efficient. 3/1/2006 VH. |
---|
4507 | // ------------------------------------------------------------------------------- |
---|
4508 | // TRIAL TO IMPROVE for a given X,Y,Z-axis search for the best splitting plane position. |
---|
4509 | // Starts from start item, the rest of the information is set to 'state' variable. |
---|
4510 | // It does not work for gcc compiler better than GetSplitPlaneOpt |
---|
4511 | void |
---|
4512 | CKTBABuildUp::GetSplitPlaneOptUnroll4(SItemVec *vec, int axisToTest) |
---|
4513 | { |
---|
4514 | #ifdef _DEBUG |
---|
4515 | if ((vec == NULL) || (vec->size() == 0)) { |
---|
4516 | cerr << "Trying to subdivide some node without an object" << endl; |
---|
4517 | abort();; |
---|
4518 | } |
---|
4519 | #endif // _DEBUG |
---|
4520 | |
---|
4521 | #if 0 |
---|
4522 | static int index = 0; |
---|
4523 | cout << "index = " << index << endl; |
---|
4524 | const int indexToFind = 8; |
---|
4525 | if (index == indexToFind) { |
---|
4526 | cout << "Index found = " << index << endl; |
---|
4527 | } |
---|
4528 | index++; |
---|
4529 | #endif |
---|
4530 | |
---|
4531 | // some necessary space is required to cut off |
---|
4532 | const float eps = 1.0e-6 * state.width; |
---|
4533 | const float MinPosition = state.box.Min(axisToTest); |
---|
4534 | const float MaxPosition = state.box.Max(axisToTest); |
---|
4535 | //float MinPositionAccept = MinPosition + eps; |
---|
4536 | //float MaxPositionAccept = MaxPosition - eps; |
---|
4537 | |
---|
4538 | // wherefrom to start |
---|
4539 | // Set the type of splitting by this function, which is in this case |
---|
4540 | // not overwritten in Evaluate() function |
---|
4541 | state.bestTwoSplits = 1; |
---|
4542 | float val4 = MinPosition; |
---|
4543 | |
---|
4544 | //-------------------- TEST LOOP --------------------------------------- |
---|
4545 | // make evaluation for each splitting position |
---|
4546 | |
---|
4547 | // the first position was already evaluated and the last is also a special case |
---|
4548 | const int imax = vec->size() - 1; |
---|
4549 | int cntDebug = 0; |
---|
4550 | int imax4 = 4*(imax/4); |
---|
4551 | int imax4rest = imax % 4; |
---|
4552 | int i; |
---|
4553 | // This is manual unrolling |
---|
4554 | if (imax4 >= 4) { |
---|
4555 | for(i = 0; i < imax4; i += 4) |
---|
4556 | { |
---|
4557 | // The evaluation I |
---|
4558 | cntDebug++; |
---|
4559 | float pval1 = val4; |
---|
4560 | SItem* curr1 = &((*vec)[i+0]); float val1 = (*vec)[i+0].pos; |
---|
4561 | SItem* next1 = &((*vec)[i+1]); float nval1 = (*vec)[i+1].pos; |
---|
4562 | if (curr1->IsRightBoundary()) { |
---|
4563 | state.cntRight--; state.thickness--; |
---|
4564 | if ( (val1 != nval1) || |
---|
4565 | ((curr1->IsRightBoundary()) && (next1->IsLeftBoundary())) ) { |
---|
4566 | state.position = val1 - MinPosition; state.position2 = nval1 - MinPosition; |
---|
4567 | state.it = vec->begin() + i; EvaluateCost(state); |
---|
4568 | } |
---|
4569 | } |
---|
4570 | else { |
---|
4571 | if (pval1 != val1) { |
---|
4572 | state.position = val1 - MinPosition; state.position2 = nval1 - MinPosition; |
---|
4573 | state.it = vec->begin() + i; EvaluateCost(state); |
---|
4574 | } |
---|
4575 | state.cntLeft++; state.thickness++; |
---|
4576 | } |
---|
4577 | // The evaluation II |
---|
4578 | cntDebug++; |
---|
4579 | float pval2 = (*vec)[i+0].pos; |
---|
4580 | SItem* curr2 = &((*vec)[i+1]); float val2 = (*vec)[i+1].pos; |
---|
4581 | SItem* next2 = &((*vec)[i+2]); float nval2 = (*vec)[i+2].pos; |
---|
4582 | if (curr2->IsRightBoundary()) { |
---|
4583 | state.cntRight--; state.thickness--; |
---|
4584 | if ( (val2 != nval2) || |
---|
4585 | ((curr2->IsRightBoundary()) && (next2->IsLeftBoundary())) ) { |
---|
4586 | state.position = val2 - MinPosition; state.position2 = nval2 - MinPosition; |
---|
4587 | state.it = vec->begin() + i + 1; EvaluateCost(state); |
---|
4588 | } |
---|
4589 | } |
---|
4590 | else { |
---|
4591 | if (pval2 != val2) { |
---|
4592 | state.position = val2 - MinPosition; state.position2 = nval2 - MinPosition; |
---|
4593 | state.it = vec->begin() + i + 1; EvaluateCost(state); |
---|
4594 | } |
---|
4595 | state.cntLeft++; state.thickness++; |
---|
4596 | } |
---|
4597 | // The evaluation III |
---|
4598 | cntDebug++; |
---|
4599 | float pval3 = (*vec)[i+1].pos; |
---|
4600 | SItem* curr3 = &((*vec)[i+2]); float val3 = (*vec)[i+2].pos; |
---|
4601 | SItem* next3 = &((*vec)[i+3]); float nval3 = (*vec)[i+3].pos; |
---|
4602 | if (curr3->IsRightBoundary()) { |
---|
4603 | state.cntRight--; state.thickness--; |
---|
4604 | if ( (val3 != nval3) || |
---|
4605 | ((curr3->IsRightBoundary()) && (next3->IsLeftBoundary())) ) { |
---|
4606 | state.position = val3 - MinPosition; state.position2 = nval3 - MinPosition; |
---|
4607 | state.it = vec->begin() + i + 2; EvaluateCost(state); |
---|
4608 | } |
---|
4609 | } |
---|
4610 | else { |
---|
4611 | if (pval3 != val3) { |
---|
4612 | state.position = val3 - MinPosition; state.position2 = nval3 - MinPosition; |
---|
4613 | state.it = vec->begin() + i + 2; EvaluateCost(state); |
---|
4614 | } |
---|
4615 | state.cntLeft++; state.thickness++; |
---|
4616 | } |
---|
4617 | // The evaluation IV |
---|
4618 | cntDebug++; |
---|
4619 | float pval4 = (*vec)[i+2].pos; |
---|
4620 | SItem* curr4 = &((*vec)[i+3]); val4 = (*vec)[i+3].pos; |
---|
4621 | SItem* next4 = &((*vec)[i+4]); float nval4 = (*vec)[i+4].pos; |
---|
4622 | if (curr4->IsRightBoundary()) { |
---|
4623 | state.cntRight--; state.thickness--; |
---|
4624 | if ( (val4 != nval4) || |
---|
4625 | ((curr4->IsRightBoundary()) && (next4->IsLeftBoundary())) ) { |
---|
4626 | state.position = val4 - MinPosition; state.position2 = nval4 - MinPosition; |
---|
4627 | state.it = vec->begin() + i + 3; EvaluateCost(state); |
---|
4628 | } |
---|
4629 | } |
---|
4630 | else { |
---|
4631 | if (pval4 != val4) { |
---|
4632 | state.position = val4 - MinPosition; state.position2 = nval4 - MinPosition; |
---|
4633 | state.it = vec->begin() + i + 3; EvaluateCost(state); |
---|
4634 | } |
---|
4635 | state.cntLeft++; state.thickness++; |
---|
4636 | } |
---|
4637 | } // for, unrolled loop by factor 4 |
---|
4638 | } // if more than 4 evaluations |
---|
4639 | |
---|
4640 | for(i = imax4; i < imax; i ++) |
---|
4641 | { |
---|
4642 | cntDebug++; |
---|
4643 | float pvalI = val4; |
---|
4644 | SItem* currI = &((*vec)[i+0]); float valI = (*vec)[i+0].pos; |
---|
4645 | SItem* nextI = &((*vec)[i+1]); float nvalI = (*vec)[i+1].pos; |
---|
4646 | if (currI->IsRightBoundary()) { |
---|
4647 | state.cntRight--; state.thickness--; |
---|
4648 | if ( (valI != nvalI) || |
---|
4649 | ((currI->IsRightBoundary()) && (nextI->IsLeftBoundary())) ) { |
---|
4650 | state.position = valI - MinPosition; state.position2 = nvalI - MinPosition; |
---|
4651 | state.it = vec->begin() + i; EvaluateCost(state); |
---|
4652 | } |
---|
4653 | } |
---|
4654 | else { |
---|
4655 | if (pvalI != valI) { |
---|
4656 | state.position = valI - MinPosition; state.position2 = nvalI - MinPosition; |
---|
4657 | state.it = vec->begin() + i; EvaluateCost(state); |
---|
4658 | } |
---|
4659 | state.cntLeft++; state.thickness++; |
---|
4660 | } |
---|
4661 | val4 = valI; |
---|
4662 | } // for i |
---|
4663 | |
---|
4664 | //cout << "i = " << i << endl; |
---|
4665 | assert(cntDebug == imax); |
---|
4666 | |
---|
4667 | assert(state.cntLeft == state.cntAll); |
---|
4668 | state.cntRight--; |
---|
4669 | assert(state.cntRight == 0); |
---|
4670 | state.thickness--; |
---|
4671 | assert(state.thickness == 0); |
---|
4672 | |
---|
4673 | // Evaluate last possible position |
---|
4674 | state.position = (*vec)[imax-1].pos - MinPosition; |
---|
4675 | if (state.position < MaxPosition) { |
---|
4676 | state.position2 = state.width; |
---|
4677 | state.it = vec->end() - 1; |
---|
4678 | // Here evaluate the cost of surface area heuristics |
---|
4679 | EvaluateCost(state); |
---|
4680 | } |
---|
4681 | |
---|
4682 | // In this case the best result is kept in 'state' variable |
---|
4683 | return; |
---|
4684 | } // CTestAx::GetSplitPlaneX,Y,Z |
---|
4685 | #endif |
---|
4686 | |
---|
4687 | } |
---|
4688 | |
---|