Salome HOME
Add test function : QApplication::postEvent(SALOME_Event)
[modules/visu.git] / src / PIPELINE / VISU_ScalarBarActor.cxx
1 //  VISU OBJECT : interactive object for VISU entities implementation
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 // File:    VISU_PipeLine.hxx
24 // Author:  Alexey PETROV
25 // Module : VISU
26
27 #include "VISU_ScalarBarActor.hxx"
28
29 #include <vtkPolyDataMapper2D.h>
30 #include <vtkCellArray.h>
31 #include <vtkCellData.h>
32 #include <vtkObjectFactory.h>
33 #include <vtkPolyData.h>
34 #include <vtkPolyDataMapper2D.h>
35 #include <vtkScalarsToColors.h>
36 #include <vtkTextMapper.h>
37 #include <vtkTextProperty.h>
38 #include <vtkViewport.h>
39 #include <vtkWindow.h>
40 #include <vtkLogLookupTable.h>
41
42 using namespace std;
43
44 vtkCxxRevisionMacro(VISU_ScalarBarActor, "$Revision$");
45
46 vtkCxxSetObjectMacro(VISU_ScalarBarActor,LookupTable,VISU_LookupTable);
47 vtkCxxSetObjectMacro(VISU_ScalarBarActor,LabelTextProperty,vtkTextProperty);
48 vtkCxxSetObjectMacro(VISU_ScalarBarActor,TitleTextProperty,vtkTextProperty);
49
50 //------------------------------------------------------------------------------
51 VISU_ScalarBarActor* VISU_ScalarBarActor::New(){
52   vtkObject* ret = vtkObjectFactory::CreateInstance("VISU_ScalarBarActor");
53   if(ret)
54     return (VISU_ScalarBarActor*)ret;
55   return new VISU_ScalarBarActor;
56 }
57
58 VISU_ScalarBarActor::VISU_ScalarBarActor()
59 {
60   this->LookupTable = NULL;
61   this->Position2Coordinate->SetValue(0.17, 0.8);
62   
63   this->PositionCoordinate->SetCoordinateSystemToNormalizedViewport();
64   this->PositionCoordinate->SetValue(0.82,0.1);
65   
66   this->MaximumNumberOfColors = 64;
67   this->NumberOfLabels = 5;
68   this->NumberOfLabelsBuilt = 0;
69   this->Orientation = VTK_ORIENT_VERTICAL;
70   this->Title = NULL;
71
72   this->LabelTextProperty = vtkTextProperty::New();
73   this->LabelTextProperty->SetFontSize(12);
74   this->LabelTextProperty->SetBold(1);
75   this->LabelTextProperty->SetItalic(1);
76   this->LabelTextProperty->SetShadow(1);
77   this->LabelTextProperty->SetFontFamilyToArial();
78
79   this->TitleTextProperty = vtkTextProperty::New();
80   this->TitleTextProperty->ShallowCopy(this->LabelTextProperty);
81
82   this->LabelFormat = new char[8]; 
83   sprintf(this->LabelFormat,"%s","%-#6.3g");
84
85   this->TitleMapper = vtkTextMapper::New();
86   this->TitleActor = vtkActor2D::New();
87   this->TitleActor->SetMapper(this->TitleMapper);
88   this->TitleActor->GetPositionCoordinate()->
89     SetReferenceCoordinate(this->PositionCoordinate);
90   
91   this->TextMappers = NULL;
92   this->TextActors = NULL;
93
94   this->ScalarBar = vtkPolyData::New();
95   this->ScalarBarMapper = vtkPolyDataMapper2D::New();
96   this->ScalarBarMapper->SetInput(this->ScalarBar);
97   this->ScalarBarActor = vtkActor2D::New();
98   this->ScalarBarActor->SetMapper(this->ScalarBarMapper);
99   this->ScalarBarActor->GetPositionCoordinate()->
100     SetReferenceCoordinate(this->PositionCoordinate);
101   this->LastOrigin[0] = 0;
102   this->LastOrigin[1] = 0;
103   this->LastSize[0] = 0;
104   this->LastSize[1] = 0;
105 }
106
107 void VISU_ScalarBarActor::ReleaseGraphicsResources(vtkWindow *win)
108 {
109   this->TitleActor->ReleaseGraphicsResources(win);
110   if (this->TextMappers != NULL )
111     {
112     for (int i=0; i < this->NumberOfLabelsBuilt; i++)
113       {
114       this->TextActors[i]->ReleaseGraphicsResources(win);
115       }
116     }
117   this->ScalarBarActor->ReleaseGraphicsResources(win);
118 }
119
120 VISU_ScalarBarActor::~VISU_ScalarBarActor()
121 {
122   if (this->LabelFormat) 
123     {
124     delete [] this->LabelFormat;
125     this->LabelFormat = NULL;
126     }
127
128   this->TitleMapper->Delete();
129   this->TitleActor->Delete();
130
131   if (this->TextMappers != NULL )
132     {
133     for (int i=0; i < this->NumberOfLabelsBuilt; i++)
134       {
135       this->TextMappers[i]->Delete();
136       this->TextActors[i]->Delete();
137       }
138     delete [] this->TextMappers;
139     delete [] this->TextActors;
140     }
141
142   this->ScalarBar->Delete();
143   this->ScalarBarMapper->Delete();
144   this->ScalarBarActor->Delete();
145
146   if (this->Title)
147     {
148     delete [] this->Title;
149     this->Title = NULL;
150     }
151   
152   this->SetLookupTable(NULL);
153   this->SetLabelTextProperty(NULL);
154   this->SetTitleTextProperty(NULL);
155 }
156
157 int VISU_ScalarBarActor::RenderOverlay(vtkViewport *viewport)
158 {
159   int renderedSomething = 0;
160   int i;
161   
162   // Everything is built, just have to render
163   if (this->Title != NULL)
164     {
165     renderedSomething += this->TitleActor->RenderOverlay(viewport);
166     }
167   this->ScalarBarActor->RenderOverlay(viewport);
168   if( this->TextActors == NULL)
169     {
170      vtkWarningMacro(<<"Need a mapper to render a scalar bar");
171      return renderedSomething;
172     }
173   
174   for (i=0; i<this->NumberOfLabels; i++)
175     {
176     renderedSomething += this->TextActors[i]->RenderOverlay(viewport);
177     }
178
179   renderedSomething = (renderedSomething > 0)?(1):(0);
180
181   return renderedSomething;
182 }
183
184 int VISU_ScalarBarActor::RenderOpaqueGeometry(vtkViewport *viewport)
185 {
186   int renderedSomething = 0;
187   int i;
188   int size[2];
189   
190   if (!this->LookupTable)
191     {
192     vtkWarningMacro(<<"Need a mapper to render a scalar bar");
193     return 0;
194     }
195
196   if (!this->TitleTextProperty)
197     {
198     vtkErrorMacro(<<"Need title text property to render a scalar bar");
199     return 0;
200     }
201
202   if (!this->LabelTextProperty)
203     {
204     vtkErrorMacro(<<"Need label text property to render a scalar bar");
205     return 0;
206     }
207
208   // Check to see whether we have to rebuild everything
209   int positionsHaveChanged = 0;
210   if (viewport->GetMTime() > this->BuildTime || 
211       (viewport->GetVTKWindow() && 
212        viewport->GetVTKWindow()->GetMTime() > this->BuildTime))
213     {
214     // if the viewport has changed we may - or may not need
215     // to rebuild, it depends on if the projected coords chage
216     int *barOrigin;
217     barOrigin = this->PositionCoordinate->GetComputedViewportValue(viewport);
218     size[0] = 
219       this->Position2Coordinate->GetComputedViewportValue(viewport)[0] -
220       barOrigin[0];
221     size[1] = 
222       this->Position2Coordinate->GetComputedViewportValue(viewport)[1] -
223       barOrigin[1];
224     if (this->LastSize[0] != size[0] || 
225         this->LastSize[1] != size[1] ||
226         this->LastOrigin[0] != barOrigin[0] || 
227         this->LastOrigin[1] != barOrigin[1])
228       {
229       positionsHaveChanged = 1;
230       }
231     }
232   
233   // Check to see whether we have to rebuild everything
234   if (positionsHaveChanged ||
235       this->GetMTime() > this->BuildTime || 
236       this->LookupTable->GetMTime() > this->BuildTime ||
237       this->LabelTextProperty->GetMTime() > this->BuildTime ||
238       this->TitleTextProperty->GetMTime() > this->BuildTime)
239     {
240
241     // Delete previously constructed objects
242     //
243     if (this->TextMappers != NULL )
244       {
245       for (i=0; i < this->NumberOfLabelsBuilt; i++)
246         {
247         this->TextMappers[i]->Delete();
248         this->TextActors[i]->Delete();
249         }
250       delete [] this->TextMappers;
251       delete [] this->TextActors;
252       }
253
254     // Build scalar bar object; determine its type
255     //
256     VISU_LookupTable *lut = this->LookupTable; //SALOME specific
257     int isLogTable = lut->GetScale() == VTK_SCALE_LOG10;
258     
259     // we hard code how many steps to display
260     int numColors = this->MaximumNumberOfColors;
261     float *range = lut->GetRange();
262
263     int numPts = 2*(numColors + 1);
264     vtkPoints *pts = vtkPoints::New();
265     pts->SetNumberOfPoints(numPts);
266     vtkCellArray *polys = vtkCellArray::New();
267     polys->Allocate(polys->EstimateSize(numColors,4));
268     vtkUnsignedCharArray *colors = vtkUnsignedCharArray::New();
269     colors->SetNumberOfComponents(3);
270     colors->SetNumberOfTuples(numColors);
271
272     this->ScalarBarActor->SetProperty(this->GetProperty());
273     this->ScalarBar->Initialize();
274     this->ScalarBar->SetPoints(pts);
275     this->ScalarBar->SetPolys(polys);
276     this->ScalarBar->GetCellData()->SetScalars(colors);
277     pts->Delete(); polys->Delete(); colors->Delete();
278
279     // get the viewport size in display coordinates
280     int *barOrigin, barWidth, barHeight;
281     barOrigin = this->PositionCoordinate->GetComputedViewportValue(viewport);
282     size[0] = 
283       this->Position2Coordinate->GetComputedViewportValue(viewport)[0] -
284       barOrigin[0];
285     size[1] = 
286       this->Position2Coordinate->GetComputedViewportValue(viewport)[1] -
287       barOrigin[1];
288     this->LastOrigin[0] = barOrigin[0];
289     this->LastOrigin[1] = barOrigin[1];
290     this->LastSize[0] = size[0];
291     this->LastSize[1] = size[1];
292     
293     // Update all the composing objects
294     this->TitleActor->SetProperty(this->GetProperty());
295     this->TitleMapper->SetInput(this->Title);
296     if (this->TitleTextProperty->GetMTime() > this->BuildTime)
297       {
298       // Shallow copy here so that the size of the title prop is not affected
299       // by the automatic adjustment of its text mapper's size (i.e. its
300       // mapper's text property is identical except for the font size
301       // which will be modified later). This allows text actors to
302       // share the same text property, and in that case specifically allows
303       // the title and label text prop to be the same.
304       this->TitleMapper->GetTextProperty()->ShallowCopy(this->TitleTextProperty);
305       this->TitleMapper->GetTextProperty()->SetJustificationToCentered();
306       }
307     
308     // find the best size for the title font
309     int titleSize[2];
310     this->SizeTitle(titleSize, size, viewport);
311     
312     // find the best size for the ticks
313     int labelSize[2];
314     this->AllocateAndSizeLabels(labelSize, size, viewport,range);
315     this->NumberOfLabelsBuilt = this->NumberOfLabels;
316     
317     // generate points
318     float x[3]; x[2] = 0.0;
319     float delta, val;
320     if ( this->Orientation == VTK_ORIENT_VERTICAL )
321       {
322       barWidth = size[0] - 4 - labelSize[0];
323       barHeight = (int)(0.86*size[1]);
324       delta=(float)barHeight/numColors;
325       for (i=0; i<numPts/2; i++)
326         {
327         x[0] = 0;
328         x[1] = i*delta;
329         pts->SetPoint(2*i,x);
330         x[0] = barWidth;
331         pts->SetPoint(2*i+1,x);
332         }
333       }
334     else
335       {
336       barWidth = size[0];
337       barHeight = (int)(0.4*size[1]);
338       delta=(float)barWidth/numColors;
339       for (i=0; i<numPts/2; i++)
340         {
341         x[0] = i*delta;
342         x[1] = barHeight;
343         pts->SetPoint(2*i,x);
344         x[1] = 0;
345         pts->SetPoint(2*i+1,x);
346         }
347       }
348
349     //polygons & cell colors
350     unsigned char *rgba, *rgb;
351     vtkIdType ptIds[4];
352     for (i=0; i<numColors; i++)
353       {
354       ptIds[0] = 2*i;
355       ptIds[1] = ptIds[0] + 1;
356       ptIds[2] = ptIds[1] + 2;
357       ptIds[3] = ptIds[0] + 2;
358       polys->InsertNextCell(4,ptIds);
359
360       if ( isLogTable ){ //SALOME specific
361         float rgbval = log10(range[0]) + 
362           i*(log10(range[1])-log10(range[0]))/(numColors -1);
363         rgba = lut->MapValue(rgbval);
364       }else{
365         rgba = lut->MapValue(range[0] + (range[1] - range[0])*
366                              ((float)i /(numColors-1.0)));
367       }
368
369       rgb = colors->GetPointer(3*i); //write into array directly
370       rgb[0] = rgba[0];
371       rgb[1] = rgba[1];
372       rgb[2] = rgba[2];
373     }
374
375     // Now position everything properly
376     //
377     if (this->Orientation == VTK_ORIENT_VERTICAL)
378       {
379       int sizeTextData[2];
380       
381       // center the title
382       this->TitleActor->SetPosition(size[0]/2, 0.9*size[1]);
383       
384       for (i=0; i < this->NumberOfLabels; i++)
385         {
386         val = (float)i/(this->NumberOfLabels-1) *barHeight;
387         this->TextMappers[i]->GetSize(viewport,sizeTextData);
388         this->TextMappers[i]->GetTextProperty()->SetJustificationToLeft();
389         this->TextActors[i]->SetPosition(barWidth+3,
390                                          val - sizeTextData[1]/2);
391         }
392       }
393     else
394       {
395       this->TitleActor->SetPosition(size[0]/2, 
396                                     barHeight + labelSize[1] + 0.1*size[1]);
397       for (i=0; i < this->NumberOfLabels; i++)
398         {
399         this->TextMappers[i]->GetTextProperty()->SetJustificationToCentered();
400         val = (float)i/(this->NumberOfLabels-1) * barWidth;
401         this->TextActors[i]->SetPosition(val, barHeight + 0.05*size[1]);
402         }
403       }
404
405     this->BuildTime.Modified();
406     }
407
408   // Everything is built, just have to render
409   if (this->Title != NULL)
410     {
411     renderedSomething += this->TitleActor->RenderOpaqueGeometry(viewport);
412     }
413   this->ScalarBarActor->RenderOpaqueGeometry(viewport);
414   for (i=0; i<this->NumberOfLabels; i++)
415     {
416     renderedSomething += this->TextActors[i]->RenderOpaqueGeometry(viewport);
417     }
418
419   renderedSomething = (renderedSomething > 0)?(1):(0);
420
421   return renderedSomething;
422 }
423
424 void VISU_ScalarBarActor::PrintSelf(ostream& os, vtkIndent indent)
425 {
426   this->Superclass::PrintSelf(os,indent);
427
428   if ( this->LookupTable )
429     {
430     os << indent << "Lookup Table:\n";
431     this->LookupTable->PrintSelf(os,indent.GetNextIndent());
432     }
433   else
434     {
435     os << indent << "Lookup Table: (none)\n";
436     }
437
438   if (this->TitleTextProperty)
439     {
440     os << indent << "Title Text Property:\n";
441     this->TitleTextProperty->PrintSelf(os,indent.GetNextIndent());
442     }
443   else
444     {
445     os << indent << "Title Text Property: (none)\n";
446     }
447
448   if (this->LabelTextProperty)
449     {
450     os << indent << "Label Text Property:\n";
451     this->LabelTextProperty->PrintSelf(os,indent.GetNextIndent());
452     }
453   else
454     {
455     os << indent << "Label Text Property: (none)\n";
456     }
457
458   os << indent << "Title: " << (this->Title ? this->Title : "(none)") << "\n";
459   os << indent << "Maximum Number Of Colors: " 
460      << this->MaximumNumberOfColors << "\n";
461   os << indent << "Number Of Labels: " << this->NumberOfLabels << "\n";
462   os << indent << "Number Of Labels Built: " << this->NumberOfLabelsBuilt << "\n";
463
464   os << indent << "Orientation: ";
465   if ( this->Orientation == VTK_ORIENT_HORIZONTAL )
466     {
467     os << "Horizontal\n";
468     }
469   else
470     {
471     os << "Vertical\n";
472     }
473
474   os << indent << "Label Format: " << this->LabelFormat << "\n";
475 }
476
477 void VISU_ScalarBarActor::ShallowCopy(vtkProp *prop)
478 {
479   VISU_ScalarBarActor *a = VISU_ScalarBarActor::SafeDownCast(prop);
480   if ( a != NULL )
481     {
482     this->SetPosition2(a->GetPosition2());
483     this->SetLookupTable(a->GetLookupTable());
484     this->SetMaximumNumberOfColors(a->GetMaximumNumberOfColors());
485     this->SetOrientation(a->GetOrientation());
486     this->SetLabelTextProperty(a->GetLabelTextProperty());
487     this->SetTitleTextProperty(a->GetTitleTextProperty());
488     this->SetLabelFormat(a->GetLabelFormat());
489     this->SetTitle(a->GetTitle());
490     this->GetPositionCoordinate()->SetCoordinateSystem(
491       a->GetPositionCoordinate()->GetCoordinateSystem());    
492     this->GetPositionCoordinate()->SetValue(
493       a->GetPositionCoordinate()->GetValue());
494     this->GetPosition2Coordinate()->SetCoordinateSystem(
495       a->GetPosition2Coordinate()->GetCoordinateSystem());    
496     this->GetPosition2Coordinate()->SetValue(
497       a->GetPosition2Coordinate()->GetValue());
498     }
499
500   // Now do superclass
501   this->vtkActor2D::ShallowCopy(prop);
502 }
503
504 void VISU_ScalarBarActor::AllocateAndSizeLabels(int *labelSize, int *size,
505                                               vtkViewport *viewport,
506                                               float *range)
507 {
508   labelSize[0] = labelSize[1] = 0;
509
510   this->TextMappers = new vtkTextMapper * [this->NumberOfLabels];
511   this->TextActors = new vtkActor2D * [this->NumberOfLabels];
512
513   char string[512];
514
515   float val;
516   int i;
517   
518   // TODO: this should be optimized, maybe by keeping a list of
519   // allocated mappers, in order to avoid creation/destruction of
520   // their underlying text properties (i.e. each time a mapper is
521   // created, text properties are created and shallow-assigned a font size
522   // which value might be "far" from the target font size).
523
524   VISU_LookupTable *lut = this->LookupTable; //SALOME specific
525   int isLogTable = lut->GetScale() == VTK_SCALE_LOG10;
526
527   for (i=0; i < this->NumberOfLabels; i++)
528     {
529     this->TextMappers[i] = vtkTextMapper::New();
530
531     if(isLogTable && 0 < i && i < this->NumberOfLabels - 1){ // SALOME specific
532       float lval = log10(range[0]) + (float)i/(this->NumberOfLabels-1) *
533         (log10(range[1])-log10(range[0]));
534       val = pow(10,lval);
535     }else{
536       val = range[0] + (float)i/(this->NumberOfLabels-1) * (range[1]-range[0]);
537     }
538     sprintf(string, this->LabelFormat, val);
539     this->TextMappers[i]->SetInput(string);
540
541     // Shallow copy here so that the size of the label prop is not affected
542     // by the automatic adjustment of its text mapper's size (i.e. its
543     // mapper's text property is identical except for the font size
544     // which will be modified later). This allows text actors to
545     // share the same text property, and in that case specifically allows
546     // the title and label text prop to be the same.
547     this->TextMappers[i]->GetTextProperty()->ShallowCopy(
548       this->LabelTextProperty);
549
550     this->TextActors[i] = vtkActor2D::New();
551     this->TextActors[i]->SetMapper(this->TextMappers[i]);
552     this->TextActors[i]->SetProperty(this->GetProperty());
553     this->TextActors[i]->GetPositionCoordinate()->
554       SetReferenceCoordinate(this->PositionCoordinate);
555     }
556
557   if (this->NumberOfLabels)
558     {
559     int targetWidth, targetHeight;
560
561     if ( this->Orientation == VTK_ORIENT_VERTICAL )
562       {
563       targetWidth = (int)(0.6*size[0]);
564       targetHeight = (int)(0.86*size[1]/this->NumberOfLabels);
565       }
566     else
567       {
568       targetWidth = (int)(size[0]*0.8/this->NumberOfLabels);
569       targetHeight = (int)(0.25*size[1]);
570       }
571
572     vtkTextMapper::SetMultipleConstrainedFontSize(viewport, 
573                                                   targetWidth, 
574                                                   targetHeight,
575                                                   this->TextMappers,
576                                                   this->NumberOfLabels,
577                                                   labelSize);
578     }
579 }
580
581 void VISU_ScalarBarActor::SizeTitle(int *titleSize, int *size, 
582                                   vtkViewport *viewport)
583 {
584   titleSize[0] = titleSize[1] = 0;
585
586   if (this->Title == NULL || !strlen(this->Title))
587     {
588     return;
589     }
590
591   int targetWidth, targetHeight;
592   
593   targetWidth = size[0];
594   if ( this->Orientation == VTK_ORIENT_VERTICAL )
595     {
596     targetHeight = (int)(0.1*size[1]);
597     }
598   else
599     {
600     targetHeight = (int)(0.25*size[1]);
601     }
602
603   this->TitleMapper->SetConstrainedFontSize(
604     viewport, targetWidth, targetHeight);
605
606   this->TitleMapper->GetSize(viewport, titleSize);
607 }