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