diff --git a/src/AIS/AIS_LightSource.cxx b/src/AIS/AIS_LightSource.cxx index cd5f97835d..42a25a9a4d 100644 --- a/src/AIS/AIS_LightSource.cxx +++ b/src/AIS/AIS_LightSource.cxx @@ -16,7 +16,9 @@ #include #include +#include #include +#include #include #include #include @@ -27,6 +29,7 @@ #include #include #include +#include #include 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() diff --git a/src/AIS/AIS_LightSource.hxx b/src/AIS/AIS_LightSource.hxx index 5ff70250cc..1d9a433ab7 100644 --- a/src/AIS/AIS_LightSource.hxx +++ b/src/AIS/AIS_LightSource.hxx @@ -21,6 +21,7 @@ #include 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 diff --git a/src/Select3D/Select3D_SensitiveSphere.cxx b/src/Select3D/Select3D_SensitiveSphere.cxx index b289ca3fb3..f452db3cea 100644 --- a/src/Select3D/Select3D_SensitiveSphere.cxx +++ b/src/Select3D/Select3D_SensitiveSphere.cxx @@ -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; } diff --git a/src/Select3D/Select3D_SensitiveSphere.hxx b/src/Select3D/Select3D_SensitiveSphere.hxx index 9a976c697a..3202401b3c 100644 --- a/src/Select3D/Select3D_SensitiveSphere.hxx +++ b/src/Select3D/Select3D_SensitiveSphere.hxx @@ -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; }; diff --git a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx index c47f770bf3..9b8925f12d 100644 --- a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx +++ b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx @@ -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); diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 43c6067ffd..534f07e332 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -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", diff --git a/tests/v3d/light_source/dyn_highlight b/tests/v3d/light_source/dyn_highlight new file mode 100644 index 0000000000..1af3e7e3da --- /dev/null +++ b/tests/v3d/light_source/dyn_highlight @@ -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 \ No newline at end of file