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