1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkUnstructuredGridVolumeZSweepMapper.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkUnstructuredGridVolumeZSweepMapper.h"
16
17 #include "vtkObjectFactory.h"
18 #include "vtkUnstructuredGrid.h"
19 #include "vtkTimerLog.h"
20 #include "vtkVolume.h"
21 #include "vtkRenderer.h"
22 #include "vtkRenderWindow.h"
23 #include "vtkRayCastImageDisplayHelper.h"
24 #include "vtkTransform.h"
25 #include "vtkCamera.h"
26 #include "vtkCellIterator.h"
27 #include "vtkGenericCell.h"
28 #include "vtkPriorityQueue.h"
29 #include "vtkIdList.h"
30 #include "vtkVolumeProperty.h"
31 #include "vtkColorTransferFunction.h"
32 #include "vtkPiecewiseFunction.h"
33 #include "vtkSmartPointer.h"
34 #include "vtkUnstructuredGridPreIntegration.h"
35 #include "vtkUnstructuredGridPartialPreIntegration.h"
36 #include "vtkUnstructuredGridHomogeneousRayIntegrator.h"
37 #include "vtkDoubleArray.h"
38 #include "vtkDataArray.h"
39
40 #include "vtkPolyData.h"
41 #include "vtkCellArray.h"
42 //#include "vtkXMLPolyDataWriter.h"
43 #include "vtkPointData.h"
44
45 #include <cassert>
46 #include <cstring> // memset()
47 #include <vector>
48 #include <list>
49
50 // do not remove the following line:
51 //#define BACK_TO_FRONT
52
53 // Put the internal classes in a namespace to avoid potential naming conflicts.
54 namespace vtkUnstructuredGridVolumeZSweepMapperNamespace
55 {
56
57 enum
58 {
59 VTK_VALUES_X_INDEX=0, // world coordinate
60 VTK_VALUES_Y_INDEX, // world coordinate
61 VTK_VALUES_Z_INDEX, // world coordinate
62 VTK_VALUES_SCALAR_INDEX,
63 VTK_VALUES_SIZE // size of a value array
64 };
65
66 // Internal classes
67 //-----------------------------------------------------------------------------
68 // Store the result of the scan conversion at some pixel.
69 class vtkPixelListEntry
70 {
71 public:
72 vtkPixelListEntry() = default;
73
Init(double values[VTK_VALUES_SIZE],double zView,bool exitFace)74 void Init(double values[VTK_VALUES_SIZE],
75 double zView,
76 bool exitFace)
77 {
78 this->Zview=zView;
79 int i=0;
80 while(i<VTK_VALUES_SIZE)
81 {
82 this->Values[i]=values[i];
83 ++i;
84 }
85 this->ExitFace = exitFace;
86 }
87
88
89 // Return the interpolated values at this pixel.
GetValues()90 inline double *GetValues() { return this->Values; }
91 // Return the interpolated z coordinate in view space at this pixel.
GetZview() const92 inline double GetZview() const { return this->Zview; }
93 // Return whether the fragment comes from an external face.
GetExitFace() const94 inline bool GetExitFace() const { return this->ExitFace; }
95
GetPrevious()96 vtkPixelListEntry *GetPrevious() { return this->Previous; }
GetNext()97 vtkPixelListEntry *GetNext() { return this->Next; }
98
SetPrevious(vtkPixelListEntry * e)99 void SetPrevious(vtkPixelListEntry *e) { this->Previous=e; }
SetNext(vtkPixelListEntry * e)100 void SetNext(vtkPixelListEntry *e) { this->Next=e; }
101
102 protected:
103 double Values[VTK_VALUES_SIZE];
104 double Zview;
105 bool ExitFace;
106
107 // List structure: both for the free block list (one-way) and any
108 // pixel list (two-way)
109 vtkPixelListEntry *Next;
110 // List structure: only for the pixel list (two-way)
111 vtkPixelListEntry *Previous;
112 private:
113 vtkPixelListEntry(const vtkPixelListEntry &other) = delete;
114 vtkPixelListEntry &operator=(const vtkPixelListEntry &other) = delete;
115 };
116
117 //-----------------------------------------------------------------------------
118 // Cache the projection of a vertex
119 class vtkVertexEntry
120 {
121 public:
122 vtkVertexEntry() = default;
123
vtkVertexEntry(int screenX,int screenY,double xWorld,double yWorld,double zWorld,double zView,double scalar,double invW)124 vtkVertexEntry(int screenX,
125 int screenY,
126 double xWorld,
127 double yWorld,
128 double zWorld,
129 double zView,
130 double scalar,
131 double invW)
132 :ScreenX(screenX),ScreenY(screenY),Zview(zView),InvW(invW)
133 {
134 this->Values[VTK_VALUES_X_INDEX]=xWorld;
135 this->Values[VTK_VALUES_Y_INDEX]=yWorld;
136 this->Values[VTK_VALUES_Z_INDEX]=zWorld;
137 this->Values[VTK_VALUES_SCALAR_INDEX]=scalar;
138 }
139
Set(int screenX,int screenY,double xWorld,double yWorld,double zWorld,double zView,double scalar,double invW)140 void Set(int screenX,
141 int screenY,
142 double xWorld,
143 double yWorld,
144 double zWorld,
145 double zView,
146 double scalar,
147 double invW)
148 {
149 this->ScreenX=screenX;
150 this->ScreenY=screenY;
151 this->Zview=zView;
152 this->Values[VTK_VALUES_X_INDEX]=xWorld;
153 this->Values[VTK_VALUES_Y_INDEX]=yWorld;
154 this->Values[VTK_VALUES_Z_INDEX]=zWorld;
155 this->Values[VTK_VALUES_SCALAR_INDEX]=scalar;
156 this->InvW=invW;
157 }
158
GetScreenX()159 int GetScreenX()
160 {
161 return this->ScreenX;
162 }
GetScreenY()163 int GetScreenY()
164 {
165 return this->ScreenY;
166 }
GetValues()167 double *GetValues()
168 {
169 return this->Values;
170 }
GetZview()171 double GetZview()
172 {
173 return this->Zview;
174 }
GetInvW()175 double GetInvW()
176 {
177 return this->InvW;
178 }
179
operator =(const vtkVertexEntry & other)180 vtkVertexEntry &operator=(const vtkVertexEntry &other) {
181 ScreenX = other.ScreenX;
182 ScreenY = other.ScreenY;
183 memcpy(Values, other.Values, sizeof(double)*VTK_VALUES_SIZE);
184 Zview = other.Zview;
185 InvW = other.InvW;
186 return *this;
187 }
vtkVertexEntry(const vtkVertexEntry & other)188 vtkVertexEntry(const vtkVertexEntry &other) {
189 if( this != &other)
190 {
191 *this = other;
192 }
193 }
194
195 protected:
196 int ScreenX;
197 int ScreenY;
198 double Values[VTK_VALUES_SIZE];
199 double Zview;
200 double InvW;
201 };
202
203
204 //-----------------------------------------------------------------------------
205 // Abstract interface for an edge of a triangle in the screen space.
206 // Used during scan-conversion.
207 class vtkScreenEdge
208 {
209 public:
210 // If the edge is a composite edge (top+bottom) switch to the bottom edge.
211 // Otherwise, do nothing.
OnBottom(int skipped,int y)212 virtual void OnBottom(int skipped, int y)
213 {
214 if(!skipped)
215 {
216 this->NextLine(y);
217 }
218 }
219 // Increment edge state to the next line.
220 virtual void NextLine(int y)=0;
221 // Increment edge state to the next deltaY line.
222 virtual void SkipLines(int deltaY,
223 int y)=0;
224 // Return the abscissa for the current line.
225 virtual int GetX()=0;
226 // Return the projected values for the current line. They are linearly
227 // incrementally interpolated in view space. The actual values are
228 // given by projectedValue/InvW. This is the way the values in world space
229 // are incrementally (not linearly) interpolated in view space.
230 virtual double *GetPValues()=0;
231 // Return 1/W, linearly interpolated in view space.
232 virtual double GetInvW()=0;
233 // Return Z in view coordinates, linearly interpolated in view space.
234 virtual double GetZview()=0;
235 protected:
236 // Destructor.
237 virtual ~vtkScreenEdge() = default;
238 };
239
240 //-----------------------------------------------------------------------------
241 // Do an incremental traversing of an edge based on an Y increment.
242 enum
243 {
244 VTK_CASE_VERTICAL=0,
245 VTK_CASE_MOSTLY_VERTICAL,
246 VTK_CASE_DIAGONAL,
247 VTK_CASE_HORIZONTAL_BEGIN,
248 VTK_CASE_HORIZONTAL_END,
249 VTK_CASE_HORIZONTAL_MS, // most significant pixel
250 VTK_CASE_VERTICAL_IN_TO_OUT, // with edge equation
251 VTK_CASE_VERTICAL_OUT_TO_IN,
252 VTK_CASE_HORIZONTAL_IN_TO_OUT,
253 VTK_CASE_HORIZONTAL_OUT_TO_IN,
254 VTK_CASE_UNDEFINED
255 };
256
257 // We use an edge equation as described in:
258 // Juan Pineda
259 // A Parallel Algorithm for Polygon Rasterization
260 // In Computer Graphics, Volume 22, Number 4, August 1988
261 // SIGGRAPH'88, Atlanta, August 1-5, 1988.
262 // pages 17--20.
263
264 // or in:
265
266 // Marc Olano and Trey Greer
267 // Triangle Scan Conversion using 2D Homogeneous Coordinates
268 // In 1997 SIGGRAPH/Eurographics Workshop
269 // pages 89--95.
270 // http://www.cs.unc.edu/~olano/papers/2dh-tri/2dh-tri.pdf
271
272 #define MOST_SIGNIFICANT
273 #define EDGE_EQUATION
274 #define HORI_EDGE_EQUATION
275 //#define STRICTLY_INSIDE
276
277 class vtkSimpleScreenEdge
278 : public vtkScreenEdge
279 {
280 public:
vtkSimpleScreenEdge()281 vtkSimpleScreenEdge()
282 {
283 this->Case = VTK_CASE_UNDEFINED;
284 }
285 // Initialize the edge by the vertices v0 and v2 (ordered in y)
286 // `onRight' is true if the edge in on the right side of the triangle.
Init(vtkVertexEntry * v0,vtkVertexEntry * v2,int dx20,int dy20,int onRight)287 void Init(vtkVertexEntry *v0,
288 vtkVertexEntry *v2,
289 int dx20,
290 int dy20,
291 int onRight)
292 {
293 double z0=v0->GetZview();
294 double z2=v2->GetZview();
295
296 double invW0=v0->GetInvW();
297 double invW2=v2->GetInvW();
298
299 double pv0[VTK_VALUES_SIZE];
300 double pv2[VTK_VALUES_SIZE];
301 int i=0;
302 while(i<VTK_VALUES_SIZE)
303 {
304 pv0[i]=v0->GetValues()[i]*invW0;
305 this->PValues[i]=pv0[i];
306 pv2[i]=v2->GetValues()[i]*invW2;
307 ++i;
308 }
309
310 this->InvW=invW0;
311 this->Zview=z0;
312
313 int x0=v0->GetScreenX();
314 int x2=v2->GetScreenX();
315
316 this->X0=x0;
317 this->X2=x2;
318
319 this->V2=v2;
320
321 this->X=x0;
322
323 if(dx20==0)
324 {
325 this->Case=VTK_CASE_VERTICAL;
326 double invDy20=1.0/dy20;
327 i=0;
328 while(i<VTK_VALUES_SIZE)
329 {
330 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
331 ++i;
332 }
333 this->DinvW=(invW2-invW0)*invDy20;
334 this->Dz=(z2-z0)*invDy20;
335 }
336 else
337 {
338 if(dx20>0)
339 {
340 this->IncX=1;
341 if(dx20>dy20)
342 {
343 // Mostly horizontal
344 #ifdef HORI_EDGE_EQUATION
345 if(onRight)
346 {
347 this->Case=VTK_CASE_HORIZONTAL_IN_TO_OUT;
348 }
349 else
350 {
351 this->Case=VTK_CASE_HORIZONTAL_OUT_TO_IN;
352 }
353 this->Error=0;
354 this->SDy=dy20;
355 this->XStep=dx20/dy20; // integral division
356 this->Dx=dx20-this->XStep*this->SDy;
357
358 double invDy20=1.0/dy20;
359 i=0;
360 while(i<VTK_VALUES_SIZE)
361 {
362 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
363 ++i;
364 }
365 this->DinvW=(invW2-invW0)*invDy20;
366 this->Dz=(z2-z0)*invDy20;
367 #else
368 #ifdef MOST_SIGNIFICANT
369 this->Case=VTK_CASE_HORIZONTAL_MS;
370 this->XStep=dx20/dy20; // integral division
371 this->Dy=dy20;
372 this->Dy2=dy20<<1; // *2
373 this->Error=0;
374 this->ErrorStep=(dx20-this->XStep*dy20)<<1; // 2*r, dx=q*dy+r, r<dy
375 double invDx20=1.0/dx20;
376 i=0;
377 while(i<VTK_VALUES_SIZE)
378 {
379 this->Dpv[i]=(pv2[i]-pv0[i])*invDx20;
380 this->PValuesStep[i]=this->Dpv[i]*this->XStep;
381 ++i;
382 }
383 this->DinvW=(invW2-invW0)*invDx20;
384 this->Dz=(z2-z0)*invDx20;
385 this->InvWStep=this->DinvW*this->XStep;
386 this->ZStep=this->Dz*this->XStep;
387
388 #else
389 if(!onRight)
390 {
391 this->Case=VTK_CASE_HORIZONTAL_BEGIN;
392 this->First=1;
393 this->Dy2=dy20<<1; // *2
394 this->Dx2=dx20<<1; // *2
395 this->Error=dx20;
396
397 this->XStep=dx20/dy20; // integral division
398
399 this->ErrorStep=this->XStep*this->Dy2;
400
401 double invDx20=1.0/dx20;
402 i=0;
403 while(i<VTK_VALUES_SIZE)
404 {
405 this->Dpv[i]=(pv2[i]-pv0[i])*invDx20;
406 this->PValuesStep[i]=this->Dpv[i]*this->XStep;
407 ++i;
408 }
409 this->DinvW=(invW2-invW0)*invDx20;
410 this->Dz=(z2-z0)*invDx20;
411 this->InvWStep=this->DinvW*this->XStep;
412 this->ZStep=this->Dz*this->XStep;
413 }
414 else
415 {
416 this->Case=VTK_CASE_HORIZONTAL_END;
417
418 this->InvW2=invW2;
419 i=0;
420 while(i<VTK_VALUES_SIZE)
421 {
422 this->PValues2[i]=pv2[i];
423 ++i;
424 }
425
426 this->Zview2=z2;
427
428 this->Dy2=dy20<<1; // *2
429 this->Dx2=dx20<<1; // *2
430 this->Error=dx20;
431 this->XStep=dx20/dy20;
432 this->ErrorStep=this->XStep*this->Dy2;
433
434 double invDx20=1.0/dx20;
435 i=0;
436 while(i<VTK_VALUES_SIZE)
437 {
438 this->Dpv[i]=(pv2[i]-pv0[i])*invDx20;
439 this->PValuesStep[i]=this->Dpv[i]*this->XStep;
440 ++i;
441 }
442 this->DinvW=(invW2-invW0)*invDx20;
443 this->Dz=(z2-z0)*invDx20;
444 this->InvWStep=this->DinvW*this->XStep;
445 this->ZStep=this->Dz*this->XStep;
446
447 while(this->Error<this->Dx2)
448 {
449 this->X+=this->IncX;
450 this->InvW+= this->DinvW;
451 i=0;
452 while(i<VTK_VALUES_SIZE)
453 {
454 this->PValues[i]+=this->Dpv[i];
455 ++i;
456 }
457 this->Zview+=this->Dz;
458
459 this->Error+=this->Dy2;
460 }
461 this->Error-=this->Dx2;
462 this->X-=this->IncX;
463 this->InvW-= this->DinvW;
464 i=0;
465 while(i<VTK_VALUES_SIZE)
466 {
467 this->PValues[i]-=this->Dpv[i];
468 ++i;
469 }
470 this->Zview-=this->Dz;
471 }
472 #endif
473 #endif // EDGE_EQUATION
474 }
475 else
476 {
477 if(dx20==dy20)
478 {
479 this->Case=VTK_CASE_DIAGONAL;
480
481 double invDy20=1.0/dy20;
482 i=0;
483 while(i<VTK_VALUES_SIZE)
484 {
485 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
486 ++i;
487 }
488 this->DinvW=(invW2-invW0)*invDy20;
489 this->Dz=(z2-z0)*invDy20;
490 }
491 else
492 {
493 #ifdef EDGE_EQUATION
494 if(onRight)
495 {
496 this->Case=VTK_CASE_VERTICAL_IN_TO_OUT;
497 }
498 else
499 {
500 this->Case=VTK_CASE_VERTICAL_OUT_TO_IN;
501 }
502 this->Error=0;
503 this->SDy=dy20;
504 this->Dx=dx20;
505
506 double invDy20=1.0/dy20;
507 i=0;
508 while(i<VTK_VALUES_SIZE)
509 {
510 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
511 ++i;
512 }
513 this->DinvW=(invW2-invW0)*invDy20;
514 this->Dz=(z2-z0)*invDy20;
515 #else
516 this->Case=VTK_CASE_MOSTLY_VERTICAL;
517 this->Dx2=dx20<<1; // *2
518 this->Dy2=dy20<<1; // *2
519 this->Error=dy20;
520
521 double invDy20=1.0/dy20;
522 i=0;
523 while(i<VTK_VALUES_SIZE)
524 {
525 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
526 ++i;
527 }
528 this->DinvW=(invW2-invW0)*invDy20;
529 this->Dz=(z2-z0)*invDy20;
530 #endif
531 }
532 }
533 }
534 else
535 {
536 this->IncX=-1;
537 if(-dx20>dy20)
538 {
539 // Mostly horizontal
540 #ifdef HORI_EDGE_EQUATION
541 if(onRight)
542 {
543 this->Case=VTK_CASE_HORIZONTAL_OUT_TO_IN;
544 }
545 else
546 {
547 this->Case=VTK_CASE_HORIZONTAL_IN_TO_OUT;
548 }
549 this->Error=0;
550 this->SDy=-dy20;
551 this->XStep=dx20/dy20; // integral division
552 this->Dx=dx20+this->XStep*this->SDy;
553
554 double invDy20=1.0/dy20;
555 i=0;
556 while(i<VTK_VALUES_SIZE)
557 {
558 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
559 ++i;
560 }
561 this->DinvW=(invW2-invW0)*invDy20;
562 this->Dz=(z2-z0)*invDy20;
563 #else
564 #ifdef MOST_SIGNIFICANT
565 this->Case=VTK_CASE_HORIZONTAL_MS;
566 this->XStep=dx20/dy20; // integral division
567 this->Dy=dy20;
568 this->Dy2=dy20<<1; // *2
569 this->Error=0;
570 this->ErrorStep=(dx20+this->XStep*dy20)<<1; // 2*r, dx=q*dy+r, r<dy
571 double invDx20=-1.0/dx20;
572 i=0;
573 while(i<VTK_VALUES_SIZE)
574 {
575 this->Dpv[i]=(pv2[i]-pv0[i])*invDx20;
576 this->PValuesStep[i]=-this->Dpv[i]*this->XStep;
577 ++i;
578 }
579 this->DinvW=(invW2-invW0)*invDx20;
580 this->Dz=(z2-z0)*invDx20;
581 this->InvWStep=-this->DinvW*this->XStep;
582 this->ZStep=-this->Dz*this->XStep;
583
584
585 #else
586 if(onRight)
587 {
588 this->Case=VTK_CASE_HORIZONTAL_BEGIN;
589 this->First=1;
590 this->Dy2=dy20<<1; // *2
591 this->Dx2=(-dx20)<<1; // *2
592 this->Error=-dx20;
593 this->XStep=dx20/dy20;
594 this->ErrorStep=-this->XStep*this->Dy2;
595
596 double invDx20=-1.0/dx20;
597
598 i=0;
599 while(i<VTK_VALUES_SIZE)
600 {
601 this->Dpv[i]=(pv2[i]-pv0[i])*invDx20;
602 this->PValuesStep[i]=-this->Dpv[i]*this->XStep;
603 ++i;
604 }
605 this->DinvW=(invW2-invW0)*invDx20;
606 this->Dz=(z2-z0)*invDx20;
607 this->InvWStep=-this->DinvW*this->XStep;
608 this->ZStep=-this->Dz*this->XStep;
609 }
610 else
611 {
612 this->Case=VTK_CASE_HORIZONTAL_END;
613
614 this->InvW2=invW2;
615 i=0;
616 while(i<VTK_VALUES_SIZE)
617 {
618 this->PValues2[i]=pv2[i];
619 ++i;
620 }
621 this->Zview2=z2;
622
623 this->Dy2=dy20<<1; // *2
624 this->Dx2=(-dx20)<<1; // *2
625 this->Error=-dx20;
626 this->XStep=dx20/dy20;
627 this->ErrorStep=-this->XStep*this->Dy2;
628
629 double invDx20=-1.0/dx20;
630
631 i=0;
632 while(i<VTK_VALUES_SIZE)
633 {
634 this->Dpv[i]=(pv2[i]-pv0[i])*invDx20;
635 this->PValuesStep[i]=-this->Dpv[i]*this->XStep;
636 ++i;
637 }
638 this->DinvW=(invW2-invW0)*invDx20;
639 this->Dz=(z2-z0)*invDx20;
640 this->InvWStep=-this->DinvW*this->XStep;
641 this->ZStep=-this->Dz*this->XStep;
642
643 while(this->Error<this->Dx2)
644 {
645 this->X+=this->IncX;
646 this->InvW+= this->DinvW;
647 i=0;
648 while(i<VTK_VALUES_SIZE)
649 {
650 this->PValues[i]+=this->Dpv[i];
651 ++i;
652 }
653 this->Zview+=this->Dz;
654
655 this->Error+=this->Dy2;
656 }
657 this->Error-=this->Dx2;
658 this->X-=this->IncX;
659
660 this->InvW-= this->DinvW;
661 i=0;
662 while(i<VTK_VALUES_SIZE)
663 {
664 this->PValues[i]-=this->Dpv[i];
665 ++i;
666 }
667 this->Zview-=this->Dz;
668 }
669 #endif
670 #endif // EDGE_EQUATION
671 }
672 else
673 {
674 if(dx20==-dy20)
675 {
676 this->Case=VTK_CASE_DIAGONAL;
677
678 double invDy20=1.0/dy20;
679 i=0;
680 while(i<VTK_VALUES_SIZE)
681 {
682 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
683 ++i;
684 }
685 this->DinvW=(invW2-invW0)*invDy20;
686 this->Dz=(z2-z0)*invDy20;
687 }
688 else
689 {
690 #ifdef EDGE_EQUATION
691 if(onRight)
692 {
693 this->Case=VTK_CASE_VERTICAL_OUT_TO_IN;
694 }
695 else
696 {
697 this->Case=VTK_CASE_VERTICAL_IN_TO_OUT;
698 }
699 this->Error=0;
700 this->SDy=-dy20;
701 this->Dx=dx20;
702
703 double invDy20=1.0/dy20;
704 i=0;
705 while(i<VTK_VALUES_SIZE)
706 {
707 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
708 ++i;
709 }
710 this->DinvW=(invW2-invW0)*invDy20;
711 this->Dz=(z2-z0)*invDy20;
712 #else
713 this->Case=VTK_CASE_MOSTLY_VERTICAL;
714 this->Dx2=(-dx20)<<1; // *2
715 this->Dy2=dy20<<1; // *2
716 this->Error=dy20;
717
718 double invDy20=1.0/dy20;
719 i=0;
720 while(i<VTK_VALUES_SIZE)
721 {
722 this->Dpv[i]=(pv2[i]-pv0[i])*invDy20;
723 ++i;
724 }
725 this->DinvW=(invW2-invW0)*invDy20;
726 this->Dz=(z2-z0)*invDy20;
727 #endif
728 }
729 }
730 }
731 }
732 }
733
734 // Check that the current abscissa is in the range given by the vertices.
ValidXRange()735 int ValidXRange()
736 {
737 if(this->X0<=this->X2)
738 {
739 return (this->X>=this->X0) && (this->X<=this->X2);
740 }
741 else
742 {
743 return (this->X>=this->X2) && (this->X<=this->X0);
744 }
745 }
GetX()746 int GetX() override
747 {
748 // assert("pre: valid_range" && ValidXRange() );
749 return this->X;
750 }
GetInvW()751 double GetInvW() override { return this->InvW; }
GetPValues()752 double *GetPValues() override { return this->PValues; }
GetZview()753 double GetZview() override { return this->Zview; }
754
NextLine(int y)755 void NextLine(int y) override
756 {
757 int i;
758 switch(this->Case)
759 {
760 case VTK_CASE_VERTICAL:
761 // nothing to do with X
762 this->InvW+=this->DinvW;
763 i=0;
764 while(i<VTK_VALUES_SIZE)
765 {
766 this->PValues[i]+=this->Dpv[i];
767 ++i;
768 }
769 this->Zview+=this->Dz;
770 break;
771 case VTK_CASE_DIAGONAL:
772 // X
773 this->X+=this->IncX;
774 this->InvW+=this->DinvW;
775 i=0;
776 while(i<VTK_VALUES_SIZE)
777 {
778 this->PValues[i]+=this->Dpv[i];
779 ++i;
780 }
781 this->Zview+=this->Dz;
782 break;
783 case VTK_CASE_MOSTLY_VERTICAL:
784 // X
785 this->Error+=this->Dx2;
786 if(this->Error>=this->Dy2)
787 {
788 this->Error-=this->Dy2;
789 this->X+=this->IncX;
790 }
791 this->InvW+=this->DinvW;
792 i=0;
793 while(i<VTK_VALUES_SIZE)
794 {
795 this->PValues[i]+=this->Dpv[i];
796 ++i;
797 }
798 this->Zview+=this->Dz;
799 break;
800 case VTK_CASE_VERTICAL_OUT_TO_IN:
801 this->Error-=this->Dx;
802 if(this->SDy>0)
803 {
804 #ifdef STRICTLY_INSIDE
805 if(this->Error<=0)
806 #else
807 if(this->Error<0) // we are no more on the right side
808 #endif
809 {
810 this->Error+=this->SDy;
811 #ifdef STRICTLY_INSIDE
812 assert("check: positive_equation" && this->Error>0);
813 #else
814 assert("check: positive_equation" && this->Error>=0);
815 #endif
816 this->X+=this->IncX;
817 }
818 }
819 else
820 {
821 #ifdef STRICTLY_INSIDE
822 if(this->Error>=0) // we are no more on the left side
823 #else
824 if(this->Error>0) // we are no more on the left side
825 #endif
826 {
827 this->Error+=this->SDy;
828 #ifdef STRICTLY_INSIDE
829 // assert("check: negative_equation" && this->Error>0);
830 #else
831 assert("check: negative_equation" && this->Error<=0);
832 #endif
833 this->X+=this->IncX;
834 }
835 }
836 // Interpolate the values on inc y
837 this->InvW+=this->DinvW;
838 i=0;
839 while(i<VTK_VALUES_SIZE)
840 {
841 this->PValues[i]+=this->Dpv[i];
842 ++i;
843 }
844 this->Zview+=this->Dz;
845 break;
846 case VTK_CASE_VERTICAL_IN_TO_OUT:
847 this->Error+=this->SDy-this->Dx;
848 if(this->SDy<0)
849 {
850 #ifdef STRICTLY_INSIDE
851 if(this->Error<=0) // out: too far on left
852 #else
853 if(this->Error<0) // out: too far on left
854 #endif
855 {
856 this->Error-=this->SDy;
857 #ifdef STRICTLY_INSIDE
858 assert("check: positive_equation" && this->Error>0);
859 #else
860 assert("check: positive_equation" && this->Error>=0);
861 #endif
862 }
863 else
864 {
865 this->X+=this->IncX;
866 }
867 }
868 else
869 {
870 #ifdef STRICTLY_INSIDE
871 if(this->Error>=0) // out: too far on right
872 #else
873 if(this->Error>0) // out: too far on right
874 #endif
875 {
876 this->Error-=this->SDy;
877 #ifdef STRICTLY_INSIDE
878 assert("check: negative_equation" && this->Error<0);
879 #else
880 assert("check: negative_equation" && this->Error<=0);
881 #endif
882 }
883 else
884 {
885 this->X+=this->IncX;
886 }
887 }
888 // Interpolate the values on inc y
889 this->InvW+=this->DinvW;
890 i=0;
891 while(i<VTK_VALUES_SIZE)
892 {
893 this->PValues[i]+=this->Dpv[i];
894 ++i;
895 }
896 this->Zview+=this->Dz;
897 break;
898
899 case VTK_CASE_HORIZONTAL_OUT_TO_IN:
900 this->Error-=this->Dx;
901 this->X+=this->XStep;
902 if(this->SDy>0)
903 {
904 #ifdef STRICTLY_INSIDE
905 if(this->Error<=0) // we are no more on the right side
906 #else
907 if(this->Error<0) // we are no more on the right side
908 #endif
909 {
910 this->Error+=this->SDy;
911 #ifdef STRICTLY_INSIDE
912 assert("check: positive_equation" && this->Error>0);
913 #else
914 assert("check: positive_equation" && this->Error>=0);
915 #endif
916 this->X+=this->IncX;
917 }
918 }
919 else
920 {
921 #ifdef STRICTLY_INSIDE
922 if(this->Error>=0) // we are no more on the left side
923 #else
924 if(this->Error>0) // we are no more on the left side
925 #endif
926 {
927 this->Error+=this->SDy;
928 #ifdef STRICTLY_INSIDE
929 assert("check: negative_equation" && this->Error<0);
930 #else
931 assert("check: negative_equation" && this->Error<=0);
932 #endif
933 this->X+=this->IncX;
934 }
935 }
936 // Interpolate the values on inc y
937 this->InvW+=this->DinvW;
938 i=0;
939 while(i<VTK_VALUES_SIZE)
940 {
941 this->PValues[i]+=this->Dpv[i];
942 ++i;
943 }
944 this->Zview+=this->Dz;
945 break;
946
947 case VTK_CASE_HORIZONTAL_IN_TO_OUT:
948 this->Error+=this->SDy-this->Dx;
949 this->X+=this->XStep;
950 if(this->SDy<0)
951 {
952 #ifdef STRICTLY_INSIDE
953 if(this->Error<=0) // out: too far on left
954 #else
955 if(this->Error<0) // out: too far on left
956 #endif
957 {
958 this->Error-=this->SDy;
959 #ifdef STRICTLY_INSIDE
960 // assert("check: positive_equation" && this->Error>0);
961 #else
962 assert("check: positive_equation" && this->Error>=0);
963 #endif
964 }
965 else
966 {
967 this->X+=this->IncX;
968 }
969 }
970 else
971 {
972 #ifdef STRICTLY_INSIDE
973 if(this->Error>=0) // out: too far on right
974 #else
975 if(this->Error>0) // out: too far on right
976 #endif
977 {
978 this->Error-=this->SDy;
979 #ifdef STRICTLY_INSIDE
980 // assert("check: negative_equation" && this->Error<0);
981 #else
982 assert("check: negative_equation" && this->Error<=0);
983 #endif
984 }
985 else
986 {
987 this->X+=this->IncX;
988 }
989 }
990 // Interpolate the values on inc y
991 this->InvW+=this->DinvW;
992 i=0;
993 while(i<VTK_VALUES_SIZE)
994 {
995 this->PValues[i]+=this->Dpv[i];
996 ++i;
997 }
998 this->Zview+=this->Dz;
999 break;
1000
1001 case VTK_CASE_HORIZONTAL_BEGIN:
1002 if(this->First)
1003 {
1004 this->First=0;
1005 }
1006 else
1007 {
1008 this->X+=this->XStep;
1009
1010 this->InvW+=this->InvWStep;
1011 i=0;
1012 while(i<VTK_VALUES_SIZE)
1013 {
1014 this->PValues[i]+=this->PValuesStep[i];
1015 ++i;
1016 }
1017 this->Zview+=this->ZStep;
1018 this->Error+=this->ErrorStep;
1019 }
1020 while(this->Error<this->Dx2)
1021 {
1022 this->X+=this->IncX;
1023 this->InvW+=this->DinvW;
1024 i=0;
1025 while(i<VTK_VALUES_SIZE)
1026 {
1027 this->PValues[i]+=this->Dpv[i];
1028 ++i;
1029 }
1030 this->Zview+=this->Dz;
1031
1032 this->Error+=this->Dy2;
1033 }
1034 this->Error-=this->Dx2;
1035 break;
1036 case VTK_CASE_HORIZONTAL_END:
1037 if(y==this->V2->GetScreenY())
1038 {
1039 this->X=this->V2->GetScreenX();
1040 i=0;
1041 while(i<VTK_VALUES_SIZE)
1042 {
1043 this->PValues[i]=this->PValues2[i];
1044 ++i;
1045 }
1046 this->Zview=this->Zview2;
1047 this->InvW=this->InvW2;
1048 }
1049 else
1050 {
1051 this->X+=this->XStep;
1052
1053 this->InvW+=this->InvWStep;
1054 i=0;
1055 while(i<VTK_VALUES_SIZE)
1056 {
1057 this->PValues[i]+=this->PValuesStep[i];
1058 ++i;
1059 }
1060 this->Zview+=this->ZStep;
1061
1062 this->Error+=this->ErrorStep;
1063
1064 while(this->Error<this->Dx2)
1065 {
1066 this->X+=this->IncX;
1067 this->InvW+=this->DinvW;
1068 i=0;
1069 while(i<VTK_VALUES_SIZE)
1070 {
1071 this->PValues[i]+=this->Dpv[i];
1072 ++i;
1073 }
1074 this->Zview+=this->Dz;
1075
1076 this->Error+=this->Dy2;
1077 }
1078 this->Error-=this->Dx2;
1079 }
1080 break;
1081 case VTK_CASE_HORIZONTAL_MS:
1082 this->Error+=this->ErrorStep;
1083 if(this->Error>=this->Dy)
1084 {
1085 this->Error-=this->Dy2;
1086 this->X+=this->XStep+this->IncX;
1087 this->InvW+=this->InvWStep+this->DinvW;
1088 i=0;
1089 while(i<VTK_VALUES_SIZE)
1090 {
1091 this->PValues[i]+=this->PValuesStep[i]+this->Dpv[i];
1092 ++i;
1093 }
1094 this->Zview+=this->ZStep+this->Dz;
1095 }
1096 else
1097 {
1098 this->X+=this->XStep;
1099 this->InvW+=this->InvWStep;
1100 i=0;
1101 while(i<VTK_VALUES_SIZE)
1102 {
1103 this->PValues[i]+=this->PValuesStep[i];
1104 ++i;
1105 }
1106 this->Zview+=this->ZStep;
1107 }
1108 break;
1109 default:
1110 vtkGenericWarningMacro(<< "Undefined edge case");
1111 }
1112 }
1113
SkipLines(int deltaY,int y)1114 void SkipLines(int deltaY,
1115 int y) override
1116 {
1117 if(deltaY==1)
1118 {
1119 this->NextLine(0);
1120 return;
1121 }
1122
1123 int firstDeltaY;
1124 int i;
1125 switch(this->Case)
1126 {
1127 case VTK_CASE_VERTICAL:
1128 // nothing to do with X
1129 this->InvW+=this->DinvW*deltaY;
1130 i=0;
1131 while(i<VTK_VALUES_SIZE)
1132 {
1133 this->PValues[i]+=this->Dpv[i]*deltaY;
1134 ++i;
1135 }
1136 this->Zview+=this->Dz*deltaY;
1137 break;
1138 case VTK_CASE_DIAGONAL:
1139 // X
1140 this->X+=this->IncX*deltaY;
1141 this->InvW+=this->DinvW*deltaY;
1142 i=0;
1143 while(i<VTK_VALUES_SIZE)
1144 {
1145 this->PValues[i]+=this->Dpv[i]*deltaY;
1146 ++i;
1147 }
1148 this->Zview+=this->Dz*deltaY;
1149 break;
1150 case VTK_CASE_MOSTLY_VERTICAL:
1151 // X
1152 this->Error+=this->Dx2*deltaY;
1153 while(this->Error>=this->Dy2)
1154 {
1155 this->Error-=this->Dy2;
1156 this->X+=this->IncX;
1157 }
1158 this->InvW+=this->DinvW*deltaY;
1159 i=0;
1160 while(i<VTK_VALUES_SIZE)
1161 {
1162 this->PValues[i]+=this->Dpv[i]*deltaY;
1163 ++i;
1164 }
1165 this->Zview+=this->Dz*deltaY;
1166 break;
1167 case VTK_CASE_VERTICAL_OUT_TO_IN:
1168 this->Error-=this->Dx*deltaY;
1169 if(this->SDy>0)
1170 {
1171 #ifdef STRICTLY_INSIDE
1172 while(this->Error<=0) // we are no more on the right side
1173 #else
1174 while(this->Error<0) // we are no more on the right side
1175 #endif
1176 {
1177 this->Error+=this->SDy;
1178 this->X+=this->IncX;
1179 }
1180 }
1181 else
1182 {
1183 #ifdef STRICTLY_INSIDE
1184 while(this->Error>=0) // we are no more on the left side
1185 #else
1186 while(this->Error>0) // we are no more on the left side
1187 #endif
1188 {
1189 this->Error+=this->SDy;
1190 this->X+=this->IncX;
1191 }
1192 }
1193 // Interpolate the values on inc y
1194 this->InvW+=this->DinvW*deltaY;
1195 i=0;
1196 while(i<VTK_VALUES_SIZE)
1197 {
1198 this->PValues[i]+=this->Dpv[i]*deltaY;
1199 ++i;
1200 }
1201 this->Zview+=this->Dz*deltaY;
1202 break;
1203 case VTK_CASE_VERTICAL_IN_TO_OUT:
1204 this->Error+=(this->SDy-this->Dx)*deltaY;
1205 this->X+=this->IncX*deltaY;
1206 if(this->SDy<0)
1207 {
1208 #ifdef STRICTLY_INSIDE
1209 while(this->Error<=0) // out: too far on left
1210 #else
1211 while(this->Error<0) // out: too far on left
1212 #endif
1213 {
1214 this->Error-=this->SDy;
1215 this->X-=this->IncX;
1216 }
1217 }
1218 else
1219 {
1220 #ifdef STRICTLY_INSIDE
1221 while(this->Error>=0) // out: too far on right
1222 #else
1223 while(this->Error>0) // out: too far on right
1224 #endif
1225 {
1226 this->Error-=this->SDy;
1227 this->X-=this->IncX;
1228 }
1229 }
1230 // Interpolate the values on inc y
1231 this->InvW+=this->DinvW*deltaY;
1232 i=0;
1233 while(i<VTK_VALUES_SIZE)
1234 {
1235 this->PValues[i]+=this->Dpv[i]*deltaY;
1236 ++i;
1237 }
1238 this->Zview+=this->Dz*deltaY;
1239 break;
1240
1241 case VTK_CASE_HORIZONTAL_OUT_TO_IN:
1242 this->Error-=this->Dx*deltaY;
1243 this->X+=this->XStep*deltaY;
1244 if(this->SDy>0)
1245 {
1246 #ifdef STRICTLY_INSIDE
1247 while(this->Error<=0) // we are no more on the right side
1248 #else
1249 while(this->Error<0) // we are no more on the right side
1250 #endif
1251 {
1252 this->Error+=this->SDy;
1253 this->X+=this->IncX;
1254 }
1255 }
1256 else
1257 {
1258 #ifdef STRICTLY_INSIDE
1259 while(this->Error>=0) // we are no more on the left side
1260 #else
1261 while(this->Error>0) // we are no more on the left side
1262 #endif
1263 {
1264 this->Error+=this->SDy;
1265 this->X+=this->IncX;
1266 }
1267 }
1268 // Interpolate the values on inc y
1269 this->InvW+=this->DinvW*deltaY;
1270 i=0;
1271 while(i<VTK_VALUES_SIZE)
1272 {
1273 this->PValues[i]+=this->Dpv[i]*deltaY;
1274 ++i;
1275 }
1276 this->Zview+=this->Dz*deltaY;
1277 break;
1278 case VTK_CASE_HORIZONTAL_IN_TO_OUT:
1279 this->Error+=(this->SDy-this->Dx)*deltaY;
1280 this->X+=(this->XStep+this->IncX)*deltaY;
1281 // this->X+=this->IncX*deltaY;
1282 if(this->SDy<0)
1283 {
1284 #ifdef STRICTLY_INSIDE
1285 while(this->Error<=0) // out: too far on left
1286 #else
1287 while(this->Error<0) // out: too far on left
1288 #endif
1289 {
1290 this->Error-=this->SDy;
1291 this->X-=this->IncX;
1292 }
1293 }
1294 else
1295 {
1296 #ifdef STRICTLY_INSIDE
1297 while(this->Error>=0) // out: too far on right
1298 #else
1299 while(this->Error>0) // out: too far on right
1300 #endif
1301 {
1302 this->Error-=this->SDy;
1303 this->X-=this->IncX;
1304 }
1305 }
1306 // Interpolate the values on inc y
1307 this->InvW+=this->DinvW*deltaY;
1308 i=0;
1309 while(i<VTK_VALUES_SIZE)
1310 {
1311 this->PValues[i]+=this->Dpv[i]*deltaY;
1312 ++i;
1313 }
1314 this->Zview+=this->Dz*deltaY;
1315 break;
1316
1317 case VTK_CASE_HORIZONTAL_BEGIN:
1318
1319 if(this->First)
1320 {
1321 this->First=0;
1322 firstDeltaY=deltaY-1;
1323 }
1324 else
1325 {
1326 firstDeltaY=deltaY;
1327 }
1328
1329 this->X+=this->XStep*firstDeltaY;
1330
1331 this->InvW+=this->InvWStep*firstDeltaY;
1332 i=0;
1333 while(i<VTK_VALUES_SIZE)
1334 {
1335 this->PValues[i]+=this->PValuesStep[i]*firstDeltaY;
1336 ++i;
1337 }
1338 this->Zview+=this->ZStep*firstDeltaY;
1339 this->Error+=this->ErrorStep*firstDeltaY;
1340
1341 while(this->Error<this->Dx2)
1342 {
1343 this->X+=this->IncX;
1344 this->InvW+=this->DinvW;
1345 i=0;
1346 while(i<VTK_VALUES_SIZE)
1347 {
1348 this->PValues[i]+=this->Dpv[i];
1349 ++i;
1350 }
1351 this->Zview+=this->Dz;
1352
1353 this->Error+=this->Dy2;
1354 }
1355 this->Error-=this->Dx2;
1356 break;
1357 case VTK_CASE_HORIZONTAL_END:
1358 if(y==this->V2->GetScreenY())
1359 {
1360 this->X=this->V2->GetScreenX();
1361 i=0;
1362 while(i<VTK_VALUES_SIZE)
1363 {
1364 this->PValues[i]=this->PValues2[i];
1365 ++i;
1366 }
1367 this->Zview=this->Zview2;
1368 this->InvW=this->InvW2;
1369 }
1370 else
1371 {
1372 this->X+=this->XStep*deltaY;
1373
1374 this->InvW+=this->InvWStep*deltaY;
1375 i=0;
1376 while(i<VTK_VALUES_SIZE)
1377 {
1378 this->PValues[i]+=this->PValuesStep[i]*deltaY;
1379 ++i;
1380 }
1381 this->Zview+=this->ZStep*deltaY;
1382
1383 this->Error+=this->ErrorStep*deltaY;
1384
1385 while(this->Error<this->Dx2)
1386 {
1387 this->X+=this->IncX;
1388 this->InvW+=this->DinvW;
1389 i=0;
1390 while(i<VTK_VALUES_SIZE)
1391 {
1392 this->PValues[i]+=this->Dpv[i];
1393 ++i;
1394 }
1395 this->Zview+=this->Dz;
1396
1397 this->Error+=this->Dy2;
1398 }
1399 this->Error-=this->Dx2;
1400 }
1401 break;
1402 case VTK_CASE_HORIZONTAL_MS:
1403 this->Error+=this->ErrorStep*deltaY;
1404 this->X+=this->XStep*deltaY;
1405 this->InvW+=this->InvWStep*deltaY;
1406 i=0;
1407 while(i<VTK_VALUES_SIZE)
1408 {
1409 this->PValues[i]+=this->PValuesStep[i]*deltaY;
1410 ++i;
1411 }
1412 this->Zview+=this->ZStep*deltaY;
1413
1414 while(this->Error>=this->Dy)
1415 {
1416 this->Error-=this->Dy2;
1417 this->X+=this->IncX;
1418 this->InvW+=this->DinvW;
1419 i=0;
1420 while(i<VTK_VALUES_SIZE)
1421 {
1422 this->PValues[i]+=this->Dpv[i];
1423 ++i;
1424 }
1425 this->Zview+=this->Dz;
1426 }
1427 break;
1428 }
1429 }
1430
1431 protected:
1432 int Case;
1433 int Error; // error to the mid-point
1434 int Dx2; // 2*dx
1435 int Dy2; // 2*dy
1436 int First; // use only with VTK_CASE_HORIZONTAL_BEGIN case
1437 int XStep; // dx/dy
1438 int ErrorStep; // XStep*Dy2
1439
1440 vtkVertexEntry *V2;
1441
1442 int IncX; // -1 or 1
1443
1444 int X; // Current abscissa
1445
1446 int X0; // for debugging
1447 int X2; // for debugging
1448
1449 // Slope of 1/w
1450 double DinvW;
1451 // Current 1/W
1452 double InvW;
1453 // DinvW*XStep
1454 double InvWStep;
1455 // 1/W at the end vertex
1456 double InvW2;
1457
1458 // Slope of the z coordinate in view space
1459 double Dz;
1460 // current z in view space
1461 double Zview;
1462 // Dz*XStep
1463 double ZStep;
1464 // z coordinate in view space at the end vertex
1465 double Zview2;
1466
1467 // Slope of each projected values on the edge
1468 double Dpv[VTK_VALUES_SIZE];
1469
1470
1471 // Current projected values
1472 double PValues[VTK_VALUES_SIZE];
1473 // Dpv*XStep
1474 double PValuesStep[VTK_VALUES_SIZE];
1475 // Values at the end vertex.
1476 double PValues2[VTK_VALUES_SIZE];
1477
1478 int Dy; // VTK_HORIZONTAL_MS
1479 int SDy; // VTK_VERTICAL_LEFT/RIGHT
1480 int Dx; // VTK_VERTICAL_LEFT/RIGHT
1481 };
1482
1483 //-----------------------------------------------------------------------------
1484 // During rasterization of a triangle, there is always one side with two
1485 // edges and the other side with a single edge.
1486 // This class manages the side with the two edges called top and bottom edges.
1487 class vtkDoubleScreenEdge
1488 :public vtkScreenEdge
1489 {
1490 public:
Init(vtkVertexEntry * v0,vtkVertexEntry * v1,vtkVertexEntry * v2,int dx10,int dy10,int onRight)1491 void Init(vtkVertexEntry *v0,
1492 vtkVertexEntry *v1,
1493 vtkVertexEntry *v2,
1494 int dx10,
1495 int dy10,
1496 int onRight)
1497 {
1498 this->Current=nullptr;
1499 if(dy10!=0)
1500 {
1501 this->Top.Init(v0,v1,dx10,dy10,onRight);
1502 this->Current=&this->Top;
1503 }
1504
1505 int dx21=v2->GetScreenX()-v1->GetScreenX();
1506 int dy21=v2->GetScreenY()-v1->GetScreenY();
1507
1508 if(dy21!=0)
1509 {
1510 this->Bottom.Init(v1,v2,dx21,dy21,onRight);
1511 if(this->Current==nullptr)
1512 {
1513 this->Current=&this->Bottom;
1514 }
1515 }
1516 }
1517
GetX()1518 int GetX() override { return this->Current->GetX(); }
GetInvW()1519 double GetInvW() override { return this->Current->GetInvW(); }
GetZview()1520 double GetZview() override { return this->Current->GetZview(); }
GetPValues()1521 double *GetPValues() override { return this->Current->GetPValues(); }
1522
OnBottom(int skipped,int y)1523 void OnBottom(int skipped, int y) override
1524 {
1525 this->Current=&this->Bottom;
1526 this->Current->OnBottom(skipped,y);
1527 }
1528
NextLine(int y)1529 void NextLine(int y) override
1530 {
1531 this->Current->NextLine(y);
1532 }
SkipLines(int deltaY,int y)1533 void SkipLines(int deltaY,
1534 int y) override
1535 {
1536 this->Current->SkipLines(deltaY,y);
1537 }
1538
1539 protected:
1540 vtkSimpleScreenEdge Top;
1541 vtkSimpleScreenEdge Bottom;
1542 vtkScreenEdge *Current;
1543 };
1544
1545 //-----------------------------------------------------------------------------
1546 // Horizontal span between two points of two edges.
1547 // Used during scan-conversion.
1548 // It interpolates the values along the span.
1549
1550 class vtkSpan
1551 {
1552 public:
1553 // Initialize the span from the left abcissa x0 and the right absissa x1 and
1554 // from 1/W, the projected values and the z coordinate in view space at
1555 // those points. Set the current state to the left point.
Init(int x0,double invW0,double pValues0[VTK_VALUES_SIZE],double zView0,int x1,double invW1,double pValues1[VTK_VALUES_SIZE],double zView1)1556 void Init(int x0,
1557 double invW0,
1558 double pValues0[VTK_VALUES_SIZE], // projected values
1559 double zView0,
1560 int x1,
1561 double invW1,
1562 double pValues1[VTK_VALUES_SIZE], // projected values
1563 double zView1)
1564 {
1565 // assert("pre: dx>=0" && x1-x0>=0);
1566 // x0=x1: the span is just a point
1567
1568 int i;
1569 if(x0!=x1)
1570 {
1571
1572 double invDx10=1.0/(x1-x0);
1573 i=0;
1574 while(i<VTK_VALUES_SIZE)
1575 {
1576 this->Dpv[i]=(pValues1[i]-pValues0[i])*invDx10;
1577 ++i;
1578 }
1579 this->DinvW=(invW1-invW0)*invDx10;
1580 this->Dz=(zView1-zView0)*invDx10;
1581 }
1582 else
1583 {
1584 i=0;
1585 while(i<VTK_VALUES_SIZE)
1586 {
1587 this->Dpv[i]=0;
1588 ++i;
1589 }
1590 this->DinvW=0;
1591 this->Dz=0;
1592 }
1593
1594 this->Zview=zView0;
1595 this->InvW=invW0;
1596 i=0;
1597 double w=1/this->InvW;
1598 while(i<VTK_VALUES_SIZE)
1599 {
1600 this->PValues[i]=pValues0[i];
1601 this->Values[i]=this->PValues[i]*w;
1602 ++i;
1603 }
1604 this->X=x0;
1605 this->X1=x1;
1606 }
1607
1608 // Is the current state after the right point?
IsAtEnd()1609 vtkTypeBool IsAtEnd()
1610 {
1611 return this->X>this->X1;
1612 }
1613
1614 // Current abscissa.
GetX()1615 int GetX() { return this->X; }
1616 // Current values.
GetValues()1617 double *GetValues() { return this->Values; }
1618 // Current z coordinate in view space.
GetZview()1619 double GetZview() { return this->Zview; }
1620
1621 // Go the next abscissa from left to right.
NextPixel()1622 void NextPixel()
1623 {
1624 ++this->X;
1625
1626 this->InvW+=this->DinvW;
1627 int i=0;
1628 double w=1/this->InvW;
1629 while(i<VTK_VALUES_SIZE)
1630 {
1631 this->PValues[i]+=this->Dpv[i];
1632 this->Values[i]=this->PValues[i]*w;
1633 ++i;
1634 }
1635 this->Zview+=this->Dz;
1636 }
1637
1638 protected:
1639 int X1; // abscissa at the right point.
1640
1641 int X; // current abscissa
1642
1643 // Slope of 1/w
1644 double DinvW;
1645 // current 1/W
1646 double InvW;
1647
1648 // Slope of the z coordinate in view space
1649 double Dz;
1650 // current z coordinate in view space
1651 double Zview;
1652
1653 // Slope of each projected values on the span
1654 double Dpv[VTK_VALUES_SIZE];
1655 // Current projected values
1656 double PValues[VTK_VALUES_SIZE];
1657
1658 // Current values: Values=PValues/InvW
1659 double Values[VTK_VALUES_SIZE];
1660 };
1661
1662
1663 // Pimpl (i.e. private implementation) idiom
1664
1665 //typedef std::list<vtkPixelListEntry *> vtkPixelList;
1666
1667 class vtkPixelListEntryBlock
1668 {
1669 public:
vtkPixelListEntryBlock(vtkIdType size)1670 vtkPixelListEntryBlock(vtkIdType size)
1671 {
1672 assert("pre: positive_size" && size>0);
1673 this->Size=size;
1674 this->Next=nullptr;
1675 this->Array=new vtkPixelListEntry[size];
1676 this->Last=this->Array+size-1;
1677 // link each entry to the next one
1678 vtkPixelListEntry *p;
1679 vtkPixelListEntry *q;
1680 p=this->Array;
1681 q=p+1;
1682 vtkIdType i=1;
1683 while(i<size)
1684 {
1685 p->SetNext(q);
1686 ++i;
1687 p=q;
1688 ++q;
1689 }
1690 p->SetNext(nullptr);
1691 }
~vtkPixelListEntryBlock()1692 ~vtkPixelListEntryBlock()
1693 {
1694 delete[] this->Array;
1695 }
GetSize()1696 vtkIdType GetSize() { return this->Size; }
GetNext()1697 vtkPixelListEntryBlock *GetNext() { return this->Next; }
GetFirst()1698 vtkPixelListEntry *GetFirst() { return this->Array; }
GetLast()1699 vtkPixelListEntry *GetLast() { return this->Last; }
SetNext(vtkPixelListEntryBlock * other)1700 void SetNext(vtkPixelListEntryBlock *other) { this->Next=other; }
1701
1702 protected:
1703 vtkIdType Size;
1704 vtkPixelListEntryBlock *Next;
1705 vtkPixelListEntry *Array;
1706 vtkPixelListEntry *Last;
1707 };
1708
1709 const vtkIdType VTK_PIXEL_BLOCK_SIZE=64;
1710
1711 class vtkPixelListEntryMemory
1712 {
1713 public:
vtkPixelListEntryMemory()1714 vtkPixelListEntryMemory()
1715 {
1716 this->FirstBlock=new vtkPixelListEntryBlock(VTK_PIXEL_BLOCK_SIZE);
1717 this->FirstFreeElement=this->FirstBlock->GetFirst();
1718 this->Size=VTK_PIXEL_BLOCK_SIZE;
1719 }
~vtkPixelListEntryMemory()1720 ~vtkPixelListEntryMemory()
1721 {
1722 vtkPixelListEntryBlock *p=this->FirstBlock;
1723 vtkPixelListEntryBlock *q;
1724 while(p!=nullptr)
1725 {
1726 q=p->GetNext();
1727 delete p;
1728 p=q;
1729 }
1730 }
AllocateEntry()1731 vtkPixelListEntry *AllocateEntry()
1732 {
1733 if(this->FirstFreeElement==nullptr)
1734 {
1735 this->AllocateBlock(this->Size<<1);
1736 // this->AllocateBlock(BLOCK_SIZE);
1737 }
1738 vtkPixelListEntry *result=this->FirstFreeElement;
1739 this->FirstFreeElement=result->GetNext();
1740 assert("post: result_exists" && result!=nullptr);
1741 return result;
1742 }
FreeEntry(vtkPixelListEntry * e)1743 void FreeEntry(vtkPixelListEntry *e)
1744 {
1745 assert("pre: e_exists" && e!=nullptr);
1746
1747 // the following line works even if this->FirstFreeElement==0
1748 e->SetNext(this->FirstFreeElement);
1749 this->FirstFreeElement=e;
1750 }
FreeSubList(vtkPixelListEntry * first,vtkPixelListEntry * last)1751 void FreeSubList(vtkPixelListEntry *first,
1752 vtkPixelListEntry *last)
1753 {
1754 assert("pre: first_exists" && first!=nullptr);
1755 assert("pre: last_exists" && last!=nullptr);
1756 // pre: first==last can be true
1757 // the following line works even if this->FirstFreeElement==0
1758 last->SetNext(this->FirstFreeElement);
1759 this->FirstFreeElement=first;
1760 }
1761 protected:
1762
AllocateBlock(vtkIdType size)1763 void AllocateBlock(vtkIdType size)
1764 {
1765 assert("pre: positive_size" && size>0);
1766 vtkPixelListEntryBlock *b=new vtkPixelListEntryBlock(size);
1767 this->Size+=size;
1768 // Update the block linked list: starts with the new block
1769 b->SetNext(this->FirstBlock);
1770 this->FirstBlock=b;
1771
1772 // Update the free element linked list.
1773 // It works even if this->FirstFreeElement==0
1774 b->GetLast()->SetNext(this->FirstFreeElement);
1775 this->FirstFreeElement=b->GetFirst();
1776 }
1777
1778 vtkPixelListEntryBlock *FirstBlock;
1779 vtkPixelListEntry *FirstFreeElement;
1780 vtkIdType Size; // overall size, in number of elements, not in bytes
1781 };
1782
1783
1784 class vtkPixelList
1785 {
1786 public:
vtkPixelList()1787 vtkPixelList()
1788 {
1789 this->Size=0;
1790 }
GetFirst()1791 vtkPixelListEntry *GetFirst()
1792 {
1793 assert("pre: not_empty" && this->Size>0);
1794 return this->First;
1795 }
GetSize()1796 vtkIdType GetSize() { return this->Size; }
1797
AddAndSort(vtkPixelListEntry * p)1798 void AddAndSort(vtkPixelListEntry *p)
1799 {
1800 assert("pre: p_exists" && p!=nullptr);
1801 if(this->Size==0)
1802 {
1803 p->SetPrevious(nullptr);
1804 p->SetNext(nullptr);
1805 this->First=p;
1806 this->Last=p;
1807 }
1808 else
1809 {
1810 vtkPixelListEntry *it=this->Last;
1811 int sorted=0;
1812 double z=p->GetZview();
1813 while(!sorted && it!=nullptr)
1814 {
1815 // It is not uncommon for an external face and internal face to meet.
1816 // On the edge where this happens, an exit fragment and non-exit
1817 // fragment could be generated at the same point. In this case, it is
1818 // very important that the exit fragment be last in the list.
1819 // Otherwise, the ray exit may be improperly marked as between the two
1820 // overlapping fragments. (Note that if you start to see "speckling"
1821 // in the image from filled spaces, we may need to add adjust the
1822 // tolerance to this calculation.)
1823 const double tolerance = 1.0e-8;
1824 if (p->GetExitFace())
1825 {
1826 #ifdef BACK_TO_FRONT
1827 sorted=it->GetZview() >= z-tolerance;
1828 #else
1829 sorted=it->GetZview() <= z+tolerance;
1830 #endif
1831 }
1832 else
1833 {
1834 #ifdef BACK_TO_FRONT
1835 sorted=it->GetZview() > z+tolerance;
1836 #else
1837 sorted=it->GetZview() < z-tolerance;
1838 #endif
1839 }
1840 if(!sorted)
1841 {
1842 it=it->GetPrevious();
1843 }
1844 }
1845 if(it==nullptr) // first element
1846 {
1847 p->SetPrevious(nullptr);
1848 p->SetNext(this->First);
1849 // this->First==0 is handled by case size==0
1850 this->First->SetPrevious(p);
1851 this->First=p;
1852 }
1853 else
1854 {
1855 if(it->GetNext()==nullptr) // last element
1856 {
1857 it->SetNext(p);
1858 p->SetPrevious(it);
1859 p->SetNext(nullptr);
1860 this->Last=p;
1861 }
1862 else // general case
1863 {
1864 vtkPixelListEntry *q=it->GetNext();
1865 q->SetPrevious(p);
1866 p->SetNext(q);
1867 p->SetPrevious(it);
1868 it->SetNext(p);
1869 }
1870 }
1871 }
1872 ++this->Size;
1873 }
1874
1875 // the return pointer is used by the memory manager.
RemoveFirst(vtkPixelListEntryMemory * mm)1876 void RemoveFirst(vtkPixelListEntryMemory *mm)
1877 {
1878 assert("pre: not_empty" && this->Size>0);
1879 assert("pre: mm_exists" && mm!=nullptr);
1880
1881 vtkPixelListEntry *p=this->First;
1882 if(this->Size>1)
1883 {
1884 this->First=p->GetNext();
1885 this->First->SetPrevious(nullptr);
1886 }
1887 --this->Size;
1888 mm->FreeEntry(p);
1889 }
1890
1891 // the return pointer on the first element is used by the memory manager.
Clear(vtkPixelListEntryMemory * mm)1892 void Clear(vtkPixelListEntryMemory *mm)
1893 {
1894 assert("pre: mm_exists" && mm!=nullptr);
1895 if(this->Size>0)
1896 {
1897 // it works even if first==last
1898 mm->FreeSubList(this->First,this->Last);
1899 this->Size=0;
1900 }
1901 }
1902
1903 protected:
1904 vtkIdType Size;
1905 vtkPixelListEntry *First;
1906 vtkPixelListEntry *Last;
1907 };
1908
1909 //-----------------------------------------------------------------------------
1910 // Store the pixel lists for all the frame.
1911 class vtkPixelListFrame
1912 {
1913 public:
1914 typedef std::vector<vtkPixelList> VectorType;
1915
vtkPixelListFrame(int size)1916 vtkPixelListFrame(int size)
1917 :Vector(size)
1918 {
1919 }
1920
1921 // Return width*height
GetSize()1922 vtkIdType GetSize() { return static_cast<vtkIdType>(this->Vector.size()); }
1923
1924 // Return the size of the list at pixel `i'.
GetListSize(int i)1925 vtkIdType GetListSize(int i)
1926 {
1927 assert("pre: valid_i" && i>=0 && i<this->GetSize());
1928 return this->Vector[i].GetSize();
1929 }
1930
1931 // Add a value the pixel list of pixel `i' and sort it in the list.
AddAndSort(int i,vtkPixelListEntry * pixelEntry)1932 void AddAndSort(int i,
1933 vtkPixelListEntry *pixelEntry)
1934 {
1935 assert("pre: valid_i" && i>=0 && i<this->GetSize());
1936 assert("pre: pixelEntry_exists" && pixelEntry!=nullptr);
1937
1938 this->Vector[i].AddAndSort(pixelEntry);
1939 }
1940
1941 // Return the first entry for pixel `i'.
GetFront(int i)1942 vtkPixelListEntry *GetFront(int i)
1943 {
1944 assert("pre: valid_i" && i>=0 && i<this->GetSize());
1945 assert("pre: not_empty" && this->GetListSize(i)>0);
1946 return this->Vector[i].GetFirst();
1947 }
1948
1949 // Remove the first entry for pixel `i'.
PopFront(int i,vtkPixelListEntryMemory * mm)1950 void PopFront(int i,
1951 vtkPixelListEntryMemory *mm)
1952 {
1953 assert("pre: valid_i" && i>=0 && i<this->GetSize());
1954 assert("pre: not_empty" && this->GetListSize(i)>0);
1955 assert("pre: mm_exists" && mm!=nullptr);
1956 this->Vector[i].RemoveFirst(mm);
1957 }
1958
1959 // Return the begin iterator for pixel `i'.
GetFirst(int i)1960 vtkPixelListEntry *GetFirst(int i)
1961 {
1962 assert("pre: valid_i" && i>=0 && i<this->GetSize());
1963 return this->Vector[i].GetFirst();
1964 }
1965 #if 0
1966 // Return the end iterator for pixel `i'.
1967 std::list<vtkPixelListEntry *>::iterator GetEndIterator(int i)
1968 {
1969 assert("pre: valid_i" && i>=0 && i<this->GetSize());
1970 return this->Vector[i].end();
1971 }
1972 #endif
1973 // Clear the list of each pixel of the frame.
Clean(vtkPixelListEntryMemory * mm)1974 void Clean(vtkPixelListEntryMemory *mm)
1975 {
1976 assert("pre: mm_exists" && mm!=nullptr);
1977 vtkIdType i=0;
1978 vtkIdType c = static_cast<vtkIdType>(this->Vector.size());
1979 while(i<c)
1980 {
1981 vtkPixelList *l=&(Vector[i]);
1982 l->Clear(mm);
1983 ++i;
1984 }
1985 }
1986
1987 // Destructor.
~vtkPixelListFrame()1988 ~vtkPixelListFrame()
1989 {
1990 #if 0
1991 vtkIdType i=0;
1992 vtkIdType c=this->Vector.size();
1993 while(i<c)
1994 {
1995 vtkPixelList *l=&(Vector[i]);
1996 while(!l->empty())
1997 {
1998 delete l->front();
1999 l->pop_front();
2000 }
2001 ++i;
2002 }
2003 #endif
2004 }
2005
GetList(int i)2006 vtkPixelList *GetList(int i)
2007 {
2008 assert("pre: valid_i" && i>=0 && i<this->GetSize());
2009 return &(this->Vector[i]);
2010 }
2011
2012 protected:
2013 VectorType Vector;
2014
2015 // the STL specification claims that
2016 // size() on a std: :list is permitted to be O(n)!!!!
2017 // std::vector<vtkIdType> Sizes;
2018
2019 // std::list<vtkPixelListEntry *>::iterator It;
2020 // std::list<vtkPixelListEntry *>::iterator PreviousIt;
2021 // std::list<vtkPixelListEntry *>::iterator ItEnd;
2022 };
2023
2024 //-----------------------------------------------------------------------------
2025 // Store a triangle face. Ids are in increasing order. Orientation does not
2026 // matter for the algorithm.
2027 class vtkFace
2028 {
2029 public:
2030 enum {
2031 NOT_EXTERNAL,
2032 FRONT_FACE,
2033 BACK_FACE
2034 };
2035
2036 // Initialization from face ids in increasing order.
vtkFace(vtkIdType faceIds[3],int externalSide)2037 vtkFace(vtkIdType faceIds[3], int externalSide)
2038 {
2039 assert("pre: ordered ids" && faceIds[0]<faceIds[1]
2040 && faceIds[1]<faceIds[2]);
2041 this->FaceIds[0]=faceIds[0];
2042 this->FaceIds[1]=faceIds[1];
2043 this->FaceIds[2]=faceIds[2];
2044 this->Count=0;
2045 this->Rendered = 0;
2046 this->ExternalSide = externalSide;
2047 }
2048
2049 // Return the 3 face ids.
GetFaceIds()2050 inline vtkIdType *GetFaceIds() { return this->FaceIds; }
2051
2052 // Return whether this face is external.
GetExternalSide()2053 inline int GetExternalSide() { return this->ExternalSide; }
2054
2055 // Are `this' and faceIds equal?
IsEqual(vtkIdType faceIds[3])2056 int IsEqual(vtkIdType faceIds[3])
2057 {
2058 return (this->FaceIds[0]==faceIds[0])&&(this->FaceIds[1]==faceIds[1])
2059 &&(this->FaceIds[2]==faceIds[2]);
2060 }
2061
Ref()2062 void Ref() { ++this->Count; }
Unref()2063 void Unref()
2064 {
2065 --this->Count;
2066 if(this->Count==0)
2067 {
2068 delete this;
2069 }
2070 }
2071
GetRendered()2072 int GetRendered() { return this->Rendered; }
SetRendered(int value)2073 void SetRendered(int value) { this->Rendered=value; }
2074
GetScalar(int index)2075 double GetScalar(int index)
2076 {
2077 assert("pre: valid_index" && index>=0 && index<=1);
2078 return this->Scalar[index];
2079 }
2080
SetScalar(int index,double value)2081 void SetScalar(int index,
2082 double value)
2083 {
2084 assert("pre: valid_index" && index>=0 && index<=1);
2085 this->Scalar[index]=value;
2086 assert("post: is_set" && this->GetScalar(index)==value);
2087 }
2088
2089 protected:
2090 vtkIdType FaceIds[3];
2091 int Count;
2092 int Rendered;
2093 int ExternalSide;
2094
2095 double Scalar[2]; // 0: value for positive orientation,
2096 // 1: value for negative orientation.
2097
2098 private:
2099 vtkFace() = delete;
2100 vtkFace(const vtkFace &other) = delete;
2101 vtkFace &operator=(const vtkFace &other) = delete;
2102 };
2103
2104 //-----------------------------------------------------------------------------
2105 // For each vertex, store the list of faces incident on this vertex.
2106 // It is view independent.
2107 class vtkUseSet
2108 {
2109 public:
2110 typedef std::vector<std::list<vtkFace *> *> VectorType;
2111 VectorType Vector;
2112
2113 std::list<vtkFace *> AllFaces; // to set up rendering to false.
2114
2115 // Initialize with the number of vertices.
vtkUseSet(int size)2116 vtkUseSet(int size)
2117 :Vector(size)
2118 {
2119 vtkIdType i=0;
2120 vtkIdType c = static_cast<vtkIdType>(this->Vector.size());
2121 while(i<c)
2122 {
2123 this->Vector[i]=nullptr;
2124 ++i;
2125 }
2126 this->CellScalars=0;
2127 this->NumberOfComponents=0;
2128 }
2129
2130 // Destructor.
~vtkUseSet()2131 ~vtkUseSet()
2132 {
2133 vtkIdType i=0;
2134 vtkIdType c = static_cast<vtkIdType>(this->Vector.size());
2135 while(i<c)
2136 {
2137 if(this->Vector[i]!=nullptr)
2138 {
2139 while(!this->Vector[i]->empty())
2140 {
2141 (*this->Vector[i]->begin())->Unref();
2142 this->Vector[i]->pop_front();
2143 }
2144 delete this->Vector[i];
2145 }
2146 ++i;
2147 }
2148 while(!this->AllFaces.empty())
2149 {
2150 (*this->AllFaces.begin())->Unref();
2151 this->AllFaces.pop_front();
2152 }
2153 }
2154
SetCellScalars(int cellScalars)2155 void SetCellScalars(int cellScalars)
2156 {
2157 this->CellScalars=cellScalars;
2158 }
SetNumberOfComponents(int numberOfComponents)2159 void SetNumberOfComponents(int numberOfComponents)
2160 {
2161 assert("pre: cell_mode" && this->CellScalars);
2162 this->NumberOfComponents=numberOfComponents;
2163 }
2164
2165 // For each vertex, clear the list of faces incident to it.
2166 // also set number of cells per vertex to 0.
Clear()2167 void Clear()
2168 {
2169 vtkIdType i=0;
2170 vtkIdType c = static_cast<vtkIdType>(this->Vector.size());
2171 while(i<c)
2172 {
2173 if(this->Vector[i]!=nullptr)
2174 {
2175 while(!this->Vector[i]->empty())
2176 {
2177 (*this->Vector[i]->begin())->Unref();
2178 this->Vector[i]->pop_front();
2179 }
2180 delete this->Vector[i];
2181 this->Vector[i]=nullptr;
2182 }
2183 ++i;
2184 }
2185 while(!this->AllFaces.empty())
2186 {
2187 (*this->AllFaces.begin())->Unref();
2188 this->AllFaces.pop_front();
2189 }
2190 }
2191
2192 // Add face to each vertex only if the useset does not have the face yet.
AddFace(vtkIdType faceIds[3],vtkDataArray * scalars,vtkIdType cellIdx,int orientationChanged,bool external)2193 void AddFace(vtkIdType faceIds[3],
2194 vtkDataArray *scalars,
2195 vtkIdType cellIdx,
2196 int orientationChanged,
2197 bool external)
2198 {
2199 // Ignore degenerate faces.
2200 if ((faceIds[0] == faceIds[1]) || (faceIds[1] == faceIds[2])) return;
2201
2202 assert("pre: ordered ids" && faceIds[0]<faceIds[1]
2203 && faceIds[1]<faceIds[2]);
2204
2205 vtkFace *f=this->GetFace(faceIds);
2206 if(f==nullptr)
2207 {
2208 int externalSide;
2209 if (external)
2210 {
2211 if (orientationChanged)
2212 {
2213 externalSide = vtkFace::BACK_FACE;
2214 }
2215 else
2216 {
2217 externalSide = vtkFace::FRONT_FACE;
2218 }
2219 }
2220 else
2221 {
2222 externalSide = vtkFace::NOT_EXTERNAL;
2223 }
2224 f=new vtkFace(faceIds, externalSide);
2225 this->AllFaces.push_back(f);
2226 f->Ref();
2227 // All the vertices of this face need to be fed
2228 int i=0;
2229 while(i<3)
2230 {
2231 std::list<vtkFace *> *p=this->Vector[faceIds[i]];
2232 if(p==nullptr)
2233 {
2234 p=new std::list<vtkFace *>;
2235 this->Vector[faceIds[i]]=p;
2236 }
2237 p->push_back(f);
2238 f->Ref();
2239 ++i;
2240 }
2241 if(this->CellScalars)
2242 {
2243 int c=this->NumberOfComponents;
2244 int scalarNumber;
2245 if(orientationChanged)
2246 {
2247 scalarNumber=1;
2248 }
2249 else
2250 {
2251 scalarNumber=0;
2252 }
2253 if(c==1)
2254 {
2255 f->SetScalar(scalarNumber,scalars->GetComponent(cellIdx,0));
2256 }
2257 else
2258 {
2259 double tmp=0;
2260 double tmp2;
2261 i=0;
2262 while(i<c)
2263 {
2264 tmp2=scalars->GetComponent(cellIdx,i);
2265 tmp+=tmp2*tmp2;
2266 ++i;
2267 }
2268 f->SetScalar(scalarNumber,sqrt(tmp));
2269 }
2270 }
2271 }
2272 else
2273 {
2274 if(this->CellScalars)
2275 {
2276 int scalarNumber;
2277 if(orientationChanged)
2278 {
2279 scalarNumber=1;
2280 }
2281 else
2282 {
2283 scalarNumber=0;
2284 }
2285 int c=this->NumberOfComponents;
2286 if(c==1)
2287 {
2288 f->SetScalar(scalarNumber,scalars->GetComponent(cellIdx,0));
2289 }
2290 else
2291 {
2292 double tmp=0;
2293 double tmp2;
2294 int i=0;
2295 while(i<c)
2296 {
2297 tmp2=scalars->GetComponent(cellIdx,i);
2298 tmp+=tmp2*tmp2;
2299 ++i;
2300 }
2301 f->SetScalar(scalarNumber,sqrt(tmp));
2302 }
2303 }
2304 }
2305 }
2306
2307
SetNotRendered()2308 void SetNotRendered()
2309 {
2310 std::list<vtkFace *>::iterator it;
2311 std::list<vtkFace *>::iterator end;
2312 it=this->AllFaces.begin();
2313 end=this->AllFaces.end();
2314 while(it!=end)
2315 {
2316 (*it)->SetRendered(0);
2317 ++it;
2318 }
2319 }
2320
2321 protected:
2322 // Return pointer to face faceIds if the use set of vertex faceIds[0] have
2323 // this face, otherwise return null.
GetFace(vtkIdType faceIds[3])2324 vtkFace *GetFace(vtkIdType faceIds[3])
2325 {
2326 std::list<vtkFace *> *useSet=this->Vector[faceIds[0]];
2327 vtkFace *result=nullptr;
2328
2329 if(useSet!=nullptr)
2330 {
2331 this->It=(*useSet).begin();
2332 this->ItEnd=(*useSet).end();
2333 int found=0;
2334 while(!found && this->It!=this->ItEnd)
2335 {
2336 result=*this->It;
2337 found=result->IsEqual(faceIds);
2338 ++this->It;
2339 }
2340 if(!found)
2341 {
2342 result=nullptr;
2343 }
2344 }
2345 return result;
2346 }
2347
2348 int CellScalars;
2349 int NumberOfComponents;
2350
2351
2352 // Used in GetFace()
2353 std::list<vtkFace *>::iterator It;
2354 std::list<vtkFace *>::iterator ItEnd;
2355 };
2356
2357 // For each vertex, store its projection. It is view-dependent.
2358 class vtkVertices
2359 {
2360 public:
2361 typedef std::vector<vtkVertexEntry> VectorType;
2362 VectorType Vector;
2363
2364 // Initialize with the number of vertices.
vtkVertices(int size)2365 vtkVertices(int size)
2366 :Vector(size)
2367 {
2368 }
2369 };
2370
2371 };
2372
2373 using namespace vtkUnstructuredGridVolumeZSweepMapperNamespace;
2374
2375 //-----------------------------------------------------------------------------
2376 // Implementation of the public class.
2377
2378 vtkStandardNewMacro(vtkUnstructuredGridVolumeZSweepMapper);
2379
2380 vtkCxxSetObjectMacro(vtkUnstructuredGridVolumeZSweepMapper, RayIntegrator,
2381 vtkUnstructuredGridVolumeRayIntegrator);
2382
2383
2384 //-----------------------------------------------------------------------------
2385 // Description:
2386 // Set MaxPixelListSize to 32.
vtkUnstructuredGridVolumeZSweepMapper()2387 vtkUnstructuredGridVolumeZSweepMapper::vtkUnstructuredGridVolumeZSweepMapper()
2388 {
2389 this->MaxPixelListSize=64; // default value.
2390
2391 this->ImageSampleDistance = 1.0;
2392 this->MinimumImageSampleDistance = 1.0;
2393 this->MaximumImageSampleDistance = 10.0;
2394 this->AutoAdjustSampleDistances = 1;
2395
2396 this->ImageMemorySize[0] = 0;
2397 this->ImageMemorySize[1] = 0;
2398
2399 this->Image = nullptr;
2400 this->RealRGBAImage=nullptr;
2401
2402 this->RenderTimeTable = nullptr;
2403 this->RenderVolumeTable = nullptr;
2404 this->RenderRendererTable = nullptr;
2405 this->RenderTableSize = 0;
2406 this->RenderTableEntries = 0;
2407
2408 this->ZBuffer = nullptr;
2409 this->ZBufferSize[0] = 0;
2410 this->ZBufferSize[1] = 0;
2411 this->ZBufferOrigin[0] = 0;
2412 this->ZBufferOrigin[1] = 0;
2413
2414 this->IntermixIntersectingGeometry = 1;
2415
2416 this->ImageDisplayHelper = vtkRayCastImageDisplayHelper::New();
2417
2418 this->PixelListFrame=nullptr;
2419
2420 this->Cell=vtkGenericCell::New();
2421
2422 this->EventList=vtkPriorityQueue::New();
2423
2424 this->UseSet=nullptr;
2425 this->Vertices=nullptr;
2426
2427 this->PerspectiveTransform = vtkTransform::New();
2428 this->PerspectiveMatrix = vtkMatrix4x4::New();
2429
2430 this->SimpleEdge=new vtkSimpleScreenEdge;
2431 this->DoubleEdge=new vtkDoubleScreenEdge;
2432
2433 this->Span=new vtkSpan;
2434
2435 this->RayIntegrator = nullptr;
2436 this->RealRayIntegrator = nullptr;
2437
2438 this->IntersectionLengths=vtkDoubleArray::New();
2439 this->IntersectionLengths->SetNumberOfValues(1);
2440 this->NearIntersections=vtkDoubleArray::New();
2441 this->NearIntersections->SetNumberOfValues(1);
2442 this->FarIntersections=vtkDoubleArray::New();
2443 this->FarIntersections->SetNumberOfValues(1);
2444
2445 this->MemoryManager=nullptr;
2446 }
2447
2448 //-----------------------------------------------------------------------------
~vtkUnstructuredGridVolumeZSweepMapper()2449 vtkUnstructuredGridVolumeZSweepMapper::~vtkUnstructuredGridVolumeZSweepMapper()
2450 {
2451 delete this->MemoryManager;
2452 delete this->PixelListFrame;
2453 this->Cell->Delete();
2454 this->EventList->Delete();
2455
2456 this->ImageDisplayHelper->Delete();
2457
2458 delete this->UseSet;
2459 delete this->Vertices;
2460
2461 this->PerspectiveTransform->Delete();
2462 this->PerspectiveMatrix->Delete();
2463
2464 delete this->SimpleEdge;
2465 delete this->DoubleEdge;
2466 delete this->Span;
2467
2468 if ( this->Image )
2469 {
2470 delete [] this->Image;
2471 delete [] this->RealRGBAImage;
2472 }
2473
2474 if ( this->RenderTableSize )
2475 {
2476 delete [] this->RenderTimeTable;
2477 delete [] this->RenderVolumeTable;
2478 delete [] this->RenderRendererTable;
2479 }
2480
2481 this->SetRayIntegrator(nullptr);
2482 if (this->RealRayIntegrator)
2483 {
2484 this->RealRayIntegrator->UnRegister(this);
2485 }
2486
2487 this->IntersectionLengths->Delete();
2488 this->NearIntersections->Delete();
2489 this->FarIntersections->Delete();
2490 }
2491
2492 //-----------------------------------------------------------------------------
RetrieveRenderTime(vtkRenderer * ren,vtkVolume * vol)2493 float vtkUnstructuredGridVolumeZSweepMapper::RetrieveRenderTime(
2494 vtkRenderer *ren,
2495 vtkVolume *vol )
2496 {
2497 int i;
2498
2499 for ( i = 0; i < this->RenderTableEntries; i++ )
2500 {
2501 if ( this->RenderVolumeTable[i] == vol &&
2502 this->RenderRendererTable[i] == ren )
2503 {
2504 return this->RenderTimeTable[i];
2505 }
2506 }
2507
2508 return 0.0;
2509 }
2510
2511 //-----------------------------------------------------------------------------
StoreRenderTime(vtkRenderer * ren,vtkVolume * vol,float time)2512 void vtkUnstructuredGridVolumeZSweepMapper::StoreRenderTime(
2513 vtkRenderer *ren,
2514 vtkVolume *vol,
2515 float time )
2516 {
2517 int i;
2518 for ( i = 0; i < this->RenderTableEntries; i++ )
2519 {
2520 if ( this->RenderVolumeTable[i] == vol &&
2521 this->RenderRendererTable[i] == ren )
2522 {
2523 this->RenderTimeTable[i] = time;
2524 return;
2525 }
2526 }
2527
2528
2529 // Need to increase size
2530 if ( this->RenderTableEntries >= this->RenderTableSize )
2531 {
2532 if ( this->RenderTableSize == 0 )
2533 {
2534 this->RenderTableSize = 10;
2535 }
2536 else
2537 {
2538 this->RenderTableSize *= 2;
2539 }
2540
2541 float *oldTimePtr = this->RenderTimeTable;
2542 vtkVolume **oldVolumePtr = this->RenderVolumeTable;
2543 vtkRenderer **oldRendererPtr = this->RenderRendererTable;
2544
2545 this->RenderTimeTable = new float [this->RenderTableSize];
2546 this->RenderVolumeTable = new vtkVolume *[this->RenderTableSize];
2547 this->RenderRendererTable = new vtkRenderer *[this->RenderTableSize];
2548
2549 for (i = 0; i < this->RenderTableEntries; i++ )
2550 {
2551 this->RenderTimeTable[i] = oldTimePtr[i];
2552 this->RenderVolumeTable[i] = oldVolumePtr[i];
2553 this->RenderRendererTable[i] = oldRendererPtr[i];
2554 }
2555
2556 delete [] oldTimePtr;
2557 delete [] oldVolumePtr;
2558 delete [] oldRendererPtr;
2559 }
2560
2561 this->RenderTimeTable[this->RenderTableEntries] = time;
2562 this->RenderVolumeTable[this->RenderTableEntries] = vol;
2563 this->RenderRendererTable[this->RenderTableEntries] = ren;
2564
2565 this->RenderTableEntries++;
2566 }
2567
2568 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)2569 void vtkUnstructuredGridVolumeZSweepMapper::PrintSelf(ostream& os,
2570 vtkIndent indent)
2571 {
2572 this->Superclass::PrintSelf(os,indent);
2573
2574 os << indent << "Max Pixel List Size: " << this->MaxPixelListSize << "\n";
2575
2576 os << indent << "Image Sample Distance: "
2577 << this->ImageSampleDistance << "\n";
2578 os << indent << "Minimum Image Sample Distance: "
2579 << this->MinimumImageSampleDistance << "\n";
2580 os << indent << "Maximum Image Sample Distance: "
2581 << this->MaximumImageSampleDistance << "\n";
2582 os << indent << "Auto Adjust Sample Distances: "
2583 << this->AutoAdjustSampleDistances << "\n";
2584 os << indent << "Intermix Intersecting Geometry: "
2585 << (this->IntermixIntersectingGeometry ? "On\n" : "Off\n");
2586
2587 // The PrintSelf test just search for words in the PrintSelf function
2588 // We add here the internal variable we don't want to display:
2589 // this->ImageViewportSize this->ImageOrigin this->ImageInUseSize
2590
2591 if (this->RayIntegrator)
2592 {
2593 os << indent << "RayIntegrator: "
2594 << this->RayIntegrator->GetClassName() << endl;
2595 }
2596 else
2597 {
2598 os << indent << "RayIntegrator: (automatic)" << endl;
2599 }
2600 }
2601
2602 //-----------------------------------------------------------------------------
2603 // Description:
2604 // Maximum size allowed for a pixel list. Default is 32.
2605 // During the rendering, if a list of pixel is full, incremental compositing
2606 // is performed. Even if it is a user setting, it is an advanced parameter.
2607 // You have to understand how the algorithm works to change this value.
GetMaxPixelListSize()2608 int vtkUnstructuredGridVolumeZSweepMapper::GetMaxPixelListSize()
2609 {
2610 return this->MaxPixelListSize;
2611 }
2612
2613 //-----------------------------------------------------------------------------
2614 // Description:
2615 // Change the maximum size allowed for a pixel list. It is an advanced
2616 // parameter.
SetMaxPixelListSize(int size)2617 void vtkUnstructuredGridVolumeZSweepMapper::SetMaxPixelListSize(int size)
2618 {
2619 assert("pre: positive_size" && size>1);
2620 this->MaxPixelListSize=size;
2621 }
2622
2623 //-----------------------------------------------------------------------------
2624 #define ESTABLISH_INTEGRATOR(classname) \
2625 if ( !this->RealRayIntegrator \
2626 || (!this->RealRayIntegrator->IsA(#classname)) ) \
2627 { \
2628 if (this->RealRayIntegrator) this->RealRayIntegrator->UnRegister(this); \
2629 this->RealRayIntegrator = classname::New(); \
2630 this->RealRayIntegrator->Register(this); \
2631 this->RealRayIntegrator->Delete(); \
2632 } \
2633
2634 //-----------------------------------------------------------------------------
2635 // Description:
2636 // WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE
2637 // DO NOT USE THIS METHOD OUTSIDE OF THE RENDERING PROCESS
2638 // Render the volume
Render(vtkRenderer * ren,vtkVolume * vol)2639 void vtkUnstructuredGridVolumeZSweepMapper::Render(vtkRenderer *ren,
2640 vtkVolume *vol)
2641 {
2642 vtkDebugMacro(<<"Render");
2643
2644 // Check for input
2645 if(this->GetInput()==nullptr)
2646 {
2647 vtkErrorMacro(<< "No Input!");
2648 return;
2649 }
2650
2651 int inputAlgPort;
2652 vtkAlgorithm* inputAlg = this->GetInputAlgorithm(0, 0, inputAlgPort);
2653 inputAlg->UpdateWholeExtent();
2654
2655 this->Scalars = this->GetScalars(this->GetInput(), this->ScalarMode,
2656 this->ArrayAccessMode,
2657 this->ArrayId, this->ArrayName,
2658 this->CellScalars);
2659
2660 if(this->Scalars==nullptr)
2661 {
2662 vtkErrorMacro("Can't use the ZSweep mapper without scalars!");
2663 return;
2664 }
2665
2666 // Check to make sure we have an appropriate integrator.
2667 if (this->RayIntegrator)
2668 {
2669 if (this->RealRayIntegrator != this->RayIntegrator)
2670 {
2671 if (this->RealRayIntegrator)
2672 {
2673 this->RealRayIntegrator->UnRegister(this);
2674 }
2675 this->RealRayIntegrator = this->RayIntegrator;
2676 this->RealRayIntegrator->Register(this);
2677 }
2678 }
2679 else
2680 {
2681 if (this->CellScalars)
2682 {
2683 ESTABLISH_INTEGRATOR(vtkUnstructuredGridHomogeneousRayIntegrator);
2684 }
2685 else
2686 {
2687 if (vol->GetProperty()->GetIndependentComponents())
2688 {
2689 ESTABLISH_INTEGRATOR(vtkUnstructuredGridPreIntegration);
2690 }
2691 else
2692 {
2693 ESTABLISH_INTEGRATOR(vtkUnstructuredGridPartialPreIntegration);
2694 }
2695 }
2696 }
2697 // Start timing now. We didn't want to capture the update of the
2698 // input data in the times
2699 this->Timer->StartTimer();
2700
2701 int oldImageMemorySize[2];
2702 oldImageMemorySize[0] = this->ImageMemorySize[0];
2703 oldImageMemorySize[1] = this->ImageMemorySize[1];
2704
2705 // If we are automatically adjusting the size to achieve a desired frame
2706 // rate, then do that adjustment here. Base the new image sample distance
2707 // on the previous one and the previous render time. Don't let
2708 // the adjusted image sample distance be less than the minimum image sample
2709 // distance or more than the maximum image sample distance.
2710 float oldImageSampleDistance = this->ImageSampleDistance;
2711 if ( this->AutoAdjustSampleDistances )
2712 {
2713 float oldTime = this->RetrieveRenderTime( ren, vol );
2714 float newTime = vol->GetAllocatedRenderTime();
2715 this->ImageSampleDistance *= sqrt(oldTime / newTime);
2716 this->ImageSampleDistance =
2717 (this->ImageSampleDistance>this->MaximumImageSampleDistance)?
2718 (this->MaximumImageSampleDistance):(this->ImageSampleDistance);
2719 this->ImageSampleDistance =
2720 (this->ImageSampleDistance<this->MinimumImageSampleDistance)?
2721 (this->MinimumImageSampleDistance):(this->ImageSampleDistance);
2722 }
2723
2724 // The full image fills the viewport. First, compute the actual viewport
2725 // size, then divide by the ImageSampleDistance to find the full image
2726 // size in pixels
2727 int width, height;
2728 ren->GetTiledSize(&width, &height);
2729 this->ImageViewportSize[0] =
2730 static_cast<int>(width/this->ImageSampleDistance);
2731 this->ImageViewportSize[1] =
2732 static_cast<int>(height/this->ImageSampleDistance);
2733
2734 this->ImageInUseSize[0] = this->ImageViewportSize[0];
2735 this->ImageInUseSize[1] = this->ImageViewportSize[1];
2736 this->ImageOrigin[0] = 0;
2737 this->ImageOrigin[1] = 0;
2738
2739 // What is a power of 2 size big enough to fit this image?
2740 this->ImageMemorySize[0] = 32;
2741 this->ImageMemorySize[1] = 32;
2742 while ( this->ImageMemorySize[0] < this->ImageInUseSize[0] )
2743 {
2744 this->ImageMemorySize[0] *= 2;
2745 }
2746 while ( this->ImageMemorySize[1] < this->ImageInUseSize[1] )
2747 {
2748 this->ImageMemorySize[1] *= 2;
2749 }
2750
2751 // If the old image size is much too big (more than twice in
2752 // either direction) then set the old width to 0 which will
2753 // cause the image to be recreated
2754 if ( oldImageMemorySize[0] > 2*this->ImageMemorySize[0] ||
2755 oldImageMemorySize[1] > 2*this->ImageMemorySize[1] )
2756 {
2757 oldImageMemorySize[0] = 0;
2758 }
2759
2760 // If the old image is big enough (but not too big - we handled
2761 // that above) then we'll bump up our required size to the
2762 // previous one. This will keep us from thrashing.
2763 if ( oldImageMemorySize[0] >= this->ImageMemorySize[0] &&
2764 oldImageMemorySize[1] >= this->ImageMemorySize[1] )
2765 {
2766 this->ImageMemorySize[0] = oldImageMemorySize[0];
2767 this->ImageMemorySize[1] = oldImageMemorySize[1];
2768 }
2769
2770 int bufferSize=this->ImageMemorySize[0] * this->ImageMemorySize[1] * 4;
2771
2772 // Do we already have a texture big enough? If not, create a new one and
2773 // clear it.
2774 if ( !this->Image ||
2775 this->ImageMemorySize[0] > oldImageMemorySize[0] ||
2776 this->ImageMemorySize[1] > oldImageMemorySize[1] )
2777 {
2778 // If there is an image there must be row bounds
2779 if ( this->Image )
2780 {
2781 delete [] this->Image;
2782 delete [] this->RealRGBAImage;
2783 }
2784 this->Image = new unsigned char[bufferSize];
2785 this->RealRGBAImage=new float[bufferSize];
2786 }
2787
2788 // We have to clear the image, each time:
2789 memset(this->Image,0,bufferSize);
2790
2791 vtkIdType j=0;
2792 while(j<bufferSize)
2793 {
2794 this->RealRGBAImage[j]=0;
2795 this->RealRGBAImage[j+1]=0;
2796 this->RealRGBAImage[j+2]=0;
2797 this->RealRGBAImage[j+3]=0;
2798 j+=4;
2799 }
2800
2801 // Capture the zbuffer if necessary
2802 if ( this->IntermixIntersectingGeometry &&
2803 ren->GetNumberOfPropsRendered() )
2804 {
2805 int x1, x2, y1, y2;
2806 double *viewport = ren->GetViewport();
2807 int *renWinSize = ren->GetRenderWindow()->GetSize();
2808
2809 // turn this->ImageOrigin into (x1,y1) in window (not viewport!)
2810 // coordinates.
2811 x1 = static_cast<int> (
2812 viewport[0] * static_cast<float>(renWinSize[0]) +
2813 static_cast<float>(this->ImageOrigin[0]) * this->ImageSampleDistance );
2814 y1 = static_cast<int> (
2815 viewport[1] * static_cast<float>(renWinSize[1]) +
2816 static_cast<float>(this->ImageOrigin[1]) * this->ImageSampleDistance);
2817
2818 // compute z buffer size
2819 this->ZBufferSize[0] = static_cast<int>(
2820 static_cast<float>(this->ImageInUseSize[0]) * this->ImageSampleDistance);
2821 this->ZBufferSize[1] = static_cast<int>(
2822 static_cast<float>(this->ImageInUseSize[1]) * this->ImageSampleDistance);
2823
2824 // Use the size to compute (x2,y2) in window coordinates
2825 x2 = x1 + this->ZBufferSize[0] - 1;
2826 y2 = y1 + this->ZBufferSize[1] - 1;
2827
2828 // This is the z buffer origin (in viewport coordinates)
2829 this->ZBufferOrigin[0] = static_cast<int>(
2830 static_cast<float>(this->ImageOrigin[0]) * this->ImageSampleDistance);
2831 this->ZBufferOrigin[1] = static_cast<int>(
2832 static_cast<float>(this->ImageOrigin[1]) * this->ImageSampleDistance);
2833
2834 // Capture the z buffer
2835 this->ZBuffer = ren->GetRenderWindow()->GetZbufferData(x1,y1,x2,y2);
2836 }
2837
2838 this->RealRayIntegrator->Initialize(vol, this->Scalars);
2839
2840 // Here is the Zsweep algorithm:
2841
2842 // 1. For each vertex, find the list of incident faces (the "use set") (3.1)
2843 // In the original paper, it deals with incident cells but the chapter about
2844 // the parallel version in the dissertation deals with faces, which makes
2845 // more sense. Hence, there is no need for the sparsification step (3.5.1)
2846 // It is view-independent, so it can be reused for the next call to Render()
2847 // if the dataset did not change.
2848 vtkDebugMacro(<<"BuildUseSets: start");
2849 this->BuildUseSets();
2850 vtkDebugMacro(<<"BuildUseSets: done");
2851
2852 // 2. Sort the vertices by z-coordinates (view-dependent) in view space.
2853 // For each vertex, compute its camera coordinates and sort it
2854 // by z in an heap. The heap is called the "event list".
2855 // The heap stores the Id of the vertices.
2856 // It is view-dependent.
2857 vtkDebugMacro(<<"ProjectAndSortVertices: start");
2858 this->ProjectAndSortVertices(ren,vol);
2859 vtkDebugMacro(<<"ProjectAndSortVertices: done");
2860
2861 // 3. Create an empty "pixel list" (two way linked list) for each pixel of
2862 // the screen.
2863 vtkDebugMacro(<<"CreateAndCleanPixelList: start");
2864 this->CreateAndCleanPixelList();
2865 vtkDebugMacro(<<"CreateAndCleanPixelList: done");
2866
2867 // 4. Main loop
2868 // (section 2 paragraph 11)
2869 vtkDebugMacro(<<"MainLoop: start");
2870 this->MainLoop(ren->GetRenderWindow());
2871 vtkDebugMacro(<<"MainLoop: done");
2872
2873 // The algorithm is done: send to result to the final image.
2874 if ( !ren->GetRenderWindow()->GetAbortRender() )
2875 {
2876 float depth;
2877 if ( this->IntermixIntersectingGeometry )
2878 {
2879 depth = this->GetMinimumBoundsDepth( ren, vol );
2880 }
2881 else
2882 {
2883 depth = -1;
2884 }
2885
2886 // copy the double image into the unsigned char image:
2887
2888 j=0;
2889 while(j<bufferSize)
2890 {
2891 float alpha=this->RealRGBAImage[j+3];
2892 if(alpha!=0)
2893 {
2894 this->Image[j+0]=this->ColorComponentRealToByte(this->RealRGBAImage[j+0]);
2895 this->Image[j+1]=this->ColorComponentRealToByte(this->RealRGBAImage[j+1]);
2896 this->Image[j+2]=this->ColorComponentRealToByte(this->RealRGBAImage[j+2]);
2897 this->Image[j+3]=this->ColorComponentRealToByte(alpha);
2898 }
2899 else
2900 {
2901 this->Image[j+0]=0;
2902 this->Image[j+1]=0;
2903 this->Image[j+2]=0;
2904 this->Image[j+3]=0;
2905 }
2906 j+=4;
2907 }
2908 this->ImageDisplayHelper->
2909 RenderTexture( vol, ren,
2910 this->ImageMemorySize,
2911 this->ImageViewportSize,
2912 this->ImageInUseSize,
2913 this->ImageOrigin,
2914 depth,
2915 this->Image );
2916
2917 this->Timer->StopTimer();
2918 this->TimeToDraw = this->Timer->GetElapsedTime();
2919 this->StoreRenderTime( ren, vol, this->TimeToDraw );
2920 }
2921 else
2922 {
2923 this->ImageSampleDistance = oldImageSampleDistance;
2924 }
2925
2926 delete [] this->ZBuffer;
2927 this->ZBuffer = nullptr;
2928
2929 this->UpdateProgress(1.0);
2930 }
2931
2932 //-----------------------------------------------------------------------------
AllocateUseSet(vtkIdType size)2933 void vtkUnstructuredGridVolumeZSweepMapper::AllocateUseSet(vtkIdType size)
2934 {
2935 if(this->UseSet!=nullptr)
2936 {
2937 if(size>static_cast<vtkIdType>(this->UseSet->Vector.size()))
2938 {
2939 delete this->UseSet;
2940 this->UseSet=new vtkUseSet(size);
2941 }
2942 else
2943 {
2944 this->UseSet->Clear();
2945 }
2946 }
2947 else
2948 {
2949 this->UseSet=new vtkUseSet(size);
2950 }
2951 }
2952
2953 //-----------------------------------------------------------------------------
AllocateVertices(vtkIdType size)2954 void vtkUnstructuredGridVolumeZSweepMapper::AllocateVertices(vtkIdType size)
2955 {
2956 if(this->Vertices!=nullptr)
2957 {
2958 if(size>static_cast<vtkIdType>(this->Vertices->Vector.size()))
2959 {
2960 delete this->Vertices;
2961 this->Vertices=new vtkVertices(size);
2962 }
2963 }
2964 else
2965 {
2966 this->Vertices=new vtkVertices(size);
2967 }
2968 }
2969
2970 //-----------------------------------------------------------------------------
BuildUseSets()2971 void vtkUnstructuredGridVolumeZSweepMapper::BuildUseSets()
2972 {
2973 int needsUpdate = 0;
2974
2975 // If we have never created the list, we need updating
2976 if (this->UseSet==nullptr )
2977 {
2978 needsUpdate = 1;
2979 }
2980
2981 // If the data has changed in some way then we need to update
2982 vtkUnstructuredGridBase *input = this->GetInput();
2983 if ( input->GetMTime() > this->SavedTriangleListMTime.GetMTime() )
2984 {
2985 needsUpdate = 1;
2986 }
2987
2988 if(this->CellScalars &&
2989 this->GetMTime() > this->SavedTriangleListMTime.GetMTime())
2990 {
2991 needsUpdate=1;
2992 }
2993
2994 // If we don't need updating, return
2995 if ( !needsUpdate )
2996 {
2997 return;
2998 }
2999
3000 vtkIdType numberOfPoints=input->GetNumberOfPoints();
3001
3002 vtkIdList *cellNeighbors = vtkIdList::New();
3003
3004 // init the use set of each vertex
3005 this->AllocateUseSet(numberOfPoints);
3006
3007 this->UseSet->SetCellScalars(this->CellScalars);
3008 if(this->CellScalars)
3009 {
3010 this->UseSet->SetNumberOfComponents(
3011 this->Scalars->GetNumberOfComponents());
3012 }
3013 // for each cell
3014 vtkSmartPointer<vtkCellIterator> cellIter =
3015 vtkSmartPointer<vtkCellIterator>::Take(input->NewCellIterator());
3016 for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal();
3017 cellIter->GoToNextCell())
3018 {
3019 cellIter->GetCell(this->Cell);
3020 vtkIdType faces = this->Cell->GetNumberOfFaces();
3021 if (faces > 0)
3022 {
3023 vtkIdType faceidx=0;
3024 vtkCell *face;
3025 vtkIdType faceIds[3];
3026 vtkIdType orderedFaceIds[3];
3027 // for each face
3028 while(faceidx<faces)
3029 {
3030 face=this->Cell->GetFace(faceidx);
3031 faceIds[0]=face->GetPointId(0);
3032 faceIds[1]=face->GetPointId(1);
3033 faceIds[2]=face->GetPointId(2);
3034 int orientationChanged=this->ReorderTriangle(faceIds,orderedFaceIds);
3035 input->GetCellNeighbors(cellIter->GetCellId(), face->GetPointIds(),
3036 cellNeighbors);
3037 bool external = (cellNeighbors->GetNumberOfIds() == 0);
3038
3039 // Add face only if it is not already in the useset.
3040 this->UseSet->AddFace(orderedFaceIds, this->Scalars,
3041 cellIter->GetCellId(), orientationChanged,
3042 external);
3043
3044 ++faceidx;
3045 }
3046 }
3047 }
3048 cellNeighbors->Delete();
3049 this->SavedTriangleListMTime.Modified();
3050 }
3051
3052 //-----------------------------------------------------------------------------
3053 // Description:
3054 // Reorder vertices `v' in increasing order in `w'. Return if the orientation
3055 // has changed.
ReorderTriangle(vtkIdType v[3],vtkIdType w[3])3056 int vtkUnstructuredGridVolumeZSweepMapper::ReorderTriangle(vtkIdType v[3],
3057 vtkIdType w[3])
3058 {
3059 if(v[0]>v[1])
3060 {
3061 if(v[1]>v[2])
3062 {
3063 // v[2] is the min
3064 w[0]=v[2];
3065 w[1]=v[0];
3066 w[2]=v[1];
3067 }
3068 else
3069 {
3070 // v[1] is the min
3071 w[0]=v[1];
3072 w[1]=v[2];
3073 w[2]=v[0];
3074 }
3075 }
3076 else
3077 {
3078 if(v[0]>v[2])
3079 {
3080 // v[2] is the min
3081 w[0]=v[2];
3082 w[1]=v[0];
3083 w[2]=v[1];
3084 }
3085 else
3086 {
3087 // v[0] is the min
3088 w[0]=v[0];
3089 w[1]=v[1];
3090 w[2]=v[2];
3091 }
3092 }
3093 // At this point the triangle start with the min id and the
3094 // order did not change
3095 // Now, ensure that the two last id are in increasing order
3096 int result=w[1]>w[2];
3097 if(result)
3098 {
3099 vtkIdType tmp=w[1];
3100 w[1]=w[2];
3101 w[2]=tmp;
3102 }
3103 return result;
3104 }
3105
3106 //-----------------------------------------------------------------------------
ProjectAndSortVertices(vtkRenderer * ren,vtkVolume * vol)3107 void vtkUnstructuredGridVolumeZSweepMapper::ProjectAndSortVertices(
3108 vtkRenderer *ren,
3109 vtkVolume *vol)
3110 {
3111 assert("pre: empty list" && this->EventList->GetNumberOfItems()==0);
3112
3113 vtkUnstructuredGridBase *input = this->GetInput();
3114 vtkIdType numberOfPoints=input->GetNumberOfPoints();
3115
3116 vtkIdType pointId=0;
3117 vtkVertexEntry *vertex=nullptr;
3118 // Pre-computation for the projection.
3119
3120 ren->ComputeAspect();
3121 double *aspect = ren->GetAspect();
3122
3123 // Get the view matrix in two steps - there is a one step method in camera
3124 // but it turns off stereo so we do not want to use that one
3125 vtkCamera *cam = ren->GetActiveCamera();
3126 this->PerspectiveTransform->Identity();
3127 this->PerspectiveTransform->Concatenate(
3128 cam->GetProjectionTransformMatrix(aspect[0]/aspect[1], 0.0, 1.0 ));
3129 this->PerspectiveTransform->Concatenate(cam->GetViewTransformMatrix());
3130 this->PerspectiveTransform->Concatenate(vol->GetMatrix());
3131 this->PerspectiveMatrix->DeepCopy(this->PerspectiveTransform->GetMatrix());
3132
3133 this->AllocateVertices(numberOfPoints);
3134
3135 while(pointId<numberOfPoints)
3136 {
3137 vertex=&(this->Vertices->Vector[pointId]);
3138
3139 // Projection
3140 //
3141 double inPoint[4];
3142 input->GetPoint(pointId,inPoint);
3143 inPoint[3] = 1.0;
3144
3145 double outPoint[4];
3146 this->PerspectiveMatrix->MultiplyPoint( inPoint, outPoint );
3147 assert("outPoint[3]" && outPoint[3]!=0.0);
3148
3149 double invW=1/outPoint[3];
3150 double zView = outPoint[2]*invW;
3151
3152 int xScreen=static_cast<int>((outPoint[0]*invW+1)*0.5*this->ImageViewportSize[0]-this->ImageOrigin[0]);
3153 int yScreen=static_cast<int>((outPoint[1]*invW+1)*0.5*this->ImageViewportSize[1]-this->ImageOrigin[1]);
3154
3155 double outWorldPoint[4];
3156
3157 vol->GetMatrix()->MultiplyPoint( inPoint, outWorldPoint );
3158
3159 assert("check: vol no projection" && outWorldPoint[3]==1);
3160
3161 double scalar;
3162 if(this->CellScalars) // cell attribute
3163 {
3164 scalar=0; // ignored
3165 }
3166 else // point attribute
3167 {
3168 int numComp=this->Scalars->GetNumberOfComponents();
3169 if(numComp==1)
3170 {
3171 scalar=this->Scalars->GetComponent(pointId,0);
3172 }
3173 else
3174 {
3175 int comp=0;
3176 scalar=0;
3177 while(comp<numComp)
3178 {
3179 double value=this->Scalars->GetComponent(pointId,comp);
3180 scalar+=value*value;
3181 ++comp;
3182 }
3183 scalar=sqrt(scalar);
3184 }
3185 }
3186
3187 vertex->Set(xScreen,yScreen,outWorldPoint[0]/outWorldPoint[3],
3188 outWorldPoint[1]/outWorldPoint[3],
3189 outWorldPoint[2]/outWorldPoint[3],zView,scalar,invW);
3190
3191 // Sorting
3192 //
3193 // we store -z because the top of the priority list is the
3194 // smallest value
3195 #ifdef BACK_TO_FRONT
3196 this->EventList->Insert(-zView,pointId);
3197 #else
3198 this->EventList->Insert(zView,pointId);
3199 #endif
3200 ++pointId;
3201 }
3202 }
3203
3204 //-----------------------------------------------------------------------------
CreateAndCleanPixelList()3205 void vtkUnstructuredGridVolumeZSweepMapper::CreateAndCleanPixelList()
3206 {
3207 // paper: a "pixel list" is a double linked list. We put that in a queue.
3208 vtkIdType size=this->ImageInUseSize[0]*this->ImageInUseSize[1];
3209 if(this->PixelListFrame!=nullptr)
3210 {
3211 if(this->PixelListFrame->GetSize()<size)
3212 {
3213 delete this->PixelListFrame;
3214 this->PixelListFrame=nullptr;
3215 }
3216 }
3217
3218 if(this->PixelListFrame==nullptr)
3219 {
3220 this->PixelListFrame=new vtkPixelListFrame(size);
3221 }
3222 }
3223
3224 //-----------------------------------------------------------------------------
MainLoop(vtkRenderWindow * renWin)3225 void vtkUnstructuredGridVolumeZSweepMapper::MainLoop(vtkRenderWindow *renWin)
3226 {
3227 // used to know if the next vertex is on the same plane
3228 double currentZ; // than the previous one. If so, the z-target has to be
3229 // updated (without calling the compositing function)
3230 if(this->EventList->GetNumberOfItems()==0)
3231 {
3232 return; // we are done.
3233 }
3234
3235 // initialize the "previous z-target" to the z-coordinate of the first
3236 // vertex.
3237 double previousZTarget=0.0;
3238 vtkIdType vertex=this->EventList->Peek(0,previousZTarget);
3239
3240 #ifdef BACK_TO_FRONT
3241 previousZTarget=-previousZTarget; // because the EventList store -z
3242 #endif
3243
3244 // (section 2 paragraph 11)
3245 // initialize the "z-target" with the maximum z-coordinate of the adjacent
3246 // vertices to the first vertex. The adjacent vertices can be found
3247 // indirectly by using the "use set" of the first vertex (cells), and
3248 // by taking the vertices of all those cells.
3249 //
3250 double zTarget=previousZTarget;
3251 std::list<vtkFace *>::iterator it;
3252 std::list<vtkFace *>::iterator itEnd;
3253
3254 // this->MaxRecordedPixelListSize=0;
3255 this->MaxPixelListSizeReached=0;
3256 this->XBounds[0]=this->ImageInUseSize[0];
3257 this->XBounds[1]=0;
3258 this->YBounds[0]=this->ImageInUseSize[1];
3259 this->YBounds[1]=0;
3260
3261 vtkIdType progressCount=0;
3262 vtkIdType sum=this->EventList->GetNumberOfItems();
3263
3264 if(this->MemoryManager==nullptr)
3265 {
3266 this->MemoryManager=new vtkPixelListEntryMemory;
3267 }
3268
3269 this->UseSet->SetNotRendered();
3270
3271 int aborded=0;
3272 // for each vertex of the "event list"
3273 while(this->EventList->GetNumberOfItems()>0)
3274 {
3275 this->UpdateProgress(static_cast<double>(progressCount)/sum);
3276
3277 aborded=renWin->CheckAbortStatus();
3278 if(aborded)
3279 {
3280 break;
3281 }
3282 ++progressCount;
3283 // the z coordinate of the current vertex defines the "sweep plane".
3284 vertex=this->EventList->Pop(0,currentZ);
3285
3286 if(this->UseSet->Vector[vertex]!=nullptr)
3287 { // otherwise the vertex is not useful, basically this is the
3288 // end we reached the last ztarget
3289
3290 #ifdef BACK_TO_FRONT
3291 currentZ=-currentZ; // because the EventList store -z
3292 #endif
3293
3294 if(previousZTarget==currentZ)
3295 {
3296 // the new vertex is on the same sweep plane than the previous vertex
3297 // that defined a z target
3298 // => the z target has to be updated accordingly
3299 // This is also the case for the first vertex.
3300 it=this->UseSet->Vector[vertex]->begin();
3301 itEnd=this->UseSet->Vector[vertex]->end();
3302
3303 // for each face incident with the vertex
3304 while(it!=itEnd)
3305 {
3306 vtkFace *face=(*it);
3307 // for each point of the face, get the closest z
3308 vtkIdType *vids=face->GetFaceIds();
3309 vtkIdType i=0;
3310 while(i<3)
3311 {
3312 double z=this->Vertices->Vector[vids[i]].GetZview();
3313 #ifdef BACK_TO_FRONT
3314 if(z<zTarget)
3315 #else
3316 if(z>zTarget)
3317 #endif
3318 {
3319 zTarget=z;
3320 }
3321 ++i;
3322 }
3323 ++it;
3324 }
3325 }
3326
3327 // Time to call the composite function?
3328 #ifdef BACK_TO_FRONT
3329 if(currentZ<zTarget)
3330 #else
3331 if(currentZ>zTarget)
3332 #endif
3333 {
3334 this->CompositeFunction(zTarget);
3335
3336 // Update the zTarget
3337 previousZTarget=zTarget;
3338
3339 it=this->UseSet->Vector[vertex]->begin();
3340 itEnd=this->UseSet->Vector[vertex]->end();
3341 // for each cell incident with the vertex
3342 while(it!=itEnd)
3343 {
3344 vtkFace *face=(*it);
3345 // for each point of the face, get the closest z
3346 vtkIdType *vids=face->GetFaceIds();
3347 vtkIdType i=0;
3348 while(i<3)
3349 {
3350 double z=this->Vertices->Vector[vids[i]].GetZview();
3351 #ifdef BACK_TO_FRONT
3352 if(z<zTarget)
3353 #else
3354 if(z>zTarget)
3355 #endif
3356 {
3357 zTarget=z;
3358 }
3359 ++i;
3360 }
3361 ++it;
3362 }
3363 }
3364 else
3365 {
3366 if(this->MaxPixelListSizeReached)
3367 {
3368 this->CompositeFunction(currentZ);
3369 // We do not update the zTarget in this case.
3370 }
3371 }
3372
3373 // use the "use set" (cells) of the vertex to get the cells that are
3374 // incident on the vertex, and that have this vertex as
3375 // minimal z-coordinate,
3376
3377 it=this->UseSet->Vector[vertex]->begin();
3378 itEnd=this->UseSet->Vector[vertex]->end();
3379
3380 while(it!=itEnd)
3381 {
3382 vtkFace *face=(*it);
3383 if(!face->GetRendered())
3384 {
3385 vtkIdType *vids=face->GetFaceIds();
3386 if(this->CellScalars)
3387 {
3388 this->FaceScalars[0]=face->GetScalar(0);
3389 this->FaceScalars[1]=face->GetScalar(1);
3390 }
3391 this->RasterizeFace(vids, face->GetExternalSide());
3392 face->SetRendered(1);
3393 }
3394 #if 0 // face search
3395 // for each point of the face, get the closest z
3396 vtkIdType *vids=face->GetFaceIds();
3397 vtkIdType minVertex=vids[0];
3398 double farestZ=this->Vertices->Vector[vids[0]].GetZview();
3399
3400 vtkIdType i=1;
3401 while(i<3)
3402 {
3403 double z=this->Vertices->Vector[vids[i]].GetZview();
3404 #ifdef BACK_TO_FRONT
3405 if(z>farestZ)
3406 #else
3407 if(z<farestZ)
3408 #endif
3409 {
3410 farestZ=z;
3411 minVertex=vids[i];
3412 }
3413 ++i;
3414 }
3415 if(minVertex==vertex)
3416 {
3417 // if(face->GetRendered())
3418 // {
3419 // cout<<"FACE ALREADY RENDERED!!!!"<<endl;
3420 // }
3421 this->RasterizeFace(vids);
3422 // face->SetRendered(1);
3423 }
3424 #endif // face search
3425 ++it;
3426 }
3427 } // if useset of vertex is not null
3428 } // while(eventList->GetNumberOfItems()>0)
3429
3430 if(!aborded)
3431 {
3432 // Here a final compositing
3433 vtkDebugMacro(<<"Flush Compositing");
3434 // this->SavePixelListFrame();
3435 #ifdef BACK_TO_FRONT
3436 this->CompositeFunction(-2);
3437 #else
3438 this->CompositeFunction(2);
3439 #endif
3440 }
3441 else
3442 {
3443 this->EventList->Reset();
3444 }
3445 this->PixelListFrame->Clean(this->MemoryManager);
3446 // vtkDebugMacro(<<"MaxRecordedPixelListSize="<<this->MaxRecordedPixelListSize);
3447
3448 assert("post: empty_list" && this->EventList->GetNumberOfItems()==0);
3449 }
3450
3451 //-----------------------------------------------------------------------------
SavePixelListFrame()3452 void vtkUnstructuredGridVolumeZSweepMapper::SavePixelListFrame()
3453 {
3454 vtkPolyData *dataset=vtkPolyData::New();
3455
3456 vtkIdType height=this->ImageInUseSize[1];
3457 vtkIdType width=this->ImageInUseSize[0];
3458 vtkPixelListEntry *current;
3459 vtkIdType i;
3460
3461 vtkPoints *pts=vtkPoints::New();
3462 pts->SetDataTypeToDouble();
3463
3464 vtkDoubleArray *dataArray=vtkDoubleArray::New();
3465 vtkCellArray *vertices=vtkCellArray::New();
3466 vtkIdType pointId=0;
3467
3468 // height=151;
3469 // width=151;
3470
3471 vtkIdType y=0; //150;
3472 while(y<height)
3473 {
3474 vtkIdType x=0; //150;
3475 while(x<width)
3476 {
3477 i=y*this->ImageInUseSize[0]+x;
3478 current=this->PixelListFrame->GetFirst(i);
3479 while(current!=nullptr)
3480 {
3481 double *values=current->GetValues();
3482
3483 double point[3];
3484 point[0]=x;
3485 point[1]=y;
3486 point[2]=values[2]; // zWorld
3487
3488 pts->InsertNextPoint(point);
3489 dataArray->InsertNextValue(values[3]);
3490 vertices->InsertNextCell(1,&pointId);
3491 current=current->GetNext();
3492 ++pointId;
3493 }
3494 ++x;
3495 }
3496 ++y;
3497 }
3498 dataset->SetPoints(pts);
3499 pts->Delete();
3500 dataset->SetVerts(vertices);
3501 vertices->Delete();
3502 dataset->GetPointData()->SetScalars(dataArray);
3503 dataArray->Delete();
3504
3505 /*
3506 vtkXMLPolyDataWriter *writer=vtkXMLPolyDataWriter::New();
3507 writer->SetFileName("pixellistframe.vtp");
3508 writer->SetInputData(dataset);
3509 writer->SetIdTypeToInt32();
3510 dataset->Delete();
3511 writer->Write();
3512 writer->Delete();
3513 */
3514 }
3515
3516 //-----------------------------------------------------------------------------
3517 // Description:
3518 // Perform a scan conversion of a triangle, interpolating z and the scalar.
RasterizeFace(vtkIdType faceIds[3],int externalSide)3519 void vtkUnstructuredGridVolumeZSweepMapper::RasterizeFace(vtkIdType faceIds[3],
3520 int externalSide)
3521 {
3522 // The triangle is split by a horizontal line passing through the
3523 // second vertex v1 (y-order)
3524 // Hence, on one side there's one edge (v0v2), on the other side there are two
3525 // edges (v0v1 and v1v2).
3526
3527 vtkVertexEntry *v0=&(this->Vertices->Vector[faceIds[0]]);
3528 vtkVertexEntry *v1=&(this->Vertices->Vector[faceIds[1]]);
3529 vtkVertexEntry *v2=&(this->Vertices->Vector[faceIds[2]]);
3530
3531 bool exitFace = false;
3532
3533 // Find the orientation of the triangle on the screen to get the right
3534 // scalar
3535 if((externalSide != vtkFace::NOT_EXTERNAL) || this->CellScalars)
3536 {
3537 // To find the "winding" of the triangle as projected in screen space, we
3538 // perform the cross section. The result trivially points along the Z axis.
3539 // Its magnitude is proportional to the triangle area and its direction
3540 // points away from the "front" face (what we are really interested in).
3541 // Since we know the cross product points in the Z direction, we only need
3542 // the Z component.
3543 int vec0[2], vec1[2];
3544 vec0[0] = v1->GetScreenX() - v0->GetScreenX();
3545 vec0[1] = v1->GetScreenY() - v0->GetScreenY();
3546 vec1[0] = v2->GetScreenX() - v0->GetScreenX();
3547 vec1[1] = v2->GetScreenY() - v0->GetScreenY();
3548 int zcross= vec0[0]*vec1[1] - vec0[1]*vec1[0];
3549 if(zcross<0)
3550 {
3551 this->FaceSide=1;
3552 }
3553 else
3554 {
3555 this->FaceSide=0;
3556 }
3557
3558 // When determining the exit face, be conservative. If the triangle is too
3559 // small to determine the orientation, it is better to assume that it is
3560 // exit than not exit. This is because if it is misclassified as exit, then
3561 // we simply will not fill a rather small tet. If it is misclassified as
3562 // not exit when it is, it could potential cause the filling of a large
3563 // space.
3564 if (externalSide == vtkFace::FRONT_FACE)
3565 {
3566 #ifdef BACK_TO_FRONT
3567 exitFace = (zcross >= 0);
3568 #else
3569 exitFace = (zcross <= 0);
3570 #endif
3571 }
3572 else if (externalSide == vtkFace::BACK_FACE)
3573 {
3574 #ifdef BACK_TO_FRONT
3575 exitFace = (zcross <= 0);
3576 #else
3577 exitFace = (zcross >= 0);
3578 #endif
3579 }
3580 }
3581
3582 this->RasterizeTriangle(v0,v1,v2,exitFace);
3583 }
3584
3585 //-----------------------------------------------------------------------------
3586 // Description:
3587 // Perform a scan conversion of a triangle, interpolating z and the scalar.
RasterizeTriangle(vtkVertexEntry * ve0,vtkVertexEntry * ve1,vtkVertexEntry * ve2,bool externalFace)3588 void vtkUnstructuredGridVolumeZSweepMapper::RasterizeTriangle(
3589 vtkVertexEntry *ve0,
3590 vtkVertexEntry *ve1,
3591 vtkVertexEntry *ve2,
3592 bool externalFace)
3593 {
3594 assert("pre: ve0_exists" && ve0!=nullptr);
3595 assert("pre: ve1_exists" && ve1!=nullptr);
3596 assert("pre: ve2_exists" && ve2!=nullptr);
3597
3598 vtkVertexEntry *v0=ve0;
3599 vtkVertexEntry *v1=ve1;
3600 vtkVertexEntry *v2=ve2;
3601
3602 // The triangle is split by a horizontal line passing through the
3603 // second vertex v1 (y-order)
3604 // Hence, on one side there's one edge (v0v2), on the other side there are two
3605 // edges (v0v1 and v1v2).
3606
3607 // Order vertices by y screen.
3608
3609 vtkVertexEntry *tmp;
3610
3611 if(v0->GetScreenY()>v1->GetScreenY())
3612 {
3613 tmp=v0;
3614 v0=v1;
3615 v1=tmp;
3616 }
3617 if(v0->GetScreenY()>v2->GetScreenY())
3618 {
3619 tmp=v1;
3620 v1=v0;
3621 v0=v2;
3622 v2=tmp;
3623 }
3624 else
3625 {
3626 if(v1->GetScreenY()>v2->GetScreenY())
3627 {
3628 tmp=v1;
3629 v1=v2;
3630 v2=tmp;
3631 }
3632 }
3633
3634 if(v0->GetScreenY()<this->YBounds[0])
3635 {
3636 if(v0->GetScreenY()>=0)
3637 {
3638 this->YBounds[0]=v0->GetScreenY();
3639 }
3640 else
3641 {
3642 this->YBounds[0]=0;
3643 }
3644 }
3645 if(v2->GetScreenY()>this->YBounds[1])
3646 {
3647 if(v2->GetScreenY()<this->ImageInUseSize[1])
3648 {
3649 this->YBounds[1]=v2->GetScreenY();
3650 }
3651 else
3652 {
3653 this->YBounds[1]=this->ImageInUseSize[1]-1;
3654 }
3655 }
3656
3657 int x=v0->GetScreenX();
3658
3659 if(x<this->XBounds[0])
3660 {
3661 if(x>=0)
3662 {
3663 this->XBounds[0]=x;
3664 }
3665 else
3666 {
3667 this->XBounds[0]=0;
3668 }
3669 }
3670 else
3671 {
3672 if(x>this->XBounds[1])
3673 {
3674 if(x<this->ImageInUseSize[0])
3675 {
3676 this->XBounds[1]=x;
3677 }
3678 else
3679 {
3680 this->XBounds[1]=this->ImageInUseSize[0]-1;
3681 }
3682 }
3683 }
3684 x=v1->GetScreenX();
3685
3686 if(x<this->XBounds[0])
3687 {
3688 if(x>=0)
3689 {
3690 this->XBounds[0]=x;
3691 }
3692 else
3693 {
3694 this->XBounds[0]=0;
3695 }
3696 }
3697 else
3698 {
3699 if(x>this->XBounds[1])
3700 {
3701 if(x<this->ImageInUseSize[0])
3702 {
3703 this->XBounds[1]=x;
3704 }
3705 else
3706 {
3707 this->XBounds[1]=this->ImageInUseSize[0]-1;
3708 }
3709 }
3710 }
3711
3712 x=v2->GetScreenX();
3713
3714 if(x<this->XBounds[0])
3715 {
3716 if(x>=0)
3717 {
3718 this->XBounds[0]=x;
3719 }
3720 else
3721 {
3722 this->XBounds[0]=0;
3723 }
3724 }
3725 else
3726 {
3727 if(x>this->XBounds[1])
3728 {
3729 if(x<this->ImageInUseSize[0])
3730 {
3731 this->XBounds[1]=x;
3732 }
3733 else
3734 {
3735 this->XBounds[1]=this->ImageInUseSize[0]-1;
3736 }
3737 }
3738 }
3739
3740 int dy20=v2->GetScreenY()-v0->GetScreenY();
3741 int dx10=v1->GetScreenX()-v0->GetScreenX();
3742 int dx20=v2->GetScreenX()-v0->GetScreenX();
3743 int dy10=v1->GetScreenY()-v0->GetScreenY();
3744
3745 int det=dy20*dx10-dx20*dy10;
3746
3747 vtkScreenEdge *leftEdge=nullptr;
3748 vtkScreenEdge *rightEdge=nullptr;
3749
3750 if(det==0) //v0v1v2 aligned or v0=v1=v2
3751 {
3752 // easy case: v0=v1=v2 render the 3 points
3753 if(v0->GetScreenX()==v1->GetScreenX() && v0->GetScreenX()==v2->GetScreenX()
3754 && v0->GetScreenY()==v1->GetScreenY()
3755 && v0->GetScreenY()==v2->GetScreenY())
3756 {
3757 x=v0->GetScreenX();
3758 int y=v0->GetScreenY();
3759 if(x>=0 && x<this->ImageInUseSize[0] && y>=0 &&
3760 y<this->ImageInUseSize[1])
3761 {
3762 vtkIdType i=y*this->ImageInUseSize[0]+x;
3763 // Write the pixel
3764 vtkPixelListEntry *p0=this->MemoryManager->AllocateEntry();
3765 p0->Init(v0->GetValues(),v0->GetZview(), externalFace);
3766 if(this->CellScalars)
3767 {
3768 p0->GetValues()[VTK_VALUES_SCALAR_INDEX]=this->FaceScalars[this->FaceSide];
3769 }
3770 this->PixelListFrame->AddAndSort(i,p0);
3771
3772 vtkPixelListEntry *p1=this->MemoryManager->AllocateEntry();
3773 p1->Init(v1->GetValues(),v1->GetZview(), externalFace);
3774 if(this->CellScalars)
3775 {
3776 p1->GetValues()[VTK_VALUES_SCALAR_INDEX]=this->FaceScalars[this->FaceSide];
3777 }
3778 this->PixelListFrame->AddAndSort(i,p1);
3779
3780 vtkPixelListEntry *p2=this->MemoryManager->AllocateEntry();
3781 p2->Init(v2->GetValues(),v2->GetZview(), externalFace);
3782 if(this->CellScalars)
3783 {
3784 p2->GetValues()[VTK_VALUES_SCALAR_INDEX]=this->FaceScalars[this->FaceSide];
3785 }
3786 this->PixelListFrame->AddAndSort(i,p2);
3787
3788
3789 // if(this->PixelListFrame->GetListSize(i)>this->MaxRecordedPixelListSize)
3790 // {
3791 // this->MaxRecordedPixelListSize=this->PixelListFrame->GetListSize(i);
3792 // }
3793
3794 if(!this->MaxPixelListSizeReached)
3795 {
3796 this->MaxPixelListSizeReached=this->PixelListFrame->GetListSize(i)>
3797 this->MaxPixelListSize;
3798 }
3799 }
3800 }
3801 else // line
3802 {
3803 this->RasterizeLine(v0,v1,externalFace);
3804 this->RasterizeLine(v1,v2,externalFace);
3805 this->RasterizeLine(v0,v2,externalFace);
3806 }
3807 return;
3808 }
3809 else
3810 {
3811 if(det>0) //v0v1 on right
3812 {
3813 this->DoubleEdge->Init(v0,v1,v2,dx10,dy10,1); // true=on right
3814 rightEdge=this->DoubleEdge;
3815 this->SimpleEdge->Init(v0,v2,dx20,dy20,0);
3816 leftEdge=this->SimpleEdge;
3817 }
3818 else
3819 {
3820 // v0v1 on left
3821 this->DoubleEdge->Init(v0,v1,v2,dx10,dy10,0); // true=on right
3822 leftEdge=this->DoubleEdge;
3823 this->SimpleEdge->Init(v0,v2,dx20,dy20,1);
3824 rightEdge=this->SimpleEdge;
3825 }
3826 }
3827
3828 int y=v0->GetScreenY();
3829 int y1=v1->GetScreenY();
3830 int y2=v2->GetScreenY();
3831
3832 int skipped=0;
3833
3834 if(y1>=0) // clipping
3835 {
3836
3837 if(y1>=this->ImageInUseSize[1]) // clipping
3838 {
3839 y1=this->ImageInUseSize[1]-1;
3840 }
3841
3842 while(y<=y1)
3843 {
3844 if(y>=0 && y<this->ImageInUseSize[1]) // clipping
3845 {
3846 this->RasterizeSpan(y,leftEdge,rightEdge,externalFace);
3847 }
3848 ++y;
3849 if(y<=y1)
3850 {
3851 leftEdge->NextLine(y);
3852 rightEdge->NextLine(y);
3853 }
3854 }
3855 }
3856 else
3857 {
3858 leftEdge->SkipLines(y1-y,y1);
3859 rightEdge->SkipLines(y1-y,y1);
3860 y=y1;
3861 skipped=1;
3862 }
3863
3864 if(y<this->ImageInUseSize[1]) // clipping
3865 {
3866 leftEdge->OnBottom(skipped,y);
3867 rightEdge->OnBottom(skipped,y);
3868
3869 if(y2>=this->ImageInUseSize[1]) // clipping
3870 {
3871 y2=this->ImageInUseSize[1]-1;
3872 }
3873
3874 while(y<=y2)
3875 {
3876 if(y>=0) // clipping, needed in case of no top
3877 {
3878 this->RasterizeSpan(y,leftEdge,rightEdge,externalFace);
3879 }
3880 ++y;
3881 leftEdge->NextLine(y);
3882 rightEdge->NextLine(y);
3883 }
3884 }
3885 }
3886
3887 //-----------------------------------------------------------------------------
RasterizeSpan(int y,vtkScreenEdge * left,vtkScreenEdge * right,bool exitFace)3888 void vtkUnstructuredGridVolumeZSweepMapper::RasterizeSpan(int y,
3889 vtkScreenEdge *left,
3890 vtkScreenEdge *right,
3891 bool exitFace)
3892 {
3893 assert("pre: left_exists" && left!=nullptr);
3894 assert("pre: right_exists" && right!=nullptr);
3895
3896 vtkIdType i=y*this->ImageInUseSize[0];
3897
3898 this->Span->Init(left->GetX(),
3899 left->GetInvW(),
3900 left->GetPValues(),
3901 left->GetZview(),
3902 right->GetX(),
3903 right->GetInvW(),
3904 right->GetPValues(),
3905 right->GetZview());
3906
3907 while(!this->Span->IsAtEnd())
3908 {
3909 int x=this->Span->GetX();
3910 if(x>=0 && x<this->ImageInUseSize[0]) // clipping
3911 {
3912 vtkIdType j=i+x;
3913 // Write the pixel
3914 vtkPixelListEntry *p=this->MemoryManager->AllocateEntry();
3915 p->Init(this->Span->GetValues(),this->Span->GetZview(), exitFace);
3916
3917 if(this->CellScalars)
3918 {
3919 p->GetValues()[VTK_VALUES_SCALAR_INDEX]=this->FaceScalars[this->FaceSide];
3920 }
3921 this->PixelListFrame->AddAndSort(j,p);
3922
3923
3924 // if(this->PixelListFrame->GetListSize(j)>this->MaxRecordedPixelListSize)
3925 // {
3926 // this->MaxRecordedPixelListSize=this->PixelListFrame->GetListSize(j);
3927 // }
3928
3929 if(!this->MaxPixelListSizeReached)
3930 {
3931 this->MaxPixelListSizeReached=this->PixelListFrame->GetListSize(j)>
3932 this->MaxPixelListSize;
3933 }
3934 }
3935 this->Span->NextPixel();
3936 }
3937 }
3938
3939 enum
3940 {
3941 VTK_LINE_CONSTANT=0,
3942 VTK_LINE_BRESENHAM,
3943 VTK_LINE_DIAGONAL
3944 };
3945
3946 //-----------------------------------------------------------------------------
RasterizeLine(vtkVertexEntry * v0,vtkVertexEntry * v1,bool exitFace)3947 void vtkUnstructuredGridVolumeZSweepMapper::RasterizeLine(vtkVertexEntry *v0,
3948 vtkVertexEntry *v1,
3949 bool exitFace)
3950 {
3951 assert("pre: v0_exists" && v0!=nullptr);
3952 assert("pre: v1_exists" && v1!=nullptr);
3953 assert("pre: y_ordered" && v0->GetScreenY()<=v1->GetScreenY());
3954
3955 int lineCase;
3956 int xIncrement; // if true increment x, if false increment y
3957 int dx;
3958 int dy;
3959 int xSign;
3960
3961 // initialization is not useful, it is just to remove compiler warnings
3962 int dx2=0;
3963 int dy2=0;
3964 int e=0;
3965
3966 double values[VTK_VALUES_SIZE];
3967 double pValues[VTK_VALUES_SIZE];
3968
3969 double dPv[VTK_VALUES_SIZE];
3970 double dInvW;
3971 double dZ;
3972
3973 double zView;
3974 double invW;
3975
3976 int i;
3977
3978 int x=v0->GetScreenX();
3979 int y=v0->GetScreenY();
3980
3981 // 1. Find the case
3982 dx=v1->GetScreenX()-v0->GetScreenX();
3983 if(dx<0)
3984 {
3985 dx=-dx;
3986 xSign=-1;
3987 }
3988 else
3989 {
3990 xSign=1;
3991 }
3992 dy=v1->GetScreenY()-v0->GetScreenY();
3993 xIncrement=dx>dy;
3994 if(xIncrement)
3995 {
3996 if(dy==0)
3997 {
3998 lineCase=VTK_LINE_CONSTANT;
3999 }
4000 else
4001 {
4002 lineCase=VTK_LINE_BRESENHAM;
4003 dx2=dx<<1;
4004 dy2=dy<<1;
4005 e=dx;
4006 }
4007
4008 double invDx=1.0/dx;
4009 i=0;
4010 invW=v0->GetInvW();
4011 double invW1=v1->GetInvW();
4012 double *val0=v0->GetValues();
4013 double *val1=v1->GetValues();
4014 while(i<VTK_VALUES_SIZE)
4015 {
4016 values[i]=val0[i];
4017 pValues[i]=values[i]*invW;
4018 dPv[i]=(val1[i]*invW1-pValues[i])*invDx;
4019 ++i;
4020 }
4021 dInvW=(invW1-invW)*invDx;
4022 zView=v0->GetZview();
4023 dZ=(v1->GetZview()-zView)*invDx;
4024 }
4025 else
4026 {
4027 if(dx==0)
4028 {
4029 if(dy==0)
4030 {
4031 // render both points and return
4032 // write pixel
4033 if(x>=0 && x<this->ImageInUseSize[0] && y>=0 &&
4034 y<this->ImageInUseSize[1]) // clipping
4035 {
4036 vtkIdType j=y*this->ImageInUseSize[0]+x; // mult==bad!!
4037 // Write the pixel
4038 vtkPixelListEntry *p0=this->MemoryManager->AllocateEntry();
4039 p0->Init(v0->GetValues(),v0->GetZview(), exitFace);
4040
4041 if(this->CellScalars)
4042 {
4043 p0->GetValues()[VTK_VALUES_SCALAR_INDEX]=this->FaceScalars[this->FaceSide];
4044 }
4045 this->PixelListFrame->AddAndSort(j,p0);
4046
4047 // Write the pixel
4048 vtkPixelListEntry *p1=this->MemoryManager->AllocateEntry();
4049 p1->Init(v1->GetValues(),v1->GetZview(), exitFace);
4050
4051 if(this->CellScalars)
4052 {
4053 p1->GetValues()[VTK_VALUES_SCALAR_INDEX]=this->FaceScalars[this->FaceSide];
4054 }
4055 this->PixelListFrame->AddAndSort(j,p1);
4056
4057 if(!this->MaxPixelListSizeReached)
4058 {
4059 this->MaxPixelListSizeReached=this->PixelListFrame->GetListSize(j)>
4060 this->MaxPixelListSize;
4061 }
4062 }
4063 return;
4064 }
4065 else
4066 {
4067 lineCase=VTK_LINE_CONSTANT;
4068 }
4069 }
4070 else
4071 {
4072 if(dy==dx)
4073 {
4074 lineCase=VTK_LINE_DIAGONAL;
4075 }
4076 else
4077 {
4078 lineCase=VTK_LINE_BRESENHAM;
4079 dx2=dx<<1;
4080 dy2=dy<<1;
4081 e=dy;
4082 }
4083 }
4084 double invDy=1.0/dy;
4085 i=0;
4086 invW=v0->GetInvW();
4087 double invW1=v1->GetInvW();
4088 double *val0=v0->GetValues();
4089 double *val1=v1->GetValues();
4090 while(i<VTK_VALUES_SIZE)
4091 {
4092 values[i]=val0[i];
4093 pValues[i]=values[i]*invW;
4094 dPv[i]=(val1[i]*invW1-pValues[i])*invDy;
4095 ++i;
4096 }
4097 dInvW=(invW1-invW)*invDy;
4098 zView=v0->GetZview();
4099 dZ=(v1->GetZview()-zView)*invDy;
4100 }
4101
4102 // 2. Iterate over each pixel of the straight line.
4103 int done=0;
4104 while(!done)
4105 {
4106 // write pixel
4107 if(x>=0 && x<this->ImageInUseSize[0] && y>=0 &&
4108 y<this->ImageInUseSize[1]) // clipping
4109 {
4110 vtkIdType j=y*this->ImageInUseSize[0]+x; // mult==bad!!
4111 // Write the pixel
4112 vtkPixelListEntry *p0=this->MemoryManager->AllocateEntry();
4113 p0->Init(values,zView,exitFace);
4114
4115 if(this->CellScalars)
4116 {
4117 p0->GetValues()[VTK_VALUES_SCALAR_INDEX]=this->FaceScalars[this->FaceSide];
4118 }
4119 this->PixelListFrame->AddAndSort(j,p0);
4120
4121 if(!this->MaxPixelListSizeReached)
4122 {
4123 this->MaxPixelListSizeReached=this->PixelListFrame->GetListSize(j)>
4124 this->MaxPixelListSize;
4125 }
4126 }
4127
4128 // next pixel
4129 switch(lineCase)
4130 {
4131 case VTK_LINE_CONSTANT:
4132 if(xIncrement)
4133 {
4134 x+=xSign;
4135 if(xSign>0)
4136 {
4137 done=x>v1->GetScreenX();
4138 }
4139 else
4140 {
4141 done=x<v1->GetScreenX();
4142 }
4143 }
4144 else
4145 {
4146 ++y;
4147 done=y>v1->GetScreenY();
4148 }
4149 //values, invw, zview
4150 break;
4151 case VTK_LINE_DIAGONAL:
4152 ++y;
4153 x+=xSign;
4154 done=y>v1->GetScreenY();
4155 //values, invw, zview
4156 break;
4157 case VTK_LINE_BRESENHAM:
4158 if(xIncrement)
4159 {
4160 x+=xSign;
4161 e+=dy2;
4162 if(e>=dx2)
4163 {
4164 e-=dx2;
4165 ++y;
4166 }
4167 if(xSign>0)
4168 {
4169 done=x>v1->GetScreenX();
4170 }
4171 else
4172 {
4173 done=x<v1->GetScreenX();
4174 }
4175 }
4176 else
4177 {
4178 ++y;
4179 e+=dx2;
4180 if(e>=dy2)
4181 {
4182 e-=dy2;
4183 x+=xSign;
4184 }
4185 done=y>v1->GetScreenY();
4186 }
4187 // values, invw, zview
4188 break;
4189 }
4190 if(!done)
4191 {
4192 invW+=dInvW;
4193 i=0;
4194 double w=1.0/invW;
4195 while(i<VTK_VALUES_SIZE)
4196 {
4197 pValues[i]+=dPv[i];
4198 values[i]=pValues[i]*w;
4199 ++i;
4200 }
4201 zView+=dZ;
4202 }
4203 }
4204 }
4205
4206 //-----------------------------------------------------------------------------
CompositeFunction(double zTarget)4207 void vtkUnstructuredGridVolumeZSweepMapper::CompositeFunction(double zTarget)
4208 {
4209 int y=this->YBounds[0];
4210 vtkIdType i=y*this->ImageInUseSize[0]+this->XBounds[0];
4211
4212 vtkIdType index=(y*this->ImageMemorySize[0]+this->XBounds[0])<< 2; // *4
4213 vtkIdType indexStep=this->ImageMemorySize[0]<<2; // *4
4214
4215 vtkPixelListEntry *current;
4216 vtkPixelListEntry *next;
4217 double zBuffer=0;
4218
4219 int newXBounds[2];
4220 int newYBounds[2];
4221
4222 newXBounds[0]=this->ImageInUseSize[0];
4223 newXBounds[1]=0;
4224 newYBounds[0]=this->ImageInUseSize[1];
4225 newYBounds[1]=0;
4226
4227 int xMin=this->XBounds[0];
4228 int xMax=this->XBounds[1];
4229 int yMax=this->YBounds[1];
4230
4231 vtkPixelList *pixel;
4232 int x;
4233 vtkIdType j;
4234 vtkIdType index2;
4235 int done;
4236 int doIntegration;
4237 double length;
4238 float *color;
4239
4240 // for each pixel in the bounding box
4241 while(y<=yMax)
4242 {
4243 x=xMin;
4244 j=i;
4245 index2=index;
4246 while(x<=xMax)
4247 {
4248 pixel=this->PixelListFrame->GetList(j);
4249 // we need at least two entries per pixel to perform compositing
4250 if(pixel->GetSize()>=2)
4251 {
4252 current=pixel->GetFirst();
4253 next=current->GetNext();
4254 #ifdef BACK_TO_FRONT
4255 done=current->GetZview()<=zTarget || next->GetZview()<=zTarget;
4256 #else
4257 done=current->GetZview()>=zTarget || next->GetZview()>=zTarget;
4258 #endif
4259
4260 if(!done && this->ZBuffer!=nullptr)
4261 {
4262 // value of the z buffer at the current pixel.
4263 zBuffer=this->GetZBufferValue(x,y);
4264 }
4265
4266 while(!done)
4267 {
4268 if (current->GetExitFace())
4269 {
4270 // Do not do the integration if the current face is an exit face.
4271 // The space between current and next should be empty.
4272 doIntegration = 0;
4273 }
4274 else
4275 {
4276 if(this->ZBuffer!=nullptr)
4277 {
4278 // check that current and next are in front of the z-buffer value
4279 doIntegration=current->GetZview()<zBuffer
4280 && next->GetZview()<zBuffer;
4281 }
4282 else
4283 {
4284 doIntegration=1;
4285 }
4286 }
4287
4288 if(doIntegration)
4289 {
4290 if(current->GetZview()!=next->GetZview())
4291 {
4292 // length in world coordinates
4293 length=sqrt(vtkMath::Distance2BetweenPoints(
4294 current->GetValues(),next->GetValues()));
4295 if(length!=0)
4296 // if(length>=0.4)
4297 {
4298 color=this->RealRGBAImage+index2;
4299 this->IntersectionLengths->SetValue(0,length);
4300
4301 if(this->CellScalars)
4302 {
4303 // same value for near and far intersection
4304 this->NearIntersections->SetValue(0,current->GetValues()[VTK_VALUES_SCALAR_INDEX]);
4305 this->FarIntersections->SetValue(0,current->GetValues()[VTK_VALUES_SCALAR_INDEX]);
4306 }
4307 else
4308 {
4309 this->NearIntersections->SetValue(0,current->GetValues()[VTK_VALUES_SCALAR_INDEX]);
4310 this->FarIntersections->SetValue(0,next->GetValues()[VTK_VALUES_SCALAR_INDEX]);
4311 }
4312 #ifdef BACK_TO_FRONT
4313 this->RealRayIntegrator->Integrate(this->IntersectionLengths,
4314 this->FarIntersections,
4315 this->NearIntersections,
4316 color);
4317 #else
4318 this->RealRayIntegrator->Integrate(this->IntersectionLengths,
4319 this->NearIntersections,
4320 this->FarIntersections,
4321 color);
4322 #endif
4323 } // length!=0
4324 } // current->GetZview()!=next->GetZview()
4325 } // doIntegration
4326
4327 // Next entry
4328 pixel->RemoveFirst(this->MemoryManager); // remove current
4329 done=pixel->GetSize()<2; // empty queue?
4330 if(!done)
4331 {
4332 current=next;
4333 next=current->GetNext();
4334 #ifdef BACK_TO_FRONT
4335 done=next->GetZview()<=zTarget;
4336 #else
4337 done=next->GetZview()>=zTarget;
4338 #endif
4339 }
4340 } // while(!done)
4341 }
4342 if(pixel->GetSize()>=2)
4343 {
4344 if(x<newXBounds[0])
4345 {
4346 newXBounds[0]=x;
4347 }
4348 else
4349 {
4350 if(x>newXBounds[1])
4351 {
4352 newXBounds[1]=x;
4353 }
4354 }
4355 if(y<newYBounds[0])
4356 {
4357 newYBounds[0]=y;
4358 }
4359 else
4360 {
4361 if(y>newYBounds[1])
4362 {
4363 newYBounds[1]=y;
4364 }
4365 }
4366 }
4367
4368 // next abscissa
4369 ++j;
4370 index2+=4;
4371 ++x;
4372 }
4373 // next ordinate
4374 i=i+this->ImageInUseSize[0];
4375 index+=indexStep;
4376 ++y;
4377 }
4378
4379 // Update the bounding box. Useful for the delayed compositing
4380
4381 this->XBounds[0]=newXBounds[0];
4382 this->XBounds[1]=newXBounds[1];
4383 this->YBounds[0]=newYBounds[0];
4384 this->YBounds[1]=newYBounds[1];
4385
4386 this->MaxPixelListSizeReached=0;
4387 }
4388
4389 //-----------------------------------------------------------------------------
4390 // Description:
4391 // Convert and clamp a float color component into an unsigned char.
ColorComponentRealToByte(float color)4392 unsigned char vtkUnstructuredGridVolumeZSweepMapper::ColorComponentRealToByte(
4393 float color)
4394 {
4395 int val=static_cast<int>(color*255.0);
4396 if(val>255)
4397 {
4398 val=255;
4399 }
4400 else
4401 {
4402 if(val<0)
4403 {
4404 val=0;
4405 }
4406 }
4407 return static_cast<unsigned char>(val);
4408 }
4409
4410 //-----------------------------------------------------------------------------
GetZBufferValue(int x,int y)4411 double vtkUnstructuredGridVolumeZSweepMapper::GetZBufferValue(int x,
4412 int y)
4413 {
4414 int xPos, yPos;
4415
4416 xPos = static_cast<int>(static_cast<float>(x) * this->ImageSampleDistance);
4417 yPos = static_cast<int>(static_cast<float>(y) * this->ImageSampleDistance);
4418
4419 xPos = (xPos >= this->ZBufferSize[0])?(this->ZBufferSize[0]-1):(xPos);
4420 yPos = (yPos >= this->ZBufferSize[1])?(this->ZBufferSize[1]-1):(yPos);
4421
4422 return *(this->ZBuffer + yPos*this->ZBufferSize[0] + xPos);
4423 }
4424
4425 //-----------------------------------------------------------------------------
GetMinimumBoundsDepth(vtkRenderer * ren,vtkVolume * vol)4426 double vtkUnstructuredGridVolumeZSweepMapper::GetMinimumBoundsDepth(
4427 vtkRenderer *ren,
4428 vtkVolume *vol )
4429 {
4430 double bounds[6];
4431 vol->GetBounds( bounds );
4432
4433 ren->ComputeAspect();
4434 double *aspect = ren->GetAspect();
4435
4436 // Get the view matrix in two steps - there is a one step method in camera
4437 // but it turns off stereo so we do not want to use that one
4438 vtkCamera *cam = ren->GetActiveCamera();
4439 this->PerspectiveTransform->Identity();
4440 this->PerspectiveTransform->Concatenate(
4441 cam->GetProjectionTransformMatrix(aspect[0]/aspect[1], 0.0, 1.0 ));
4442 this->PerspectiveTransform->Concatenate(cam->GetViewTransformMatrix());
4443 this->PerspectiveMatrix->DeepCopy(this->PerspectiveTransform->GetMatrix());
4444
4445 double minZ = 1.0;
4446
4447 for ( int k = 0; k < 2; k++ )
4448 {
4449 for ( int j = 0; j < 2; j++ )
4450 {
4451 for ( int i = 0; i < 2; i++ )
4452 {
4453 double inPoint[4];
4454 inPoint[0] = bounds[ i];
4455 inPoint[1] = bounds[2+j];
4456 inPoint[2] = bounds[4+k];
4457 inPoint[3] = 1.0;
4458
4459 double outPoint[4];
4460 this->PerspectiveMatrix->MultiplyPoint( inPoint, outPoint );
4461 double testZ = outPoint[2] / outPoint[3];
4462 minZ = ( testZ < minZ ) ? (testZ) : (minZ);
4463 }
4464 }
4465 }
4466
4467 return minZ;
4468 }
4469