Salome HOME
Fix for Bug IPAL8945
[modules/visu.git] / src / PIPELINE / VISU_SphereWidget.cxx
1 #include "VISU_SphereWidget.hxx"
2
3 #include <vtkActor.h>
4 #include <vtkAssemblyNode.h>
5 #include <vtkAssemblyPath.h>
6 #include <vtkCallbackCommand.h>
7 #include <vtkCamera.h>
8 #include <vtkCellPicker.h>
9 #include <vtkDoubleArray.h>
10 #include <vtkMath.h>
11 #include <vtkObjectFactory.h>
12 #include <vtkPolyData.h>
13 #include <vtkPolyDataMapper.h>
14 #include <vtkProperty.h>
15 #include <vtkRenderWindowInteractor.h>
16 #include <vtkRenderer.h>
17 #include <vtkSphere.h>
18 #include <vtkSphereSource.h>
19 #include <vtkPoints.h>
20 #include <vtkSphere.h>
21 #include <vtkImplicitSum.h>
22 #include <vtkImplicitFunction.h>
23
24 vtkCxxRevisionMacro(VISU_SphereWidget, "$Revision$");
25 vtkStandardNewMacro(VISU_SphereWidget);
26 //====================================================================
27 // function:
28 // purpose:
29 //====================================================================
30 VISU_SphereWidget::VISU_SphereWidget()
31 {
32   myState = VISU_SphereWidget::Start;
33   this->EventCallbackCommand->SetCallback(VISU_SphereWidget::ProcessEvents);
34   
35   //Build the representation of the widget
36   mySphereSource = vtkSphereSource::New();
37   mySphereSource->SetThetaResolution(16);
38   mySphereSource->SetPhiResolution(15);
39   mySphereSource->LatLongTessellationOn();
40   mySphereMapper = vtkPolyDataMapper::New();
41   mySphereMapper->SetInput(mySphereSource->GetOutput());
42   mySphereActor = vtkActor::New();
43   mySphereActor->SetMapper(mySphereMapper);
44   //
45   // Define the point coordinates
46   float bounds[6];
47   for(int i = 0; i < 6; i += 2){
48     bounds[i]=-.5;
49     bounds[i+1]=-bounds[i];
50   }
51   // Initial creation of the widget, serves to initialize it
52   PlaceWidget(bounds);
53
54   //Manage the picking stuff
55   myPicker = vtkCellPicker::New();
56   myPicker->SetTolerance(0.005); //need some fluff
57   myPicker->AddPickList(mySphereActor);
58   myPicker->PickFromListOn();
59   
60   // Set up the initial properties
61   mySphereProperty = NULL;
62   mySelectedSphereProperty = NULL;
63   CreateDefaultProperties();
64   myRmin=1.e-7;
65
66   mySphere=vtkSphere::New();
67   myImplicitSum=vtkImplicitSum::New();
68   myImplicitSum->AddFunction(mySphere,-1.0);
69   
70   myRatio = 2.0;
71 }
72 //====================================================================
73 // function: ~
74 // purpose:
75 //====================================================================
76 VISU_SphereWidget::~VISU_SphereWidget()
77 {
78   mySphereActor->Delete();
79   mySphereMapper->Delete();
80   mySphereSource->Delete();
81
82   myPicker->Delete();
83
84   if ( mySphereProperty ) {
85     mySphereProperty->Delete();
86   }
87   if ( mySelectedSphereProperty ) {
88     mySelectedSphereProperty->Delete();
89   }
90   mySphere->Delete();
91   myImplicitSum->Delete();
92 }
93 //====================================================================
94 // function: SetThetaResolution
95 // purpose :
96 //====================================================================
97 void VISU_SphereWidget::SetThetaResolution(int r) 
98
99   mySphereSource->SetThetaResolution(r); 
100 }
101 //====================================================================
102 // function: GetThetaResolution
103 // purpose :
104 //====================================================================
105 int VISU_SphereWidget::GetThetaResolution() 
106
107   return mySphereSource->GetThetaResolution(); 
108 }
109 //====================================================================
110 // function: SetPhiResolution
111 // purpose :
112 //====================================================================
113 void VISU_SphereWidget::SetPhiResolution(int r)
114
115   mySphereSource->SetPhiResolution(r); 
116 }
117 //====================================================================
118 // function: SetPhiResolution
119 // purpose :
120 //====================================================================
121 int VISU_SphereWidget::GetPhiResolution()   
122
123   return mySphereSource->GetPhiResolution(); 
124 }
125 //====================================================================
126 // function: SetRadius
127 // purpose :
128 //====================================================================
129 void VISU_SphereWidget::SetRadius(float theRadius) 
130 {
131   if ( theRadius <= myRmin ) {
132     theRadius = myRmin;
133   }
134   mySphereSource->SetRadius(theRadius); 
135   mySphere->SetRadius(theRadius);
136 }
137 //====================================================================
138 // function: GetRadius
139 // purpose :
140 //====================================================================
141 float VISU_SphereWidget::GetRadius()
142
143   return mySphereSource->GetRadius(); 
144 }
145 //====================================================================
146 // function: SetCenter
147 // purpose :
148 //====================================================================
149 void VISU_SphereWidget::SetCenter(float theCenter[3]) 
150 {
151   mySphereSource->SetCenter(theCenter);
152   mySphere->SetCenter(theCenter);
153 }
154 //====================================================================
155 // function: SetCenter
156 // purpose :
157 //====================================================================
158 void VISU_SphereWidget::SetCenter(float theX, float theY, float theZ) 
159 {
160   float aCenter[3] = {theX, theY, theZ};
161   SetCenter(aCenter);
162 }
163
164 //====================================================================
165 // function: GetCenter
166 // purpose :
167 //====================================================================
168 float*  VISU_SphereWidget::GetCenter() 
169 {
170   return mySphereSource->GetCenter();
171 }
172 //====================================================================
173 // function: GetCenter
174 // purpose :
175 //====================================================================
176 void  VISU_SphereWidget::GetCenter(float theCenter[3]) 
177 {
178   mySphereSource->GetCenter(theCenter);
179 }
180 //====================================================================
181 // function: GetSphereProperty
182 // purpose :
183 //====================================================================
184 vtkProperty*  VISU_SphereWidget::GetSphereProperty ()
185 {
186   return mySphereProperty;
187 }
188 //====================================================================
189 // function: GetSelectedSphereProperty
190 // purpose :
191 //====================================================================
192 vtkProperty*  VISU_SphereWidget::GetSelectedSphereProperty ()
193 {
194   return mySelectedSphereProperty;
195 }
196 //====================================================================
197 // function: ImplicitFunction
198 // purpose :
199 //====================================================================
200 vtkImplicitFunction* VISU_SphereWidget::ImplicitFunction()
201 {
202   return myImplicitSum;
203 }
204 //====================================================================
205 // function: SetEnabled
206 // purpose :
207 //====================================================================
208 void VISU_SphereWidget::SetEnabled(int enabling)
209 {
210   if ( !Interactor )    {
211     vtkErrorMacro(<<"The interactor must be set prior to enabling/disabling widget");
212     return;
213   }
214
215   if ( enabling )  {
216     vtkDebugMacro(<<"Enabling sphere widget");
217     if ( Enabled ) {//already enabled, just return
218       return;
219     }
220     
221     if ( ! CurrentRenderer )    {
222       int aPos[2];
223       Interactor->GetLastEventPosition(aPos);
224       CurrentRenderer=Interactor->FindPokedRenderer(aPos[0], aPos[1]);
225       if (!CurrentRenderer) {
226         return;
227       }
228     }
229
230     Enabled = 1;
231
232     // listen for the following events
233     Interactor->AddObserver(vtkCommand::MouseMoveEvent, 
234                             EventCallbackCommand, 
235                             Priority);
236     Interactor->AddObserver(vtkCommand::LeftButtonPressEvent, 
237                             EventCallbackCommand, 
238                             Priority);
239     Interactor->AddObserver(vtkCommand::LeftButtonReleaseEvent, 
240                             EventCallbackCommand,
241                             Priority);
242     Interactor->AddObserver(vtkCommand::MiddleButtonPressEvent, 
243                             EventCallbackCommand,
244                             Priority);
245     Interactor->AddObserver(vtkCommand::MiddleButtonReleaseEvent, 
246                             EventCallbackCommand,
247                             Priority);
248
249     // Add the sphere
250     CurrentRenderer->AddActor(mySphereActor);
251     mySphereActor->SetProperty(mySphereProperty);
252     mySphere->SetCenter(mySphereSource->GetCenter());
253     mySphere->SetRadius(mySphereSource->GetRadius());
254     
255     InvokeEvent(vtkCommand::EnableEvent,NULL); //!!!see what will be done
256   }
257   //disabling----------------------------------------------------------
258   else {
259     vtkDebugMacro(<<"Disabling sphere widget");
260
261     if ( !Enabled ){ //already disabled, just return
262       return;
263     }
264     
265     Enabled = 0;
266
267     // don't listen for events any more
268     Interactor->RemoveObserver(EventCallbackCommand);
269
270     // turn off the sphere
271     CurrentRenderer->RemoveActor(mySphereActor);
272     InvokeEvent(vtkCommand::DisableEvent,NULL);
273     CurrentRenderer = NULL;
274   }
275
276   Interactor->Render();
277 }
278 //====================================================================
279 // function:ProcessEvents
280 // purpose:
281 //====================================================================
282 void VISU_SphereWidget::ProcessEvents(vtkObject* vtkNotUsed(object), 
283                                     unsigned long event,
284                                     void* clientdata, 
285                                     void* vtkNotUsed(calldata))
286 {
287   VISU_SphereWidget* self = reinterpret_cast<VISU_SphereWidget *>( clientdata );
288
289   switch(event)  {
290     case vtkCommand::LeftButtonPressEvent:
291       self->OnLeftButtonDown();
292       break;
293     case vtkCommand::LeftButtonReleaseEvent:
294       self->OnLeftButtonUp();
295       break;
296     case vtkCommand::MiddleButtonPressEvent:
297       self->OnMiddleButtonDown();
298       break;
299     case vtkCommand::MiddleButtonReleaseEvent:
300       self->OnMiddleButtonUp();
301       break;
302     case vtkCommand::MouseMoveEvent:
303       self->OnMouseMove();
304       break;
305     default:
306       break;
307   }
308 }
309 //====================================================================
310 // function:OnLeftButtonDown
311 // purpose:
312 //====================================================================
313 void VISU_SphereWidget::OnLeftButtonDown()
314 {
315   int X = Interactor->GetEventPosition()[0];
316   int Y = Interactor->GetEventPosition()[1];
317
318   // Okay, make sure that the pick is in the current renderer
319   vtkRenderer *aRenderer = Interactor->FindPokedRenderer(X,Y);
320   //
321   if (aRenderer != CurrentRenderer) {
322     myState = VISU_SphereWidget::Outside;
323     return;
324   }
325   // Okay, we can process this. Try to pick handles first;
326   // if no places picked, then try to pick the sphere.
327   myPicker->Pick(X, Y, 0., CurrentRenderer);
328   if(vtkAssemblyPath *aPath = myPicker->GetPath()){
329     if(aPath->GetFirstNode()->GetProp() == mySphereActor){
330       myState = VISU_SphereWidget::Moving;
331       HighlightSphere(1);
332     }
333   }else{
334     myState = VISU_SphereWidget::Outside;
335     return;
336   }
337   //
338   EventCallbackCommand->SetAbortFlag(1);
339   StartInteraction();
340   InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
341   Interactor->Render();
342 }
343 //====================================================================
344 // function:OnMouseMove
345 // purpose:
346 //====================================================================
347 void VISU_SphereWidget::OnMouseMove()
348 {
349   // See whether we're active
350   if ( myState == VISU_SphereWidget::Outside || 
351        myState == VISU_SphereWidget::Start )    {
352     return;
353   }
354   
355   int X = Interactor->GetEventPosition()[0];
356   int Y = Interactor->GetEventPosition()[1];
357
358   // Do different things depending on state
359   // Calculations everybody does
360   double focalPoint[4], pickPoint[4], prevPickPoint[4], z;
361
362   vtkRenderer *aRenderer=Interactor->FindPokedRenderer(X, Y);
363   vtkCamera *aCamera=aRenderer->GetActiveCamera();
364   if (!aCamera ) {
365     return;
366   }
367   // Compute the two points defining the motion vector
368   aCamera->GetFocalPoint(focalPoint);
369   ComputeWorldToDisplay(focalPoint[0], 
370                         focalPoint[1],
371                         focalPoint[2], 
372                         focalPoint);
373   z = focalPoint[2];
374   ComputeDisplayToWorld(double(Interactor->GetLastEventPosition()[0]),
375                         double(Interactor->GetLastEventPosition()[1]),
376                         z, 
377                         prevPickPoint);
378   ComputeDisplayToWorld(double(X), double(Y), z, pickPoint);
379
380   // Process the motion
381   if ( myState == VISU_SphereWidget::Moving ) {
382     Translate(prevPickPoint, pickPoint);
383   }
384   else if ( myState == VISU_SphereWidget::Scaling ) {
385     Scale(prevPickPoint, pickPoint, X, Y);
386   }
387   // Interact, if desired
388   EventCallbackCommand->SetAbortFlag(1);
389   InvokeEvent(vtkCommand::InteractionEvent,NULL);
390   //
391   Interactor->Render();
392 }
393 //====================================================================
394 // function:OnLeftButtonUp
395 // purpose:
396 //====================================================================
397 void VISU_SphereWidget::OnLeftButtonUp()
398 {
399   if ( myState == VISU_SphereWidget::Outside ) {
400     return;
401   }
402
403   myState = VISU_SphereWidget::Start;
404   HighlightSphere(0);
405
406   EventCallbackCommand->SetAbortFlag(1);
407   EndInteraction();
408   InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
409   
410   Interactor->Render();
411 }
412 //====================================================================
413 // function:OnMiddleButtonDown
414 // purpose:
415 //====================================================================
416 void VISU_SphereWidget::OnMiddleButtonDown()
417 {
418   myState = VISU_SphereWidget::Scaling;
419
420   int X = Interactor->GetEventPosition()[0];
421   int Y = Interactor->GetEventPosition()[1];
422
423   // Okay, make sure that the pick is in the current renderer
424   vtkRenderer *aRenderer = Interactor->FindPokedRenderer(X,Y);
425   if (aRenderer!=CurrentRenderer) {
426     myState = VISU_SphereWidget::Outside;
427     return;
428   }
429   
430   // Okay, we can process this. Try to pick handles first;
431   // if no handles picked, then pick the bounding box.
432   myPicker->Pick(X, Y, 0., CurrentRenderer);
433   vtkAssemblyPath *aPath = myPicker->GetPath();
434   if ( !aPath ) {
435     myState=VISU_SphereWidget::Outside;
436     HighlightSphere(0);
437     return;
438   }
439   
440   HighlightSphere(1);
441
442   EventCallbackCommand->SetAbortFlag(1);
443   StartInteraction();
444   InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
445   //
446   Interactor->Render();
447 }
448 //====================================================================
449 // function:OnMiddleButtonUp
450 // purpose:
451 //====================================================================
452 void VISU_SphereWidget::OnMiddleButtonUp()
453 {
454   if ( myState == VISU_SphereWidget::Outside ) {
455     return;
456   }
457   myState = VISU_SphereWidget::Start;
458   HighlightSphere(0);
459   
460   EventCallbackCommand->SetAbortFlag(1);
461   EndInteraction();
462   InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
463   //
464   Interactor->Render();
465 }
466 //====================================================================
467 // function:Translate
468 // purpose:
469 //====================================================================
470 void VISU_SphereWidget::Translate(double *p1, double *p2)
471 {
472   float v[3], aC[3], aC1[3];
473   //
474   v[0] = p2[0] - p1[0];
475   v[1] = p2[1] - p1[1];
476   v[2] = p2[2] - p1[2];
477   //  
478   mySphereSource->GetCenter(aC);
479   aC1[0] = aC[0] + v[0];
480   aC1[1] = aC[1] + v[1];
481   aC1[2] = aC[2] + v[2];
482   mySphereSource->SetCenter(aC1);
483   mySphere->SetCenter(mySphereSource->GetCenter());
484   mySphere->SetRadius(mySphereSource->GetRadius());
485 }
486 //====================================================================
487 // function:Scale
488 // purpose:
489 //====================================================================
490 void VISU_SphereWidget::Scale(double *p1, double *p2, 
491                               int aX, int aY)
492 {
493   double v[3];
494   v[0] = p2[0] - p1[0];
495   v[1] = p2[1] - p1[1];
496   v[2] = p2[2] - p1[2];
497   //
498   float aC[3], aR, sf, aR1;
499   aR=mySphereSource->GetRadius();
500   mySphereSource->GetCenter(aC);
501   sf=vtkMath::Norm(v)/aR;
502   int aCoordLast[2], iDX, iDY, iSign;
503   Interactor->GetLastEventPosition(aCoordLast);
504   //
505   iDX=aX-aCoordLast[0];
506   iDY=aCoordLast[1]-aY; 
507   iSign=(iDX+iDY>0)? 1 : -1;
508   sf=1.+iSign*sf;
509   aR1=sf*aR;
510   if (aR1<myRmin){
511     aR1=myRmin;
512   }
513   mySphereSource->SetRadius(aR1);
514   mySphere->SetCenter(mySphereSource->GetCenter());
515   mySphere->SetRadius(mySphereSource->GetRadius());
516 }
517 //====================================================================
518 // function:GetSphere
519 // purpose:
520 //====================================================================
521 void VISU_SphereWidget::GetSphere(vtkSphere *sphere)
522 {
523   sphere->SetRadius(mySphereSource->GetRadius());
524   sphere->SetCenter(mySphereSource->GetCenter());
525 }
526 //====================================================================
527 // function:HighlightSphere
528 // purpose:
529 //====================================================================
530 void VISU_SphereWidget::HighlightSphere(int highlight)
531 {
532   if ( highlight )  {
533     this->ValidPick = 1;
534     myPicker->GetPickPosition(this->LastPickPosition);// -> def in vtk3DWidget
535     mySphereActor->SetProperty(mySelectedSphereProperty);
536   }
537   else {
538     mySphereActor->SetProperty(mySphereProperty);
539   }
540 }
541 //====================================================================
542 // function:CreateDefaultProperties
543 // purpose:
544 //====================================================================
545 void VISU_SphereWidget::CreateDefaultProperties()
546 {
547   if (!mySphereProperty)    {
548     mySphereProperty = vtkProperty::New();
549     mySphereProperty->SetColor(0.,.5, .7);
550     mySphereProperty->SetSpecular(0.5);
551     mySphereProperty->SetRepresentationToWireframe();
552   }
553   if (!mySelectedSphereProperty)    {
554     mySelectedSphereProperty = vtkProperty::New();
555     mySelectedSphereProperty->SetColor(0.5, 0.5, 0.);
556     mySelectedSphereProperty->SetSpecular(1.);
557     mySelectedSphereProperty->SetRepresentationToWireframe();
558   }
559 }
560 //====================================================================
561 // function:PlaceWidget
562 // purpose:
563 //====================================================================
564 void VISU_SphereWidget::PlaceWidget(float bds[6])
565 {
566   float bounds[6], center[3], radius;
567
568   this->AdjustBounds(bds, bounds, center);
569   float dX, dY, dZ;
570   //
571   dX=bounds[1]-bounds[0];
572   dY=bounds[3]-bounds[2];
573   dZ=bounds[5]-bounds[4];
574   radius = dX;
575   if (radius>dY){
576     radius = dY;
577   }
578   if (radius>dZ)   {
579     radius=dZ;
580   }
581   radius*=0.5;
582
583   mySphereSource->SetCenter(center);
584   mySphereSource->SetRadius(radius);
585   mySphereSource->Update();
586   //
587   for (int i=0; i<6; i++) {
588     InitialBounds[i]=bounds[i];
589   }
590   InitialLength = sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
591                        (bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
592                        (bounds[5]-bounds[4])*(bounds[5]-bounds[4]));
593
594   static float EPS = 1.0E-1;
595   myRmin = EPS*InitialLength;
596
597 }
598
599 //====================================================================
600 // function:ChangeRadius
601 // purpose:
602 //====================================================================
603 void VISU_SphereWidget::ChangeRadius(bool up)
604 {
605   SetRadius( GetRadius() * ( up ? myRatio : 1 / myRatio ) );
606 }
607 //====================================================================
608 // function:GetPolyData
609 // purpose:
610 //====================================================================
611 void VISU_SphereWidget::GetPolyData(vtkPolyData *pd)
612
613   pd->ShallowCopy(mySphereSource->GetOutput()); 
614 }
615 //====================================================================
616 // function:PrintSelf
617 // purpose:
618 //====================================================================
619 void VISU_SphereWidget::PrintSelf(ostream& os, vtkIndent indent)
620 {
621   this->Superclass::PrintSelf(os,indent);
622 }