]> Creatis software - clitk.git/blob - vv/vvGlyph2D.cxx
Initial revision
[clitk.git] / vv / vvGlyph2D.cxx
1 /*=========================================================================
2
3  Program:   vv
4  Module:    $RCSfile: vvGlyph2D.cxx,v $
5  Language:  C++
6  Date:      $Date: 2010/01/06 13:31:57 $
7  Version:   $Revision: 1.1 $
8  Author :   Pierre Seroul (pierre.seroul@gmail.com)
9
10 Copyright (C) 2008
11 Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr
12 CREATIS-LRMN http://www.creatis.insa-lyon.fr
13
14 This program is free software: you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation, version 3 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
26 =========================================================================*/
27 #include "vvGlyph2D.h"
28
29 #include "vtkCell.h"
30 #include "vtkDataSet.h"
31 #include "vtkFloatArray.h"
32 #include "vtkIdList.h"
33 #include "vtkIdTypeArray.h"
34 #include "vtkInformation.h"
35 #include "vtkInformationVector.h"
36 #include "vtkMath.h"
37 #include "vtkObjectFactory.h"
38 #include "vtkPointData.h"
39 #include "vtkPolyData.h"
40 #include "vtkStreamingDemandDrivenPipeline.h"
41 #include "vtkTransform.h"
42 #include "vtkUnsignedCharArray.h"
43
44 vtkCxxRevisionMacro(vvGlyph2D, "$Revision: 1.1 $");
45 vtkStandardNewMacro(vvGlyph2D);
46
47 vvGlyph2D::vvGlyph2D()
48 {
49     mOrientation[0] = 1;
50     mOrientation[1] = 1;
51     mOrientation[2] = 1;
52     mUseLog = 0;
53 }
54
55 //----------------------------------------------------------------------------
56 int vvGlyph2D::RequestData(
57     vtkInformation *vtkNotUsed(request),
58     vtkInformationVector **inputVector,
59     vtkInformationVector *outputVector)
60 {
61     // get the info objects
62     vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
63     vtkInformation *outInfo = outputVector->GetInformationObject(0);
64
65     // get the input and ouptut
66     vtkDataSet *input = vtkDataSet::SafeDownCast(
67                             inInfo->Get(vtkDataObject::DATA_OBJECT()));
68     vtkPolyData *output = vtkPolyData::SafeDownCast(
69                               outInfo->Get(vtkDataObject::DATA_OBJECT()));
70
71     vtkPointData *pd;
72     vtkDataArray *inSScalars; // Scalars for Scaling
73     vtkDataArray *inCScalars; // Scalars for Coloring
74     vtkDataArray *inVectors;
75     int requestedGhostLevel;
76     unsigned char* inGhostLevels=0;
77     vtkDataArray *inNormals, *sourceNormals = NULL;
78     vtkDataArray *sourceTCoords = NULL;
79     vtkIdType numPts, numSourcePts, numSourceCells, inPtId, i;
80     int index;
81     vtkPoints *sourcePts = NULL;
82     vtkPoints *newPts;
83     vtkDataArray *newScalars=NULL;
84     vtkDataArray *newVectors=NULL;
85     vtkDataArray *newNormals=NULL;
86     vtkDataArray *newTCoords = NULL;
87     double x[3], v[3], vNew[3], s = 0.0, vMag = 0.0, value, tc[3];
88     vtkTransform *trans = vtkTransform::New();
89     vtkCell *cell;
90     vtkIdList *cellPts;
91     int npts;
92     vtkIdList *pts;
93     vtkIdType ptIncr, cellId;
94     int haveVectors, haveNormals, haveTCoords = 0;
95     double scalex,scaley,scalez, den;
96     vtkPointData *outputPD = output->GetPointData();
97     int numberOfSources = this->GetNumberOfInputConnections(1);
98     vtkPolyData *defaultSource = NULL;
99     vtkIdTypeArray *pointIds=0;
100     vtkPolyData *source = 0;
101
102     vtkDebugMacro(<<"Generating glyphs");
103
104     pts = vtkIdList::New();
105     pts->Allocate(VTK_CELL_SIZE);
106
107     pd = input->GetPointData();
108     inSScalars = this->GetInputArrayToProcess(0,inputVector);
109     inVectors = this->GetInputArrayToProcess(1,inputVector);
110     inNormals = this->GetInputArrayToProcess(2,inputVector);
111     inCScalars = this->GetInputArrayToProcess(3,inputVector);
112     if (inCScalars == NULL)
113     {
114         inCScalars = inSScalars;
115     }
116
117     vtkDataArray* temp = 0;
118     if (pd)
119     {
120         temp = pd->GetArray("vtkGhostLevels");
121     }
122     if ( (!temp) || (temp->GetDataType() != VTK_UNSIGNED_CHAR)
123             || (temp->GetNumberOfComponents() != 1))
124     {
125         vtkDebugMacro("No appropriate ghost levels field available.");
126     }
127     else
128     {
129         inGhostLevels = ((vtkUnsignedCharArray*)temp)->GetPointer(0);
130     }
131
132     requestedGhostLevel =
133         outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS());
134
135     numPts = input->GetNumberOfPoints();
136     if (numPts < 1)
137     {
138         vtkDebugMacro(<<"No points to glyph!");
139         pts->Delete();
140         trans->Delete();
141         return 1;
142     }
143
144     // Check input for consistency
145     //
146     if ( (den = this->Range[1] - this->Range[0]) == 0.0 )
147     {
148         den = 1.0;
149     }
150     if ( this->VectorMode != VTK_VECTOR_ROTATION_OFF &&
151             ((this->VectorMode == VTK_USE_VECTOR && inVectors != NULL) ||
152              (this->VectorMode == VTK_USE_NORMAL && inNormals != NULL)) )
153     {
154         haveVectors = 1;
155     }
156     else
157     {
158         haveVectors = 0;
159     }
160
161     if ( (this->IndexMode == VTK_INDEXING_BY_SCALAR && !inSScalars) ||
162             (this->IndexMode == VTK_INDEXING_BY_VECTOR &&
163              ((!inVectors && this->VectorMode == VTK_USE_VECTOR) ||
164               (!inNormals && this->VectorMode == VTK_USE_NORMAL))) )
165     {
166         if ( this->GetSource(0, inputVector[1]) == NULL )
167         {
168             vtkErrorMacro(<<"Indexing on but don't have data to index with");
169             pts->Delete();
170             trans->Delete();
171             return 1;
172         }
173         else
174         {
175             vtkWarningMacro(<<"Turning indexing off: no data to index with");
176             this->IndexMode = VTK_INDEXING_OFF;
177         }
178     }
179
180     // Allocate storage for output PolyData
181     //
182     outputPD->CopyVectorsOff();
183     outputPD->CopyNormalsOff();
184     outputPD->CopyTCoordsOff();
185
186     if (!this->GetSource(0, inputVector[1]))
187     {
188         defaultSource = vtkPolyData::New();
189         defaultSource->Allocate();
190         vtkPoints *defaultPoints = vtkPoints::New();
191         defaultPoints->Allocate(6);
192         defaultPoints->InsertNextPoint(0, 0, 0);
193         defaultPoints->InsertNextPoint(1, 0, 0);
194         vtkIdType defaultPointIds[2];
195         defaultPointIds[0] = 0;
196         defaultPointIds[1] = 1;
197         defaultSource->SetPoints(defaultPoints);
198         defaultSource->InsertNextCell(VTK_LINE, 2, defaultPointIds);
199         defaultSource->SetUpdateExtent(0, 1, 0);
200         this->SetSource(defaultSource);
201         defaultSource->Delete();
202         defaultSource = NULL;
203         defaultPoints->Delete();
204         defaultPoints = NULL;
205     }
206
207     if ( this->IndexMode != VTK_INDEXING_OFF )
208     {
209         pd = NULL;
210         haveNormals = 1;
211         for (numSourcePts=numSourceCells=i=0; i < numberOfSources; i++)
212         {
213             source = this->GetSource(i, inputVector[1]);
214             if ( source != NULL )
215             {
216                 if (source->GetNumberOfPoints() > numSourcePts)
217                 {
218                     numSourcePts = source->GetNumberOfPoints();
219                 }
220                 if (source->GetNumberOfCells() > numSourceCells)
221                 {
222                     numSourceCells = source->GetNumberOfCells();
223                 }
224                 if ( !(sourceNormals = source->GetPointData()->GetNormals()) )
225                 {
226                     haveNormals = 0;
227                 }
228             }
229         }
230     }
231     else
232     {
233         source = this->GetSource(0, inputVector[1]);
234         sourcePts = source->GetPoints();
235         numSourcePts = sourcePts->GetNumberOfPoints();
236         numSourceCells = source->GetNumberOfCells();
237
238         sourceNormals = source->GetPointData()->GetNormals();
239         if ( sourceNormals )
240         {
241             haveNormals = 1;
242         }
243         else
244         {
245             haveNormals = 0;
246         }
247
248         sourceTCoords = source->GetPointData()->GetTCoords();
249         if (sourceTCoords)
250         {
251             haveTCoords = 1;
252         }
253         else
254         {
255             haveTCoords = 0;
256         }
257
258         // Prepare to copy output.
259         pd = input->GetPointData();
260         outputPD->CopyAllocate(pd,numPts*numSourcePts);
261     }
262
263     newPts = vtkPoints::New();
264     newPts->Allocate(numPts*numSourcePts);
265     if ( this->GeneratePointIds )
266     {
267         pointIds = vtkIdTypeArray::New();
268         pointIds->SetName(this->PointIdsName);
269         pointIds->Allocate(numPts*numSourcePts);
270         outputPD->AddArray(pointIds);
271         pointIds->Delete();
272     }
273     if ( this->ColorMode == VTK_COLOR_BY_SCALAR && inCScalars )
274     {
275         newScalars = inCScalars->NewInstance();
276         newScalars->SetNumberOfComponents(inCScalars->GetNumberOfComponents());
277         newScalars->Allocate(inCScalars->GetNumberOfComponents()*numPts*numSourcePts);
278         newScalars->SetName(inCScalars->GetName());
279     }
280     else if ( (this->ColorMode == VTK_COLOR_BY_SCALE) && inSScalars)
281     {
282         newScalars = vtkFloatArray::New();
283         newScalars->Allocate(numPts*numSourcePts);
284         newScalars->SetName("GlyphScale");
285         if (this->ScaleMode == VTK_SCALE_BY_SCALAR)
286         {
287             newScalars->SetName(inSScalars->GetName());
288         }
289     }
290     else if ( (this->ColorMode == VTK_COLOR_BY_VECTOR) && haveVectors)
291     {
292         newScalars = vtkFloatArray::New();
293         newScalars->Allocate(numPts*numSourcePts);
294         newScalars->SetName("VectorMagnitude");
295     }
296     if ( haveVectors )
297     {
298         newVectors = vtkFloatArray::New();
299         newVectors->SetNumberOfComponents(3);
300         newVectors->Allocate(3*numPts*numSourcePts);
301         newVectors->SetName("GlyphVector");
302     }
303     if ( haveNormals )
304     {
305         newNormals = vtkFloatArray::New();
306         newNormals->SetNumberOfComponents(3);
307         newNormals->Allocate(3*numPts*numSourcePts);
308         newNormals->SetName("Normals");
309     }
310     if (haveTCoords)
311     {
312         newTCoords = vtkFloatArray::New();
313         int numComps = sourceTCoords->GetNumberOfComponents();
314         newTCoords->SetNumberOfComponents(numComps);
315         newTCoords->Allocate(numComps*numPts*numSourcePts);
316         newTCoords->SetName("TCoords");
317     }
318
319     // Setting up for calls to PolyData::InsertNextCell()
320     if (this->IndexMode != VTK_INDEXING_OFF )
321     {
322         output->Allocate(3*numPts*numSourceCells,numPts*numSourceCells);
323     }
324     else
325     {
326         output->Allocate(this->GetSource(0, inputVector[1]),
327                          3*numPts*numSourceCells, numPts*numSourceCells);
328     }
329
330     // Traverse all Input points, transforming Source points and copying
331     // point attributes.
332     //
333     ptIncr=0;
334     for (inPtId=0; inPtId < numPts; inPtId++)
335     {
336         scalex = scaley = scalez = 1.0;
337         if ( ! (inPtId % 10000) )
338         {
339             this->UpdateProgress ((double)inPtId/numPts);
340             if (this->GetAbortExecute())
341             {
342                 break;
343             }
344         }
345
346         // Get the scalar and vector data
347         if ( inSScalars )
348         {
349             s = inSScalars->GetComponent(inPtId, 0);
350             if ( this->ScaleMode == VTK_SCALE_BY_SCALAR ||
351                     this->ScaleMode == VTK_DATA_SCALING_OFF )
352             {
353                 scalex = scaley = scalez = s;
354             }
355         }
356
357         if ( haveVectors )
358         {
359             if ( this->VectorMode == VTK_USE_NORMAL )
360             {
361                 inNormals->GetTuple(inPtId, v);
362             }
363             else
364             {
365                 inVectors->GetTuple(inPtId, v);
366             }
367
368             vMag = vtkMath::Norm(v);
369             if ( this->ScaleMode == VTK_SCALE_BY_VECTORCOMPONENTS )
370             {
371                 scalex = v[0];
372                 scaley = v[1];
373                 scalez = v[2];
374             }
375             else if ( this->ScaleMode == VTK_SCALE_BY_VECTOR )
376             {
377                 scalex = scaley = scalez = vMag;
378             }
379         }
380
381         // Clamp data scale if enabled
382         if ( this->Clamping )
383         {
384             scalex = (scalex < this->Range[0] ? this->Range[0] :
385                       (scalex > this->Range[1] ? this->Range[1] : scalex));
386             scalex = (scalex - this->Range[0]) / den;
387             scaley = (scaley < this->Range[0] ? this->Range[0] :
388                       (scaley > this->Range[1] ? this->Range[1] : scaley));
389             scaley = (scaley - this->Range[0]) / den;
390             scalez = (scalez < this->Range[0] ? this->Range[0] :
391                       (scalez > this->Range[1] ? this->Range[1] : scalez));
392             scalez = (scalez - this->Range[0]) / den;
393         }
394
395         // Compute index into table of glyphs
396         if ( this->IndexMode == VTK_INDEXING_OFF )
397         {
398             index = 0;
399         }
400         else
401         {
402             if ( this->IndexMode == VTK_INDEXING_BY_SCALAR )
403             {
404                 value = s;
405             }
406             else
407             {
408                 value = vMag;
409             }
410
411             index = (int) ((double)(value - this->Range[0]) * numberOfSources / den);
412             index = (index < 0 ? 0 :
413                      (index >= numberOfSources ? (numberOfSources-1) : index));
414
415             source = this->GetSource(index, inputVector[1]);
416             if ( source != NULL )
417             {
418                 sourcePts = source->GetPoints();
419                 sourceNormals = source->GetPointData()->GetNormals();
420                 numSourcePts = sourcePts->GetNumberOfPoints();
421                 numSourceCells = source->GetNumberOfCells();
422             }
423         }
424
425         // Make sure we're not indexing into empty glyph
426         if ( this->GetSource(index, inputVector[1]) == NULL )
427         {
428             continue;
429         }
430
431         // Check ghost points.
432         // If we are processing a piece, we do not want to duplicate
433         // glyphs on the borders.  The corrct check here is:
434         // ghostLevel > 0.  I am leaving this over glyphing here because
435         // it make a nice example (sphereGhost.tcl) to show the
436         // point ghost levels with the glyph filter.  I am not certain
437         // of the usefullness of point ghost levels over 1, but I will have
438         // to think about it.
439         if (inGhostLevels && inGhostLevels[inPtId] > requestedGhostLevel)
440         {
441             continue;
442         }
443
444         if (!this->IsPointVisible(input, inPtId))
445         {
446             continue;
447         }
448
449         // Now begin copying/transforming glyph
450         trans->Identity();
451
452         // Copy all topology (transformation independent)
453         for (cellId=0; cellId < numSourceCells; cellId++)
454         {
455             cell = this->GetSource(index, inputVector[1])->GetCell(cellId);
456             cellPts = cell->GetPointIds();
457             npts = cellPts->GetNumberOfIds();
458             for (pts->Reset(), i=0; i < npts; i++)
459             {
460                 pts->InsertId(i,cellPts->GetId(i) + ptIncr);
461             }
462             output->InsertNextCell(cell->GetCellType(),pts);
463         }
464
465         // translate Source to Input point
466         input->GetPoint(inPtId, x);
467
468         //projection on the plane orthogonale to the camera
469         trans->Scale(mOrientation[0],mOrientation[1],mOrientation[2]);
470
471         trans->Translate(x[0], x[1], x[2]);
472
473         if ( haveVectors )
474         {
475             // Copy Input vector
476             for (i=0; i < numSourcePts; i++)
477             {
478                 newVectors->InsertTuple(i+ptIncr, v);
479             }
480             if (this->Orient && (vMag > 0.0))
481             {
482                 // if there is no y or z component
483                 if ( v[1] == 0.0 && v[2] == 0.0 )
484                 {
485                     if (v[0] < 0) //just flip x if we need to
486                     {
487                         trans->RotateWXYZ(180.0,0,1,0);
488                     }
489                 }
490                 else
491                 {
492                     vNew[0] = (v[0]+vMag) / 2.0;
493                     vNew[1] = v[1] / 2.0;
494                     vNew[2] = v[2] / 2.0;
495                     trans->RotateWXYZ((double)180.0,vNew[0],vNew[1],vNew[2]);
496                 }
497             }
498         }
499
500         if (haveTCoords)
501         {
502             for (i = 0; i < numSourcePts; i++)
503             {
504                 sourceTCoords->GetTuple(i, tc);
505                 newTCoords->InsertTuple(i+ptIncr, tc);
506             }
507         }
508
509         // determine scale factor from scalars if appropriate
510         // Copy scalar value
511         if (inSScalars && (this->ColorMode == VTK_COLOR_BY_SCALE))
512         {
513             for (i=0; i < numSourcePts; i++)
514             {
515                 newScalars->InsertTuple(i+ptIncr, &scalex); // = scaley = scalez
516             }
517         }
518         else if (inCScalars && (this->ColorMode == VTK_COLOR_BY_SCALAR))
519         {
520             for (i=0; i < numSourcePts; i++)
521             {
522                 outputPD->CopyTuple(inCScalars, newScalars, inPtId, ptIncr+i);
523             }
524         }
525         if (haveVectors && this->ColorMode == VTK_COLOR_BY_VECTOR)
526         {
527             double color = 1;
528             for (i=0; i < numSourcePts; i++)
529             {
530                 newScalars->InsertTuple(i+ptIncr, &color);
531             }
532         }
533
534         // scale data if appropriate
535         if ( this->Scaling )
536         {
537             if ( this->ScaleMode == VTK_DATA_SCALING_OFF )
538             {
539                 scalex = scaley = scalez = this->ScaleFactor;
540             }
541             else
542             {
543                 scalex *= this->ScaleFactor;
544                 scaley *= this->ScaleFactor;
545                 scalez *= this->ScaleFactor;
546             }
547
548             if ( scalex == 0.0 )
549             {
550                 scalex = 1.0e-10;
551             }
552             if ( scaley == 0.0 )
553             {
554                 scaley = 1.0e-10;
555             }
556             if ( scalez == 0.0 )
557             {
558                 scalez = 1.0e-10;
559             }
560             trans->Scale(scalex,scaley,scalez);
561         }
562         // multiply points and normals by resulting matrix
563         trans->TransformPoints(sourcePts,newPts);
564
565         if ( haveNormals )
566         {
567             trans->TransformNormals(sourceNormals,newNormals);
568         }
569
570         // Copy point data from source (if possible)
571         if ( pd )
572         {
573             for (i=0; i < numSourcePts; i++)
574             {
575                 outputPD->CopyData(pd,inPtId,ptIncr+i);
576             }
577         }
578
579         // If point ids are to be generated, do it here
580         if ( this->GeneratePointIds )
581         {
582             for (i=0; i < numSourcePts; i++)
583             {
584                 pointIds->InsertNextValue(inPtId);
585             }
586         }
587
588         ptIncr += numSourcePts;
589     }
590
591     // Update ourselves and release memory
592     //
593     output->SetPoints(newPts);
594     newPts->Delete();
595
596     if (newScalars)
597     {
598         int idx = outputPD->AddArray(newScalars);
599         outputPD->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
600         newScalars->Delete();
601     }
602
603     if (newVectors)
604     {
605         outputPD->SetVectors(newVectors);
606         newVectors->Delete();
607     }
608
609     if (newNormals)
610     {
611         outputPD->SetNormals(newNormals);
612         newNormals->Delete();
613     }
614
615     if (newTCoords)
616     {
617         outputPD->SetTCoords(newTCoords);
618         newTCoords->Delete();
619     }
620
621     output->Squeeze();
622     trans->Delete();
623     pts->Delete();
624
625     return 1;
626 }
627
628 void vvGlyph2D::PrintSelf(ostream& os, vtkIndent indent)
629 {
630     this->Superclass::PrintSelf(os,indent);
631 }
632
633 void vvGlyph2D::SetOrientation(int x, int y, int z)
634 {
635     if (x == 0)
636         mOrientation[0] = 1.0e-10;
637     else
638         mOrientation[0] = 1.0;
639     if (y == 0)
640         mOrientation[1] = 1.0e-10;
641     else
642         mOrientation[1] = 1.0;
643     if (z == 0)
644         mOrientation[2] = 1.0e-10;
645     else
646         mOrientation[2] = 1.0;
647 }