0031704: Visualization - add an interactive object AIS_LightSource representing a...
[occt.git] / src / AIS / AIS_LightSource.cxx
diff --git a/src/AIS/AIS_LightSource.cxx b/src/AIS/AIS_LightSource.cxx
new file mode 100644 (file)
index 0000000..f5112fa
--- /dev/null
@@ -0,0 +1,693 @@
+// Created on: 2020-09-07
+// Created by: Maria KRYLOVA
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <AIS_LightSource.hxx>
+
+#include <AIS_InteractiveContext.hxx>
+#include <Graphic3d_ArrayOfPoints.hxx>
+#include <Graphic3d_ArrayOfSegments.hxx>
+#include <Graphic3d_ArrayOfTriangles.hxx>
+#include <Graphic3d_CView.hxx>
+#include <Graphic3d_Group.hxx>
+#include <Prs3d_ArrowAspect.hxx>
+#include <Prs3d_PointAspect.hxx>
+#include <Prs3d_Text.hxx>
+#include <Prs3d_ToolCylinder.hxx>
+#include <Prs3d_ToolSphere.hxx>
+#include <Select3D_SensitivePoint.hxx>
+#include <V3d_View.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(AIS_LightSource, AIS_InteractiveObject)
+IMPLEMENT_STANDARD_RTTIEXT(AIS_LightSourceOwner, SelectMgr_EntityOwner)
+
+// =======================================================================
+// function : AIS_LightSourceOwner
+// purpose  :
+// =======================================================================
+AIS_LightSourceOwner::AIS_LightSourceOwner (const Handle(AIS_LightSource)& theObject,
+                                            Standard_Integer thePriority)
+: SelectMgr_EntityOwner ((const Handle(SelectMgr_SelectableObject)&)theObject, thePriority)
+{
+  //
+}
+
+// =======================================================================
+// function : HandleMouseClick
+// purpose  :
+// =======================================================================
+Standard_Boolean AIS_LightSourceOwner::HandleMouseClick (const Graphic3d_Vec2i& ,
+                                                         Aspect_VKeyMouse theKey,
+                                                         Aspect_VKeyFlags theFlags,
+                                                         bool )
+{
+  AIS_LightSource* aLightSource = dynamic_cast<AIS_LightSource*>(mySelectable);
+  if (aLightSource != NULL
+   && aLightSource->ToSwitchOnClick()
+   && theKey == Aspect_VKeyMouse_LeftButton
+   && theFlags == Aspect_VKeyFlags_NONE)
+  {
+    aLightSource->Light()->SetEnabled (!aLightSource->Light()->IsEnabled());
+    aLightSource->updateLightAspects();
+    return true;
+  }
+  return false;
+}
+
+// =======================================================================
+// function : Constructor
+// purpose  :
+// =======================================================================
+AIS_LightSource::AIS_LightSource (const Handle(Graphic3d_CLight)& theLight)
+: myLightSource (theLight),
+  myCodirMarkerType (Aspect_TOM_X),
+  myOpposMarkerType (Aspect_TOM_O_POINT),
+  mySize (50),
+  myNbArrows (5),
+  myNbSplitsQuadric (theLight->Type() == Graphic3d_TOLS_AMBIENT ? 10 : 30),
+  myNbSplitsArrow (20),
+  myIsZoomable (theLight->Type() == Graphic3d_TOLS_POSITIONAL
+             || theLight->Type() == Graphic3d_TOLS_SPOT),
+  myToDisplayName (true),
+  myToDisplayRange (true),
+  myToSwitchOnClick (true)
+{
+  myMarkerTypes[0] = Aspect_TOM_O_X;
+  myMarkerTypes[1] = Aspect_TOM_O_POINT;
+
+  myInfiniteState = true;
+
+  const Quantity_Color aColor = theLight->Color();
+  myDrawer->SetPointAspect (new Prs3d_PointAspect (myMarkerTypes[1], aColor, 3.0f));
+  myDisabledMarkerAspect = new Graphic3d_AspectMarker3d (Aspect_TOM_EMPTY, aColor, 3.0f);
+
+  Graphic3d_MaterialAspect aMat (Graphic3d_NameOfMaterial_UserDefined);
+  aMat.SetColor (aColor);
+  myDrawer->SetArrowAspect (new Prs3d_ArrowAspect());
+  myDrawer->ArrowAspect()->SetColor (aColor);
+  myDrawer->ArrowAspect()->Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
+  myDrawer->ArrowAspect()->Aspect()->ChangeFrontMaterial() = aMat;
+  myDrawer->ArrowAspect()->Aspect()->SetMarkerType (Aspect_TOM_EMPTY);
+  myDrawer->ArrowAspect()->Aspect()->SetMarkerScale (2.0f);
+  myArrowLineAspectShadow = new Graphic3d_AspectLine3d (Quantity_NOC_BLACK, Aspect_TOL_SOLID,
+                                                        theLight->Type() != Graphic3d_TOLS_AMBIENT ? 3.0f : 1.0f);
+
+  myDrawer->SetupOwnShadingAspect();
+  myDrawer->ShadingAspect()->SetColor (aColor);
+  myDrawer->ShadingAspect()->SetMaterial (aMat);
+  myDrawer->ShadingAspect()->SetTransparency (0.5f);
+  myDrawer->ShadingAspect()->Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
+
+  myDrawer->SetTextAspect (new Prs3d_TextAspect());
+  myDrawer->TextAspect()->Aspect()->SetDisplayType (Aspect_TODT_SHADOW);
+  myDrawer->TextAspect()->Aspect()->SetColorSubTitle (Quantity_NOC_BLACK);
+  myDrawer->TextAspect()->SetHorizontalJustification (Graphic3d_HTA_LEFT);
+  myDrawer->TextAspect()->SetVerticalJustification (Graphic3d_VTA_TOPFIRSTLINE);
+
+  updateLightTransformPersistence();
+
+  myDrawer->SetDisplayMode (0);
+  myDynHilightDrawer = new Prs3d_Drawer();
+  myDynHilightDrawer->Link (myDrawer);
+  myDynHilightDrawer->SetDisplayMode (1);
+  myDynHilightDrawer->SetColor (Quantity_NOC_CYAN1);
+
+  if (!myTransformPersistence.IsNull()
+    && myTransformPersistence->IsTrihedronOr2d())
+  {
+    myDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
+    myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
+    myDrawer->TextAspect()->SetHorizontalJustification (Graphic3d_HTA_CENTER);
+    myDrawer->TextAspect()->SetVerticalJustification (Graphic3d_VTA_TOP);
+  }
+}
+
+// =======================================================================
+// function : updateLightAspects
+// purpose  :
+// =======================================================================
+void AIS_LightSource::updateLightAspects()
+{
+  const Quantity_Color aBaseColor = myLightSource->Color();
+  const Quantity_Color aDimColor (aBaseColor.Rgb() * 0.3f);
+  const Quantity_Color aColor = myLightSource->IsEnabled() ? aBaseColor : aDimColor;
+  myDrawer->PointAspect()->SetColor (aColor);
+  myDrawer->PointAspect()->Aspect()->SetMarkerType (MarkerType (myLightSource->IsEnabled()));
+  myDrawer->PointAspect()->Aspect()->SetMarkerImage(MarkerImage(myLightSource->IsEnabled()));
+
+  myDisabledMarkerAspect->SetColor (aColor);
+  myDisabledMarkerAspect->SetMarkerScale(myDrawer->PointAspect()->Aspect()->MarkerScale());
+  myDisabledMarkerAspect->SetMarkerType (myLightSource->IsEnabled() ? Aspect_TOM_EMPTY : MarkerType (false));
+  myDisabledMarkerAspect->SetMarkerImage(MarkerImage (false));
+
+  myDrawer->ShadingAspect()->SetColor (aColor);
+  myDrawer->ArrowAspect()  ->SetColor (aColor);
+  myDrawer->ArrowAspect()->Aspect()->ChangeFrontMaterial().SetColor (aColor);
+
+  if (myLightSource->Type() == Graphic3d_TOLS_DIRECTIONAL)
+  {
+    const Standard_Real anAngleTol = 2.0 * M_PI / 180.0;
+    Aspect_TypeOfMarker aDirMark = Aspect_TOM_EMPTY;
+    if (myLightSource->IsEnabled()
+     && myLightSource->IsHeadlight()
+     && myLightSource->Direction().IsParallel (gp::DZ(), anAngleTol))
+    {
+      aDirMark = myLightSource->Direction().IsOpposite (-gp::DZ(), anAngleTol) ? myOpposMarkerType : myCodirMarkerType;
+    }
+    myDrawer->ArrowAspect()->Aspect()->SetMarkerType (aDirMark);
+  }
+  SynchronizeAspects();
+}
+
+// =======================================================================
+// function : updateLightTransformPersistence
+// purpose  :
+// =======================================================================
+void AIS_LightSource::updateLightTransformPersistence()
+{
+  Handle(Graphic3d_TransformPers) aTrsfPers = myTransformPersistence;
+  switch (myLightSource->Type())
+  {
+    case Graphic3d_TOLS_AMBIENT:
+    {
+      if (!myIsZoomable)
+      {
+        if (aTrsfPers.IsNull() || !aTrsfPers->IsTrihedronOr2d())
+        {
+          aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i(50));
+        }
+      }
+      else
+      {
+        aTrsfPers.Nullify();
+      }
+      break;
+    }
+    case Graphic3d_TOLS_DIRECTIONAL:
+    {
+      Graphic3d_TransModeFlags aMode = myLightSource->IsHeadlight() ? Graphic3d_TMF_2d : Graphic3d_TMF_TriedronPers;
+      if (myIsZoomable)
+      {
+        aMode = myLightSource->IsHeadlight() ? Graphic3d_TMF_CameraPers : Graphic3d_TMF_None;
+      }
+      if (aMode != Graphic3d_TMF_None)
+      {
+        if (aTrsfPers.IsNull() || aTrsfPers->Mode() != aMode)
+        {
+          if (aMode == Graphic3d_TMF_CameraPers)
+          {
+            aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_CameraPers);
+          }
+          else
+          {
+            aTrsfPers = new Graphic3d_TransformPers (aMode, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i(50));
+          }
+        }
+      }
+      else
+      {
+        aTrsfPers.Nullify();
+      }
+      break;
+    }
+    case Graphic3d_TOLS_POSITIONAL:
+    case Graphic3d_TOLS_SPOT:
+    {
+      Graphic3d_TransModeFlags aMode = myLightSource->IsHeadlight()
+                                     ? Graphic3d_TMF_CameraPers
+                                     : (!myIsZoomable ? Graphic3d_TMF_ZoomPers : Graphic3d_TMF_None);
+      if (aMode != Graphic3d_TMF_None)
+      {
+        if (aTrsfPers.IsNull() || aTrsfPers->Mode() != aMode)
+        {
+          if (aMode == Graphic3d_TMF_CameraPers)
+          {
+            aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_CameraPers);
+          }
+          else
+          {
+            aTrsfPers = new Graphic3d_TransformPers (aMode, myLightSource->Position());
+          }
+        }
+        if (aMode == Graphic3d_TMF_ZoomPers)
+        {
+          aTrsfPers->SetAnchorPoint (myLightSource->Position());
+        }
+      }
+      else
+      {
+        aTrsfPers.Nullify();
+      }
+      break;
+    }
+  }
+
+  SetTransformPersistence (aTrsfPers);
+}
+
+// =======================================================================
+// function : updateLightLocalTransformation
+// purpose  :
+// =======================================================================
+void AIS_LightSource::updateLightLocalTransformation()
+{
+  myLocalTransformation.Nullify();
+  switch (myLightSource->Type())
+  {
+    case Graphic3d_TOLS_AMBIENT:
+    {
+      if (myIsZoomable)
+      {
+        gp_Trsf aTrsf;
+        aTrsf.SetTranslation (gp::Origin(), myLightSource->Position());
+        myLocalTransformation = new TopLoc_Datum3D (aTrsf);
+      }
+      break;
+    }
+    case Graphic3d_TOLS_DIRECTIONAL:
+    {
+      const gp_Pnt aLightPos = (myIsZoomable && !myLightSource->IsHeadlight())
+                             ? myLightSource->DisplayPosition()
+                             : gp::Origin();
+      gp_Trsf aTrsf;
+      const gp_Ax2 anAx2 (aLightPos, -myLightSource->Direction());
+      aTrsf.SetTransformation (anAx2, gp_Ax3());
+      myLocalTransformation = new TopLoc_Datum3D (aTrsf);
+      break;
+    }
+    case Graphic3d_TOLS_POSITIONAL:
+    {
+      if (myIsZoomable)
+      {
+        gp_Trsf aTrsf;
+        aTrsf.SetTranslation (gp::Origin(), myLightSource->Position());
+        myLocalTransformation = new TopLoc_Datum3D (aTrsf);
+      }
+      break;
+    }
+    case Graphic3d_TOLS_SPOT:
+    {
+      gp_Trsf aTrsf;
+      const gp_Ax2 anAx2 (myIsZoomable ? myLightSource->Position() : gp::Origin(), -myLightSource->Direction());
+      aTrsf.SetTransformation (anAx2, gp_Ax3());
+      myLocalTransformation = new TopLoc_Datum3D (aTrsf);
+      break;
+    }
+  }
+  UpdateTransformation();
+}
+
+// =======================================================================
+// function : setLocalTransformation
+// purpose  :
+// =======================================================================
+void AIS_LightSource::setLocalTransformation (const Handle(TopLoc_Datum3D)& theTrsf)
+{
+  const gp_Trsf aTrsf = theTrsf->Transformation();
+  switch (myLightSource->Type())
+  {
+    case Graphic3d_TOLS_AMBIENT:
+    {
+      break;
+    }
+    case Graphic3d_TOLS_DIRECTIONAL:
+    {
+      gp_Dir aNewDir = (-gp::DZ()).Transformed (aTrsf);
+      myLightSource->SetDirection (aNewDir);
+      if (myIsZoomable)
+      {
+        gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf);
+        myLightSource->SetDisplayPosition (aNewPos);
+      }
+      break;
+    }
+    case Graphic3d_TOLS_POSITIONAL:
+    {
+      gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf);
+      myLightSource->SetPosition (aNewPos);
+      break;
+    }
+    case Graphic3d_TOLS_SPOT:
+    {
+      gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf);
+      myLightSource->SetPosition (aNewPos);
+
+      gp_Dir aNewDir = (-gp::DZ()).Transformed (aTrsf);
+      myLightSource->SetDirection (aNewDir);
+      break;
+    }
+  }
+
+  base_type::setLocalTransformation (new TopLoc_Datum3D (aTrsf));
+
+  updateLightAspects();
+  updateLightTransformPersistence();
+}
+
+// =======================================================================
+// function : Compute
+// purpose  :
+// =======================================================================
+void AIS_LightSource::Compute (const Handle(PrsMgr_PresentationManager3d)& ,
+                               const Handle(Prs3d_Presentation)& thePrs,
+                               const Standard_Integer theMode)
+{
+  thePrs->SetInfiniteState (myInfiniteState);
+  if (theMode != 0
+   && theMode != 1)
+  {
+    return;
+  }
+
+  if (theMode == 0)
+  {
+    updateLightAspects();
+    updateLightTransformPersistence();
+    updateLightLocalTransformation();
+  }
+
+  switch (myLightSource->Type())
+  {
+    case Graphic3d_TOLS_AMBIENT:     computeAmbient    (thePrs, theMode); break;
+    case Graphic3d_TOLS_DIRECTIONAL: computeDirectional(thePrs, theMode); break;
+    case Graphic3d_TOLS_POSITIONAL:  computePositional (thePrs, theMode); break;
+    case Graphic3d_TOLS_SPOT:        computeSpot       (thePrs, theMode); break;
+  }
+
+  if (myToDisplayName)
+  {
+    TCollection_AsciiString aPrefix = !myTransformPersistence.IsNull()
+                                    && myTransformPersistence->IsTrihedronOr2d()
+                                    ? "\n" : "   ";
+    TCollection_AsciiString aName = aPrefix + myLightSource->Name();
+    Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), aName, gp::Origin());
+  }
+}
+
+// =======================================================================
+// function : computeAmbient
+// purpose  :
+// =======================================================================
+void AIS_LightSource::computeAmbient (const Handle(Prs3d_Presentation)& thePrs,
+                                      const Standard_Integer theMode)
+{
+  const gp_XYZ aLightPos = gp::Origin().XYZ();
+  if (theMode == 0)
+  {
+    Handle(Graphic3d_ArrayOfTriangles) aSphereArray = Prs3d_ToolSphere::Create (mySize * 0.25, myNbSplitsQuadric, myNbSplitsQuadric, gp_Trsf());
+    Handle(Graphic3d_Group) aSphereGroup = thePrs->NewGroup();
+    aSphereGroup->SetClosed (true);
+    aSphereGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
+    aSphereGroup->AddPrimitiveArray (aSphereArray);
+  }
+  if (theMode == 0
+   || theMode == 1)
+  {
+    const Standard_Real aLen = mySize * 0.25;
+    const Standard_Integer aNbArrows = 6;
+    const gp_Dir aDirList[6] = { -gp::DX(), gp::DX(), -gp::DY(), gp::DY(), -gp::DZ(), gp::DZ() };
+
+    const Prs3d_ToolCylinder aCylTool (mySize * 0.1, 0.0, mySize * 0.2, myNbSplitsArrow, myNbSplitsArrow);
+    Handle(Graphic3d_ArrayOfTriangles) aTrisArray = new Graphic3d_ArrayOfTriangles (aNbArrows * aCylTool.VerticesNb(),
+                                                                                    aNbArrows * aCylTool.TrianglesNb() * 3,
+                                                                                    Graphic3d_ArrayFlags_VertexNormal);
+    Handle(Graphic3d_ArrayOfSegments) aLineArray = new Graphic3d_ArrayOfSegments (aNbArrows * 2);
+    for (Standard_Integer anArrIter = 0; anArrIter < aNbArrows; ++anArrIter)
+    {
+      const gp_Dir& aDir = aDirList[anArrIter];
+      const gp_XYZ  aPnt = aLightPos + aDir.XYZ() * aLen;
+      if (!aLineArray.IsNull())
+      {
+        aLineArray->AddVertex (aPnt + aDir.XYZ() * aLen * 0.5);
+        aLineArray->AddVertex (aPnt + aDir.XYZ() * aLen * 1.5);
+      }
+      if (!aTrisArray.IsNull())
+      {
+        const gp_Ax3 aSystem (aPnt + aDir.XYZ() * aLen, -aDir);
+        gp_Trsf aTrsfCone;
+        aTrsfCone.SetTransformation (aSystem, gp_Ax3());
+        aCylTool.FillArray (aTrisArray, aTrsfCone);
+      }
+    }
+
+    if (!aLineArray.IsNull())
+    {
+      Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup();
+      aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow);
+      aDirGroupShadow->AddPrimitiveArray (aLineArray);
+    }
+    if (!aTrisArray.IsNull())
+    {
+      Handle(Graphic3d_Group) anArrowGroup = thePrs->NewGroup();
+      anArrowGroup->SetClosed (true);
+      anArrowGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
+      anArrowGroup->AddPrimitiveArray (aTrisArray);
+    }
+  }
+
+  {
+    Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1);
+    aPoints->AddVertex (aLightPos);
+    Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
+    aGroup->SetGroupPrimitivesAspect (theMode == 1 ? myDrawer->PointAspect()->Aspect() : myDisabledMarkerAspect);
+    aGroup->AddPrimitiveArray (aPoints);
+  }
+}
+
+// =======================================================================
+// function : computeDirectional
+// purpose  :
+// =======================================================================
+void AIS_LightSource::computeDirectional (const Handle(Prs3d_Presentation)& thePrs,
+                                          const Standard_Integer theMode)
+{
+  const Standard_Real aDistance = mySize * 0.5;
+  const Standard_Real aStep = aDistance * 0.5;
+
+  // light source direction is set to local transformation
+  const gp_Dir aLightDir = -gp::DZ();
+  const gp_XYZ aLightPos = -aStep * aLightDir.XYZ();
+
+  Standard_Integer aNbArrows = 1;
+  if      (myNbArrows >= 9) { aNbArrows = 9; }
+  else if (myNbArrows >= 5) { aNbArrows = 5; }
+  else if (myNbArrows >= 3) { aNbArrows = 3; }
+  TColgp_Array1OfPnt aPoints (1, aNbArrows);
+  {
+    const gp_Ax2 anAxes (gp::Origin(), aLightDir);
+    const gp_XYZ aDY = anAxes.YDirection().XYZ() * aStep;
+    const gp_XYZ aDX = anAxes.XDirection().XYZ() * aStep;
+    const gp_XYZ aDXY = aDX + aDY;
+    switch (aNbArrows)
+    {
+      case 9:
+      {
+        aPoints.SetValue (6, aLightPos + aDY);
+        aPoints.SetValue (7, aLightPos + aDX);
+        aPoints.SetValue (8, aLightPos - aDY);
+        aPoints.SetValue (9, aLightPos - aDX);
+      }
+      Standard_FALLTHROUGH
+      case 5:
+      {
+        aPoints.SetValue (4, aLightPos - aDY + aDX);
+        aPoints.SetValue (5, aLightPos + aDY - aDX);
+      }
+      Standard_FALLTHROUGH
+      case 3:
+      {
+        aPoints.SetValue (2, aLightPos + aDXY);
+        aPoints.SetValue (3, aLightPos - aDXY);
+      }
+      Standard_FALLTHROUGH
+      case 1:
+      {
+        aPoints.SetValue (1, aLightPos);
+        break;
+      }
+    }
+  }
+
+  const Prs3d_ToolCylinder aCylTool (aDistance * 0.1, 0.0, aDistance * 0.2, myNbSplitsArrow, myNbSplitsArrow);
+  Handle(Graphic3d_ArrayOfTriangles) aTrisArray;
+  if (theMode == 0)
+  {
+    aTrisArray = new Graphic3d_ArrayOfTriangles (aNbArrows * aCylTool.VerticesNb(),
+                                                 aNbArrows * aCylTool.TrianglesNb() * 3,
+                                                 Graphic3d_ArrayFlags_VertexNormal);
+  }
+  Handle(Graphic3d_ArrayOfPoints) aPntArray = new Graphic3d_ArrayOfPoints (aNbArrows);
+  Handle(Graphic3d_ArrayOfSegments) aLineArray = new Graphic3d_ArrayOfSegments (aNbArrows * 2);
+  for (Standard_Integer aPntIter = aPoints.Lower(); aPntIter <= aPoints.Upper(); ++aPntIter)
+  {
+    const gp_Pnt aPnt = aPoints.Value (aPntIter);
+    if (!aPntArray.IsNull())
+    {
+      aPntArray->AddVertex (aPnt);
+    }
+    if (!aLineArray.IsNull())
+    {
+      aLineArray->AddVertex (aPnt);
+      aLineArray->AddVertex (gp_Pnt (aPnt.XYZ() + aLightDir.XYZ() * aDistance));
+    }
+    if (!aTrisArray.IsNull())
+    {
+      const gp_Ax3 aSystem (aPnt.XYZ() + aLightDir.XYZ() * aDistance, aLightDir);
+      gp_Trsf aTrsfCone;
+      aTrsfCone.SetTransformation (aSystem, gp_Ax3());
+      aCylTool.FillArray (aTrisArray, aTrsfCone);
+    }
+  }
+
+  if (!aLineArray.IsNull() && theMode == 0)
+  {
+    Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup();
+    aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow);
+    aDirGroupShadow->AddPrimitiveArray (aLineArray);
+  }
+  if (!aLineArray.IsNull())
+  {
+    Handle(Graphic3d_Group) aDirGroup = thePrs->NewGroup();
+    aDirGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
+    aDirGroup->AddPrimitiveArray (aLineArray);
+  }
+  if (!aTrisArray.IsNull())
+  {
+    Handle(Graphic3d_Group) anArrowGroup = thePrs->NewGroup();
+    anArrowGroup->SetClosed (true);
+    anArrowGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
+    anArrowGroup->AddPrimitiveArray (aTrisArray);
+  }
+  if (!aPntArray.IsNull())
+  {
+    Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
+    aGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
+    aGroup->AddPrimitiveArray (aPntArray);
+  }
+  {
+    Handle(Graphic3d_ArrayOfPoints) aPntArray2 = new Graphic3d_ArrayOfPoints (1);
+    aPntArray2->AddVertex (aLightPos);
+    Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
+    aGroup->SetGroupPrimitivesAspect (myDisabledMarkerAspect);
+    aGroup->AddPrimitiveArray (aPntArray2);
+  }
+}
+
+// =======================================================================
+// function : computePositional
+// purpose  :
+// =======================================================================
+void AIS_LightSource::computePositional (const Handle(Prs3d_Presentation)& thePrs,
+                                         const Standard_Integer theMode)
+{
+  // light source position is set to local transformation
+  const gp_XYZ aLightPos = gp::Origin().XYZ();
+  const Standard_Real aRadius = (myIsZoomable && myLightSource->HasRange()) ? myLightSource->Range() : 0.0;
+  if (theMode == 0
+   && aRadius > 0.0
+   && myToDisplayRange)
+  {
+    Handle(Graphic3d_ArrayOfTriangles) aPosRangeArray = Prs3d_ToolSphere::Create (aRadius, myNbSplitsQuadric, myNbSplitsQuadric, gp_Trsf());
+    Handle(Graphic3d_Group) aRangeGroup = thePrs->NewGroup();
+    aRangeGroup->SetClosed (true);
+    aRangeGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
+    aRangeGroup->AddPrimitiveArray (aPosRangeArray);
+  }
+  {
+    Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1);
+    aPoints->AddVertex (aLightPos);
+    Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
+    aGroup->SetGroupPrimitivesAspect (myDrawer->PointAspect()->Aspect());
+    aGroup->AddPrimitiveArray (aPoints);
+  }
+}
+
+// =======================================================================
+// function : computeSpot
+// purpose  :
+// =======================================================================
+void AIS_LightSource::computeSpot (const Handle(Prs3d_Presentation)& thePrs,
+                                   const Standard_Integer theMode)
+{
+  // light source position and direction are set to local transformation
+  const gp_Dir aLightDir = -gp::DZ();
+  const gp_XYZ aLightPos = gp::Origin().XYZ();
+  const Standard_Real aDistance = (myIsZoomable && myLightSource->HasRange()) ? myLightSource->Range() : mySize;
+  {
+    Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1);
+    aPoints->AddVertex (aLightPos);
+
+    Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
+    aGroup->SetGroupPrimitivesAspect (myDrawer->PointAspect()->Aspect());
+    aGroup->AddPrimitiveArray (aPoints);
+  }
+
+  {
+    Handle(Graphic3d_ArrayOfSegments) aDirArray = new Graphic3d_ArrayOfSegments (2);
+    aDirArray->AddVertex (aLightPos);
+    aDirArray->AddVertex (gp_Pnt (aLightPos + aLightDir.XYZ() * aDistance));
+
+    Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup();
+    aDirGroupShadow->SetClosed (true);
+    aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow);
+    aDirGroupShadow->AddPrimitiveArray (aDirArray);
+
+    Handle(Graphic3d_Group) aDirGroup = thePrs->NewGroup();
+    aDirGroup->SetClosed (true);
+    aDirGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect());
+    aDirGroup->AddPrimitiveArray (aDirArray);
+  }
+
+  if (theMode == 0
+   && myToDisplayRange)
+  {
+    const Standard_ShortReal aHalfAngle = myLightSource->Angle() / 2.0f;
+    const Standard_Real aRadius = aDistance * Tan (aHalfAngle);
+    gp_Ax3  aSystem (aLightPos + aLightDir.XYZ() * aDistance, -aLightDir);
+    gp_Trsf aTrsfCone;
+    aTrsfCone.SetTransformation (aSystem, gp_Ax3());
+    Handle(Graphic3d_ArrayOfTriangles) aSpotRangeArray = Prs3d_ToolCylinder::Create (aRadius, 0.0, aDistance,
+                                                                                     myNbSplitsQuadric, myNbSplitsQuadric, aTrsfCone);
+
+    Handle(Graphic3d_Group) aRangeGroup = thePrs->NewGroup();
+    aRangeGroup->SetClosed (true);
+    aRangeGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
+    aRangeGroup->AddPrimitiveArray (aSpotRangeArray);
+  }
+}
+
+// =======================================================================
+// function : ComputeSelection
+// purpose  :
+// =======================================================================
+void AIS_LightSource::ComputeSelection (const Handle(SelectMgr_Selection)& theSel,
+                                        const Standard_Integer theMode)
+{
+  if (theMode != 0)
+  {
+    return;
+  }
+
+  Handle(AIS_LightSourceOwner) anEntityOwner = new AIS_LightSourceOwner (this, 15);
+  {
+    Handle(Select3D_SensitivePoint) aSensPosition = new Select3D_SensitivePoint (anEntityOwner, gp::Origin());
+    aSensPosition->SetSensitivityFactor (12);
+    if (!myTransformPersistence.IsNull()
+      && myTransformPersistence->IsTrihedronOr2d())
+    {
+      aSensPosition->SetSensitivityFactor (Max (12, Standard_Integer (mySize * 0.5)));
+    }
+    theSel->Add (aSensPosition);
+  }
+}