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