1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkTensorGlyph.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 "vtkTensorGlyph.h"
16 
17 #include "vtkCell.h"
18 #include "vtkCellArray.h"
19 #include "vtkDataSet.h"
20 #include "vtkExecutive.h"
21 #include "vtkFloatArray.h"
22 #include "vtkInformation.h"
23 #include "vtkInformationVector.h"
24 #include "vtkMath.h"
25 #include "vtkObjectFactory.h"
26 #include "vtkPointData.h"
27 #include "vtkPolyData.h"
28 #include "vtkStreamingDemandDrivenPipeline.h"
29 #include "vtkTransform.h"
30 
31 vtkStandardNewMacro(vtkTensorGlyph);
32 
33 //------------------------------------------------------------------------------
34 // Construct object with scaling on and scale factor 1.0. Eigenvalues are
35 // extracted, glyphs are colored with input scalar data, and logarithmic
36 // scaling is turned off.
vtkTensorGlyph()37 vtkTensorGlyph::vtkTensorGlyph()
38 {
39   this->Scaling = 1;
40   this->ScaleFactor = 1.0;
41   this->ExtractEigenvalues = 1;
42   this->ColorGlyphs = 1;
43   this->ColorMode = COLOR_BY_SCALARS;
44   this->ClampScaling = 0;
45   this->MaxScaleFactor = 100;
46   this->ThreeGlyphs = 0;
47   this->Symmetric = 0;
48   this->Length = 1.0;
49 
50   this->SetNumberOfInputPorts(2);
51 
52   // by default, process active point tensors
53   this->SetInputArrayToProcess(
54     0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::TENSORS);
55 
56   // by default, process active point scalars
57   this->SetInputArrayToProcess(
58     1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS);
59 }
60 
61 //------------------------------------------------------------------------------
62 vtkTensorGlyph::~vtkTensorGlyph() = default;
63 
64 //------------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)65 int vtkTensorGlyph::RequestUpdateExtent(vtkInformation* vtkNotUsed(request),
66   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
67 {
68   // get the info objects
69   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
70   vtkInformation* sourceInfo = inputVector[1]->GetInformationObject(0);
71   vtkInformation* outInfo = outputVector->GetInformationObject(0);
72 
73   if (sourceInfo)
74   {
75     sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), 0);
76     sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), 1);
77     sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), 0);
78   }
79 
80   inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(),
81     outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()));
82   inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(),
83     outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()));
84   inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(),
85     outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS()));
86   inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);
87 
88   return 1;
89 }
90 
91 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)92 int vtkTensorGlyph::RequestData(vtkInformation* vtkNotUsed(request),
93   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
94 {
95   // get the info objects
96   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
97   vtkInformation* sourceInfo = inputVector[1]->GetInformationObject(0);
98   vtkInformation* outInfo = outputVector->GetInformationObject(0);
99 
100   // get the input and output
101   vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
102   vtkPolyData* source = vtkPolyData::SafeDownCast(sourceInfo->Get(vtkDataObject::DATA_OBJECT()));
103   vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
104 
105   vtkDataArray* inTensors;
106   double tensor[9];
107   vtkDataArray* inScalars;
108   vtkIdType numPts, numSourcePts, numSourceCells, inPtId, i;
109   int j;
110   vtkPoints* sourcePts;
111   vtkDataArray* sourceNormals;
112   vtkCellArray *sourceCells, *cells;
113   vtkPoints* newPts;
114   vtkFloatArray* newScalars = nullptr;
115   vtkFloatArray* newNormals = nullptr;
116   double x[3], s;
117   vtkTransform* trans;
118   vtkCell* cell;
119   vtkIdList* cellPts;
120   int npts;
121   vtkIdType* pts;
122   vtkIdType ptIncr, cellId;
123   vtkIdType subIncr;
124   int numDirs, dir, eigen_dir, symmetric_dir;
125   vtkMatrix4x4* matrix;
126   double *m[3], w[3], *v[3];
127   double m0[3], m1[3], m2[3];
128   double v0[3], v1[3], v2[3];
129   double xv[3], yv[3], zv[3];
130   double maxScale;
131 
132   numDirs = (this->ThreeGlyphs ? 3 : 1) * (this->Symmetric + 1);
133 
134   // set up working matrices
135   m[0] = m0;
136   m[1] = m1;
137   m[2] = m2;
138   v[0] = v0;
139   v[1] = v1;
140   v[2] = v2;
141 
142   vtkDebugMacro(<< "Generating tensor glyphs");
143 
144   vtkPointData* outPD = output->GetPointData();
145   inTensors = this->GetInputArrayToProcess(0, inputVector);
146   inScalars = this->GetInputArrayToProcess(1, inputVector);
147   numPts = input->GetNumberOfPoints();
148 
149   if (!inTensors || numPts < 1)
150   {
151     vtkErrorMacro(<< "No data to glyph!");
152     return 1;
153   }
154 
155   pts = new vtkIdType[source->GetMaxCellSize()];
156   trans = vtkTransform::New();
157   matrix = vtkMatrix4x4::New();
158 
159   //
160   // Allocate storage for output PolyData
161   //
162   sourcePts = source->GetPoints();
163   numSourcePts = sourcePts->GetNumberOfPoints();
164   numSourceCells = source->GetNumberOfCells();
165 
166   newPts = vtkPoints::New();
167   newPts->Allocate(numDirs * numPts * numSourcePts);
168 
169   // Setting up for calls to PolyData::InsertNextCell()
170   if ((sourceCells = source->GetVerts())->GetNumberOfCells() > 0)
171   {
172     cells = vtkCellArray::New();
173     cells->AllocateEstimate(sourceCells->GetNumberOfCells(), numDirs * numPts);
174     output->SetVerts(cells);
175     cells->Delete();
176   }
177   if ((sourceCells = this->GetSource()->GetLines())->GetNumberOfCells() > 0)
178   {
179     cells = vtkCellArray::New();
180     cells->AllocateEstimate(sourceCells->GetNumberOfCells(), numDirs * numPts);
181     output->SetLines(cells);
182     cells->Delete();
183   }
184   if ((sourceCells = this->GetSource()->GetPolys())->GetNumberOfCells() > 0)
185   {
186     cells = vtkCellArray::New();
187     cells->AllocateEstimate(sourceCells->GetNumberOfCells(), numDirs * numPts);
188     output->SetPolys(cells);
189     cells->Delete();
190   }
191   if ((sourceCells = this->GetSource()->GetStrips())->GetNumberOfCells() > 0)
192   {
193     cells = vtkCellArray::New();
194     cells->AllocateEstimate(sourceCells->GetNumberOfCells(), numDirs * numPts);
195     output->SetStrips(cells);
196     cells->Delete();
197   }
198 
199   // only copy scalar data through
200   vtkPointData* pd = this->GetSource()->GetPointData();
201   // generate scalars if eigenvalues are chosen or if scalars exist.
202   if (this->ColorGlyphs &&
203     ((this->ColorMode == COLOR_BY_EIGENVALUES) ||
204       (inScalars && (this->ColorMode == COLOR_BY_SCALARS))))
205   {
206     newScalars = vtkFloatArray::New();
207     newScalars->Allocate(numDirs * numPts * numSourcePts);
208     if (this->ColorMode == COLOR_BY_EIGENVALUES)
209     {
210       newScalars->SetName("MaxEigenvalue");
211     }
212     else
213     {
214       newScalars->SetName(inScalars->GetName());
215     }
216   }
217   else
218   {
219     outPD->CopyAllOff();
220     outPD->CopyScalarsOn();
221     outPD->CopyAllocate(pd, numDirs * numPts * numSourcePts);
222   }
223   if ((sourceNormals = pd->GetNormals()))
224   {
225     newNormals = vtkFloatArray::New();
226     newNormals->SetNumberOfComponents(3);
227     newNormals->SetName("Normals");
228     newNormals->Allocate(numDirs * 3 * numPts * numSourcePts);
229   }
230   //
231   // First copy all topology (transformation independent)
232   //
233   for (inPtId = 0; inPtId < numPts; inPtId++)
234   {
235     ptIncr = numDirs * inPtId * numSourcePts;
236     for (cellId = 0; cellId < numSourceCells; cellId++)
237     {
238       cell = this->GetSource()->GetCell(cellId);
239       cellPts = cell->GetPointIds();
240       npts = cellPts->GetNumberOfIds();
241       for (dir = 0; dir < numDirs; dir++)
242       {
243         // This variable may be removed, but that
244         // will not improve readability
245         subIncr = ptIncr + dir * numSourcePts;
246         for (i = 0; i < npts; i++)
247         {
248           pts[i] = cellPts->GetId(i) + subIncr;
249         }
250         output->InsertNextCell(cell->GetCellType(), npts, pts);
251       }
252     }
253   }
254   //
255   // Traverse all Input points, transforming glyph at Source points
256   //
257   trans->PreMultiply();
258 
259   for (inPtId = 0; inPtId < numPts; inPtId++)
260   {
261     ptIncr = numDirs * inPtId * numSourcePts;
262 
263     // Translation is postponed
264     // Symmetric tensor support
265     inTensors->GetTuple(inPtId, tensor);
266     if (inTensors->GetNumberOfComponents() == 6)
267     {
268       vtkMath::TensorFromSymmetricTensor(tensor);
269     }
270 
271     // compute orientation vectors and scale factors from tensor
272     if (this->ExtractEigenvalues) // extract appropriate eigenfunctions
273     {
274       // We are interested in the symmetrical part of the tensor only, since
275       // eigenvalues are real if and only if the matrice of reals is symmetrical
276       for (j = 0; j < 3; j++)
277       {
278         for (i = 0; i < 3; i++)
279         {
280           m[i][j] = 0.5 * (tensor[i + 3 * j] + tensor[j + 3 * i]);
281         }
282       }
283       vtkMath::Jacobi(m, w, v);
284 
285       // copy eigenvectors
286       xv[0] = v[0][0];
287       xv[1] = v[1][0];
288       xv[2] = v[2][0];
289       yv[0] = v[0][1];
290       yv[1] = v[1][1];
291       yv[2] = v[2][1];
292       zv[0] = v[0][2];
293       zv[1] = v[1][2];
294       zv[2] = v[2][2];
295     }
296     else // use tensor columns as eigenvectors
297     {
298       for (i = 0; i < 3; i++)
299       {
300         xv[i] = tensor[i];
301         yv[i] = tensor[i + 3];
302         zv[i] = tensor[i + 6];
303       }
304       w[0] = vtkMath::Normalize(xv);
305       w[1] = vtkMath::Normalize(yv);
306       w[2] = vtkMath::Normalize(zv);
307     }
308 
309     // compute scale factors
310     w[0] *= this->ScaleFactor;
311     w[1] *= this->ScaleFactor;
312     w[2] *= this->ScaleFactor;
313 
314     if (this->ClampScaling)
315     {
316       for (maxScale = 0.0, i = 0; i < 3; i++)
317       {
318         if (maxScale < fabs(w[i]))
319         {
320           maxScale = fabs(w[i]);
321         }
322       }
323       if (maxScale > this->MaxScaleFactor)
324       {
325         maxScale = this->MaxScaleFactor / maxScale;
326         for (i = 0; i < 3; i++)
327         {
328           w[i] *= maxScale; // preserve overall shape of glyph
329         }
330       }
331     }
332 
333     // normalization is postponed
334 
335     // make sure scale is okay (non-zero) and scale data
336     for (maxScale = 0.0, i = 0; i < 3; i++)
337     {
338       if (w[i] > maxScale)
339       {
340         maxScale = w[i];
341       }
342     }
343     if (maxScale == 0.0)
344     {
345       maxScale = 1.0;
346     }
347     for (i = 0; i < 3; i++)
348     {
349       if (w[i] == 0.0)
350       {
351         w[i] = maxScale * 1.0e-06;
352       }
353     }
354 
355     // Now do the real work for each "direction"
356 
357     for (dir = 0; dir < numDirs; dir++)
358     {
359       eigen_dir = dir % (this->ThreeGlyphs ? 3 : 1);
360       symmetric_dir = dir / (this->ThreeGlyphs ? 3 : 1);
361 
362       // Remove previous scales ...
363       trans->Identity();
364 
365       // translate Source to Input point
366       input->GetPoint(inPtId, x);
367       trans->Translate(x[0], x[1], x[2]);
368 
369       // normalized eigenvectors rotate object for eigen direction 0
370       matrix->Element[0][0] = xv[0];
371       matrix->Element[0][1] = yv[0];
372       matrix->Element[0][2] = zv[0];
373       matrix->Element[1][0] = xv[1];
374       matrix->Element[1][1] = yv[1];
375       matrix->Element[1][2] = zv[1];
376       matrix->Element[2][0] = xv[2];
377       matrix->Element[2][1] = yv[2];
378       matrix->Element[2][2] = zv[2];
379       trans->Concatenate(matrix);
380 
381       if (eigen_dir == 1)
382       {
383         trans->RotateZ(90.0);
384       }
385 
386       if (eigen_dir == 2)
387       {
388         trans->RotateY(-90.0);
389       }
390 
391       if (this->ThreeGlyphs)
392       {
393         trans->Scale(w[eigen_dir], this->ScaleFactor, this->ScaleFactor);
394       }
395       else
396       {
397         trans->Scale(w[0], w[1], w[2]);
398       }
399 
400       // Mirror second set to the symmetric position
401       if (symmetric_dir == 1)
402       {
403         trans->Scale(-1., 1., 1.);
404       }
405 
406       // if the eigenvalue is negative, shift to reverse direction.
407       // The && is there to ensure that we do not change the
408       // old behaviour of vtkTensorGlyphs (which only used one dir),
409       // in case there is an oriented glyph, e.g. an arrow.
410       if (w[eigen_dir] < 0 && numDirs > 1)
411       {
412         trans->Translate(-this->Length, 0., 0.);
413       }
414 
415       // multiply points (and normals if available) by resulting
416       // matrix
417       trans->TransformPoints(sourcePts, newPts);
418 
419       // Apply the transformation to a series of points,
420       // and append the results to outPts.
421       if (newNormals)
422       {
423         // a negative determinant means the transform turns the
424         // glyph surface inside out, and its surface normals all
425         // point inward. The following scale corrects the surface
426         // normals to point outward.
427         if (trans->GetMatrix()->Determinant() < 0)
428         {
429           trans->Scale(-1.0, -1.0, -1.0);
430         }
431         trans->TransformNormals(sourceNormals, newNormals);
432       }
433 
434       // Copy point data from source
435       if (this->ColorGlyphs && inScalars && (this->ColorMode == COLOR_BY_SCALARS))
436       {
437         s = inScalars->GetComponent(inPtId, 0);
438         for (i = 0; i < numSourcePts; i++)
439         {
440           newScalars->InsertTuple(ptIncr + i, &s);
441         }
442       }
443       else if (this->ColorGlyphs && (this->ColorMode == COLOR_BY_EIGENVALUES))
444       {
445         // If ThreeGlyphs is false we use the first (largest)
446         // eigenvalue as scalar.
447         s = w[eigen_dir];
448         for (i = 0; i < numSourcePts; i++)
449         {
450           newScalars->InsertTuple(ptIncr + i, &s);
451         }
452       }
453       else
454       {
455         for (i = 0; i < numSourcePts; i++)
456         {
457           outPD->CopyData(pd, i, ptIncr + i);
458         }
459       }
460       ptIncr += numSourcePts;
461     }
462   }
463   vtkDebugMacro(<< "Generated " << numPts << " tensor glyphs");
464   //
465   // Update output and release memory
466   //
467   delete[] pts;
468 
469   output->SetPoints(newPts);
470   newPts->Delete();
471 
472   if (newScalars)
473   {
474     int idx = outPD->AddArray(newScalars);
475     outPD->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
476     newScalars->Delete();
477   }
478 
479   if (newNormals)
480   {
481     outPD->SetNormals(newNormals);
482     newNormals->Delete();
483   }
484 
485   output->Squeeze();
486   trans->Delete();
487   matrix->Delete();
488 
489   return 1;
490 }
491 
492 //------------------------------------------------------------------------------
SetSourceConnection(int id,vtkAlgorithmOutput * algOutput)493 void vtkTensorGlyph::SetSourceConnection(int id, vtkAlgorithmOutput* algOutput)
494 {
495   if (id < 0)
496   {
497     vtkErrorMacro("Bad index " << id << " for source.");
498     return;
499   }
500 
501   int numConnections = this->GetNumberOfInputConnections(1);
502   if (id < numConnections)
503   {
504     this->SetNthInputConnection(1, id, algOutput);
505   }
506   else if (id == numConnections && algOutput)
507   {
508     this->AddInputConnection(1, algOutput);
509   }
510   else if (algOutput)
511   {
512     vtkWarningMacro("The source id provided is larger than the maximum "
513                     "source id, using "
514       << numConnections << " instead.");
515     this->AddInputConnection(1, algOutput);
516   }
517 }
518 
519 //------------------------------------------------------------------------------
SetSourceData(vtkPolyData * source)520 void vtkTensorGlyph::SetSourceData(vtkPolyData* source)
521 {
522   this->SetInputData(1, source);
523 }
524 
525 //------------------------------------------------------------------------------
GetSource()526 vtkPolyData* vtkTensorGlyph::GetSource()
527 {
528   if (this->GetNumberOfInputConnections(1) < 1)
529   {
530     return nullptr;
531   }
532   return vtkPolyData::SafeDownCast(this->GetExecutive()->GetInputData(1, 0));
533 }
534 
535 //------------------------------------------------------------------------------
FillInputPortInformation(int port,vtkInformation * info)536 int vtkTensorGlyph::FillInputPortInformation(int port, vtkInformation* info)
537 {
538   if (port == 1)
539   {
540     info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
541     return 1;
542   }
543   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
544   return 1;
545 }
546 
547 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)548 void vtkTensorGlyph::PrintSelf(ostream& os, vtkIndent indent)
549 {
550   this->Superclass::PrintSelf(os, indent);
551 
552   os << indent << "Source: " << this->GetSource() << "\n";
553   os << indent << "Scaling: " << (this->Scaling ? "On\n" : "Off\n");
554   os << indent << "Scale Factor: " << this->ScaleFactor << "\n";
555   os << indent << "Extract Eigenvalues: " << (this->ExtractEigenvalues ? "On\n" : "Off\n");
556   os << indent << "Color Glyphs: " << (this->ColorGlyphs ? "On\n" : "Off\n");
557   os << indent << "Color Mode: " << this->ColorMode << endl;
558   os << indent << "Clamp Scaling: " << (this->ClampScaling ? "On\n" : "Off\n");
559   os << indent << "Max Scale Factor: " << this->MaxScaleFactor << "\n";
560   os << indent << "Three Glyphs: " << (this->ThreeGlyphs ? "On\n" : "Off\n");
561   os << indent << "Symmetric: " << (this->Symmetric ? "On\n" : "Off\n");
562   os << indent << "Length: " << this->Length << "\n";
563 }
564