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