1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-02 17:46:22 +03:00

0032183: Visualization - implement AIS_LightSource::ProcessDragging() for rotating directional light

- Added sensitive sphere for a light source
- Implemented AIS_LightSource::ProcessDragging() interface for rotating directional light source
- Added possibility to turn on/off directional light source dragging
- Added test
This commit is contained in:
mkrylova 2021-03-26 12:31:22 +03:00 committed by bugmaster
parent b7344f5d72
commit a3b2aaefac
7 changed files with 310 additions and 15 deletions

View File

@ -16,7 +16,9 @@
#include <AIS_LightSource.hxx>
#include <AIS_InteractiveContext.hxx>
#include <gp_Quaternion.hxx>
#include <Graphic3d_ArrayOfPoints.hxx>
#include <Graphic3d_ArrayOfPolylines.hxx>
#include <Graphic3d_ArrayOfSegments.hxx>
#include <Graphic3d_ArrayOfTriangles.hxx>
#include <Graphic3d_CView.hxx>
@ -27,6 +29,7 @@
#include <Prs3d_ToolCylinder.hxx>
#include <Prs3d_ToolSphere.hxx>
#include <Select3D_SensitivePoint.hxx>
#include <Select3D_SensitiveSphere.hxx>
#include <V3d_View.hxx>
IMPLEMENT_STANDARD_RTTIEXT(AIS_LightSource, AIS_InteractiveObject)
@ -65,6 +68,105 @@ Standard_Boolean AIS_LightSourceOwner::HandleMouseClick (const Graphic3d_Vec2i&
return false;
}
//=======================================================================
//function : HilightWithColor
//purpose :
//=======================================================================
void AIS_LightSourceOwner::HilightWithColor (const Handle(PrsMgr_PresentationManager)& thePM,
const Handle(Prs3d_Drawer)& theStyle,
const Standard_Integer theMode)
{
Handle(AIS_LightSource) aLightSource = Handle(AIS_LightSource)::DownCast (mySelectable);
if (aLightSource.IsNull())
{
return;
}
if (aLightSource->Light()->Type() == Graphic3d_TypeOfLightSource_Directional && aLightSource->myIsDraggable)
{
Handle(Prs3d_Presentation) aPrs = aLightSource->GetHilightPresentation (thePM);
const Graphic3d_ZLayerId aZLayer = theStyle->ZLayer() != -1
? theStyle->ZLayer()
: (thePM->IsImmediateModeOn() ? Graphic3d_ZLayerId_Top : aLightSource->ZLayer());
aPrs->Clear();
if (aPrs->GetZLayer() != aZLayer)
{
aPrs->SetZLayer (aZLayer);
}
Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1);
const gp_Pnt aDetPnt = aLightSource->mySensSphere->LastDetectedPoint();
if (aDetPnt.X() == RealLast())
{
return;
}
aPoints->AddVertex (aDetPnt);
Handle(Graphic3d_Group) aGroup = aPrs->NewGroup();
const Handle(Prs3d_PointAspect) aPointAspect = new Prs3d_PointAspect (Aspect_TOM_O_POINT, theStyle->Color(), 3.0f);
aGroup->SetGroupPrimitivesAspect (aPointAspect->Aspect());
aGroup->AddPrimitiveArray (aPoints);
const Standard_Real aRadius = aLightSource->Size() * 0.5;
const Standard_Integer aNbPnts = int (aLightSource->ArcSize() * 180 / (M_PI * aRadius));
TColgp_Array1OfPnt aCircPoints (0, aNbPnts);
const gp_Dir aDirNorm (gp_Vec (gp::Origin(), aDetPnt));
gp_Dir aDirNormToPln (gp::DY());
if (!gp::DX().IsParallel (aDirNorm, Precision::Angular()))
{
aDirNormToPln = gp::DX().Crossed (aDirNorm);
}
for (Standard_Integer aStep = 0; aStep < aNbPnts; ++aStep)
{
aCircPoints.SetValue (aStep, (aDetPnt.Rotated (gp_Ax1 (gp::Origin(), aDirNormToPln), M_PI / 90 * (aStep - aNbPnts / 2))));
}
Handle(Graphic3d_Group) aCircGroup = aPrs->NewGroup();
Handle(Graphic3d_ArrayOfPolylines) aPolylines = new Graphic3d_ArrayOfPolylines (aNbPnts * 2, 2);
aPolylines->AddBound (aNbPnts);
for (Standard_Integer anIdx = 0; anIdx < aNbPnts; ++anIdx)
{
aPolylines->AddVertex (aCircPoints.Value (anIdx).Rotated (gp_Ax1 (gp::Origin(), aDirNorm), M_PI / 2));
}
aPolylines->AddBound (aNbPnts);
for (Standard_Integer anIdx = 0; anIdx < aNbPnts; ++anIdx)
{
aPolylines->AddVertex (aCircPoints.Value (anIdx));
}
aCircGroup->AddPrimitiveArray (aPolylines, Standard_False);
aCircGroup->SetGroupPrimitivesAspect (theStyle->ArrowAspect()->Aspect());
if (thePM->IsImmediateModeOn())
{
thePM->AddToImmediateList (aPrs);
}
else
{
aPrs->Display();
}
}
else
{
base_type::HilightWithColor (thePM, theStyle, theMode);;
}
}
//=======================================================================
//function : IsForcedHilight
//purpose :
//=======================================================================
Standard_Boolean AIS_LightSourceOwner::IsForcedHilight() const
{
Handle(AIS_LightSource) aLightSource = Handle(AIS_LightSource)::DownCast (mySelectable);
if (aLightSource.IsNull())
{
return Standard_False;
}
if (aLightSource->Light()->Type() == Graphic3d_TypeOfLightSource_Directional)
{
return Standard_True;
}
return Standard_False;
}
// =======================================================================
// function : Constructor
// purpose :
@ -77,8 +179,10 @@ AIS_LightSource::AIS_LightSource (const Handle(Graphic3d_CLight)& theLight)
myNbArrows (5),
myNbSplitsQuadric (theLight->Type() == Graphic3d_TypeOfLightSource_Ambient ? 10 : 30),
myNbSplitsArrow (20),
mySensSphereArcSize (25),
myIsZoomable (theLight->Type() == Graphic3d_TypeOfLightSource_Positional
|| theLight->Type() == Graphic3d_TypeOfLightSource_Spot),
myIsDraggable (theLight->Type() == Graphic3d_TypeOfLightSource_Directional),
myToDisplayName (true),
myToDisplayRange (true),
myToSwitchOnClick (true)
@ -133,6 +237,63 @@ AIS_LightSource::AIS_LightSource (const Handle(Graphic3d_CLight)& theLight)
}
}
//=======================================================================
//function : ProcessDragging
//purpose :
//=======================================================================
Standard_Boolean AIS_LightSource::ProcessDragging (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView,
const Handle(SelectMgr_EntityOwner)& theOwner,
const Graphic3d_Vec2i& theDragFrom,
const Graphic3d_Vec2i& theDragTo,
const AIS_DragAction theAction)
{
if (Light()->Type() != Graphic3d_TypeOfLightSource_Directional)
{
return Standard_False;
}
switch (theAction)
{
case AIS_DragAction_Start:
{
myStartTransform = theDragFrom;
myLocTrsfStart = LocalTransformation();
return Standard_True;
}
case AIS_DragAction_Update:
{
theCtx->MainSelector()->Pick (myStartTransform.x(), myStartTransform.y(), theView);
gp_Pnt aStartPosition = mySensSphere->LastDetectedPoint();
theCtx->MainSelector()->Pick (theDragTo.x(), theDragTo.y(), theView);
gp_Pnt aCurrPosition = mySensSphere->LastDetectedPoint();
if (aCurrPosition.X() != RealLast() && aStartPosition.Distance (aCurrPosition) > Precision::Confusion())
{
gp_Quaternion aQRot;
aQRot.SetRotation (gp_Vec (gp_Pnt (0, 0, 0), aStartPosition), gp_Vec (gp_Pnt (0, 0, 0), aCurrPosition));
gp_Trsf aTrsf;
aTrsf.SetRotation (aQRot);
SetLocalTransformation (myLocTrsfStart * aTrsf);
myLocTrsfStart = LocalTransformation();
myStartTransform = theDragTo;
theOwner->Selectable()->ClearDynamicHighlight (theCtx->MainPrsMgr());
theCtx->HilightWithColor (this, Handle(Prs3d_Drawer)(), false);
}
return Standard_True;
}
case AIS_DragAction_Abort:
{
return Standard_True;
}
case AIS_DragAction_Stop:
{
GetHilightPresentation (theCtx->MainPrsMgr())->Clear();
break;
}
}
return Standard_False;
}
// =======================================================================
// function : updateLightAspects
// purpose :
@ -681,6 +842,12 @@ void AIS_LightSource::ComputeSelection (const Handle(SelectMgr_Selection)& theSe
Handle(AIS_LightSourceOwner) anEntityOwner = new AIS_LightSourceOwner (this, 15);
{
if (myLightSource->Type() == Graphic3d_TypeOfLightSource_Directional)
{
mySensSphere = new Select3D_SensitiveSphere (anEntityOwner, gp::Origin(), mySize * 0.5);
theSel->Add (mySensSphere);
}
Handle(Select3D_SensitivePoint) aSensPosition = new Select3D_SensitivePoint (anEntityOwner, gp::Origin());
aSensPosition->SetSensitivityFactor (12);
if (!myTransformPersistence.IsNull()

View File

@ -21,6 +21,7 @@
#include <SelectMgr_EntityOwner.hxx>
class Prs3d_ShadingAspect;
class Select3D_SensitiveSphere;
//! Interactive object for a light source.
//! Each type of light source has it's own presentation:
@ -90,6 +91,19 @@ public: //! @name Light properties
}
}
//! Returns Sensitive sphere arc size in pixels; 20 by default.
Standard_Integer ArcSize() const { return mySensSphereArcSize; }
//! Sets the size of sensitive sphere arc.
void SetArcSize (Standard_Integer theSize)
{
if (mySensSphereArcSize != theSize)
{
mySensSphereArcSize = theSize;
SetToUpdate();
}
}
//! Returns TRUE if transform-persistence is allowed;
//! TRUE by default for Ambient and Directional lights
//! and FALSE by default for Positional and Spot lights.
@ -105,6 +119,15 @@ public: //! @name Light properties
}
}
//! Sets if dragging is allowed.
void SetDraggable (bool theIsDraggable)
{
if (myIsDraggable != theIsDraggable)
{
myIsDraggable = theIsDraggable;
}
}
//! Returns TRUE if mouse click will turn light on/off; TRUE by default.
bool ToSwitchOnClick() const { return myToSwitchOnClick; }
@ -182,6 +205,21 @@ protected:
Standard_EXPORT virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel,
const Standard_Integer theMode) Standard_OVERRIDE;
//! Drag object in the viewer.
//! @param[in] theCtx interactive context
//! @param[in] theView active View
//! @param[in] theOwner the owner of detected entity
//! @param[in] theDragFrom drag start point
//! @param[in] theDragTo drag end point
//! @param[in] theAction drag action
//! @return FALSE if object rejects dragging action (e.g. AIS_DragAction_Start)
Standard_EXPORT virtual Standard_Boolean ProcessDragging (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView,
const Handle(SelectMgr_EntityOwner)& theOwner,
const Graphic3d_Vec2i& theDragFrom,
const Graphic3d_Vec2i& theDragTo,
const AIS_DragAction theAction) Standard_OVERRIDE;
//! Sets new local transformation, which is propagated to Graphic3d_CLight instance.
Standard_EXPORT virtual void setLocalTransformation (const Handle(TopLoc_Datum3D)& theTrsf) Standard_OVERRIDE;
@ -217,18 +255,23 @@ protected:
Handle(Graphic3d_AspectMarker3d) myDisabledMarkerAspect; //!< disabled light source marker style
Handle(Graphic3d_AspectLine3d) myArrowLineAspectShadow; //!< arrow shadow style
Handle(Graphic3d_MarkerImage) myMarkerImages[2]; //!< icon of disabled (0) and enabled (1) light
Handle(Select3D_SensitiveSphere) mySensSphere; //!< sensitive sphere of directional light source
Aspect_TypeOfMarker myMarkerTypes[2]; //!< icon of disabled (0) and enabled (1) light
Aspect_TypeOfMarker myCodirMarkerType; //!< icon of arrow co-directional to camera direction (look from)
Aspect_TypeOfMarker myOpposMarkerType; //!< icon of arrow opposite to camera direction (look at)
Standard_Real mySize; //!< presentation size
Standard_Integer myNbArrows; //!< number of directional light arrows
Standard_Integer myNbSplitsQuadric; //!< tessellation level for quadric surfaces
Standard_Integer myNbSplitsArrow; //!< tessellation level for arrows
Standard_Boolean myIsZoomable; //!< flag to allow/disallow transform-persistence when possible
Standard_Boolean myToDisplayName; //!< flag to show/hide name
Standard_Boolean myToDisplayRange; //!< flag to show/hide range of positional/spot light
Standard_Boolean myToSwitchOnClick; //!< flag to handle mouse click to turn light on/off
Graphic3d_Vec2i myStartTransform; //!< position of starting transformation
gp_Trsf myLocTrsfStart; //!< object transformation before transformation
Standard_Real mySize; //!< presentation size
Standard_Integer myNbArrows; //!< number of directional light arrows
Standard_Integer myNbSplitsQuadric; //!< tessellation level for quadric surfaces
Standard_Integer myNbSplitsArrow; //!< tessellation level for arrows
Standard_Integer mySensSphereArcSize; //! sensitive sphere arc size in pixels
Standard_Boolean myIsZoomable; //!< flag to allow/disallow transform-persistence when possible
Standard_Boolean myIsDraggable; //!< flag to allow/disallow rotate directional light source by dragging
Standard_Boolean myToDisplayName; //!< flag to show/hide name
Standard_Boolean myToDisplayRange; //!< flag to show/hide range of positional/spot light
Standard_Boolean myToSwitchOnClick; //!< flag to handle mouse click to turn light on/off
};
@ -248,6 +291,16 @@ public:
Aspect_VKeyFlags theModifiers,
bool theIsDoubleClick) Standard_OVERRIDE;
//! Highlights selectable object's presentation with display mode in presentation manager with given highlight style.
//! Also a check for auto-highlight is performed - if selectable object manages highlighting on its own,
//! execution will be passed to SelectMgr_SelectableObject::HilightOwnerWithColor method.
Standard_EXPORT virtual void HilightWithColor (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
const Handle(Prs3d_Drawer)& theStyle,
const Standard_Integer theMode) Standard_OVERRIDE;
//! Always update dynamic highlighting.
Standard_EXPORT virtual Standard_Boolean IsForcedHilight() const Standard_OVERRIDE;
};
#endif // _AIS_LightSource_HeaderFile

View File

@ -26,6 +26,7 @@ Select3D_SensitiveSphere::Select3D_SensitiveSphere (const Handle(SelectMgr_Entit
const Standard_Real theRadius)
: Select3D_SensitiveEntity (theOwnerId),
myCenter (theCenter),
myLastDetectedPoint (RealLast(), RealLast(), RealLast()),
myRadius (theRadius)
{
}
@ -37,6 +38,7 @@ Select3D_SensitiveSphere::Select3D_SensitiveSphere (const Handle(SelectMgr_Entit
Standard_Boolean Select3D_SensitiveSphere::Matches (SelectBasics_SelectingVolumeManager& theMgr,
SelectBasics_PickResult& thePickResult)
{
myLastDetectedPoint = gp_Pnt (RealLast(), RealLast(), RealLast());
if (theMgr.GetActiveSelectionType() != SelectMgr_SelectionType_Point)
{
if (!theMgr.IsOverlapAllowed())
@ -53,7 +55,7 @@ Standard_Boolean Select3D_SensitiveSphere::Matches (SelectBasics_SelectingVolume
{
return Standard_False;
}
myLastDetectedPoint = thePickResult.PickedPoint();
thePickResult.SetDistToGeomCenter (theMgr.DistToGeometryCenter (myCenter));
return Standard_True;
}

View File

@ -55,8 +55,12 @@ public:
//! Returns center of the sphere with transformation applied
virtual gp_Pnt CenterOfGeometry() const Standard_OVERRIDE { return myCenter; };
//! Returns the position of detected point on the sphere.
const gp_Pnt& LastDetectedPoint() const { return myLastDetectedPoint; }
protected:
gp_Pnt myCenter;
gp_Pnt myLastDetectedPoint;
Standard_Real myRadius;
};

View File

@ -764,11 +764,6 @@ Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSphere (const gp_Pnt& the
{
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
"Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
if (!hasSphereOverlap (theCenter, theRadius))
{
return Standard_False;
}
Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
if (!RaySphereIntersection (theCenter, theRadius, myNearPickedPnt, myViewRayDir, aTimeEnter, aTimeLeave))
{
@ -780,7 +775,7 @@ Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSphere (const gp_Pnt& the
{
thePickResult.SetDepth (aTimeLeave * myScale);
}
gp_Pnt aPntOnSphere (myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * thePickResult.Depth());
gp_Pnt aPntOnSphere (myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * thePickResult.Depth() / myScale);
gp_Vec aNormal (aPntOnSphere.XYZ() - theCenter.XYZ());
thePickResult.SetPickedPoint (aPntOnSphere);
thePickResult.SetSurfaceNormal (aNormal);

View File

@ -10754,6 +10754,14 @@ static int VLight (Draw_Interpretor& theDi,
const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
aLightPrs->SetZoomable (isZoomable);
}
else if (!aLightPrs.IsNull()
&& (anArgCase == "-showdraggable"
|| anArgCase == "-prsdraggable"
|| anArgCase == "-draggable"))
{
const bool isDraggable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
aLightPrs->SetDraggable (isDraggable);
}
else if (!aLightPrs.IsNull()
&& (anArgCase == "-showname"
|| anArgCase == "-prsname"))
@ -10786,6 +10794,23 @@ static int VLight (Draw_Interpretor& theDi,
aLightPrs->SetSize (aSize);
}
else if (!aLightPrs.IsNull()
&& (anArgCase == "-dirarcsize"
|| anArgCase == "-arcsize"
|| anArgCase == "-arc")
&& anArgIt + 1 < theArgsNb)
{
Standard_Integer aSize = 0;
if (!Draw::ParseInteger (theArgVec[anArgIt + 1], aSize)
|| aSize <= 0
|| aLightPrs->Light()->Type() != Graphic3d_TypeOfLightSource_Directional)
{
Message::SendFail() << "Syntax error at argument '" << anArg << "'";
return 1;
}
++anArgIt;
aLightPrs->SetArcSize (aSize);
}
else if (!aLightNew.IsNull()
&& aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
&& (anArgCase == "-castshadow"
@ -14887,6 +14912,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
"\n\t\t: [-spotExponent value] [-spotAngle angleDeg]"
"\n\t\t: [-smoothAngle value] [-smoothRadius value]"
"\n\t\t: [-display] [-showName 1|0] [-showRange 1|0] [-prsZoomable 1|0] [-prsSize Value]"
"\n\t\t: [-arcSize Value]"
"\n\t\t: Command manages light sources. Without arguments shows list of lights."
"\n\t\t: Arguments affecting the list of defined/active lights:"
"\n\t\t: -clear remove all light sources"
@ -14931,7 +14957,9 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
"\n\t\t: -showName shows/hides the name of light source; 1 by default"
"\n\t\t: -showRange shows/hides the range of spot/positional light source; 1 by default"
"\n\t\t: -prsZoomable makes light presentation zoomable/non-zoomable"
"\n\t\t: -prsDraggable makes light presentation draggable/non-draggable"
"\n\t\t: -prsSize sets light presentation size"
"\n\t\t: -arcSize sets arc presentation size(in pixels) for rotation directional light source; 25 by default"
"\n\t\t: Examples:"
"\n\t\t: vlight redlight -type POSITIONAL -headlight 1 -pos 0 1 1 -color RED"
"\n\t\t: vlight redlight -delete",

View File

@ -0,0 +1,46 @@
puts "================================="
puts "0032183: Visualization - implement AIS_LightSource::ProcessDragging() for rotating directional light"
puts "Tests dynamic highlighting of directional light source"
puts "================================="
pload MODELING VISUALIZATION
vclear
vinit View1 -height 480 -width 640
vlight -clear
vbackground -color GRAY
vrenderparams -shadingModel PHONG
box b 10 10 10 10 10 10
vdisplay b -dispMode 1
vaspects b -material Brass
vfit
vlight -add ambient -color WHITE -name AMBIENT -display
vlight -add directional -dir 1 0 0 -name DIR1 -color BLUE -display
vlight -add directional -dir 0 1 0 -name DIR2 -color RED -display -prsSize 200 -arcsize 50
vmoveto 350 202
vdump $imagedir/${casename}_dyn_highlighting_red_light_draggable.png
if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
vmoveto 354 101
if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
vmoveto 445 169
if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
vmoveto 259 239
if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
vmoveto 122 50
vdump $imagedir/${casename}_dyn_highlighting_blue_light_draggable.png
if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
vmoveto 126 25
if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
vmoveto 149 46
if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
vmoveto 101 47
if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
vlight -change 2 -prsDraggable 0
vmoveto 350 202
vdump $imagedir/${casename}_dyn_highlighting_red_light_non_draggable.png
vlight -change 1 -prsDraggable 0
vmoveto 122 50
vdump $imagedir/${casename}_dyn_highlighting_blue_light_non_draggable.png