0032183: Visualization - implement AIS_LightSource::ProcessDragging() for rotating...
[occt.git] / src / AIS / AIS_LightSource.cxx
1 // Created on: 2020-09-07
2 // Created by: Maria KRYLOVA
3 // Copyright (c) 2020 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <AIS_LightSource.hxx>
17
18 #include <AIS_InteractiveContext.hxx>
19 #include <gp_Quaternion.hxx>
20 #include <Graphic3d_ArrayOfPoints.hxx>
21 #include <Graphic3d_ArrayOfPolylines.hxx>
22 #include <Graphic3d_ArrayOfSegments.hxx>
23 #include <Graphic3d_ArrayOfTriangles.hxx>
24 #include <Graphic3d_CView.hxx>
25 #include <Graphic3d_Group.hxx>
26 #include <Prs3d_ArrowAspect.hxx>
27 #include <Prs3d_PointAspect.hxx>
28 #include <Prs3d_Text.hxx>
29 #include <Prs3d_ToolCylinder.hxx>
30 #include <Prs3d_ToolSphere.hxx>
31 #include <Select3D_SensitivePoint.hxx>
32 #include <Select3D_SensitiveSphere.hxx>
33 #include <V3d_View.hxx>
34
35 IMPLEMENT_STANDARD_RTTIEXT(AIS_LightSource, AIS_InteractiveObject)
36 IMPLEMENT_STANDARD_RTTIEXT(AIS_LightSourceOwner, SelectMgr_EntityOwner)
37
38 // =======================================================================
39 // function : AIS_LightSourceOwner
40 // purpose  :
41 // =======================================================================
42 AIS_LightSourceOwner::AIS_LightSourceOwner (const Handle(AIS_LightSource)& theObject,
43                                             Standard_Integer thePriority)
44 : SelectMgr_EntityOwner ((const Handle(SelectMgr_SelectableObject)&)theObject, thePriority)
45 {
46   //
47 }
48
49 // =======================================================================
50 // function : HandleMouseClick
51 // purpose  :
52 // =======================================================================
53 Standard_Boolean AIS_LightSourceOwner::HandleMouseClick (const Graphic3d_Vec2i& ,
54                                                          Aspect_VKeyMouse theKey,
55                                                          Aspect_VKeyFlags theFlags,
56                                                          bool )
57 {
58   AIS_LightSource* aLightSource = dynamic_cast<AIS_LightSource*>(mySelectable);
59   if (aLightSource != NULL
60    && aLightSource->ToSwitchOnClick()
61    && theKey == Aspect_VKeyMouse_LeftButton
62    && theFlags == Aspect_VKeyFlags_NONE)
63   {
64     aLightSource->Light()->SetEnabled (!aLightSource->Light()->IsEnabled());
65     aLightSource->updateLightAspects();
66     return true;
67   }
68   return false;
69 }
70
71 //=======================================================================
72 //function : HilightWithColor
73 //purpose  :
74 //=======================================================================
75 void AIS_LightSourceOwner::HilightWithColor (const Handle(PrsMgr_PresentationManager)& thePM,
76                                              const Handle(Prs3d_Drawer)& theStyle,
77                                              const Standard_Integer theMode)
78 {
79   Handle(AIS_LightSource) aLightSource = Handle(AIS_LightSource)::DownCast (mySelectable);
80   if (aLightSource.IsNull())
81   {
82     return;
83   }
84
85   if (aLightSource->Light()->Type() == Graphic3d_TypeOfLightSource_Directional && aLightSource->myIsDraggable)
86   {
87     Handle(Prs3d_Presentation) aPrs = aLightSource->GetHilightPresentation (thePM);
88     const Graphic3d_ZLayerId aZLayer = theStyle->ZLayer() != -1
89                                      ? theStyle->ZLayer()
90                                      : (thePM->IsImmediateModeOn() ? Graphic3d_ZLayerId_Top : aLightSource->ZLayer());
91     aPrs->Clear();
92     if (aPrs->GetZLayer() != aZLayer)
93     {
94       aPrs->SetZLayer (aZLayer);
95     }
96     Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1);
97     const gp_Pnt aDetPnt = aLightSource->mySensSphere->LastDetectedPoint();
98     if (aDetPnt.X() == RealLast())
99     {
100       return;
101     }
102     aPoints->AddVertex (aDetPnt);
103     Handle(Graphic3d_Group) aGroup = aPrs->NewGroup();
104     const Handle(Prs3d_PointAspect) aPointAspect = new Prs3d_PointAspect (Aspect_TOM_O_POINT, theStyle->Color(), 3.0f);
105     aGroup->SetGroupPrimitivesAspect (aPointAspect->Aspect());
106     aGroup->AddPrimitiveArray (aPoints);
107
108     const Standard_Real aRadius = aLightSource->Size() * 0.5;
109     const Standard_Integer aNbPnts = int (aLightSource->ArcSize() * 180 / (M_PI * aRadius));
110     TColgp_Array1OfPnt aCircPoints (0, aNbPnts);
111     const gp_Dir aDirNorm (gp_Vec (gp::Origin(), aDetPnt));
112     gp_Dir aDirNormToPln (gp::DY());
113     if (!gp::DX().IsParallel (aDirNorm, Precision::Angular()))
114     {
115       aDirNormToPln = gp::DX().Crossed (aDirNorm);
116     }
117     for (Standard_Integer aStep = 0; aStep < aNbPnts; ++aStep)
118     {
119       aCircPoints.SetValue (aStep, (aDetPnt.Rotated (gp_Ax1 (gp::Origin(), aDirNormToPln), M_PI / 90 * (aStep - aNbPnts / 2))));
120     }
121
122     Handle(Graphic3d_Group) aCircGroup = aPrs->NewGroup();
123     Handle(Graphic3d_ArrayOfPolylines) aPolylines = new Graphic3d_ArrayOfPolylines (aNbPnts * 2, 2);
124     aPolylines->AddBound (aNbPnts);
125
126     for (Standard_Integer anIdx = 0; anIdx < aNbPnts; ++anIdx)
127     {
128       aPolylines->AddVertex (aCircPoints.Value (anIdx).Rotated (gp_Ax1 (gp::Origin(), aDirNorm), M_PI / 2));
129     }
130     aPolylines->AddBound (aNbPnts);
131     for (Standard_Integer anIdx = 0; anIdx < aNbPnts; ++anIdx)
132     {
133       aPolylines->AddVertex (aCircPoints.Value (anIdx));
134     }
135     aCircGroup->AddPrimitiveArray (aPolylines, Standard_False);
136     aCircGroup->SetGroupPrimitivesAspect (theStyle->ArrowAspect()->Aspect());
137     if (thePM->IsImmediateModeOn())
138     {
139       thePM->AddToImmediateList (aPrs);
140     }
141     else
142     {
143       aPrs->Display();
144     }
145   }
146   else
147   {
148     base_type::HilightWithColor (thePM, theStyle, theMode);;
149   }
150 }
151
152 //=======================================================================
153 //function : IsForcedHilight
154 //purpose  :
155 //=======================================================================
156 Standard_Boolean AIS_LightSourceOwner::IsForcedHilight() const
157 {
158   Handle(AIS_LightSource) aLightSource = Handle(AIS_LightSource)::DownCast (mySelectable);
159   if (aLightSource.IsNull())
160   {
161     return Standard_False;
162   }
163   if (aLightSource->Light()->Type() == Graphic3d_TypeOfLightSource_Directional)
164   {
165     return Standard_True;
166   }
167   return Standard_False;
168 }
169
170 // =======================================================================
171 // function : Constructor
172 // purpose  :
173 // =======================================================================
174 AIS_LightSource::AIS_LightSource (const Handle(Graphic3d_CLight)& theLight)
175 : myLightSource (theLight),
176   myCodirMarkerType (Aspect_TOM_X),
177   myOpposMarkerType (Aspect_TOM_O_POINT),
178   mySize (50),
179   myNbArrows (5),
180   myNbSplitsQuadric (theLight->Type() == Graphic3d_TypeOfLightSource_Ambient ? 10 : 30),
181   myNbSplitsArrow (20),
182   mySensSphereArcSize (25),
183   myIsZoomable (theLight->Type() == Graphic3d_TypeOfLightSource_Positional
184              || theLight->Type() == Graphic3d_TypeOfLightSource_Spot),
185   myIsDraggable (theLight->Type() == Graphic3d_TypeOfLightSource_Directional),
186   myToDisplayName (true),
187   myToDisplayRange (true),
188   myToSwitchOnClick (true)
189 {
190   myMarkerTypes[0] = Aspect_TOM_O_X;
191   myMarkerTypes[1] = Aspect_TOM_O_POINT;
192
193   myInfiniteState = true;
194
195   const Quantity_Color aColor = theLight->Color();
196   myDrawer->SetPointAspect (new Prs3d_PointAspect (myMarkerTypes[1], aColor, 3.0f));
197   myDisabledMarkerAspect = new Graphic3d_AspectMarker3d (Aspect_TOM_EMPTY, aColor, 3.0f);
198
199   Graphic3d_MaterialAspect aMat (Graphic3d_NameOfMaterial_UserDefined);
200   aMat.SetColor (aColor);
201   myDrawer->SetArrowAspect (new Prs3d_ArrowAspect());
202   myDrawer->ArrowAspect()->SetColor (aColor);
203   myDrawer->ArrowAspect()->Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
204   myDrawer->ArrowAspect()->Aspect()->ChangeFrontMaterial() = aMat;
205   myDrawer->ArrowAspect()->Aspect()->SetMarkerType (Aspect_TOM_EMPTY);
206   myDrawer->ArrowAspect()->Aspect()->SetMarkerScale (2.0f);
207   myArrowLineAspectShadow = new Graphic3d_AspectLine3d (Quantity_NOC_BLACK, Aspect_TOL_SOLID,
208                                                         theLight->Type() != Graphic3d_TypeOfLightSource_Ambient ? 3.0f : 1.0f);
209
210   myDrawer->SetupOwnShadingAspect();
211   myDrawer->ShadingAspect()->SetColor (aColor);
212   myDrawer->ShadingAspect()->SetMaterial (aMat);
213   myDrawer->ShadingAspect()->SetTransparency (0.5f);
214   myDrawer->ShadingAspect()->Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
215
216   myDrawer->SetTextAspect (new Prs3d_TextAspect());
217   myDrawer->TextAspect()->Aspect()->SetDisplayType (Aspect_TODT_SHADOW);
218   myDrawer->TextAspect()->Aspect()->SetColorSubTitle (Quantity_NOC_BLACK);
219   myDrawer->TextAspect()->SetHorizontalJustification (Graphic3d_HTA_LEFT);
220   myDrawer->TextAspect()->SetVerticalJustification (Graphic3d_VTA_TOPFIRSTLINE);
221
222   updateLightTransformPersistence();
223
224   myDrawer->SetDisplayMode (0);
225   myDynHilightDrawer = new Prs3d_Drawer();
226   myDynHilightDrawer->Link (myDrawer);
227   myDynHilightDrawer->SetDisplayMode (1);
228   myDynHilightDrawer->SetColor (Quantity_NOC_CYAN1);
229
230   if (!myTransformPersistence.IsNull()
231     && myTransformPersistence->IsTrihedronOr2d())
232   {
233     myDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
234     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
235     myDrawer->TextAspect()->SetHorizontalJustification (Graphic3d_HTA_CENTER);
236     myDrawer->TextAspect()->SetVerticalJustification (Graphic3d_VTA_TOP);
237   }
238 }
239
240 //=======================================================================
241 //function : ProcessDragging
242 //purpose  :
243 //=======================================================================
244 Standard_Boolean AIS_LightSource::ProcessDragging (const Handle(AIS_InteractiveContext)& theCtx,
245                                                    const Handle(V3d_View)& theView,
246                                                    const Handle(SelectMgr_EntityOwner)& theOwner,
247                                                    const Graphic3d_Vec2i& theDragFrom,
248                                                    const Graphic3d_Vec2i& theDragTo,
249                                                    const AIS_DragAction theAction)
250 {
251   if (Light()->Type() != Graphic3d_TypeOfLightSource_Directional)
252   {
253     return Standard_False;
254   }
255
256   switch (theAction)
257   {
258     case AIS_DragAction_Start:
259     {
260       myStartTransform = theDragFrom;
261       myLocTrsfStart = LocalTransformation();
262       return Standard_True;
263     }
264     case AIS_DragAction_Update:
265     {
266       theCtx->MainSelector()->Pick (myStartTransform.x(), myStartTransform.y(), theView);
267       gp_Pnt aStartPosition = mySensSphere->LastDetectedPoint();
268       theCtx->MainSelector()->Pick (theDragTo.x(), theDragTo.y(), theView);
269       gp_Pnt aCurrPosition = mySensSphere->LastDetectedPoint();
270       if (aCurrPosition.X() != RealLast() && aStartPosition.Distance (aCurrPosition) > Precision::Confusion())
271       {
272         gp_Quaternion aQRot;
273         aQRot.SetRotation (gp_Vec (gp_Pnt (0, 0, 0), aStartPosition), gp_Vec (gp_Pnt (0, 0, 0), aCurrPosition));
274         gp_Trsf aTrsf;
275         aTrsf.SetRotation (aQRot);
276         SetLocalTransformation (myLocTrsfStart * aTrsf);
277         myLocTrsfStart = LocalTransformation();
278         myStartTransform = theDragTo;
279         theOwner->Selectable()->ClearDynamicHighlight (theCtx->MainPrsMgr());
280         theCtx->HilightWithColor (this, Handle(Prs3d_Drawer)(), false);
281       }
282       return Standard_True;
283     }
284     case AIS_DragAction_Abort:
285     {
286       return Standard_True;
287     }
288     case AIS_DragAction_Stop:
289     {
290       GetHilightPresentation (theCtx->MainPrsMgr())->Clear();
291       break;
292     }
293   }
294   return Standard_False;
295 }
296
297 // =======================================================================
298 // function : updateLightAspects
299 // purpose  :
300 // =======================================================================
301 void AIS_LightSource::updateLightAspects()
302 {
303   const Quantity_Color aBaseColor = myLightSource->Color();
304   const Quantity_Color aDimColor (aBaseColor.Rgb() * 0.3f);
305   const Quantity_Color aColor = myLightSource->IsEnabled() ? aBaseColor : aDimColor;
306   myDrawer->PointAspect()->SetColor (aColor);
307   myDrawer->PointAspect()->Aspect()->SetMarkerType (MarkerType (myLightSource->IsEnabled()));
308   myDrawer->PointAspect()->Aspect()->SetMarkerImage(MarkerImage(myLightSource->IsEnabled()));
309
310   myDisabledMarkerAspect->SetColor (aColor);
311   myDisabledMarkerAspect->SetMarkerScale(myDrawer->PointAspect()->Aspect()->MarkerScale());
312   myDisabledMarkerAspect->SetMarkerType (myLightSource->IsEnabled() ? Aspect_TOM_EMPTY : MarkerType (false));
313   myDisabledMarkerAspect->SetMarkerImage(MarkerImage (false));
314
315   myDrawer->ShadingAspect()->SetColor (aColor);
316   myDrawer->ArrowAspect()  ->SetColor (aColor);
317   myDrawer->ArrowAspect()->Aspect()->ChangeFrontMaterial().SetColor (aColor);
318
319   if (myLightSource->Type() == Graphic3d_TypeOfLightSource_Directional)
320   {
321     const Standard_Real anAngleTol = 2.0 * M_PI / 180.0;
322     Aspect_TypeOfMarker aDirMark = Aspect_TOM_EMPTY;
323     if (myLightSource->IsEnabled()
324      && myLightSource->IsHeadlight()
325      && myLightSource->Direction().IsParallel (gp::DZ(), anAngleTol))
326     {
327       aDirMark = myLightSource->Direction().IsOpposite (-gp::DZ(), anAngleTol) ? myOpposMarkerType : myCodirMarkerType;
328     }
329     myDrawer->ArrowAspect()->Aspect()->SetMarkerType (aDirMark);
330   }
331   SynchronizeAspects();
332 }
333
334 // =======================================================================
335 // function : updateLightTransformPersistence
336 // purpose  :
337 // =======================================================================
338 void AIS_LightSource::updateLightTransformPersistence()
339 {
340   Handle(Graphic3d_TransformPers) aTrsfPers = myTransformPersistence;
341   switch (myLightSource->Type())
342   {
343     case Graphic3d_TypeOfLightSource_Ambient:
344     {
345       if (!myIsZoomable)
346       {
347         if (aTrsfPers.IsNull() || !aTrsfPers->IsTrihedronOr2d())
348         {
349           aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i(50));
350         }
351       }
352       else
353       {
354         aTrsfPers.Nullify();
355       }
356       break;
357     }
358     case Graphic3d_TypeOfLightSource_Directional:
359     {
360       Graphic3d_TransModeFlags aMode = myLightSource->IsHeadlight() ? Graphic3d_TMF_2d : Graphic3d_TMF_TriedronPers;
361       if (myIsZoomable)
362       {
363         aMode = myLightSource->IsHeadlight() ? Graphic3d_TMF_CameraPers : Graphic3d_TMF_None;
364       }
365       if (aMode != Graphic3d_TMF_None)
366       {
367         if (aTrsfPers.IsNull() || aTrsfPers->Mode() != aMode)
368         {
369           if (aMode == Graphic3d_TMF_CameraPers)
370           {
371             aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_CameraPers);
372           }
373           else
374           {
375             aTrsfPers = new Graphic3d_TransformPers (aMode, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i(50));
376           }
377         }
378       }
379       else
380       {
381         aTrsfPers.Nullify();
382       }
383       break;
384     }
385     case Graphic3d_TypeOfLightSource_Positional:
386     case Graphic3d_TypeOfLightSource_Spot:
387     {
388       Graphic3d_TransModeFlags aMode = myLightSource->IsHeadlight()
389                                      ? Graphic3d_TMF_CameraPers
390                                      : (!myIsZoomable ? Graphic3d_TMF_ZoomPers : Graphic3d_TMF_None);
391       if (aMode != Graphic3d_TMF_None)
392       {
393         if (aTrsfPers.IsNull() || aTrsfPers->Mode() != aMode)
394         {
395           if (aMode == Graphic3d_TMF_CameraPers)
396           {
397             aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_CameraPers);
398           }
399           else
400           {
401             aTrsfPers = new Graphic3d_TransformPers (aMode, myLightSource->Position());
402           }
403         }
404         if (aMode == Graphic3d_TMF_ZoomPers)
405         {
406           aTrsfPers->SetAnchorPoint (myLightSource->Position());
407         }
408       }
409       else
410       {
411         aTrsfPers.Nullify();
412       }
413       break;
414     }
415   }
416
417   SetTransformPersistence (aTrsfPers);
418 }
419
420 // =======================================================================
421 // function : updateLightLocalTransformation
422 // purpose  :
423 // =======================================================================
424 void AIS_LightSource::updateLightLocalTransformation()
425 {
426   myLocalTransformation.Nullify();
427   switch (myLightSource->Type())
428   {
429     case Graphic3d_TypeOfLightSource_Ambient:
430     {
431       if (myIsZoomable)
432       {
433         gp_Trsf aTrsf;
434         aTrsf.SetTranslation (gp::Origin(), myLightSource->Position());
435         myLocalTransformation = new TopLoc_Datum3D (aTrsf);
436       }
437       break;
438     }
439     case Graphic3d_TypeOfLightSource_Directional:
440     {
441       const gp_Pnt aLightPos = (myIsZoomable && !myLightSource->IsHeadlight())
442                              ? myLightSource->DisplayPosition()
443                              : gp::Origin();
444       gp_Trsf aTrsf;
445       const gp_Ax2 anAx2 (aLightPos, -myLightSource->Direction());
446       aTrsf.SetTransformation (anAx2, gp_Ax3());
447       myLocalTransformation = new TopLoc_Datum3D (aTrsf);
448       break;
449     }
450     case Graphic3d_TypeOfLightSource_Positional:
451     {
452       if (myIsZoomable)
453       {
454         gp_Trsf aTrsf;
455         aTrsf.SetTranslation (gp::Origin(), myLightSource->Position());
456         myLocalTransformation = new TopLoc_Datum3D (aTrsf);
457       }
458       break;
459     }
460     case Graphic3d_TypeOfLightSource_Spot:
461     {
462       gp_Trsf aTrsf;
463       const gp_Ax2 anAx2 (myIsZoomable ? myLightSource->Position() : gp::Origin(), -myLightSource->Direction());
464       aTrsf.SetTransformation (anAx2, gp_Ax3());
465       myLocalTransformation = new TopLoc_Datum3D (aTrsf);
466       break;
467     }
468   }
469   UpdateTransformation();
470 }
471
472 // =======================================================================
473 // function : setLocalTransformation
474 // purpose  :
475 // =======================================================================
476 void AIS_LightSource::setLocalTransformation (const Handle(TopLoc_Datum3D)& theTrsf)
477 {
478   const gp_Trsf aTrsf = theTrsf->Transformation();
479   switch (myLightSource->Type())
480   {
481     case Graphic3d_TypeOfLightSource_Ambient:
482     {
483       break;
484     }
485     case Graphic3d_TypeOfLightSource_Directional:
486     {
487       gp_Dir aNewDir = (-gp::DZ()).Transformed (aTrsf);
488       myLightSource->SetDirection (aNewDir);
489       if (myIsZoomable)
490       {
491         gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf);
492         myLightSource->SetDisplayPosition (aNewPos);
493       }
494       break;
495     }
496     case Graphic3d_TypeOfLightSource_Positional:
497     {
498       gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf);
499       myLightSource->SetPosition (aNewPos);
500       break;
501     }
502     case Graphic3d_TypeOfLightSource_Spot:
503     {
504       gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf);
505       myLightSource->SetPosition (aNewPos);
506
507       gp_Dir aNewDir = (-gp::DZ()).Transformed (aTrsf);
508       myLightSource->SetDirection (aNewDir);
509       break;
510     }
511   }
512
513   base_type::setLocalTransformation (new TopLoc_Datum3D (aTrsf));
514
515   updateLightAspects();
516   updateLightTransformPersistence();
517 }
518
519 // =======================================================================
520 // function : Compute
521 // purpose  :
522 // =======================================================================
523 void AIS_LightSource::Compute (const Handle(PrsMgr_PresentationManager)& ,
524                                const Handle(Prs3d_Presentation)& thePrs,
525                                const Standard_Integer theMode)
526 {
527   thePrs->SetInfiniteState (myInfiniteState);
528   if (theMode != 0
529    && theMode != 1)
530   {
531     return;
532   }
533
534   if (theMode == 0)
535   {
536     updateLightAspects();
537     updateLightTransformPersistence();
538     updateLightLocalTransformation();
539   }
540
541   switch (myLightSource->Type())
542   {
543     case Graphic3d_TypeOfLightSource_Ambient:     computeAmbient    (thePrs, theMode); break;
544     case Graphic3d_TypeOfLightSource_Directional: computeDirectional(thePrs, theMode); break;
545     case Graphic3d_TypeOfLightSource_Positional:  computePositional (thePrs, theMode); break;
546     case Graphic3d_TypeOfLightSource_Spot:        computeSpot       (thePrs, theMode); break;
547   }
548
549   if (myToDisplayName)
550   {
551     TCollection_AsciiString aPrefix = !myTransformPersistence.IsNull()
552                                     && myTransformPersistence->IsTrihedronOr2d()
553                                     ? "\n" : "   ";
554     TCollection_AsciiString aName = aPrefix + myLightSource->Name();
555     Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), aName, gp::Origin());
556   }
557 }
558
559 // =======================================================================
560 // function : computeAmbient
561 // purpose  :
562 // =======================================================================
563 void AIS_LightSource::computeAmbient (const Handle(Prs3d_Presentation)& thePrs,
564                                       const Standard_Integer theMode)
565 {
566   const gp_XYZ aLightPos = gp::Origin().XYZ();
567   if (theMode == 0)
568   {
569     Handle(Graphic3d_ArrayOfTriangles) aSphereArray = Prs3d_ToolSphere::Create (mySize * 0.25, myNbSplitsQuadric, myNbSplitsQuadric, gp_Trsf());
570     Handle(Graphic3d_Group) aSphereGroup = thePrs->NewGroup();
571     aSphereGroup->SetClosed (true);
572     aSphereGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
573     aSphereGroup->AddPrimitiveArray (aSphereArray);
574   }
575   if (theMode == 0
576    || theMode == 1)
577   {
578     const Standard_Real aLen = mySize * 0.25;
579     const Standard_Integer aNbArrows = 6;
580     const gp_Dir aDirList[6] = { -gp::DX(), gp::DX(), -gp::DY(), gp::DY(), -gp::DZ(), gp::DZ() };
581
582     const Prs3d_ToolCylinder aCylTool (mySize * 0.1, 0.0, mySize * 0.2, myNbSplitsArrow, myNbSplitsArrow);
583     Handle(Graphic3d_ArrayOfTriangles) aTrisArray = new Graphic3d_ArrayOfTriangles (aNbArrows * aCylTool.VerticesNb(),
584                                                                                     aNbArrows * aCylTool.TrianglesNb() * 3,
585                                                                                     Graphic3d_ArrayFlags_VertexNormal);
586     Handle(Graphic3d_ArrayOfSegments) aLineArray = new Graphic3d_ArrayOfSegments (aNbArrows * 2);
587     for (Standard_Integer anArrIter = 0; anArrIter < aNbArrows; ++anArrIter)
588     {
589       const gp_Dir& aDir = aDirList[anArrIter];
590       const gp_XYZ  aPnt = aLightPos + aDir.XYZ() * aLen;
591       if (!aLineArray.IsNull())
592       {
593         aLineArray->AddVertex (aPnt + aDir.XYZ() * aLen * 0.5);
594         aLineArray->AddVertex (aPnt + aDir.XYZ() * aLen * 1.5);
595       }
596       if (!aTrisArray.IsNull())
597       {
598         const gp_Ax3 aSystem (aPnt + aDir.XYZ() * aLen, -aDir);
599         gp_Trsf aTrsfCone;
600         aTrsfCone.SetTransformation (aSystem, gp_Ax3());
601         aCylTool.FillArray (aTrisArray, aTrsfCone);
602       }
603     }
604
605     if (!aLineArray.IsNull())
606     {
607       Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup();
608       aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow);
609       aDirGroupShadow->AddPrimitiveArray (aLineArray);
610     }
611     if (!aTrisArray.IsNull())
612     {
613       Handle(Graphic3d_Group) anArrowGroup = thePrs->NewGroup();
614       anArrowGroup->SetClosed (true);
615       anArrowGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
616       anArrowGroup->AddPrimitiveArray (aTrisArray);
617     }
618   }
619
620   {
621     Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1);
622     aPoints->AddVertex (aLightPos);
623     Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
624     aGroup->SetGroupPrimitivesAspect (theMode == 1 ? myDrawer->PointAspect()->Aspect() : myDisabledMarkerAspect);
625     aGroup->AddPrimitiveArray (aPoints);
626   }
627 }
628
629 // =======================================================================
630 // function : computeDirectional
631 // purpose  :
632 // =======================================================================
633 void AIS_LightSource::computeDirectional (const Handle(Prs3d_Presentation)& thePrs,
634                                           const Standard_Integer theMode)
635 {
636   const Standard_Real aDistance = mySize * 0.5;
637   const Standard_Real aStep = aDistance * 0.5;
638
639   // light source direction is set to local transformation
640   const gp_Dir aLightDir = -gp::DZ();
641   const gp_XYZ aLightPos = -aStep * aLightDir.XYZ();
642
643   Standard_Integer aNbArrows = 1;
644   if      (myNbArrows >= 9) { aNbArrows = 9; }
645   else if (myNbArrows >= 5) { aNbArrows = 5; }
646   else if (myNbArrows >= 3) { aNbArrows = 3; }
647   TColgp_Array1OfPnt aPoints (1, aNbArrows);
648   {
649     const gp_Ax2 anAxes (gp::Origin(), aLightDir);
650     const gp_XYZ aDY = anAxes.YDirection().XYZ() * aStep;
651     const gp_XYZ aDX = anAxes.XDirection().XYZ() * aStep;
652     const gp_XYZ aDXY = aDX + aDY;
653     switch (aNbArrows)
654     {
655       case 9:
656       {
657         aPoints.SetValue (6, aLightPos + aDY);
658         aPoints.SetValue (7, aLightPos + aDX);
659         aPoints.SetValue (8, aLightPos - aDY);
660         aPoints.SetValue (9, aLightPos - aDX);
661       }
662       Standard_FALLTHROUGH
663       case 5:
664       {
665         aPoints.SetValue (4, aLightPos - aDY + aDX);
666         aPoints.SetValue (5, aLightPos + aDY - aDX);
667       }
668       Standard_FALLTHROUGH
669       case 3:
670       {
671         aPoints.SetValue (2, aLightPos + aDXY);
672         aPoints.SetValue (3, aLightPos - aDXY);
673       }
674       Standard_FALLTHROUGH
675       case 1:
676       {
677         aPoints.SetValue (1, aLightPos);
678         break;
679       }
680     }
681   }
682
683   const Prs3d_ToolCylinder aCylTool (aDistance * 0.1, 0.0, aDistance * 0.2, myNbSplitsArrow, myNbSplitsArrow);
684   Handle(Graphic3d_ArrayOfTriangles) aTrisArray;
685   if (theMode == 0)
686   {
687     aTrisArray = new Graphic3d_ArrayOfTriangles (aNbArrows * aCylTool.VerticesNb(),
688                                                  aNbArrows * aCylTool.TrianglesNb() * 3,
689                                                  Graphic3d_ArrayFlags_VertexNormal);
690   }
691   Handle(Graphic3d_ArrayOfPoints) aPntArray = new Graphic3d_ArrayOfPoints (aNbArrows);
692   Handle(Graphic3d_ArrayOfSegments) aLineArray = new Graphic3d_ArrayOfSegments (aNbArrows * 2);
693   for (Standard_Integer aPntIter = aPoints.Lower(); aPntIter <= aPoints.Upper(); ++aPntIter)
694   {
695     const gp_Pnt aPnt = aPoints.Value (aPntIter);
696     if (!aPntArray.IsNull())
697     {
698       aPntArray->AddVertex (aPnt);
699     }
700     if (!aLineArray.IsNull())
701     {
702       aLineArray->AddVertex (aPnt);
703       aLineArray->AddVertex (gp_Pnt (aPnt.XYZ() + aLightDir.XYZ() * aDistance));
704     }
705     if (!aTrisArray.IsNull())
706     {
707       const gp_Ax3 aSystem (aPnt.XYZ() + aLightDir.XYZ() * aDistance, aLightDir);
708       gp_Trsf aTrsfCone;
709       aTrsfCone.SetTransformation (aSystem, gp_Ax3());
710       aCylTool.FillArray (aTrisArray, aTrsfCone);
711     }
712   }
713
714   if (!aLineArray.IsNull() && theMode == 0)
715   {
716     Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup();
717     aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow);
718     aDirGroupShadow->AddPrimitiveArray (aLineArray);
719   }
720   if (!aLineArray.IsNull())
721   {
722     Handle(Graphic3d_Group) aDirGroup = thePrs->NewGroup();
723     aDirGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
724     aDirGroup->AddPrimitiveArray (aLineArray);
725   }
726   if (!aTrisArray.IsNull())
727   {
728     Handle(Graphic3d_Group) anArrowGroup = thePrs->NewGroup();
729     anArrowGroup->SetClosed (true);
730     anArrowGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
731     anArrowGroup->AddPrimitiveArray (aTrisArray);
732   }
733   if (!aPntArray.IsNull())
734   {
735     Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
736     aGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
737     aGroup->AddPrimitiveArray (aPntArray);
738   }
739   {
740     Handle(Graphic3d_ArrayOfPoints) aPntArray2 = new Graphic3d_ArrayOfPoints (1);
741     aPntArray2->AddVertex (aLightPos);
742     Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
743     aGroup->SetGroupPrimitivesAspect (myDisabledMarkerAspect);
744     aGroup->AddPrimitiveArray (aPntArray2);
745   }
746 }
747
748 // =======================================================================
749 // function : computePositional
750 // purpose  :
751 // =======================================================================
752 void AIS_LightSource::computePositional (const Handle(Prs3d_Presentation)& thePrs,
753                                          const Standard_Integer theMode)
754 {
755   // light source position is set to local transformation
756   const gp_XYZ aLightPos = gp::Origin().XYZ();
757   const Standard_Real aRadius = (myIsZoomable && myLightSource->HasRange()) ? myLightSource->Range() : 0.0;
758   if (theMode == 0
759    && aRadius > 0.0
760    && myToDisplayRange)
761   {
762     Handle(Graphic3d_ArrayOfTriangles) aPosRangeArray = Prs3d_ToolSphere::Create (aRadius, myNbSplitsQuadric, myNbSplitsQuadric, gp_Trsf());
763     Handle(Graphic3d_Group) aRangeGroup = thePrs->NewGroup();
764     aRangeGroup->SetClosed (true);
765     aRangeGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
766     aRangeGroup->AddPrimitiveArray (aPosRangeArray);
767   }
768   {
769     Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1);
770     aPoints->AddVertex (aLightPos);
771     Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
772     aGroup->SetGroupPrimitivesAspect (myDrawer->PointAspect()->Aspect());
773     aGroup->AddPrimitiveArray (aPoints);
774   }
775 }
776
777 // =======================================================================
778 // function : computeSpot
779 // purpose  :
780 // =======================================================================
781 void AIS_LightSource::computeSpot (const Handle(Prs3d_Presentation)& thePrs,
782                                    const Standard_Integer theMode)
783 {
784   // light source position and direction are set to local transformation
785   const gp_Dir aLightDir = -gp::DZ();
786   const gp_XYZ aLightPos = gp::Origin().XYZ();
787   const Standard_Real aDistance = (myIsZoomable && myLightSource->HasRange()) ? myLightSource->Range() : mySize;
788   {
789     Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1);
790     aPoints->AddVertex (aLightPos);
791
792     Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
793     aGroup->SetGroupPrimitivesAspect (myDrawer->PointAspect()->Aspect());
794     aGroup->AddPrimitiveArray (aPoints);
795   }
796
797   {
798     Handle(Graphic3d_ArrayOfSegments) aDirArray = new Graphic3d_ArrayOfSegments (2);
799     aDirArray->AddVertex (aLightPos);
800     aDirArray->AddVertex (gp_Pnt (aLightPos + aLightDir.XYZ() * aDistance));
801
802     Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup();
803     aDirGroupShadow->SetClosed (true);
804     aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow);
805     aDirGroupShadow->AddPrimitiveArray (aDirArray);
806
807     Handle(Graphic3d_Group) aDirGroup = thePrs->NewGroup();
808     aDirGroup->SetClosed (true);
809     aDirGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
810     aDirGroup->AddPrimitiveArray (aDirArray);
811   }
812
813   if (theMode == 0
814    && myToDisplayRange)
815   {
816     const Standard_ShortReal aHalfAngle = myLightSource->Angle() / 2.0f;
817     const Standard_Real aRadius = aDistance * Tan (aHalfAngle);
818     gp_Ax3  aSystem (aLightPos + aLightDir.XYZ() * aDistance, -aLightDir);
819     gp_Trsf aTrsfCone;
820     aTrsfCone.SetTransformation (aSystem, gp_Ax3());
821     Handle(Graphic3d_ArrayOfTriangles) aSpotRangeArray = Prs3d_ToolCylinder::Create (aRadius, 0.0, aDistance,
822                                                                                      myNbSplitsQuadric, myNbSplitsQuadric, aTrsfCone);
823
824     Handle(Graphic3d_Group) aRangeGroup = thePrs->NewGroup();
825     aRangeGroup->SetClosed (true);
826     aRangeGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
827     aRangeGroup->AddPrimitiveArray (aSpotRangeArray);
828   }
829 }
830
831 // =======================================================================
832 // function : ComputeSelection
833 // purpose  :
834 // =======================================================================
835 void AIS_LightSource::ComputeSelection (const Handle(SelectMgr_Selection)& theSel,
836                                         const Standard_Integer theMode)
837 {
838   if (theMode != 0)
839   {
840     return;
841   }
842
843   Handle(AIS_LightSourceOwner) anEntityOwner = new AIS_LightSourceOwner (this, 15);
844   {
845     if (myLightSource->Type() == Graphic3d_TypeOfLightSource_Directional)
846     {
847       mySensSphere = new Select3D_SensitiveSphere (anEntityOwner, gp::Origin(), mySize * 0.5);
848       theSel->Add (mySensSphere);
849     }
850
851     Handle(Select3D_SensitivePoint) aSensPosition = new Select3D_SensitivePoint (anEntityOwner, gp::Origin());
852     aSensPosition->SetSensitivityFactor (12);
853     if (!myTransformPersistence.IsNull()
854       && myTransformPersistence->IsTrihedronOr2d())
855     {
856       aSensPosition->SetSensitivityFactor (Max (12, Standard_Integer (mySize * 0.5)));
857     }
858     theSel->Add (aSensPosition);
859   }
860 }