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