From 625e1958191fcb8c5e2eaaced9341e9a4fbf2d67 Mon Sep 17 00:00:00 2001 From: apl Date: Fri, 27 May 2016 13:15:40 +0300 Subject: [PATCH] 0027038: Visualization - add new presentation for object manipulation AIS_Manipulator class has been created to provide interactive services for manipulating with mouse local transformations of other interactive objects. The class features three kinds of transformation modes for attached objects: - translation of through axis - scaling within axis - rotation around axis For more details please have a look at description of the class in reference manual or in header file. The patch includes DRAW test workbench for evaluating the AIS_Manipulator features. Clang warning (override) --- src/AIS/AIS_Manipulator.cxx | 1219 ++++++++++++++++++ src/AIS/AIS_Manipulator.hxx | 670 ++++++++++ src/AIS/AIS_ManipulatorMode.hxx | 28 + src/AIS/AIS_ManipulatorOwner.cxx | 94 ++ src/AIS/AIS_ManipulatorOwner.hxx | 60 + src/AIS/FILES | 5 + src/StdPrs/FILES | 8 + src/StdPrs/StdPrs_ToolCylinder.cxx | 64 + src/StdPrs/StdPrs_ToolCylinder.hxx | 51 + src/StdPrs/StdPrs_ToolDisk.cxx | 58 + src/StdPrs/StdPrs_ToolDisk.hxx | 50 + src/StdPrs/StdPrs_ToolQuadric.cxx | 118 ++ src/StdPrs/StdPrs_ToolQuadric.hxx | 64 + src/StdPrs/StdPrs_ToolSphere.cxx | 59 + src/StdPrs/StdPrs_ToolSphere.hxx | 55 + src/ViewerTest/ViewerTest_CmdParser.cxx | 64 +- src/ViewerTest/ViewerTest_CmdParser.hxx | 29 +- src/ViewerTest/ViewerTest_ViewerCommands.cxx | 427 +++++- tests/v3d/grids.list | 1 + tests/v3d/manipulator/rotate | 142 ++ tests/v3d/manipulator/scale | 63 + tests/v3d/manipulator/translate | 150 +++ tests/v3d/manipulator/zoom_persistence | 87 ++ 23 files changed, 3521 insertions(+), 45 deletions(-) create mode 100644 src/AIS/AIS_Manipulator.cxx create mode 100644 src/AIS/AIS_Manipulator.hxx create mode 100644 src/AIS/AIS_ManipulatorMode.hxx create mode 100644 src/AIS/AIS_ManipulatorOwner.cxx create mode 100644 src/AIS/AIS_ManipulatorOwner.hxx create mode 100644 src/StdPrs/StdPrs_ToolCylinder.cxx create mode 100644 src/StdPrs/StdPrs_ToolCylinder.hxx create mode 100644 src/StdPrs/StdPrs_ToolDisk.cxx create mode 100644 src/StdPrs/StdPrs_ToolDisk.hxx create mode 100644 src/StdPrs/StdPrs_ToolQuadric.cxx create mode 100644 src/StdPrs/StdPrs_ToolQuadric.hxx create mode 100644 src/StdPrs/StdPrs_ToolSphere.cxx create mode 100644 src/StdPrs/StdPrs_ToolSphere.hxx create mode 100644 tests/v3d/manipulator/rotate create mode 100644 tests/v3d/manipulator/scale create mode 100644 tests/v3d/manipulator/translate create mode 100644 tests/v3d/manipulator/zoom_persistence diff --git a/src/AIS/AIS_Manipulator.cxx b/src/AIS/AIS_Manipulator.cxx new file mode 100644 index 0000000000..2434229b6d --- /dev/null +++ b/src/AIS/AIS_Manipulator.cxx @@ -0,0 +1,1219 @@ +// Created on: 2015-12-23 +// Created by: Anastasia BORISOVA +// Copyright (c) 2015 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_STANDARD_HANDLE (AIS_Manipulator, AIS_InteractiveObject) +IMPLEMENT_STANDARD_RTTIEXT(AIS_Manipulator, AIS_InteractiveObject) + +IMPLEMENT_HSEQUENCE(AIS_ManipulatorObjectSequence) + +//======================================================================= +//function : init +//purpose : +//======================================================================= +void AIS_Manipulator::init() +{ + // Create axis in the default coordinate system. The custom position is applied in local transformation. + myAxes[0] = Axis (gp::OX(), Quantity_NOC_RED); + myAxes[1] = Axis (gp::OY(), Quantity_NOC_GREEN); + myAxes[2] = Axis (gp::OZ(), Quantity_NOC_BLUE1); + + Graphic3d_MaterialAspect aShadingMaterial; + aShadingMaterial.SetReflectionModeOff (Graphic3d_TOR_SPECULAR); + aShadingMaterial.SetMaterialType (Graphic3d_MATERIAL_ASPECT); + + myDrawer->SetShadingAspect (new Prs3d_ShadingAspect()); + myDrawer->ShadingAspect()->Aspect()->SetInteriorStyle (Aspect_IS_SOLID); + myDrawer->ShadingAspect()->SetColor (Quantity_NOC_WHITE); + myDrawer->ShadingAspect()->SetMaterial (aShadingMaterial); + + Graphic3d_MaterialAspect aHilightMaterial; + aHilightMaterial.SetColor (Quantity_NOC_AZURE); + aHilightMaterial.SetReflectionModeOff (Graphic3d_TOR_AMBIENT); + aHilightMaterial.SetReflectionModeOff (Graphic3d_TOR_DIFFUSE); + aHilightMaterial.SetReflectionModeOff (Graphic3d_TOR_SPECULAR); + aHilightMaterial.SetReflectionModeOff (Graphic3d_TOR_EMISSION); + aHilightMaterial.SetMaterialType (Graphic3d_MATERIAL_ASPECT); + + myHighlightAspect = new Prs3d_ShadingAspect(); + myHighlightAspect->Aspect()->SetInteriorStyle (Aspect_IS_SOLID); + myHighlightAspect->SetMaterial (aHilightMaterial); + + SetSize (100); + SetZLayer (Graphic3d_ZLayerId_Topmost); +} + +//======================================================================= +//function : getHighlightPresentation +//purpose : +//======================================================================= +Handle(Prs3d_Presentation) AIS_Manipulator::getHighlightPresentation (const Handle(SelectMgr_EntityOwner)& theOwner) const +{ + Handle(Prs3d_Presentation) aDummyPrs; + Handle(AIS_ManipulatorOwner) anOwner = Handle(AIS_ManipulatorOwner)::DownCast (theOwner); + if (anOwner.IsNull()) + { + return aDummyPrs; + } + + switch (anOwner->Mode()) + { + case AIS_MM_Translation: return myAxes[anOwner->Index()].TranslatorHighlightPrs(); + case AIS_MM_Rotation : return myAxes[anOwner->Index()].RotatorHighlightPrs(); + case AIS_MM_Scaling : return myAxes[anOwner->Index()].ScalerHighlightPrs(); + case AIS_MM_None : break; + } + + return aDummyPrs; +} + +//======================================================================= +//function : getGroup +//purpose : +//======================================================================= +Handle(Graphic3d_Group) AIS_Manipulator::getGroup (const Standard_Integer theIndex, const AIS_ManipulatorMode theMode) const +{ + Handle(Graphic3d_Group) aDummyGroup; + + if (theIndex < 0 || theIndex > 2) + { + return aDummyGroup; + } + + switch (theMode) + { + case AIS_MM_Translation: return myAxes[theIndex].TranslatorGroup(); + case AIS_MM_Rotation : return myAxes[theIndex].RotatorGroup(); + case AIS_MM_Scaling : return myAxes[theIndex].ScalerGroup(); + case AIS_MM_None : break; + } + + return aDummyGroup; +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +AIS_Manipulator::AIS_Manipulator() +: myPosition (gp::XOY()), + myCurrentIndex (-1), + myCurrentMode (AIS_MM_None), + myIsActivationOnDetection (Standard_False), + myIsZoomPersistentMode (Standard_True), + myHasStartedTransformation (Standard_False), + myStartPosition (gp::XOY()), + myStartPick (0.0, 0.0, 0.0), + myPrevState (0.0) +{ + SetInfiniteState(); + SetMutable (Standard_True); + SetDisplayMode (AIS_Shaded); + init(); +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +AIS_Manipulator::AIS_Manipulator (const gp_Ax2& thePosition) +: myPosition (thePosition), + myCurrentIndex (-1), + myCurrentMode (AIS_MM_None), + myIsActivationOnDetection (Standard_False), + myIsZoomPersistentMode (Standard_True), + myHasStartedTransformation (Standard_False), + myStartPosition (gp::XOY()), + myStartPick (0.0, 0.0, 0.0), + myPrevState (0.0) +{ + SetInfiniteState(); + SetMutable (Standard_True); + SetDisplayMode (AIS_Shaded); + init(); +} + +//======================================================================= +//function : SetPart +//purpose : +//======================================================================= +void AIS_Manipulator::SetPart (const Standard_Integer theAxisIndex, const AIS_ManipulatorMode theMode, const Standard_Boolean theIsEnabled) +{ + Standard_ProgramError_Raise_if (theAxisIndex < 0 || theAxisIndex > 2, "AIS_Manipulator::SetMode(): axis index should be between 0 and 2"); + switch (theMode) + { + case AIS_MM_Translation: + myAxes[theAxisIndex].SetTranslation (theIsEnabled); + break; + + case AIS_MM_Rotation: + myAxes[theAxisIndex].SetRotation (theIsEnabled); + break; + + case AIS_MM_Scaling: + myAxes[theAxisIndex].SetScaling (theIsEnabled); + break; + + case AIS_MM_None: + break; + } +} + +//======================================================================= +//function : EnableMode +//purpose : +//======================================================================= +void AIS_Manipulator::EnableMode (const AIS_ManipulatorMode theMode) +{ + if (!IsAttached()) + { + return; + } + + const Handle(AIS_InteractiveContext)& aContext = GetContext(); + if (aContext.IsNull()) + { + return; + } + + aContext->Activate (this, theMode); +} + +//======================================================================= +//function : attachToBox +//purpose : +//======================================================================= +void AIS_Manipulator::attachToBox (const Bnd_Box& theBox) +{ + if (theBox.IsVoid()) + { + return; + } + + Standard_Real anXmin = 0.0, anYmin = 0.0, aZmin = 0.0, anXmax = 0.0, anYmax = 0.0, aZmax = 0.0; + theBox.Get (anXmin, anYmin, aZmin, anXmax, anYmax, aZmax); + + gp_Ax2 aPosition = gp::XOY(); + aPosition.SetLocation (gp_Pnt ((anXmin + anXmax) * 0.5, (anYmin + anYmax) * 0.5, (aZmin + aZmax) * 0.5)); + SetPosition (aPosition); +} + +//======================================================================= +//function : adjustSize +//purpose : +//======================================================================= +void AIS_Manipulator::adjustSize (const Bnd_Box& theBox) +{ + Standard_Real aXmin = 0., aYmin = 0., aZmin = 0., aXmax = 0., aYmax = 0., aZmax = 0.0; + theBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + Standard_Real aXSize = aXmax - aXmin; + Standard_Real aYSize = aYmax - aYmin; + Standard_Real aZSize = aZmax - aZmin; + + SetSize ((Standard_ShortReal) (Max (aXSize, Max (aYSize, aZSize)) * 0.5)); +} + +//======================================================================= +//function : Attach +//purpose : +//======================================================================= +void AIS_Manipulator::Attach (const Handle(AIS_InteractiveObject)& theObject, const OptionsForAttach& theOptions) +{ + if (theObject->IsKind (STANDARD_TYPE(AIS_Manipulator))) + { + return; + } + + Handle(AIS_ManipulatorObjectSequence) aSeq = new AIS_ManipulatorObjectSequence(); + aSeq->Append (theObject); + Attach (aSeq, theOptions); +} + +//======================================================================= +//function : Attach +//purpose : +//======================================================================= +void AIS_Manipulator::Attach (const Handle(AIS_ManipulatorObjectSequence)& theObjects, const OptionsForAttach& theOptions) +{ + if (theObjects->Size() < 1) + { + return; + } + + SetOwner (theObjects); + Bnd_Box aBox; + const Handle(AIS_InteractiveObject)& aCurObject = theObjects->Value (theObjects->Lower()); + aCurObject->BoundingBox (aBox); + + if (theOptions.AdjustPosition) + { + attachToBox (aBox); + } + + if (theOptions.AdjustSize) + { + adjustSize (aBox); + } + + const Handle(AIS_InteractiveContext)& aContext = Object()->GetContext(); + if (!aContext.IsNull()) + { + if (!aContext->IsDisplayed (this)) + { + aContext->Display (this, Standard_False); + } + else + { + aContext->Update (this, Standard_False); + aContext->RecomputeSelectionOnly (this); + } + + aContext->Load (this); + aContext->CurrentViewer()->RedrawImmediate(); + } + + if (theOptions.EnableModes) + { + EnableMode (AIS_MM_Rotation); + EnableMode (AIS_MM_Translation); + EnableMode (AIS_MM_Scaling); + } +} + +//======================================================================= +//function : Detach +//purpose : +//======================================================================= +void AIS_Manipulator::Detach() +{ + DeactivateCurrentMode(); + + if (!IsAttached()) + { + return; + } + + Handle(AIS_InteractiveObject) anObject = Object(); + const Handle(AIS_InteractiveContext)& aContext = anObject->GetContext(); + if (!aContext.IsNull()) + { + aContext->Remove (this, Standard_False); + } + + SetOwner (NULL); +} + +//======================================================================= +//function : Objects +//purpose : +//======================================================================= +Handle(AIS_ManipulatorObjectSequence) AIS_Manipulator::Objects() const +{ + return Handle(AIS_ManipulatorObjectSequence)::DownCast (GetOwner()); +} + +//======================================================================= +//function : Object +//purpose : +//======================================================================= +Handle(AIS_InteractiveObject) AIS_Manipulator::Object (const Standard_Integer theIndex) const +{ + Handle(AIS_ManipulatorObjectSequence) anOwner = Handle(AIS_ManipulatorObjectSequence)::DownCast (GetOwner()); + + Standard_ProgramError_Raise_if (theIndex < anOwner->Lower() || theIndex > anOwner->Upper(), "AIS_Manipulator::Object(): wrong index value"); + + if (anOwner.IsNull() || anOwner->IsEmpty()) + { + return NULL; + } + + return anOwner->Value (theIndex); +} + +//======================================================================= +//function : Object +//purpose : +//======================================================================= +Handle(AIS_InteractiveObject) AIS_Manipulator::Object() const +{ + return Object (1); +} + +//======================================================================= +//function : ObjectTransformation +//purpose : +//======================================================================= +Standard_Boolean AIS_Manipulator::ObjectTransformation (const Standard_Integer theMaxX, const Standard_Integer theMaxY, + const Handle(V3d_View)& theView, gp_Trsf& theTrsf) +{ + // Initialize start reference data + if (!myHasStartedTransformation) + { + Handle(AIS_ManipulatorObjectSequence) anObjects = Objects(); + myStartTrsfs.Clear(); + for (Standard_Integer anIt = anObjects->Lower(); anIt <= anObjects->Upper(); ++anIt) + { + myStartTrsfs.Append (anObjects->Value (anIt)->LocalTransformation()); + } + myStartPosition = myPosition; + } + + // Get 3d point with projection vector + Graphic3d_Vec3d anInputPoint; + Graphic3d_Vec3d aProj; + theView->ConvertWithProj (theMaxX, theMaxY, anInputPoint.x(), anInputPoint.y(), anInputPoint.z(), aProj.x(), aProj.y(), aProj.z()); + gp_Lin anInputLine (gp_Pnt (anInputPoint.x(), anInputPoint.y(), anInputPoint.z()), gp_Dir (aProj.x(), aProj.y(), aProj.z())); + gp_Pnt aNewPosition = gp::Origin(); + + switch (myCurrentMode) + { + case AIS_MM_Translation: + { + gp_Lin aLine (myStartPick, myAxes[myCurrentIndex].Position().Direction()); + Handle(Geom_Curve) anInputCurve = new Geom_Line (anInputLine); + Handle(Geom_Curve) aCurve = new Geom_Line (aLine); + GeomAPI_ExtremaCurveCurve anExtrema (anInputCurve, aCurve); + gp_Pnt aP1, aP2; + anExtrema.NearestPoints (aP1, aP2); + aNewPosition = aP2; + + if (!myHasStartedTransformation) + { + myStartPick = aNewPosition; + myHasStartedTransformation = Standard_True; + return Standard_True; + } + + if (aNewPosition.Distance (myStartPick) < Precision::Confusion()) + { + return Standard_False; + } + + gp_Trsf aNewTrsf; + aNewTrsf.SetTranslation (gp_Vec(myStartPick, aNewPosition)); + theTrsf *= aNewTrsf; + break; + } + case AIS_MM_Rotation: + { + Handle(Geom_Curve) anInputCurve = new Geom_Line (anInputLine); + Handle(Geom_Surface) aSurface = new Geom_Plane (myPosition.Location(), myAxes[myCurrentIndex].Position().Direction()); + GeomAPI_IntCS aIntersector (anInputCurve, aSurface); + if (!aIntersector.IsDone() || aIntersector.NbPoints() < 1) + { + return Standard_False; + } + + aNewPosition = aIntersector.Point (1); + + if (!myHasStartedTransformation) + { + myStartPick = aNewPosition; + myHasStartedTransformation = Standard_True; + gp_Dir aStartAxis = gce_MakeDir (myPosition.Location(), myStartPick); + myPrevState = aStartAxis.AngleWithRef (gce_MakeDir(myPosition.Location(), aNewPosition), myAxes[myCurrentIndex].Position().Direction()); + return Standard_True; + } + + if (aNewPosition.Distance (myStartPick) < Precision::Confusion()) + { + return Standard_False; + } + + gp_Dir aStartAxis = myPosition.Location().IsEqual (myStartPick, Precision::Confusion()) + ? myAxes[(myCurrentIndex + 1) % 3].Position().Direction() + : gce_MakeDir (myPosition.Location(), myStartPick); + + gp_Dir aCurrentAxis = gce_MakeDir (myPosition.Location(), aNewPosition); + Standard_Real anAngle = aStartAxis.AngleWithRef (aCurrentAxis, myAxes[myCurrentIndex].Position().Direction()); + + // Change value of an angle if it should have different sign. + if (anAngle * myPrevState < 0 && Abs (anAngle) < M_PI_2) + { + Standard_ShortReal aSign = myPrevState > 0 ? -1.0f : 1.0f; + anAngle = aSign * (M_PI * 2 - anAngle); + } + + if (Abs (anAngle) < Precision::Confusion()) + { + return Standard_False; + } + + gp_Trsf aNewTrsf; + aNewTrsf.SetRotation (myAxes[myCurrentIndex].Position(), anAngle); + theTrsf *= aNewTrsf; + myPrevState = anAngle; + break; + } + case AIS_MM_Scaling: + { + gp_Lin aLine (myStartPosition.Location(), myAxes[myCurrentIndex].Position().Direction()); + Handle(Geom_Curve) anInputCurve = new Geom_Line (anInputLine); + Handle(Geom_Curve) aCurve = new Geom_Line (aLine); + GeomAPI_ExtremaCurveCurve anExtrema (anInputCurve, aCurve); + gp_Pnt aTmp; + anExtrema.NearestPoints (aTmp, aNewPosition); + + if (!myHasStartedTransformation) + { + myStartPick = aNewPosition; + myHasStartedTransformation = Standard_True; + return Standard_True; + } + + if (aNewPosition.Distance (myStartPick) < Precision::Confusion() + || aNewPosition.Distance (myStartPosition.Location()) < Precision::Confusion()) + { + return Standard_False; + } + + Standard_Real aCoeff = myStartPosition.Location().Distance (aNewPosition) + / myStartPosition.Location().Distance (myStartPick); + gp_Trsf aNewTrsf; + aNewTrsf.SetScale (myPosition.Location(), aCoeff); + + theTrsf = aNewTrsf; + break; + } + case AIS_MM_None: + return Standard_False; + } + + return Standard_True; +} + +//======================================================================= +//function : StartTransform +//purpose : +//======================================================================= +void AIS_Manipulator::StartTransform (const Standard_Integer theX, const Standard_Integer theY, const Handle(V3d_View)& theView) +{ + if (myHasStartedTransformation) + { + return; + } + + gp_Trsf aTrsf; + ObjectTransformation (theX, theY, theView, aTrsf); +} + +//======================================================================= +//function : StopTransform +//purpose : +//======================================================================= +void AIS_Manipulator::StopTransform (const Standard_Boolean theToApply) +{ + if (!IsAttached() || !myHasStartedTransformation) + { + return; + } + + myHasStartedTransformation = Standard_False; + + if (!theToApply) + { + Handle(AIS_ManipulatorObjectSequence) anObjects = Objects(); + + for (Standard_Integer anIt = anObjects->Lower(); anIt <= anObjects->Upper(); ++anIt) + { + anObjects->Value (anIt)->SetLocalTransformation (myStartTrsfs(anIt)); + } + + SetPosition (myStartPosition); + } +} + +//======================================================================= +//function : Transform +//purpose : +//======================================================================= +void AIS_Manipulator::Transform (const gp_Trsf& theTrsf) +{ + if (!IsAttached() || !myHasStartedTransformation) + { + return; + } + + Handle(AIS_ManipulatorObjectSequence) anObjects = Objects(); + + for (Standard_Integer anIt = anObjects->Lower(); anIt <= anObjects->Upper(); ++anIt) + { + anObjects->Value (anIt)->SetLocalTransformation (theTrsf * myStartTrsfs(anIt)); + } + + if ((myCurrentMode == AIS_MM_Translation && myBehaviorOnTransform.FollowTranslation) + || (myCurrentMode == AIS_MM_Rotation && myBehaviorOnTransform.FollowRotation)) + { + gp_Pnt aPos = myStartPosition.Location().Transformed (theTrsf); + gp_Dir aVDir = myStartPosition.Direction().Transformed (theTrsf); + gp_Dir aXDir = myStartPosition.XDirection().Transformed (theTrsf); + SetPosition (gp_Ax2 (aPos, aVDir, aXDir)); + } +} + +//======================================================================= +//function : Transform +//purpose : +//======================================================================= +gp_Trsf AIS_Manipulator::Transform (const Standard_Integer thePX, const Standard_Integer thePY, + const Handle(V3d_View)& theView) +{ + gp_Trsf aTrsf; + if (ObjectTransformation (thePX, thePY, theView, aTrsf)) + { + Transform (aTrsf); + } + + return aTrsf; +} + +//======================================================================= +//function : SetPosition +//purpose : +//======================================================================= +void AIS_Manipulator::SetPosition (const gp_Ax2& thePosition) +{ + if (!myPosition.Location().IsEqual (thePosition.Location(), Precision::Confusion()) + || !myPosition.Direction().IsEqual (thePosition.Direction(), Precision::Angular()) + || !myPosition.XDirection().IsEqual (thePosition.XDirection(), Precision::Angular())) + { + myPosition = thePosition; + myAxes[0].SetPosition (gp_Ax1 (myPosition.Location(), myPosition.XDirection())); + myAxes[1].SetPosition (gp_Ax1 (myPosition.Location(), myPosition.YDirection())); + myAxes[2].SetPosition (gp_Ax1 (myPosition.Location(), myPosition.Direction())); + + updateTransformation(); + } +} + +//======================================================================= +//function : updateTransformation +//purpose : set local transformation to avoid graphics recomputation +//======================================================================= +void AIS_Manipulator::updateTransformation() +{ + gp_Trsf aTrsf; + + if (!myIsZoomPersistentMode) + { + aTrsf.SetTransformation (myPosition, gp::XOY()); + } + else + { + const gp_Dir& aVDir = myPosition.Direction(); + const gp_Dir& aXDir = myPosition.XDirection(); + aTrsf.SetTransformation (gp_Ax2 (gp::Origin(), aVDir, aXDir), gp::XOY()); + } + + AIS_InteractiveObject::SetLocalTransformation (aTrsf); + + Handle(Geom_Transformation) aGeomTrsf = new Geom_Transformation (this->Transformation()); + + for (Standard_Integer anIt = 0; anIt < 3; ++anIt) + { + myAxes[anIt].Transform (aGeomTrsf); + } + + if (myIsZoomPersistentMode) + { + if (!(GetTransformPersistenceMode () == Graphic3d_TMF_ZoomPers + && GetTransformPersistencePoint().IsEqual (myPosition.Location(), 0.))) + { + setTransformPersistence (Graphic3d_TMF_ZoomPers, myPosition.Location()); + } + } +} + +//======================================================================= +//function : SetSize +//purpose : +//======================================================================= +void AIS_Manipulator::SetSize (const Standard_ShortReal theSideLength) +{ + for (Standard_Integer anIt = 0; anIt < 3; ++anIt) + { + myAxes[anIt].SetSize (theSideLength); + } + + SetToUpdate(); +} + +//======================================================================= +//function : SetGap +//purpose : +//======================================================================= +void AIS_Manipulator::SetGap (const Standard_ShortReal theValue) +{ + for (Standard_Integer anIt = 0; anIt < 3; ++anIt) + { + myAxes[anIt].SetIndent (theValue); + } + + SetToUpdate(); +} + +//======================================================================= +//function : DeactivateCurrentMode +//purpose : +//======================================================================= +void AIS_Manipulator::DeactivateCurrentMode() +{ + if (!myIsActivationOnDetection) + { + Handle(Graphic3d_Group) aGroup = getGroup (myCurrentIndex, myCurrentMode); + if (aGroup.IsNull()) + { + return; + } + + Handle(Prs3d_ShadingAspect) anAspect = new Prs3d_ShadingAspect(); + anAspect->Aspect()->SetInteriorStyle (Aspect_IS_SOLID); + anAspect->SetMaterial (myDrawer->ShadingAspect()->Material()); + anAspect->SetTransparency (myDrawer->ShadingAspect()->Transparency()); + anAspect->SetColor (myAxes[myCurrentIndex].Color()); + + aGroup->SetGroupPrimitivesAspect (anAspect->Aspect()); + } + + myCurrentIndex = -1; + myCurrentMode = AIS_MM_None; + + if (myHasStartedTransformation) + { + myHasStartedTransformation = Standard_False; + } +} + +//======================================================================= +//function : SetZoomPersistence +//purpose : +//======================================================================= +void AIS_Manipulator::SetZoomPersistence (const Standard_Boolean theToEnable) +{ + if (myIsZoomPersistentMode != theToEnable) + { + SetToUpdate(); + } + + myIsZoomPersistentMode = theToEnable; + + if (!theToEnable) + { + setTransformPersistence (Graphic3d_TMF_None, gp::Origin()); + } + + updateTransformation(); +} + +//======================================================================= +//function : SetTransformPersistence +//purpose : +//======================================================================= +void AIS_Manipulator::SetTransformPersistence (const Graphic3d_TransModeFlags& theFlag, const gp_Pnt& thePoint) +{ + Standard_ASSERT_RETURN (!myIsZoomPersistentMode, + "AIS_Manipulator::SetTransformPersistence: " + "Custom settings are not supported by this class in ZoomPersistence mode",); + + setTransformPersistence (theFlag, thePoint); +} + +//======================================================================= +//function : setTransformPersistence +//purpose : +//======================================================================= +void AIS_Manipulator::setTransformPersistence (const Graphic3d_TransModeFlags& theFlag, const gp_Pnt& thePoint) +{ + AIS_InteractiveObject::SetTransformPersistence (theFlag, thePoint); + + for (Standard_Integer anIt = 0; anIt < 3; ++anIt) + { + myAxes[anIt].SetTransformPersistence (theFlag, thePoint); + } +} + +//======================================================================= +//function : SetLocalTransformation +//purpose : +//======================================================================= +void AIS_Manipulator::SetLocalTransformation (const gp_Trsf& /*theTransformation*/) +{ + Standard_ASSERT_INVOKE ( + "AIS_Manipulator::SetLocalTransformation: " + "Custom transformation is not supported by this class"); +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= +void AIS_Manipulator::Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) +{ + if (theMode != AIS_Shaded) + { + return; + } + + thePrs->SetInfiniteState (Standard_True); + thePrs->SetMutable (Standard_True); + Handle(Graphic3d_Group) aGroup; + Handle(Prs3d_ShadingAspect) anAspect = new Prs3d_ShadingAspect(); + anAspect->Aspect()->SetInteriorStyle (Aspect_IS_SOLID); + anAspect->SetMaterial (myDrawer->ShadingAspect()->Material()); + anAspect->SetTransparency (myDrawer->ShadingAspect()->Transparency()); + + // Display center + myCenter.Init (myAxes[0].AxisRadius() * 2.0f, gp::Origin()); + aGroup = Prs3d_Root::NewGroup (thePrs); + aGroup->SetPrimitivesAspect (myDrawer->ShadingAspect()->Aspect()); + aGroup->AddPrimitiveArray (myCenter.Array()); + + for (Standard_Integer anIt = 0; anIt < 3; ++anIt) + { + // Display axes + aGroup = Prs3d_Root::NewGroup (thePrs); + anAspect->SetColor (myAxes[anIt].Color()); + aGroup->SetGroupPrimitivesAspect (anAspect->Aspect()); + myAxes[anIt].Compute (thePrsMgr, thePrs, anAspect); + myAxes[anIt].SetTransformPersistence (GetTransformPersistenceMode(), + GetTransformPersistencePoint()); + } + + updateTransformation(); +} + +//======================================================================= +//function : HilightSelected +//purpose : +//======================================================================= +void AIS_Manipulator::HilightSelected (const Handle(PrsMgr_PresentationManager3d)& thePM, + const SelectMgr_SequenceOfOwner& theSeq) +{ + if (theSeq.IsEmpty()) + { + return; + } + + if (myIsActivationOnDetection) + { + return; + } + + if (!theSeq (1)->IsKind (STANDARD_TYPE (AIS_ManipulatorOwner))) + { + thePM->Color (this, GetContext()->HilightColor(), 0); + return; + } + + Handle(AIS_ManipulatorOwner) anOwner = Handle(AIS_ManipulatorOwner)::DownCast (theSeq (1)); + myHighlightAspect->Aspect()->SetInteriorColor (GetContext()->HilightColor()); + Handle(Graphic3d_Group) aGroup = getGroup (anOwner->Index(), anOwner->Mode()); + if (aGroup.IsNull()) + { + return; + } + + aGroup->SetGroupPrimitivesAspect (myHighlightAspect->Aspect()); + + myCurrentIndex = anOwner->Index(); + myCurrentMode = anOwner->Mode(); +} + +//======================================================================= +//function : ClearSelected +//purpose : +//======================================================================= +void AIS_Manipulator::ClearSelected() +{ + DeactivateCurrentMode(); +} + +//======================================================================= +//function : HilightOwnerWithColor +//purpose : +//======================================================================= +void AIS_Manipulator::HilightOwnerWithColor (const Handle(PrsMgr_PresentationManager3d)& thePM, const Quantity_NameOfColor theColor, const Handle(SelectMgr_EntityOwner)& theOwner) +{ + Handle(AIS_ManipulatorOwner) anOwner = Handle(AIS_ManipulatorOwner)::DownCast (theOwner); + Handle(Prs3d_Presentation) aPresentation = getHighlightPresentation (anOwner); + if (aPresentation.IsNull()) + { + return; + } + aPresentation->Highlight (Aspect_TOHM_COLOR, theColor); + aPresentation->SetShadingAspect (myHighlightAspect); + aPresentation->SetZLayer (Graphic3d_ZLayerId_Topmost); + thePM->AddToImmediateList (aPresentation); + + if (myIsActivationOnDetection) + { + if (HasActiveMode()) + { + DeactivateCurrentMode(); + } + + myCurrentIndex = anOwner->Index(); + myCurrentMode = anOwner->Mode(); + } +} + +//======================================================================= +//function : ComputeSelection +//purpose : +//======================================================================= +void AIS_Manipulator::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection, + const Standard_Integer theMode) +{ + //Check mode + AIS_ManipulatorMode aMode = (AIS_ManipulatorMode) theMode; + if (aMode == AIS_MM_None) + { + return; + } + Handle(SelectMgr_EntityOwner) anOwner; + if (aMode == AIS_MM_None) + { + anOwner = new SelectMgr_EntityOwner (this, 5); + } + Handle(Select3D_SensitiveTriangulation) aTri; + if (aMode == AIS_MM_Translation || aMode == AIS_MM_None) + { + for (Standard_Integer anIt = 0; anIt < 3; ++anIt) + { + const Axis& anAxis = myAxes[anIt]; + if (aMode != AIS_MM_None) + { + anOwner = new AIS_ManipulatorOwner(this, anIt, AIS_MM_Translation, 9); + } + // define sensitivity by line + Handle(Select3D_SensitiveSegment) aLine = new Select3D_SensitiveSegment (anOwner, gp::Origin(), anAxis.TranslatorTipPosition()); + aLine->SetSensitivityFactor (15); + theSelection->Add (aLine); + // enlarge sensitivity by triangulation + aTri = new Select3D_SensitiveTriangulation (anOwner, anAxis.TranslatorCylinder().Triangulation(), TopLoc_Location(), Standard_True); + theSelection->Add (aTri); + aTri = new Select3D_SensitiveTriangulation (anOwner, anAxis.TranslatorArrow().Triangulation(), TopLoc_Location(), Standard_True); + theSelection->Add (aTri); + aTri = new Select3D_SensitiveTriangulation (anOwner, anAxis.TranslatorArrowBottom().Triangulation(), TopLoc_Location(), Standard_True); + theSelection->Add (aTri); + } + } + + if (aMode == AIS_MM_Rotation || aMode == AIS_MM_None) + { + for (Standard_Integer anIt = 0; anIt < 3; ++anIt) + { + const Axis& anAxis = myAxes[anIt]; + if (aMode != AIS_MM_None) + { + anOwner = new AIS_ManipulatorOwner (this, anIt, AIS_MM_Rotation, 9); + } + // define sensitivity by circle + Handle(Geom_Circle) aGeomCircle = new Geom_Circle (gp_Ax2 (gp::Origin(), anAxis.ReferenceAxis().Direction()), anAxis.RotatorDiskRadius()); + Handle(Select3D_SensitiveCircle) aCircle = new Select3D_SensitiveCircle (anOwner, aGeomCircle, Standard_False, anAxis.FacettesNumber()); + aCircle->SetSensitivityFactor (15); + theSelection->Add (aCircle); + // enlarge sensitivity by triangulation + aTri = new Select3D_SensitiveTriangulation (anOwner, myAxes[anIt].RotatorDisk().Triangulation(), TopLoc_Location(), Standard_True); + theSelection->Add (aTri); + } + } + + if (aMode == AIS_MM_Scaling || aMode == AIS_MM_None) + { + for (Standard_Integer anIt = 0; anIt < 3; ++anIt) + { + if (aMode != AIS_MM_None) + { + anOwner = new AIS_ManipulatorOwner (this, anIt, AIS_MM_Scaling, 9); + } + // define sensitivity by point + Handle(Select3D_SensitivePoint) aPnt = new Select3D_SensitivePoint (anOwner, myAxes[anIt].ScalerCubePosition()); + aPnt->SetSensitivityFactor (15); + theSelection->Add (aPnt); + // enlarge sensitivity by triangulation + aTri = new Select3D_SensitiveTriangulation (anOwner, myAxes[anIt].ScalerCube().Triangulation(), TopLoc_Location(), Standard_True); + theSelection->Add (aTri); + } + } +} + +//======================================================================= +//class : Cylinder +//function : Init +//purpose : +//======================================================================= +void AIS_Manipulator::Cylinder::Init (const Standard_ShortReal theBotRad, const Standard_ShortReal theTopRad, + const Standard_ShortReal theHeight, + const Standard_Integer theSlicesNb, const Standard_Integer theStacksNb, + const gp_Ax1& thePosition) +{ + myPosition = thePosition; + myBottomRad = theBotRad; + myTopRad = theTopRad; + myHeight = theHeight; + + StdPrs_ToolCylinder aTool (myBottomRad, myTopRad, myHeight, theSlicesNb, theStacksNb); + gp_Ax3 aSystem (myPosition.Location(), myPosition.Direction()); + gp_Trsf aTrsf; + aTrsf.SetTransformation (aSystem, gp_Ax3()); + + aTool.FillArray (myArray, myTriangulation, aTrsf); +} + +//======================================================================= +//class : Disk +//function : Init +//purpose : +//======================================================================= +void AIS_Manipulator::Disk::Init (const Standard_ShortReal theInnerRadius, + const Standard_ShortReal theOuterRadius, + const gp_Ax1& thePosition, + const Standard_Integer theSlicesNb, + const Standard_Integer theStacksNb) +{ + myPosition = thePosition; + myInnerRad = theInnerRadius; + myOuterRad = theOuterRadius; + + StdPrs_ToolDisk aTool (theInnerRadius, theOuterRadius, theSlicesNb, theStacksNb); + gp_Ax3 aSystem (myPosition.Location(), myPosition.Direction()); + gp_Trsf aTrsf; + aTrsf.SetTransformation (aSystem, gp_Ax3()); + aTool.FillArray (myArray, myTriangulation, aTrsf); +} + +//======================================================================= +//class : Sphere +//function : Init +//purpose : +//======================================================================= +void AIS_Manipulator::Sphere::Init (const Standard_ShortReal theRadius, + const gp_Pnt& thePosition, + const Standard_Integer theSlicesNb, + const Standard_Integer theStacksNb) +{ + myPosition = thePosition; + myRadius = theRadius; + + StdPrs_ToolSphere aTool (theRadius, theSlicesNb, theStacksNb); + gp_Trsf aTrsf; + aTrsf.SetTranslation (gp_Vec(gp::Origin(), thePosition)); + aTool.FillArray (myArray, myTriangulation, aTrsf); +} + +//======================================================================= +//class : Cube +//function : Init +//purpose : +//======================================================================= +void AIS_Manipulator::Cube::Init (const gp_Ax1& thePosition, const Standard_ShortReal theSize) +{ + myArray = new Graphic3d_ArrayOfTriangles (12 * 3, 0, Standard_True); + + Poly_Array1OfTriangle aPolyTriangles (1, 12); + TColgp_Array1OfPnt aPoints (1, 36); + NCollection_Array1 aNormals (1, 12); + myTriangulation = new Poly_Triangulation (aPoints, aPolyTriangles); + + gp_Ax2 aPln (thePosition.Location(), thePosition.Direction()); + gp_Pnt aBottomLeft = thePosition.Location().XYZ() - aPln.XDirection().XYZ() * theSize * 0.5 - aPln.YDirection().XYZ() * theSize * 0.5; + gp_Pnt aV2 = aBottomLeft.XYZ() + aPln.YDirection().XYZ() * theSize; + gp_Pnt aV3 = aBottomLeft.XYZ() + aPln.YDirection().XYZ() * theSize + aPln.XDirection().XYZ() * theSize; + gp_Pnt aV4 = aBottomLeft.XYZ() + aPln.XDirection().XYZ() * theSize; + gp_Pnt aTopRight = thePosition.Location().XYZ() + thePosition.Direction().XYZ() * theSize + + aPln.XDirection().XYZ() * theSize * 0.5 + aPln.YDirection().XYZ() * theSize * 0.5; + gp_Pnt aV5 = aTopRight.XYZ() - aPln.YDirection().XYZ() * theSize; + gp_Pnt aV6 = aTopRight.XYZ() - aPln.YDirection().XYZ() * theSize - aPln.XDirection().XYZ() * theSize; + gp_Pnt aV7 = aTopRight.XYZ() - aPln.XDirection().XYZ() * theSize; + + gp_Dir aRight ((gp_Vec(aTopRight, aV7) ^ gp_Vec(aTopRight, aV2)).XYZ()); + gp_Dir aFront ((gp_Vec(aV3, aV4) ^ gp_Vec(aV3, aV5)).XYZ()); + + // Bottom + addTriangle (0, aBottomLeft, aV2, aV3, -thePosition.Direction()); + addTriangle (1, aBottomLeft, aV3, aV4, -thePosition.Direction()); + + // Front + addTriangle (2, aV3, aV4, aV5, aFront); + addTriangle (3, aV3, aV5, aTopRight, aFront); + + // Back + addTriangle (4, aBottomLeft, aV2, aV7, -aFront); + addTriangle (5, aBottomLeft, aV7, aV6, -aFront); + + // aTop + addTriangle (6, aV7, aV6, aV5, thePosition.Direction()); + addTriangle (7, aTopRight, aV7, aV5, thePosition.Direction()); + + //Left + addTriangle (8, aV6, aV5, aV4, -aRight); + addTriangle (9, aBottomLeft, aV6, aV4, -aRight); + + // Right + addTriangle (10, aV3, aTopRight, aV7, aRight); + addTriangle (11, aV3, aV7, aV2, aRight); +} + +//======================================================================= +//class : Cube +//function : addTriangle +//purpose : +//======================================================================= +void AIS_Manipulator::Cube::addTriangle (const Standard_Integer theIndex, + const gp_Pnt& theP1, const gp_Pnt& theP2, const gp_Pnt& theP3, + const gp_Dir& theNormal) +{ + myTriangulation->ChangeNodes().SetValue (theIndex * 3 + 1, theP1); + myTriangulation->ChangeNodes().SetValue (theIndex * 3 + 2, theP2); + myTriangulation->ChangeNodes().SetValue (theIndex * 3 + 3, theP3); + + myTriangulation->ChangeTriangles().SetValue (theIndex + 1, Poly_Triangle (theIndex * 3 + 1, theIndex * 3 + 2, theIndex * 3 + 3)); + myArray->AddVertex (theP1, theNormal); + myArray->AddVertex (theP2, theNormal); + myArray->AddVertex (theP3, theNormal); +} + +//======================================================================= +//class : Axis +//function : Constructor +//purpose : +//======================================================================= +AIS_Manipulator::Axis::Axis (const gp_Ax1& theAxis, + const Quantity_Color& theColor, + const Standard_ShortReal theLength) +: myReferenceAxis (theAxis), + myPosition (theAxis), + myColor (theColor), + myHasTranslation (Standard_True), + myLength (theLength), + myAxisRadius (0.5f), + myHasScaling (Standard_True), + myBoxSize (2.0f), + myHasRotation (Standard_True), + myInnerRadius (myLength + myBoxSize), + myDiskThickness (myBoxSize * 0.5f), + myIndent (0.2f), + myFacettesNumber (20), + myCircleRadius (myLength + myBoxSize + myBoxSize * 0.5f * 0.5f) +{ + // +} + +//======================================================================= +//class : Axis +//function : Compute +//purpose : +//======================================================================= +void AIS_Manipulator::Axis::Compute (const Handle_PrsMgr_PresentationManager3d& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Handle(Prs3d_ShadingAspect)& theAspect) +{ + Handle(Graphic3d_Group) aGroup; + + if (myHasTranslation) + { + const Standard_ShortReal anArrowLength = 0.25f * myLength; + const Standard_ShortReal aCylinderLength = myLength - anArrowLength; + + myCylinder.Init (myAxisRadius, myAxisRadius, aCylinderLength, myFacettesNumber, 2, gp_Ax1 (gp::Origin(), myReferenceAxis.Direction())); + + gp_Pnt anArrowBottom (0.0, 0.0, 0.0); + anArrowBottom.Translate (myReferenceAxis.Direction().XYZ() * aCylinderLength); + + myArrow.Init (myAxisRadius * 1.5f, 0.0f, anArrowLength, myFacettesNumber, 2, gp_Ax1 (anArrowBottom, myReferenceAxis.Direction())); + myArrowBottom.Init (myAxisRadius, myAxisRadius * 1.5f, gp_Ax1 (anArrowBottom, myReferenceAxis.Direction()), myFacettesNumber); + myArrowTipPos = anArrowBottom; + + myTranslatorGroup = Prs3d_Root::NewGroup (thePrs); + myTranslatorGroup->SetGroupPrimitivesAspect (theAspect->Aspect()); + myTranslatorGroup->AddPrimitiveArray (myCylinder.Array()); + myTranslatorGroup->AddPrimitiveArray (myArrow.Array()); + myTranslatorGroup->AddPrimitiveArray (myArrowBottom.Array()); + + if (myHighlightTranslator.IsNull()) + { + myHighlightTranslator = new Prs3d_Presentation (thePrsMgr->StructureManager()); + } + + myHighlightTranslator->Clear(); + aGroup = Prs3d_Root::CurrentGroup (myHighlightTranslator); + aGroup->AddPrimitiveArray (myCylinder.Array()); + aGroup->AddPrimitiveArray (myArrow.Array()); + aGroup->AddPrimitiveArray (myArrowBottom.Array()); + } + + if (myHasScaling) + { + myCubePos = myReferenceAxis.Direction().XYZ() * (myLength + myIndent); + myCube.Init (gp_Ax1 (myCubePos, myReferenceAxis.Direction()), myBoxSize); + + myScalerGroup = Prs3d_Root::NewGroup (thePrs); + myScalerGroup->SetGroupPrimitivesAspect (theAspect->Aspect()); + myScalerGroup->AddPrimitiveArray (myCube.Array()); + + if (myHighlightScaler.IsNull()) + { + myHighlightScaler = new Prs3d_Presentation (thePrsMgr->StructureManager()); + } + + myHighlightScaler->Clear(); + aGroup = Prs3d_Root::CurrentGroup (myHighlightScaler); + aGroup->AddPrimitiveArray (myCube.Array()); + } + + if (myHasRotation) + { + myCircleRadius = myInnerRadius + myIndent * 2 + myDiskThickness * 0.5f; + myCircle.Init (myInnerRadius + myIndent * 2, myInnerRadius + myDiskThickness + myIndent * 2, gp_Ax1(gp::Origin(), myReferenceAxis.Direction()), myFacettesNumber * 2); + myRotatorGroup = Prs3d_Root::NewGroup (thePrs); + myRotatorGroup->SetGroupPrimitivesAspect (theAspect->Aspect()); + myRotatorGroup->AddPrimitiveArray (myCircle.Array()); + + if (myHighlightRotator.IsNull()) + { + myHighlightRotator = new Prs3d_Presentation (thePrsMgr->StructureManager()); + } + + myHighlightRotator->Clear(); + aGroup = Prs3d_Root::CurrentGroup (myHighlightRotator); + Prs3d_Root::CurrentGroup (myHighlightRotator)->AddPrimitiveArray (myCircle.Array()); + } +} diff --git a/src/AIS/AIS_Manipulator.hxx b/src/AIS/AIS_Manipulator.hxx new file mode 100644 index 0000000000..15d7c5c6b0 --- /dev/null +++ b/src/AIS/AIS_Manipulator.hxx @@ -0,0 +1,670 @@ +// Created on: 2015-12-23 +// Created by: Anastasia BORISOVA +// Copyright (c) 2015 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. + +#ifndef _AIS_Manipulator_HeaderFile +#define _AIS_Manipulator_HeaderFile + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +NCOLLECTION_HSEQUENCE(AIS_ManipulatorObjectSequence, Handle(AIS_InteractiveObject)); + +DEFINE_STANDARD_HANDLE (AIS_Manipulator, AIS_InteractiveObject) + +//! Interactive object class to manipulate local transformation of another interactive +//! object or a group of objects via mouse. +//! It manages three types of manipulations in 3D space: +//! - translation through axis +//! - scaling within axis +//! - rotation around axis +//! To enable one of this modes, selection mode (from 1 to 3) is to be activated. +//! There are three orthogonal transformation axes defined by position property of +//! the manipulator. Particular transformation mode can be disabled for each +//! of the axes or all of them. Furthermore each of the axes can be hidden or +//! made visible. +//! The following steps demonstrate how to attach, configure and use manipulator +//! for an interactive object: +//! Step 1. Create manipulator object and adjust it appearance: +//! @code +//! Handle(AIS_Manipulator) aManipulator = new AIS_Manipulator(); +//! aManipulator->SetPart (0, AIS_Manipulator::Scaling, Standard_False); +//! aManipulator->SetPart (1, AIS_Manipulator::Rotation, Standard_False); +//! // Attach manipulator to already displayed object and manage manipulation modes +//! aManipulator->AttachToObject (anAISObject); +//! aManipulator->EnableMode (AIS_Manipulator::Translation); +//! aManipulator->EnableMode (AIS_Manipulator::Rotation); +//! aManipulator->EnableMode (AIS_Manipulator::Scaling); +//! @endcode +//! Note that you can enable only one manipulation mode but have all visual parts displayed. +//! This code allows you to view manipulator and select its manipulation parts. +//! Note that manipulator activates mode on part selection. +//! If this mode is activated, no selection will be performed for manipulator. +//! It can be activated with highlighting. To enable this: +//! @code +//! aManipulator->SetModeActivationOnDetection (Standard_True); +//! @endcode +//! Step 2. To perform transformation of object use next code in your event processing chain: +//! @code +//! // catch mouse button down event +//! if (aManipulator->HasActiveMode()) +//! { +//! aManipulator->StartTransform (anXPix, anYPix, aV3dView); +//! } +//! ... +//! // or track mouse move event +//! if (aManipulator->HasActiveMode()) +//! { +//! aManipulator->Transform (anXPix, anYPix, aV3dView); +//! aV3dView->Redraw(); +//! } +//! ... +//! // or catch mouse button up event (apply) or escape event (cancel) +//! aManipulator->StopTransform(/*Standard_Boolean toApply*/); +//! @endcode +//! Step 3. To deactivate current manipulation mode use: +//! @code aManipulator->DeactivateCurrentMode(); +//! @endcode +//! Step 4. To detach manipulator from object use: +//! @code +//! aManipulator->Detach(); +//! @endcode +//! The last method erases manipulator object. +//! @warning +//! On construction an instance of AIS_Manipulator object is bound to Graphic3d_ZLayerId_Topmost layer, +//! so make sure to call for your AIS_InteractiveContext the method MainSelector()->SetPickClosest (Standard_False) +//! otherwise you may notice issues with activation of modes. +class AIS_Manipulator : public AIS_InteractiveObject +{ +public: + + //! Constructs a manipulator object with default placement and all parts to be displayed. + Standard_EXPORT AIS_Manipulator(); + + //! Constructs a manipulator object with input location and positions of axes and all parts to be displayed. + Standard_EXPORT AIS_Manipulator (const gp_Ax2& thePosition); + + //! Destructor. + Standard_EXPORT virtual ~AIS_Manipulator() {} + + //! Disable or enable visual parts for translation, rotation or scaling for some axis. + //! By default all parts are enabled (will be displayed). + //! @warning Enabling or disabling of visual parts of manipulator does not manage the manipulation (selection) mode. + //! @warning Raises program error if axis index is < 0 or > 2. + Standard_EXPORT void SetPart (const Standard_Integer theAxisIndex, const AIS_ManipulatorMode theMode, const Standard_Boolean theIsEnabled); + + //! Behavior settings to be applied when performing transformation: + //! - FollowTranslation - whether the manipulator will be moved together with an object. + //! - FollowRotation - whether the manipulator will be rotated together with an object. + struct OptionsForAttach { + + OptionsForAttach() : AdjustPosition (Standard_True), AdjustSize (Standard_False), EnableModes (Standard_True) {} + OptionsForAttach& SetAdjustPosition (const Standard_Boolean theApply) { AdjustPosition = theApply; return *this; } + OptionsForAttach& SetAdjustSize (const Standard_Boolean theApply) { AdjustSize = theApply; return *this; } + OptionsForAttach& SetEnableModes (const Standard_Boolean theApply) { EnableModes = theApply; return *this; } + + Standard_Boolean AdjustPosition; + Standard_Boolean AdjustSize; + Standard_Boolean EnableModes; + }; + + //! Attaches himself to the input interactive object and become displayed in the same context. + //! It is placed in the center of object bounding box, and its size is adjusted to the object bounding box. + Standard_EXPORT void Attach (const Handle(AIS_InteractiveObject)& theObject, const OptionsForAttach& theOptions = OptionsForAttach()); + + //! Attaches himself to the input interactive object group and become displayed in the same context. + //! It become attached to the first object, baut manage manipulation of the whole group. + //! It is placed in the center of object bounding box, and its size is adjusted to the object bounding box. + Standard_EXPORT void Attach (const Handle(AIS_ManipulatorObjectSequence)& theObject, const OptionsForAttach& theOptions = OptionsForAttach()); + + //! Enable manipualtion mode. + //! @warning It activates selection mode in the current context. + //! If manipulator is not displayed, no mode will be activated. + Standard_EXPORT void EnableMode (const AIS_ManipulatorMode theMode); + + //! Enables mode activation on detection (highlighting). + //! By default, mode is activated on selection of manipulator part. + //! @warning If this mode is enabled, selection of parts does nothing. + void SetModeActivationOnDetection (const Standard_Boolean theToEnable) + { + myIsActivationOnDetection = theToEnable; + } + + //! @return true if manual mode activation is enabled. + Standard_Boolean IsModeActivationOnDetection() const + { + return myIsActivationOnDetection; + } + +public: + + //! Init start (reference) transformation. + //! @warning It is used in chain with StartTransform-Transform(gp_Trsf)-StopTransform + //! and is used only for custom transform set. If Transform(const Standard_Integer, const Standard_Integer) is used, + //! initial data is set automatically, and it is reset on DeactivateCurrentMode call if it is not reset yet. + Standard_EXPORT void StartTransform (const Standard_Integer theX, const Standard_Integer theY, const Handle(V3d_View)& theView); + + //! Apply to the owning objects the input transformation. + //! @remark The transformation is set using SetLocalTransformation for owning objects. + //! The location of the manipulator is stored also in Local Transformation, + //! so that there's no need to redisplay objects. + //! @warning It is used in chain with StartTransform-Transform(gp_Trsf)-StopTransform + //! and is used only for custom transform set. + //! @warning It will does nothing if transformation is not initiated (with StartTransform() call). + Standard_EXPORT void Transform (const gp_Trsf& aTrsf); + + //! Reset start (reference) transformation. + //! @param theToApply [in] option to apply or to cancel the started transformation. + //! @warning It is used in chain with StartTransform-Transform(gp_Trsf)-StopTransform + //! and is used only for custom transform set. + Standard_EXPORT void StopTransform (const Standard_Boolean theToApply = Standard_True); + + //! Apply transformation made from mouse moving from start position + //! (save on the first Tranform() call and reset on DeactivateCurrentMode() call.) + //! to the in/out mouse position (theX, theY) + Standard_EXPORT gp_Trsf Transform (const Standard_Integer theX, const Standard_Integer theY, + const Handle(V3d_View)& theView); + + //! Computes transformation of parent object according to the active mode and input motion vector. + //! You can use this method to get object transformation according to current mode or use own algorithm + //! to implement any other tranformation for modes. + //! @return transformation of parent object. + Standard_EXPORT Standard_Boolean ObjectTransformation (const Standard_Integer theX, const Standard_Integer theY, + const Handle(V3d_View)& theView, gp_Trsf& theTrsf); + + //! Make inactive the current selected manipulator part and reset current axis index and current mode. + //! After its call HasActiveMode() returns false. + //! @sa HasActiveMode() + Standard_EXPORT void DeactivateCurrentMode(); + + //! Detaches himself from the owner object, and removes itself from context. + Standard_EXPORT void Detach(); + + //! @return all owning objects. + Standard_EXPORT Handle(AIS_ManipulatorObjectSequence) Objects() const; + + //! @return the first (leading) object of the owning objects. + Standard_EXPORT Handle(AIS_InteractiveObject) Object() const; + + //! @return one of the owning objects. + //! @warning raises program error if theIndex is more than owning objects count or less than 1. + Standard_EXPORT Handle(AIS_InteractiveObject) Object (const Standard_Integer theIndex) const; + + //! @return true if manipulator is attached to some interactive object (has owning object). + Standard_Boolean IsAttached() const { return HasOwner(); } + + //! @return true if some part of manipulator is selected (tranformation mode is active, and owning object can be rtansformated). + Standard_Boolean HasActiveMode() const { return IsAttached() && myCurrentMode != AIS_MM_None; } + + Standard_Boolean HasActiveTransformation() { return myHasStartedTransformation; } + + gp_Trsf StartTransformation() const { return myStartTrsfs.Size() < 1 ? gp_Trsf() : myStartTrsfs(1); } + + gp_Trsf StartTransformation (const Standard_Integer theIndex) const + { + Standard_ProgramError_Raise_if (theIndex < 1 || theIndex > Objects()->Upper(), + "AIS_Manipulator::StartTransformation(): theIndex is out of bounds"); + return myStartTrsfs.Size() < 1 ? gp_Trsf() : myStartTrsfs (theIndex); + } + +public: //! @name Configuration of graphical transformations + + //! Enable or disable zoom persistence mode for the manipulator. With + //! this mode turned on the presentation will keep fixed screen size. + //! @warning when turned on this option overrides transform persistence + //! properties and local transformation to achieve necessary visual effect. + //! @warning revise use of AdjustSize argument of of \sa AttachToObjects method + //! when enabling zoom persistence. + Standard_EXPORT void SetZoomPersistence (const Standard_Boolean theToEnable); + + //! Returns state of zoom persistence mode, whether it turned on or off. + Standard_Boolean ZoomPersistence() const { return myIsZoomPersistentMode; } + + //! Redefines transform persistence management to setup transformation for sub-presentation of axes. + //! @warning this interactive object does not support custom transformation persistence when + //! using \sa ZoomPersistence mode. In this mode the transformation persistence flags for + //! presentations are overriden by this class. + //! @warning Invokes debug assertion to catch incompatible usage of the method with \sa ZoomPersistence mode, + //! silently does nothing in release mode. + //! @warning revise use of AdjustSize argument of of \sa AttachToObjects method + //! when enabling zoom persistence. + Standard_EXPORT virtual void SetTransformPersistence (const Graphic3d_TransModeFlags& theFlag, const gp_Pnt& thePoint) Standard_OVERRIDE; + + //! Redefines local transformation management method to inform user of inproper use. + //! @warning this interactive object does not support setting custom local transformation, + //! this class solely uses this property to implement visual positioning of the manipulator + //! without need for recomputing presentation. + //! @warning Invokes debug assertion in debug to catch incompatible usage of the + //! method, silently does nothing in release mode. + Standard_EXPORT virtual void SetLocalTransformation (const gp_Trsf& theTransformation) Standard_OVERRIDE; + +public: //! @name Setters for parameters + + AIS_ManipulatorMode ActiveMode() const { return myCurrentMode; } + + //! @return poition of manipulator interactive object. + const gp_Ax2& Position() const { return myPosition; } + + //! Sets position of the manipulator object. + Standard_EXPORT void SetPosition (const gp_Ax2& thePosition); + + Standard_ShortReal Size() const { return myAxes[0].Size(); } + + //! Sets size (length of side of the manipulator cubic bounding box. + Standard_EXPORT void SetSize (const Standard_ShortReal theSideLength); + + //! Sets gaps between translator, scaler and rotator sub-presentations. + Standard_EXPORT void SetGap (const Standard_ShortReal theValue); + +public: + + //! Behavior settings to be applied when performing transformation: + //! - FollowTranslation - whether the manipulator will be moved together with an object. + //! - FollowRotation - whether the manipulator will be rotated together with an object. + struct BehaviorOnTransform { + + BehaviorOnTransform() : FollowTranslation (Standard_True), FollowRotation (Standard_True) {} + BehaviorOnTransform& SetFollowTranslation (const Standard_Boolean theApply) { FollowTranslation = theApply; return *this; } + BehaviorOnTransform& SetFollowRotation (const Standard_Boolean theApply) { FollowRotation = theApply; return *this; } + + Standard_Boolean FollowTranslation; + Standard_Boolean FollowRotation; + }; + + //! Sets behavior settings for transformation action carried on the manipulator, + //! whether it translates, rotates together with the transformed object or not. + void SetTransformBehavior (const BehaviorOnTransform& theSettings) { myBehaviorOnTransform = theSettings; } + + //! @return behavior settings for transformation action of the manipulator. + BehaviorOnTransform& ChangeTransformBehavior() { return myBehaviorOnTransform; } + + //! @return behavior settings for transformation action of the manipulator. + const BehaviorOnTransform& TransformBehavior() const { return myBehaviorOnTransform; } + +public: //! @name Presentation computation + + //! Fills presentation. + //! @note Manipulator presentation does not use display mode and for all modes has the same presenatation. + Standard_EXPORT virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode = 0) Standard_OVERRIDE; + + //! Computes selection sensitive zones (triangulation) for manipulator. + //! @param theNode [in] Seldction mode that is treated as transformation mode. + Standard_EXPORT virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSelection, + const Standard_Integer theMode) Standard_OVERRIDE; + + //! Disables auto highlighting to use HilightSelected() and HilightOwnerWithColor() overriden methods. + Standard_EXPORT virtual Standard_Boolean IsAutoHilight() const Standard_OVERRIDE + { + return Standard_False; + } + + //! Method which clear all selected owners belonging + //! to this selectable object ( for fast presentation draw ). + Standard_EXPORT virtual void ClearSelected() Standard_OVERRIDE; + + //! Method which draws selected owners ( for fast presentation draw ). + Standard_EXPORT virtual void HilightSelected (const Handle(PrsMgr_PresentationManager3d)& thePM, const SelectMgr_SequenceOfOwner& theSeq) Standard_OVERRIDE; + + //! Method which hilight an owner belonging to + //! this selectable object ( for fast presentation draw ). + Standard_EXPORT virtual void HilightOwnerWithColor (const Handle(PrsMgr_PresentationManager3d)& thePM, const Quantity_NameOfColor theColor, const Handle(SelectMgr_EntityOwner)& theOwner) Standard_OVERRIDE; + +protected: + + Standard_EXPORT void init(); + + Standard_EXPORT void updateTransformation(); + + Standard_EXPORT Handle(Prs3d_Presentation) getHighlightPresentation (const Handle(SelectMgr_EntityOwner)& theOwner) const; + + Standard_EXPORT Handle(Graphic3d_Group) getGroup (const Standard_Integer theIndex, const AIS_ManipulatorMode theMode) const; + + Standard_EXPORT void attachToBox (const Bnd_Box& theBox); + + Standard_EXPORT void adjustSize (const Bnd_Box& theBox); + + Standard_EXPORT void setTransformPersistence (const Graphic3d_TransModeFlags& theFlag, const gp_Pnt& thePoint); + +protected: //! @name Auxilliary classes to fill presentation with proper primitives + + class Quadric + { + public: + + virtual ~Quadric() + { + myTriangulation.Nullify(); + myArray.Nullify(); + } + + + const Handle(Poly_Triangulation)& Triangulation() const { return myTriangulation; } + + const Handle(Graphic3d_ArrayOfTriangles)& Array() const { return myArray; } + + protected: + + Handle(Poly_Triangulation) myTriangulation; + Handle(Graphic3d_ArrayOfTriangles) myArray; + }; + + class Cylinder : public Quadric + { + public: + + Cylinder() + : Quadric(), + myBottomRad(1.0f), + myTopRad(1.0f), + myHeight(1.0f) + { } + + virtual ~Cylinder() {} + + void Init (const Standard_ShortReal theBotRad, const Standard_ShortReal theTopRad, + const Standard_ShortReal theHeight, + const Standard_Integer theSlicesNb, const Standard_Integer theStacksNb, + const gp_Ax1& thePosition); + + protected: + + gp_Ax1 myPosition; + Standard_ShortReal myBottomRad; + Standard_ShortReal myTopRad; + Standard_ShortReal myHeight; + }; + + class Disk : public Quadric + { + public: + + Disk() + : Quadric(), + myInnerRad(0.0f), + myOuterRad(1.0f) + { } + + ~Disk() { } + + void Init (const Standard_ShortReal theInnerRadius, + const Standard_ShortReal theOuterRadius, + const gp_Ax1& thePosition, + const Standard_Integer theSlicesNb = 20, + const Standard_Integer theStacksNb = 20); + + protected: + + gp_Ax1 myPosition; + Standard_ShortReal myInnerRad; + Standard_ShortReal myOuterRad; + }; + + class Sphere : public Quadric + { + public: + Sphere() + : Quadric(), + myRadius(1.0f) + {} + + void Init (const Standard_ShortReal theRadius, + const gp_Pnt& thePosition, + const Standard_Integer theSlicesNb = 20, + const Standard_Integer theStacksNb = 20); + + protected: + + gp_Pnt myPosition; + Standard_ShortReal myRadius; + }; + + class Cube + { + public: + + Cube() { } + ~Cube() { } + + void Init (const gp_Ax1& thePosition, const Standard_ShortReal myBoxSize); + + const Handle(Poly_Triangulation)& Triangulation() const { return myTriangulation; } + + const Handle(Graphic3d_ArrayOfTriangles)& Array() const { return myArray; } + + private: + + void addTriangle (const Standard_Integer theIndex, const gp_Pnt& theP1, const gp_Pnt& theP2, const gp_Pnt& theP3, + const gp_Dir& theNormal); + + protected: + + Handle(Poly_Triangulation) myTriangulation; + Handle(Graphic3d_ArrayOfTriangles) myArray; + }; + + //! The class describes on axis sub-object. + //! It includes sub-objects itself: + //! -rotator + //! -translator + //! -scaler + class Axis + { + public: + + Axis (const gp_Ax1& theAxis = gp_Ax1(), + const Quantity_Color& theColor = Quantity_Color(), + const Standard_ShortReal theLength = 10.0f); + + void Compute (const Handle_PrsMgr_PresentationManager3d& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Handle(Prs3d_ShadingAspect)& theAspect); + + const gp_Ax1& ReferenceAxis() const { return myReferenceAxis; } + + void SetPosition (const gp_Ax1& thePosition) { myPosition = thePosition; } + + const gp_Ax1& Position() const { return myPosition; } + + void SetTransformPersistence (const Graphic3d_TransModeFlags& theFlags, const gp_Pnt& thePoint) + { + if (!myHighlightTranslator.IsNull()) + { + myHighlightTranslator->SetTransformPersistence (theFlags, thePoint); + } + + if (!myHighlightScaler.IsNull()) + { + myHighlightScaler->SetTransformPersistence (theFlags, thePoint); + } + + if (!myHighlightRotator.IsNull()) + { + myHighlightRotator->SetTransformPersistence (theFlags, thePoint); + } + } + + Graphic3d_TransModeFlags GetTransformPersistenceMode() const { return myHighlightTranslator->TransformPersistenceMode(); } + + gp_Pnt GetTransformPersistencePoint() const { return myHighlightTranslator->TransformPersistencePoint(); } + + void Transform (const Handle(Geom_Transformation)& theTransformation) + { + if (!myHighlightTranslator.IsNull()) + { + myHighlightTranslator->Transform (theTransformation); + } + + if (!myHighlightScaler.IsNull()) + { + myHighlightScaler->Transform (theTransformation); + } + + if (!myHighlightRotator.IsNull()) + { + myHighlightRotator->Transform (theTransformation); + } + } + + Standard_Boolean HasTranslation() const { return myHasTranslation; } + + Standard_Boolean HasRotation() const { return myHasRotation; } + + Standard_Boolean HasScaling() const { return myHasScaling; } + + void SetTranslation (const Standard_Boolean theIsEnabled) { myHasTranslation = theIsEnabled; } + + void SetRotation (const Standard_Boolean theIsEnabled) { myHasRotation = theIsEnabled; } + + void SetScaling (const Standard_Boolean theIsEnabled) { myHasScaling = theIsEnabled; } + + Quantity_Color Color() const { return myColor; } + + Standard_ShortReal AxisLength() const { return myLength; } + + Standard_ShortReal AxisRadius() const { return myAxisRadius; } + + void SetAxisRadius (const Standard_ShortReal theValue) { myAxisRadius = theValue; } + + const Handle(Prs3d_Presentation)& TranslatorHighlightPrs() const { return myHighlightTranslator; } + + const Handle(Prs3d_Presentation)& RotatorHighlightPrs() const { return myHighlightRotator; } + + const Handle(Prs3d_Presentation)& ScalerHighlightPrs() const { return myHighlightScaler; } + + const Handle(Graphic3d_Group)& TranslatorGroup() const { return myTranslatorGroup; } + + const Handle(Graphic3d_Group)& RotatorGroup() const { return myRotatorGroup; } + + const Handle(Graphic3d_Group)& ScalerGroup() const { return myScalerGroup; } + + void SetIndent (const Standard_ShortReal theValue) { myIndent = theValue; } + + Standard_ShortReal Size() const { return myLength + myBoxSize + myDiskThickness + myIndent * 2.0f; } + + gp_Pnt ScalerCenter (const gp_Pnt& theLocation) const { return theLocation.XYZ() + myPosition.Direction().XYZ() * (myLength + myIndent + myBoxSize * 0.5f); } + + void SetSize (const Standard_ShortReal theValue) + { + if (myIndent > theValue * 0.1f) + { + myLength = theValue * 0.7f; + myBoxSize = theValue * 0.15f; + myDiskThickness = theValue * 0.05f; + myIndent = theValue * 0.05f; + } + else // use pre-set value of predent + { + Standard_ShortReal aLength = theValue - 2 * myIndent; + myLength = aLength * 0.8f; + myBoxSize = aLength * 0.15f; + myDiskThickness = aLength * 0.05f; + } + myInnerRadius = myIndent * 2 + myBoxSize + myLength; + myAxisRadius = myBoxSize / 4.0f; + } + + Standard_Integer FacettesNumber() const { return myFacettesNumber; } + + public: + + const Cylinder& TranslatorCylinder() const { return myCylinder; } + const Cylinder& TranslatorArrow() const { return myArrow; } + const gp_Pnt& TranslatorTipPosition() const { return myArrowTipPos; } + const Disk& TranslatorArrowBottom() const { return myArrowBottom; } + const Disk& RotatorDisk() const { return myCircle; } + float RotatorDiskRadius() const { return myCircleRadius; } + const Cube& ScalerCube() const { return myCube; } + const gp_Pnt& ScalerCubePosition() const { return myCubePos; } + + protected: + + gp_Ax1 myReferenceAxis; //!< Returns reference axis assignment. + gp_Ax1 myPosition; //!< Position of the axis including local transformation. + Quantity_Color myColor; + + Standard_Boolean myHasTranslation; + Standard_ShortReal myLength; //!< Length of translation axis. + Standard_ShortReal myAxisRadius; + + Standard_Boolean myHasScaling; + Standard_ShortReal myBoxSize; //!< Size of scaling cube. + + Standard_Boolean myHasRotation; + Standard_ShortReal myInnerRadius; //!< Radius of rotation circle. + Standard_ShortReal myDiskThickness; + Standard_ShortReal myIndent; //!< Gap between visual part of the manipulator. + + protected: + + Standard_Integer myFacettesNumber; + + Cylinder myCylinder; + Cylinder myArrow; + gp_Pnt myArrowTipPos; + Disk myArrowBottom; + Disk myCircle; + float myCircleRadius; + Cube myCube; + gp_Pnt myCubePos; + + Handle(Graphic3d_Group) myTranslatorGroup; + Handle(Graphic3d_Group) myScalerGroup; + Handle(Graphic3d_Group) myRotatorGroup; + + Handle(Prs3d_Presentation) myHighlightTranslator; + Handle(Prs3d_Presentation) myHighlightScaler; + Handle(Prs3d_Presentation) myHighlightRotator; + }; + +protected: + + Axis myAxes[3]; //!< Tree axes of the manipulator. + Sphere myCenter; //!< Visual part displaying the center sphere of the manipulator. + gp_Ax2 myPosition; //!< Position of the manipualtor object. it displayes its location and position of its axes. + + Standard_Integer myCurrentIndex; //!< Index of active axis. + AIS_ManipulatorMode myCurrentMode; //!< Name of active manipualtion mode. + + Standard_Boolean myIsActivationOnDetection; //!< Manual activation of modes (not on parts selection). + Standard_Boolean myIsZoomPersistentMode; //!< Zoom persistence mode activation. + BehaviorOnTransform myBehaviorOnTransform; //!< Behavior settings applied on manipulator when transforming an object. + +protected: //! @name Fields for interactive trnasformation. Fields only for internal needs. They do not have public interface. + + NCollection_Sequence myStartTrsfs; //!< Owning object transformation for start. It is used internally. + Standard_Boolean myHasStartedTransformation; //!< Shows if transformation is processed (sequential calls of Transform()). + gp_Ax2 myStartPosition; //! Start position of manipulator. + gp_Pnt myStartPick; //! 3d point corresponding to start mouse pick. + Standard_Real myPrevState; //! Previous value of angle during rotation. + + //! Aspect used to colour current detected part and current selected part. + Handle(Prs3d_ShadingAspect) myHighlightAspect; +public: + + DEFINE_STANDARD_RTTIEXT(AIS_Manipulator, AIS_InteractiveObject) +}; +#endif // _AIS_Manipulator_HeaderFile diff --git a/src/AIS/AIS_ManipulatorMode.hxx b/src/AIS/AIS_ManipulatorMode.hxx new file mode 100644 index 0000000000..648876b6d6 --- /dev/null +++ b/src/AIS/AIS_ManipulatorMode.hxx @@ -0,0 +1,28 @@ +// Created on: 2015-02-05 +// Created by: Anastasia BORISOVA +// Copyright (c) 2015 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. + +#ifndef _AIS_ManipulatorMode_HeaderFile +#define _AIS_ManipulatorMode_HeaderFile + +//! Mode to make definite kind of transformations with AIS_Manipulator object. +enum AIS_ManipulatorMode +{ + AIS_MM_None = 0, + AIS_MM_Translation = 1, + AIS_MM_Rotation, + AIS_MM_Scaling +}; + +#endif \ No newline at end of file diff --git a/src/AIS/AIS_ManipulatorOwner.cxx b/src/AIS/AIS_ManipulatorOwner.cxx new file mode 100644 index 0000000000..dd8e98f900 --- /dev/null +++ b/src/AIS/AIS_ManipulatorOwner.cxx @@ -0,0 +1,94 @@ +// Created on: 2015-12-23 +// Created by: Anastasia BORISOVA +// Copyright (c) 2015 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 + +IMPLEMENT_STANDARD_RTTIEXT(AIS_ManipulatorOwner,SelectMgr_EntityOwner) +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +AIS_ManipulatorOwner::AIS_ManipulatorOwner (const Handle(SelectMgr_SelectableObject)& theSelObject, + const Standard_Integer theIndex, + const AIS_ManipulatorMode theMode, + const Standard_Integer thePriority) +: SelectMgr_EntityOwner(theSelObject, thePriority), + myIndex (theIndex), + myMode (theMode) +{ + // +} + +//======================================================================= +//function : HilightWithColor +//purpose : +//======================================================================= +void AIS_ManipulatorOwner::HilightWithColor (const Handle(PrsMgr_PresentationManager3d)& thePM, + const Quantity_NameOfColor theColor, + const Standard_Integer theMode) +{ + if (theMode == 0) + { + SelectMgr_EntityOwner::HilightWithColor (thePM, theColor, theMode); + return; + } + + Selectable()->HilightOwnerWithColor (thePM, theColor, this); +} + +//======================================================================= +//function : IsHilighted +//purpose : +//======================================================================= +Standard_Boolean AIS_ManipulatorOwner::IsHilighted (const Handle(PrsMgr_PresentationManager)& thePM, + const Standard_Integer /*theMode*/) const +{ + if (!HasSelectable()) + { + return Standard_False; + } + + return thePM->IsHighlighted (Selectable(), myMode); +} + +//======================================================================= +//function : Hilight +//purpose : +//======================================================================= +void AIS_ManipulatorOwner::Hilight (const Handle(PrsMgr_PresentationManager)& thePM, + const Standard_Integer /*theMode*/) +{ + if (!HasSelectable()) + { + return; + } + + thePM->Highlight (Selectable(), myMode); +} + +//======================================================================= +//function : Unhilight +//purpose : +//======================================================================= +void AIS_ManipulatorOwner::Unhilight (const Handle(PrsMgr_PresentationManager)& thePM, + const Standard_Integer /*theMode*/) +{ + if (!HasSelectable()) + { + return; + } + + thePM->Unhighlight (Selectable(), myMode); +} diff --git a/src/AIS/AIS_ManipulatorOwner.hxx b/src/AIS/AIS_ManipulatorOwner.hxx new file mode 100644 index 0000000000..95b31bb671 --- /dev/null +++ b/src/AIS/AIS_ManipulatorOwner.hxx @@ -0,0 +1,60 @@ +// Created on: 2015-12-23 +// Created by: Anastasia BORISOVA +// Copyright (c) 2015 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. + +#ifndef _AIS_ManipulatorOwner_HeaderFile +#define _AIS_ManipulatorOwner_HeaderFile + +#include + +#include +#include + +DEFINE_STANDARD_HANDLE(AIS_ManipulatorOwner, SelectMgr_EntityOwner) + +//! Entity owner for selection management of AIS_Manipulator object. +class AIS_ManipulatorOwner : public SelectMgr_EntityOwner +{ +public: + + DEFINE_STANDARD_RTTIEXT(AIS_ManipulatorOwner, SelectMgr_EntityOwner) + + Standard_EXPORT AIS_ManipulatorOwner (const Handle(SelectMgr_SelectableObject)& theSelObject, + const Standard_Integer theIndex, + const AIS_ManipulatorMode theMode, + const Standard_Integer thePriority = 0); + + Standard_EXPORT virtual ~AIS_ManipulatorOwner() {} + + Standard_EXPORT virtual void HilightWithColor (const Handle(PrsMgr_PresentationManager3d)& thePM, const Quantity_NameOfColor theColor, const Standard_Integer theMode) Standard_OVERRIDE; + + Standard_EXPORT Standard_Boolean IsHilighted (const Handle(PrsMgr_PresentationManager)& thePM, + const Standard_Integer theMode) const Standard_OVERRIDE; + + Standard_EXPORT virtual void Hilight (const Handle(PrsMgr_PresentationManager)& thePM, const Standard_Integer theMode) Standard_OVERRIDE; + + Standard_EXPORT virtual void Unhilight (const Handle(PrsMgr_PresentationManager)& thePM, const Standard_Integer theMode) Standard_OVERRIDE; + + Standard_EXPORT AIS_ManipulatorMode Mode() const { return myMode; } + + //! @return index of manipulator axis. + Standard_EXPORT Standard_Integer Index() const { return myIndex; } + +protected: + + Standard_Integer myIndex; //!< index of manipulator axis. + AIS_ManipulatorMode myMode;//!< manipulation (highlight) mode. +}; + +#endif // _AIS_ManipulatorOwner_HeaderFile diff --git a/src/AIS/FILES b/src/AIS/FILES index 2882a7c425..c4ea1469a3 100644 --- a/src/AIS/FILES +++ b/src/AIS/FILES @@ -99,6 +99,11 @@ AIS_LocalContext_1.cxx AIS_LocalStatus.cxx AIS_LocalStatus.hxx AIS_LocalStatus.lxx +AIS_Manipulator.hxx +AIS_Manipulator.cxx +AIS_ManipulatorMode.hxx +AIS_ManipulatorOwner.hxx +AIS_ManipulatorOwner.cxx AIS_MapIteratorOfMapOfInteractive.hxx AIS_MapOfInteractive.hxx AIS_MaxRadiusDimension.cxx diff --git a/src/StdPrs/FILES b/src/StdPrs/FILES index 94ffef116e..31829a8951 100644 --- a/src/StdPrs/FILES +++ b/src/StdPrs/FILES @@ -21,8 +21,16 @@ StdPrs_ShadedShape.cxx StdPrs_ShadedShape.hxx StdPrs_ShadedSurface.cxx StdPrs_ShadedSurface.hxx +StdPrs_ToolDisk.hxx +StdPrs_ToolDisk.cxx +StdPrs_ToolCylinder.hxx +StdPrs_ToolCylinder.cxx StdPrs_ToolPoint.cxx StdPrs_ToolPoint.hxx +StdPrs_ToolQuadric.hxx +StdPrs_ToolQuadric.cxx +StdPrs_ToolSphere.hxx +StdPrs_ToolSphere.cxx StdPrs_ToolRFace.cxx StdPrs_ToolRFace.hxx StdPrs_ToolTriangulatedShape.cxx diff --git a/src/StdPrs/StdPrs_ToolCylinder.cxx b/src/StdPrs/StdPrs_ToolCylinder.cxx new file mode 100644 index 0000000000..a2c119cde1 --- /dev/null +++ b/src/StdPrs/StdPrs_ToolCylinder.cxx @@ -0,0 +1,64 @@ +// Created on: 1995-07-27 +// Created by: Modelistation +// Copyright (c) 1995-1999 Matra Datavision +// Copyright (c) 1999-2014 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 + +#include +#include +#include + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +StdPrs_ToolCylinder::StdPrs_ToolCylinder (const Standard_ShortReal theBottomRad, + const Standard_ShortReal theTopRad, + const Standard_ShortReal theHeight, + const Standard_Integer theSlicesNb, + const Standard_Integer theStacksNb) +: myBottomRadius (theBottomRad), + myTopRadius (theTopRad), + myHeight (theHeight) +{ + myStacksNb = theStacksNb; + mySlicesNb = theSlicesNb; +} + +//======================================================================= +//function : Vertex +//purpose : +//======================================================================= +gp_Pnt StdPrs_ToolCylinder::Vertex (const Standard_Real theU, const Standard_Real theV) +{ + const Standard_ShortReal aU = static_cast (theU * M_PI * 2.0); + const Standard_ShortReal aRadius = myBottomRadius + (myTopRadius - myBottomRadius) * (Standard_ShortReal)theV; + return gp_Pnt (cosf(aU) * aRadius, + sinf(aU) * aRadius, + theV * myHeight); +} + +//======================================================================= +//function : Add +//purpose : +//======================================================================= +gp_Dir StdPrs_ToolCylinder::Normal (const Standard_Real theU, const Standard_Real /*theV*/) +{ + const Standard_ShortReal aU = static_cast (theU * M_PI * 2.0); + return gp_Dir (gp_Vec(cosf(aU) * myHeight, + sinf(aU) * myHeight, + myBottomRadius - myTopRadius).Normalized().XYZ()); +} diff --git a/src/StdPrs/StdPrs_ToolCylinder.hxx b/src/StdPrs/StdPrs_ToolCylinder.hxx new file mode 100644 index 0000000000..e9c2ca8c72 --- /dev/null +++ b/src/StdPrs/StdPrs_ToolCylinder.hxx @@ -0,0 +1,51 @@ +// Created on: 2016-02-04 +// Created by: Anastasia BORISOVA +// Copyright (c) 2016 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. + +#ifndef _StdPrs_ToolCylinder_HeaderFile +#define _StdPrs_ToolCylinder_HeaderFile + +#include +#include + +//! Standard presentation algorithm that outputs graphical primitives for cylindrical surface. +class StdPrs_ToolCylinder : public StdPrs_ToolQuadric +{ +public: + + DEFINE_STANDARD_ALLOC + + //! Initializes the algorithm. + Standard_EXPORT StdPrs_ToolCylinder (const Standard_ShortReal theBottomRad, + const Standard_ShortReal theTopRad, + const Standard_ShortReal theHeight, + const Standard_Integer theSlicesNb, + const Standard_Integer theStacksNb); + +protected: + + //! Computes vertex at given parameter location of the surface. + Standard_EXPORT virtual gp_Pnt Vertex (const Standard_Real theU, const Standard_Real theV) Standard_OVERRIDE; + + //! Computes normal at given parameter location of the surface. + Standard_EXPORT virtual gp_Dir Normal (const Standard_Real theU, const Standard_Real theV) Standard_OVERRIDE; + +protected: + + Standard_ShortReal myBottomRadius; + Standard_ShortReal myTopRadius; + Standard_ShortReal myHeight; +}; + +#endif // _StdPrs_ToolCylinder_HeaderFile diff --git a/src/StdPrs/StdPrs_ToolDisk.cxx b/src/StdPrs/StdPrs_ToolDisk.cxx new file mode 100644 index 0000000000..c5cd1f9605 --- /dev/null +++ b/src/StdPrs/StdPrs_ToolDisk.cxx @@ -0,0 +1,58 @@ +// Created on: 2016-02-04 +// Created by: Anastasia BORISOVA +// Copyright (c) 2016 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 + +#include +#include +#include + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +StdPrs_ToolDisk::StdPrs_ToolDisk (const Standard_ShortReal theInnerRadius, + const Standard_ShortReal theOuterRadius, + const Standard_Integer theSlicesNb, + const Standard_Integer theStacksNb) +: myInnerRadius (theInnerRadius), + myOuterRadius (theOuterRadius) +{ + mySlicesNb = theSlicesNb; + myStacksNb = theStacksNb; +} + +//======================================================================= +//function : Vertex +//purpose : +//======================================================================= +gp_Pnt StdPrs_ToolDisk::Vertex (const Standard_Real theU, const Standard_Real theV) +{ + const Standard_ShortReal aU = static_cast (theU * M_PI * 2.0); + const Standard_ShortReal aRadius = myInnerRadius + (myOuterRadius - myInnerRadius) * (Standard_ShortReal)theV; + return gp_Pnt (cosf(aU) * aRadius, + sinf(aU) * aRadius, + 0.0f); +} + +//======================================================================= +//function : Add +//purpose : +//======================================================================= +gp_Dir StdPrs_ToolDisk::Normal (const Standard_Real /*theU*/, const Standard_Real /*theV*/) +{ + return gp_Dir(0.0f, 0.0f, -1.0f); +} diff --git a/src/StdPrs/StdPrs_ToolDisk.hxx b/src/StdPrs/StdPrs_ToolDisk.hxx new file mode 100644 index 0000000000..cc30fbc2d8 --- /dev/null +++ b/src/StdPrs/StdPrs_ToolDisk.hxx @@ -0,0 +1,50 @@ +// Created on: 2016-02-04 +// Created by: Anastasia BORISOVA +// Copyright (c) 2016 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. + +#ifndef _StdPrs_ToolDisk_HeaderFile +#define _StdPrs_ToolDisk_HeaderFile + +#include +#include + +//! Standard presentation algorithm that outputs graphical primitives for disk surface. +class StdPrs_ToolDisk : public StdPrs_ToolQuadric +{ +public: + + DEFINE_STANDARD_ALLOC + + //! Initializes the algorithm. + Standard_EXPORT StdPrs_ToolDisk (const Standard_ShortReal theInnerRadius, + const Standard_ShortReal theOuterRadius, + const Standard_Integer theSlicesNb, + const Standard_Integer theStacksNb); + +protected: + + //! Computes vertex at given parameter location of the surface. + Standard_EXPORT virtual gp_Pnt Vertex (const Standard_Real theU, const Standard_Real theV) Standard_OVERRIDE; + + //! Computes normal at given parameter location of the surface. + Standard_EXPORT virtual gp_Dir Normal (const Standard_Real theU, const Standard_Real theV) Standard_OVERRIDE; + +protected: + + Standard_ShortReal myInnerRadius; + Standard_ShortReal myOuterRadius; +}; + + +#endif diff --git a/src/StdPrs/StdPrs_ToolQuadric.cxx b/src/StdPrs/StdPrs_ToolQuadric.cxx new file mode 100644 index 0000000000..f06b1fcbc2 --- /dev/null +++ b/src/StdPrs/StdPrs_ToolQuadric.cxx @@ -0,0 +1,118 @@ +// Created on: 2016-02-04 +// Created by: Anastasia BORISOVA +// Copyright (c) 2016 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 + +#include +#include +#include +#include + +//======================================================================= +//function : fillArrays +//purpose : +//======================================================================= +void StdPrs_ToolQuadric::fillArrays (const gp_Trsf& theTrsf, TColgp_Array1OfPnt& theArray, NCollection_Array1& theNormals) +{ + Standard_ShortReal aStepU = 1.0f / mySlicesNb; + Standard_ShortReal aStepV = 1.0f / myStacksNb; + + for (Standard_Integer aU = 0; aU <= mySlicesNb; aU++) + { + const Standard_Real aParamU = aU * aStepU; + for (Standard_Integer aV = 0; aV <= myStacksNb; aV++) + { + const Standard_ShortReal aParamV = aV * aStepV; + const Standard_Integer aVertId = aU * (myStacksNb + 1) + aV + 1; + gp_Pnt aVertex = Vertex(aParamU, aParamV); + gp_Dir aNormal = Normal(aParamU, aParamV); + + aVertex.Transform (theTrsf); + aNormal.Transform (theTrsf); + + theArray.SetValue (aVertId, aVertex); + theNormals.SetValue (aVertId, aNormal); + } + } +} + +//======================================================================= +//function : FIllArray +//purpose : +//======================================================================= +void StdPrs_ToolQuadric::FillArray (Handle(Graphic3d_ArrayOfTriangles)& theArray, const gp_Trsf& theTrsf) +{ + const Standard_Integer aTrianglesNb = TrianglesNb(); + theArray = new Graphic3d_ArrayOfTriangles (aTrianglesNb * 3, 0, Standard_True); + + Poly_Array1OfTriangle aPolyTriangles (1, aTrianglesNb); + TColgp_Array1OfPnt anArray (1, aTrianglesNb * 3); + NCollection_Array1 aNormals (1, aTrianglesNb * 3); + fillArrays (theTrsf, anArray, aNormals); + + // Fill primitives + for (Standard_Integer aU = 0; aU < mySlicesNb; ++aU) + { + for (Standard_Integer aV = 1; aV <= myStacksNb; ++aV) + { + theArray->AddVertex (anArray.Value (aU * (myStacksNb + 1) + aV), aNormals.Value (aU * (myStacksNb + 1) + aV)); + theArray->AddVertex (anArray.Value ((aU + 1) * (myStacksNb + 1) + aV), aNormals.Value ((aU + 1) * (myStacksNb + 1) + aV)); + theArray->AddVertex (anArray.Value ((aU + 1) * (myStacksNb + 1) + (aV + 1)), aNormals.Value ((aU + 1) * (myStacksNb + 1) + (aV + 1))); + theArray->AddVertex (anArray.Value ((aU + 1) * (myStacksNb + 1) + (aV + 1)), aNormals.Value ((aU + 1) * (myStacksNb + 1) + (aV + 1))); + theArray->AddVertex (anArray.Value (aU * (myStacksNb + 1) + (aV + 1)), aNormals.Value (aU * (myStacksNb + 1) + (aV + 1))); + theArray->AddVertex (anArray.Value (aU * (myStacksNb + 1) + aV), aNormals.Value (aU * (myStacksNb + 1) + aV)); + } + } +} + +//======================================================================= +//function : FillTriangulation +//purpose : +//======================================================================= +void StdPrs_ToolQuadric::FillArray (Handle(Graphic3d_ArrayOfTriangles)& theArray, + Handle(Poly_Triangulation)& theTriangulation, + const gp_Trsf& theTrsf) +{ + const Standard_Integer aTrianglesNb = TrianglesNb(); + theArray = new Graphic3d_ArrayOfTriangles(aTrianglesNb * 3, 0, Standard_True); + + Poly_Array1OfTriangle aPolyTriangles(1, aTrianglesNb); + TColgp_Array1OfPnt anArray(1, aTrianglesNb * 3); + NCollection_Array1 aNormals(1, aTrianglesNb * 3); + fillArrays(theTrsf, anArray, aNormals); + + // Fill triangles + for (Standard_Integer aU = 0, anIndex = 0; aU < mySlicesNb; ++aU) + { + for (Standard_Integer aV = 1; aV <= myStacksNb; ++aV) + { + theArray->AddVertex(anArray.Value(aU * (myStacksNb + 1) + aV), aNormals.Value(aU * (myStacksNb + 1) + aV)); + theArray->AddVertex(anArray.Value((aU + 1) * (myStacksNb + 1) + aV), aNormals.Value((aU + 1) * (myStacksNb + 1) + aV)); + theArray->AddVertex(anArray.Value((aU + 1) * (myStacksNb + 1) + (aV + 1)), aNormals.Value((aU + 1) * (myStacksNb + 1) + (aV + 1))); + theArray->AddVertex(anArray.Value((aU + 1) * (myStacksNb + 1) + (aV + 1)), aNormals.Value((aU + 1) * (myStacksNb + 1) + (aV + 1))); + theArray->AddVertex(anArray.Value(aU * (myStacksNb + 1) + (aV + 1)), aNormals.Value(aU * (myStacksNb + 1) + (aV + 1))); + theArray->AddVertex(anArray.Value(aU * (myStacksNb + 1) + aV), aNormals.Value(aU * (myStacksNb + 1) + aV)); + + aPolyTriangles.SetValue (++anIndex, Poly_Triangle(aU * (myStacksNb + 1) + aV, + (aU + 1) * (myStacksNb + 1) + aV, + (aU + 1) * (myStacksNb + 1) + (aV + 1))); + aPolyTriangles.SetValue (++anIndex, Poly_Triangle((aU + 1) * (myStacksNb + 1) + (aV + 1), + aU * (myStacksNb + 1) + (aV + 1), + aU * (myStacksNb + 1) + aV)); + } + } + + theTriangulation = new Poly_Triangulation (anArray, aPolyTriangles); +} diff --git a/src/StdPrs/StdPrs_ToolQuadric.hxx b/src/StdPrs/StdPrs_ToolQuadric.hxx new file mode 100644 index 0000000000..264f7bf585 --- /dev/null +++ b/src/StdPrs/StdPrs_ToolQuadric.hxx @@ -0,0 +1,64 @@ +// Created on: 2016-02-04 +// Created by: Anastasia BORISOVA +// Copyright (c) 2016 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. + +#ifndef _StdPrs_ToolQuadric_HeaderFile +#define _StdPrs_ToolQuadric_HeaderFile + +#include +#include +#include +#include +#include +#include +#include +#include + +//! Base class to build 3D surfaces presentation of quadric surfaces. +class StdPrs_ToolQuadric +{ +public: + + DEFINE_STANDARD_ALLOC + + //! Generate primitives for 3D quadric surface and fill the given array. Optional transformation is applied. + Standard_EXPORT void FillArray (Handle(Graphic3d_ArrayOfTriangles)& theArray, const gp_Trsf& theTrsf); + + //! Generate primitives for 3D quadric surface presentation and fill the given array and poly triangulation structure. Optional transformation is applied. + Standard_EXPORT void FillArray (Handle(Graphic3d_ArrayOfTriangles)& theArray, Handle(Poly_Triangulation)& theTriangulation, const gp_Trsf& theTrsf); + +protected: + + //! Method implements an algorithm to generate arrays of vertices and normals for 3D surface. + Standard_EXPORT void fillArrays (const gp_Trsf& theTrsf, TColgp_Array1OfPnt& theArray, NCollection_Array1& theNormals); + + //! Number of triangles in generated presentation. + Standard_Integer TrianglesNb() const + { + return mySlicesNb * myStacksNb * 2; + } + + //! Redefine this method to generate vertex at given parameters. + virtual gp_Pnt Vertex (const Standard_Real theU, const Standard_Real theV) = 0; + + //! Redefine this method to generate normal at given parameters. + virtual gp_Dir Normal (const Standard_Real theU, const Standard_Real theV) = 0; + +protected: + + Standard_Integer mySlicesNb; + Standard_Integer myStacksNb; +}; + +#endif // _StdPrs_ShadedSurface_HeaderFile diff --git a/src/StdPrs/StdPrs_ToolSphere.cxx b/src/StdPrs/StdPrs_ToolSphere.cxx new file mode 100644 index 0000000000..0489ae7509 --- /dev/null +++ b/src/StdPrs/StdPrs_ToolSphere.cxx @@ -0,0 +1,59 @@ +// Created on: 2016-02-04 +// Created by: Anastasia BORISOVA +// Copyright (c) 2016 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 + +#include +#include +#include + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +StdPrs_ToolSphere::StdPrs_ToolSphere (const Standard_ShortReal theRadius, + const Standard_Integer theSlicesNb, + const Standard_Integer theStacksNb) +: myRadius (theRadius) +{ + mySlicesNb = theSlicesNb; + myStacksNb = theStacksNb; +} + +//======================================================================= +//function : Vertex +//purpose : +//======================================================================= +gp_Pnt StdPrs_ToolSphere::Vertex (const Standard_Real theU, const Standard_Real theV) +{ + const Standard_ShortReal aU = static_cast (theU * M_PI * 2.0); + const Standard_ShortReal aV = static_cast (theV * M_PI); + return gp_Pnt (myRadius * cosf(aU) * sinf(aV), + -myRadius * sinf(aU) * sinf(aV), + myRadius * cosf(aV)); +} + +//======================================================================= +//function : Add +//purpose : +//======================================================================= +gp_Dir StdPrs_ToolSphere::Normal (const Standard_Real theU, const Standard_Real theV) +{ + const Standard_ShortReal aU = static_cast (theU * M_PI * 2.0); + const Standard_ShortReal aV = static_cast (theV * M_PI); + return gp_Dir (cosf(aU) * sinf(aV), + -sinf(aU) * sinf(aV), + cosf(aV)); +} diff --git a/src/StdPrs/StdPrs_ToolSphere.hxx b/src/StdPrs/StdPrs_ToolSphere.hxx new file mode 100644 index 0000000000..fad606e83b --- /dev/null +++ b/src/StdPrs/StdPrs_ToolSphere.hxx @@ -0,0 +1,55 @@ +// Created on: 2016-02-04 +// Created by: Anastasia BORISOVA +// Copyright (c) 2016 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. + +#ifndef _StdPrs_ToolSphere_HeaderFile +#define _StdPrs_ToolSphere_HeaderFile + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//! Standard presentation algorithm that outputs graphical primitives for spherical surface. +class StdPrs_ToolSphere : public StdPrs_ToolQuadric +{ +public: + + DEFINE_STANDARD_ALLOC + + //! Initializes the algorithm. + Standard_EXPORT StdPrs_ToolSphere (const Standard_ShortReal theRadius, + const Standard_Integer theSlicesNb, + const Standard_Integer theStacksNb); + +protected: + + //! Computes vertex at given parameter location of the surface. + Standard_EXPORT virtual gp_Pnt Vertex (const Standard_Real theU, const Standard_Real theV) Standard_OVERRIDE; + + //! Computes normal at given parameter location of the surface. + Standard_EXPORT virtual gp_Dir Normal (const Standard_Real theU, const Standard_Real theV) Standard_OVERRIDE; + +protected: + + Standard_ShortReal myRadius; +}; + + +#endif diff --git a/src/ViewerTest/ViewerTest_CmdParser.cxx b/src/ViewerTest/ViewerTest_CmdParser.cxx index 001f2b6d9e..bc3889626f 100644 --- a/src/ViewerTest/ViewerTest_CmdParser.cxx +++ b/src/ViewerTest/ViewerTest_CmdParser.cxx @@ -175,38 +175,78 @@ std::string ViewerTest_CmdParser::Arg (const std::string& theOptionName, Standar //function : ArgVec3f //purpose : //=============================================================================================== -Graphic3d_Vec3 ViewerTest_CmdParser::ArgVec3f (const std::string& theOptionName) +Graphic3d_Vec3 ViewerTest_CmdParser::ArgVec3f (const std::string& theOptionName, Standard_Integer theArgumentIndex) { - return Graphic3d_Vec3 (static_cast (Draw::Atof (Arg (theOptionName, 0).c_str())), - static_cast (Draw::Atof (Arg (theOptionName, 1).c_str())), - static_cast (Draw::Atof (Arg (theOptionName, 2).c_str()))); + return Graphic3d_Vec3 (static_cast (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str())), + static_cast (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str())), + static_cast (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()))); } //=============================================================================================== //function : ArgVec3d //purpose : //=============================================================================================== -Graphic3d_Vec3d ViewerTest_CmdParser::ArgVec3d (const std::string& theOptionName) +Graphic3d_Vec3d ViewerTest_CmdParser::ArgVec3d (const std::string& theOptionName, Standard_Integer theArgumentIndex) { - return Graphic3d_Vec3d ( Draw::Atof (Arg (theOptionName, 0).c_str()), - Draw::Atof (Arg (theOptionName, 1).c_str()), - Draw::Atof (Arg (theOptionName, 2).c_str())); + return Graphic3d_Vec3d ( Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()), + Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()), + Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str())); +} + +//=============================================================================================== +//function : ArgVec +//purpose : +//=============================================================================================== +gp_Vec ViewerTest_CmdParser::ArgVec (const std::string& theOptionName, Standard_Integer theArgumentIndex) +{ + return gp_Vec ( Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()), + Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()), + Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str())); +} + +//=============================================================================================== +//function : ArgPnt +//purpose : +//=============================================================================================== +gp_Pnt ViewerTest_CmdParser::ArgPnt (const std::string& theOptionName, Standard_Integer theArgumentIndex) +{ + return gp_Pnt ( Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()), + Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()), + Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str())); } //=============================================================================================== //function : ArgDouble //purpose : //=============================================================================================== -Standard_Real ViewerTest_CmdParser::ArgDouble (const std::string& theOptionName) +Standard_Real ViewerTest_CmdParser::ArgDouble (const std::string& theOptionName, Standard_Integer theArgumentIndex) { - return Draw::Atof (Arg (theOptionName, 0).c_str()); + return Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str()); } //=============================================================================================== //function : ArgFloat //purpose : //=============================================================================================== -Standard_ShortReal ViewerTest_CmdParser::ArgFloat (const std::string& theOptionName) +Standard_ShortReal ViewerTest_CmdParser::ArgFloat (const std::string& theOptionName, Standard_Integer theArgumentIndex) { - return static_cast (Draw::Atof (Arg (theOptionName, 0).c_str())); + return static_cast (Draw::Atof (Arg (theOptionName, theArgumentIndex).c_str())); +} + +//=============================================================================================== +//function : ArgInt +//purpose : +//=============================================================================================== +Standard_Integer ViewerTest_CmdParser::ArgInt (const std::string& theOptionName, const Standard_Integer theArgumentIndex) +{ + return static_cast (Draw::Atoi (Arg (theOptionName, theArgumentIndex).c_str())); +} + +//=============================================================================================== +//function : ArgBool +//purpose : +//=============================================================================================== +Standard_Boolean ViewerTest_CmdParser::ArgBool (const std::string& theOptionName, const Standard_Integer theArgumentIndex) +{ + return static_cast (Draw::Atoi (Arg (theOptionName, theArgumentIndex).c_str())); } diff --git a/src/ViewerTest/ViewerTest_CmdParser.hxx b/src/ViewerTest/ViewerTest_CmdParser.hxx index 2158a16599..d53c942b4a 100644 --- a/src/ViewerTest/ViewerTest_CmdParser.hxx +++ b/src/ViewerTest/ViewerTest_CmdParser.hxx @@ -23,6 +23,7 @@ #include #include +#include //! Command parser. class ViewerTest_CmdParser @@ -57,17 +58,29 @@ public: //! Accesses local argument of option 'theOptionName' with index 'theArgumentIndex'. std::string Arg (const std::string& theOptionName, Standard_Integer theArgumentIndex); - // Interprets arguments of option 'theOptionName' as float vector. - Graphic3d_Vec3 ArgVec3f (const std::string& theOptionName); + // Interprets arguments of option 'theOptionName' as float vector starting with index 'theArgumentIndex'. + Graphic3d_Vec3 ArgVec3f (const std::string& theOptionName, const Standard_Integer theArgumentIndex = 0); - // Interprets arguments of option 'theOptionName' as double vector. - Graphic3d_Vec3d ArgVec3d (const std::string& theOptionName); + // Interprets arguments of option 'theOptionName' as double vector starting with index 'theArgumentIndex'. + Graphic3d_Vec3d ArgVec3d (const std::string& theOptionName, const Standard_Integer theArgumentIndex = 0); - // Interprets arguments of option 'theOptionName' as double. - Standard_Real ArgDouble (const std::string& theOptionName); + // Interprets arguments of option 'theOptionName' as gp vector starting with index 'theArgumentIndex'. + gp_Vec ArgVec (const std::string& theOptionName, const Standard_Integer theArgumentIndex = 0); - // Interprets arguments of option 'theOptionName' as float. - Standard_ShortReal ArgFloat (const std::string& theOptionName); + // Interprets arguments of option 'theOptionName' as gp vector starting with index 'theArgumentIndex'. + gp_Pnt ArgPnt (const std::string& theOptionName, const Standard_Integer theArgumentIndex = 0); + + // Interprets arguments of option 'theOptionName' as double at index 'theArgumentIndex'. + Standard_Real ArgDouble (const std::string& theOptionName, const Standard_Integer theArgumentIndex = 0); + + // Interprets arguments of option 'theOptionName' as float at index 'theArgumentIndex'. + Standard_ShortReal ArgFloat (const std::string& theOptionName, const Standard_Integer theArgumentIndex = 0); + + // Interprets arguments of option 'theOptionName' as integer at index 'theArgumentIndex'. + Standard_Integer ArgInt (const std::string& theOptionName, const Standard_Integer theArgumentIndex = 0); + + // Interprets arguments of option 'theOptionName' as boolean at index 'theArgumentIndex'. + Standard_Boolean ArgBool (const std::string& theOptionName, const Standard_Integer theArgumentIndex = 0); private: diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 9e63f23627..96db8d80eb 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -207,6 +209,27 @@ Standard_EXPORT const Handle(AIS_RubberBand)& GetRubberBand() return aBand; } +typedef NCollection_Map ViewerTest_MapOfAISManipulators; + +Standard_EXPORT ViewerTest_MapOfAISManipulators& GetMapOfAISManipulators() +{ + static ViewerTest_MapOfAISManipulators aMap; + return aMap; +} + +Standard_EXPORT Handle(AIS_Manipulator) GetActiveAISManipulator() +{ + ViewerTest_MapOfAISManipulators::Iterator anIt (GetMapOfAISManipulators()); + for (; anIt.More(); anIt.Next()) + { + if (anIt.Value()->HasActiveMode()) + { + return anIt.Value(); + } + } + return NULL; +} + //============================================================================== #ifdef _WIN32 @@ -1912,9 +1935,16 @@ static LRESULT WINAPI AdvViewerWindowProc( HWND hwnd, } } break; + case WM_LBUTTONUP: - if (!DragFirst) + if (IsDragged && !DragFirst) { + if (!GetActiveAISManipulator().IsNull()) + { + GetActiveAISManipulator()->StopTransform(); + ViewerTest::GetAISContext()->ClearSelected(); + } + if (ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand())) { ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False); @@ -1926,44 +1956,77 @@ static LRESULT WINAPI AdvViewerWindowProc( HWND hwnd, IsDragged = Standard_False; return ViewerWindowProc( hwnd, Msg, wParam, lParam ); - case WM_LBUTTONDOWN: - if( fwKeys == MK_LBUTTON || fwKeys == ( MK_LBUTTON | MK_SHIFT ) ) + case WM_RBUTTONUP: + if (IsDragged && !DragFirst) + { + if (!GetActiveAISManipulator().IsNull()) + { + GetActiveAISManipulator()->StopTransform (Standard_False); + ViewerTest::GetAISContext()->ClearSelected(); + } + IsDragged = Standard_False; + } + return ViewerWindowProc (hwnd, Msg, wParam, lParam); + + case WM_LBUTTONDOWN: + if (!GetActiveAISManipulator().IsNull()) + { + IsDragged = ( fwKeys == MK_LBUTTON ); + } + else + { + IsDragged = ( fwKeys == MK_LBUTTON || fwKeys == ( MK_LBUTTON | MK_SHIFT ) ); + } + + if (IsDragged) { - IsDragged = Standard_True; DragFirst = Standard_True; X_ButtonPress = LOWORD(lParam); Y_ButtonPress = HIWORD(lParam); } return ViewerWindowProc( hwnd, Msg, wParam, lParam ); - break; - case WM_MOUSEMOVE: if (IsDragged) { - bool toRedraw = false; - if (!DragFirst && ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand())) + X_Motion = LOWORD (lParam); + Y_Motion = HIWORD (lParam); + if (!GetActiveAISManipulator().IsNull()) { - ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False); - toRedraw = true; + if (DragFirst) + { + GetActiveAISManipulator()->StartTransform (X_ButtonPress, Y_ButtonPress, ViewerTest::CurrentView()); + } + else + { + GetActiveAISManipulator()->Transform (X_Motion, Y_Motion, ViewerTest::CurrentView()); + ViewerTest::GetAISContext()->CurrentViewer()->Redraw(); + } + } + else + { + bool toRedraw = false; + if (!DragFirst && ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand())) + { + ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False); + toRedraw = true; + } + + RECT aRect; + if (GetClientRect (hwnd, &aRect)) + { + int aHeight = aRect.bottom - aRect.top; + GetRubberBand()->SetRectangle (X_ButtonPress, aHeight - Y_ButtonPress, X_Motion, aHeight - Y_Motion); + ViewerTest::GetAISContext()->Display (GetRubberBand(), 0, -1, Standard_False, Standard_True, AIS_DS_Displayed); + toRedraw = true; + } + if (toRedraw) + { + ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate(); + } } DragFirst = Standard_False; - X_Motion = LOWORD (lParam); - Y_Motion = HIWORD (lParam); - - RECT aRect; - if (GetClientRect (hwnd, &aRect)) - { - int aHeight = aRect.bottom - aRect.top; - GetRubberBand()->SetRectangle (X_ButtonPress, aHeight - Y_ButtonPress, X_Motion, aHeight - Y_Motion); - ViewerTest::GetAISContext()->Display (GetRubberBand(), 0, -1, Standard_False, Standard_True, AIS_DS_Displayed); - toRedraw = true; - } - if (toRedraw) - { - ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate(); - } } else return ViewerWindowProc( hwnd, Msg, wParam, lParam ); @@ -8786,6 +8849,295 @@ static Standard_Integer VXRotate (Draw_Interpretor& di, return 0; } +//=============================================================================================== +//class : ViewerTest_AISManipulator +//purpose : Proxy class maintaining automated registry map to enlist existing AIS_Manipulator instances +//=============================================================================================== +DEFINE_STANDARD_HANDLE (ViewerTest_AISManipulator, AIS_Manipulator) + +class ViewerTest_AISManipulator : public AIS_Manipulator +{ +public: + + ViewerTest_AISManipulator() : AIS_Manipulator() + { + GetMapOfAISManipulators().Add (this); + } + + virtual ~ViewerTest_AISManipulator() + { + GetMapOfAISManipulators().Remove (this); + } + + DEFINE_STANDARD_RTTIEXT(ViewerTest_AISManipulator, AIS_Manipulator) +}; + +IMPLEMENT_STANDARD_HANDLE (ViewerTest_AISManipulator, AIS_Manipulator) +IMPLEMENT_STANDARD_RTTIEXT(ViewerTest_AISManipulator, AIS_Manipulator) + +//=============================================================================================== +//function : VManipulator +//purpose : +//=============================================================================================== +static int VManipulator (Draw_Interpretor& theDi, + Standard_Integer theArgsNb, + const char** theArgVec) +{ + Handle(V3d_View) aView = ViewerTest::CurrentView(); + Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext(); + ViewerTest::GetAISContext()->MainSelector()->SetPickClosest (Standard_False); + if (aView.IsNull() + || aViewer.IsNull()) + { + std::cerr << "No active viewer!\n"; + return 1; + } + + ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView()); + Standard_Integer anArgIter = 1; + for (; anArgIter < theArgsNb; ++anArgIter) + { + anUpdateTool.parseRedrawMode (theArgVec[anArgIter]); + } + + ViewerTest_CmdParser aCmd; + aCmd.AddDescription ("Manages manipulator for interactive objects:"); + aCmd.AddOption ("attach", "... object - attach manipulator to an object"); + aCmd.AddOption ("adjustPosition", "... {0|1} - adjust position when attaching"); + aCmd.AddOption ("adjustSize", "... {0|1} - adjust size when attaching "); + aCmd.AddOption ("enableModes", "... {0|1} - enable modes when attaching "); + aCmd.AddOption ("detach", "... - detach manipulator"); + + aCmd.AddOption ("startTransform", "... mouse_x mouse_y - invoke start transformation"); + aCmd.AddOption ("transform", "... mouse_x mouse_y - invoke transformation"); + aCmd.AddOption ("stopTransform", "... [abort] - invoke stop transformation"); + + aCmd.AddOption ("move", "... x y z - move object"); + aCmd.AddOption ("rotate", "... x y z dx dy dz angle - rotate object"); + aCmd.AddOption ("scale", "... factor - scale object"); + + aCmd.AddOption ("autoActivate", "... {0|1} - set activation on detection"); + aCmd.AddOption ("followTranslation", "... {0|1} - set following translation transform"); + aCmd.AddOption ("followRotation", "... {0|1} - set following rotation transform"); + aCmd.AddOption ("gap", "... value - set gap between sub-parts"); + aCmd.AddOption ("part", "... axis mode {0|1} - set visual part"); + aCmd.AddOption ("pos", "... x y z [nx ny nz [xx xy xz]] - set position of manipulator"); + aCmd.AddOption ("size", "... size - set size of manipulator"); + aCmd.AddOption ("zoomable", "... {0|1} - set zoom persistence"); + + aCmd.Parse (theArgsNb, theArgVec); + + if (aCmd.HasOption ("help")) + { + theDi.PrintHelp (theArgVec[0]); + return 0; + } + + ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS(); + + TCollection_AsciiString aName (aCmd.Arg ("", 0).c_str()); + + if (aName.IsEmpty()) + { + std::cerr << theArgVec[0] << " error: please specify AIS manipulator's name as the first argument.\n"; + return 1; + } + + // ---------------------------------- + // detach existing manipulator object + // ---------------------------------- + + if (aCmd.HasOption ("detach")) + { + if (!aMapAIS.IsBound2 (aName)) + { + std::cerr << theArgVec[0] << " error: could not find \"" << aName << "\" AIS object.\n"; + return 1; + } + + Handle(AIS_Manipulator) aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName)); + if (aManipulator.IsNull()) + { + std::cerr << theArgVec[0] << " error: \"" << aName << "\" is not an AIS manipulator.\n"; + return 1; + } + + aManipulator->Detach(); + aMapAIS.UnBind2 (aName); + ViewerTest::GetAISContext()->Remove (aManipulator); + + return 0; + } + + // ----------------------------------------------- + // find or create manipulator if it does not exist + // ----------------------------------------------- + + Handle(AIS_Manipulator) aManipulator; + if (!aMapAIS.IsBound2 (aName)) + { + std::cout << theArgVec[0] << ": AIS object \"" << aName << "\" has been created.\n"; + + aManipulator = new ViewerTest_AISManipulator(); + aMapAIS.Bind (aManipulator, aName); + } + else + { + aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName)); + if (aManipulator.IsNull()) + { + std::cerr << theArgVec[0] << " error: \"" << aName << "\" is not an AIS manipulator.\n"; + return 1; + } + } + + // ----------------------------------------- + // change properties of manipulator instance + // ----------------------------------------- + + if (aCmd.HasOption ("autoActivate", 1, Standard_True)) + { + aManipulator->SetModeActivationOnDetection (aCmd.ArgBool ("autoActivate")); + } + if (aCmd.HasOption ("followTranslation", 1, Standard_True)) + { + aManipulator->ChangeTransformBehavior().SetFollowTranslation (aCmd.ArgBool ("followTranslation")); + } + if (aCmd.HasOption ("followRotation", 1, Standard_True)) + { + aManipulator->ChangeTransformBehavior().SetFollowRotation (aCmd.ArgBool ("followRotation")); + } + if (aCmd.HasOption ("gap", 1, Standard_True)) + { + aManipulator->SetGap (aCmd.ArgFloat ("gap")); + } + if (aCmd.HasOption ("part", 3, Standard_True)) + { + Standard_Integer anAxis = aCmd.ArgInt ("part", 0); + Standard_Integer aMode = aCmd.ArgInt ("part", 1); + Standard_Boolean aOnOff = aCmd.ArgBool ("part", 2); + if (aMode < 1 || aMode > 3) + { + std::cerr << theArgVec[0] << " error: mode value should be in range [1, 3].\n"; + return 1; + } + + aManipulator->SetPart (anAxis, static_cast (aMode), aOnOff); + } + if (aCmd.HasOption ("pos", 3, Standard_True)) + { + gp_Pnt aLocation = aCmd.ArgPnt ("pos", 0); + gp_Dir aVDir = aCmd.HasOption ("pos", 6) ? gp_Dir (aCmd.ArgVec ("pos", 3)) : aManipulator->Position().Direction(); + gp_Dir aXDir = aCmd.HasOption ("pos", 9) ? gp_Dir (aCmd.ArgVec ("pos", 6)) : aManipulator->Position().XDirection(); + + aManipulator->SetPosition (gp_Ax2 (aLocation, aVDir, aXDir)); + } + if (aCmd.HasOption ("size", 1, Standard_True)) + { + aManipulator->SetSize (aCmd.ArgFloat ("size")); + } + if (aCmd.HasOption ("zoomable", 1, Standard_True)) + { + aManipulator->SetZoomPersistence (!aCmd.ArgBool ("zoomable")); + + if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator)) + { + ViewerTest::GetAISContext()->Remove (aManipulator, Standard_False); + ViewerTest::GetAISContext()->Display (aManipulator, Standard_False); + } + } + + // --------------------------------------------------- + // attach, detach or access manipulator from an object + // --------------------------------------------------- + + if (aCmd.HasOption ("attach")) + { + // Find an object and attach manipulator to it + if (!aCmd.HasOption ("attach", 1, Standard_True)) + { + return 1; + } + + TCollection_AsciiString anObjName (aCmd.Arg ("attach", 0).c_str()); + if (!aMapAIS.IsBound2 (anObjName)) + { + std::cerr << theArgVec[0] << " error: AIS object \"" << anObjName << "\" does not exist.\n"; + return 1; + } + + Handle(AIS_InteractiveObject) anObject = Handle(AIS_InteractiveObject)::DownCast (aMapAIS.Find2 (anObjName)); + ViewerTest_MapOfAISManipulators::Iterator anIt (GetMapOfAISManipulators()); + for (; anIt.More(); anIt.Next()) + { + if (anIt.Value()->IsAttached() + && anIt.Value()->Object() == anObject) + { + std::cerr << theArgVec[0] << " error: AIS object \"" << anObjName << "\" already has manipulator.\n"; + return 1; + } + } + + AIS_Manipulator::OptionsForAttach anOptions; + if (aCmd.HasOption ("adjustPosition", 1, Standard_True)) + { + anOptions.SetAdjustPosition (aCmd.ArgBool ("adjustPosition")); + } + if (aCmd.HasOption ("adjustSize", 1, Standard_True)) + { + anOptions.SetAdjustSize (aCmd.ArgBool ("adjustSize")); + } + if (aCmd.HasOption ("enableModes", 1, Standard_True)) + { + anOptions.SetEnableModes (aCmd.ArgBool ("enableModes")); + } + + aManipulator->Attach (anObject, anOptions); + } + + // -------------------------------------- + // apply transformation using manipulator + // -------------------------------------- + + if (aCmd.HasOption ("startTransform", 2, Standard_True)) + { + aManipulator->StartTransform (aCmd.ArgInt ("startTransform", 0), aCmd.ArgInt ("startTransform", 1), ViewerTest::CurrentView()); + } + if (aCmd.HasOption ("transform", 2, Standard_True)) + { + aManipulator->Transform (aCmd.ArgInt ("transform", 0), aCmd.ArgInt ("transform", 1), ViewerTest::CurrentView()); + } + if (aCmd.HasOption ("stopTransform")) + { + Standard_Boolean toApply = !aCmd.HasOption ("stopTransform", 1) || (aCmd.Arg ("stopTransform", 0) != "abort"); + + aManipulator->StopTransform (toApply); + } + + gp_Trsf aT; + if (aCmd.HasOption ("move", 3, Standard_True)) + { + aT.SetTranslationPart (aCmd.ArgVec ("move")); + } + if (aCmd.HasOption ("rotate", 7, Standard_True)) + { + aT.SetRotation (gp_Ax1 (aCmd.ArgPnt ("rotate", 0), aCmd.ArgVec ("rotate", 3)), aCmd.ArgDouble ("rotate", 6)); + } + if (aCmd.HasOption ("scale", 1)) + { + aT.SetScale (gp_Pnt(), aCmd.ArgDouble("scale")); + } + + if (aT.Form() != gp_Identity) + { + aManipulator->Transform (aT); + } + + ViewerTest::GetAISContext()->Redisplay (aManipulator); + + return 0; +} + //======================================================================= //function : ViewerCommands //purpose : @@ -9308,6 +9660,31 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "vxrotate", __FILE__,VXRotate,group); + theCommands.Add("vmanipulator", + "\n vmanipulator Name [-attach AISObject | -detach | ...]" + "\n tool to create and manage AIS manipulators." + "\n Options: " + "\n '-attach AISObject' attach manipulator to AISObject" + "\n '-adjustPosition {0|1}' adjust position when attaching" + "\n '-adjustSize {0|1}' adjust size when attaching" + "\n '-enableModes {0|1}' enable modes when attaching" + "\n '-detach' detach manipulator" + "\n '-startTransform mouse_x mouse_y' - invoke start of transformation" + "\n '-transform mouse_x mouse_y' - invoke transformation" + "\n '-stopTransform [abort]' - invoke stop of transformation" + "\n '-move x y z' - move attached object" + "\n '-rotate x y z dx dy dz angle' - rotate attached object" + "\n '-scale factor' - scale attached object" + "\n '-autoActivate {0|1}' - set activation on detection" + "\n '-followTranslation {0|1}' - set following translation transform" + "\n '-followRotation {0|1}' - set following rotation transform" + "\n '-gap value' - set gap between sub-parts" + "\n '-part axis mode {0|1}' - set visual part" + "\n '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator" + "\n '-size value' - set size of manipulator" + "\n '-zoomable {0|1}' - set zoom persistence", + __FILE__, VManipulator, group); + #if defined(_WIN32) theCommands.Add("vprogressive", "vprogressive", diff --git a/tests/v3d/grids.list b/tests/v3d/grids.list index 2c20c13f5e..bb50862310 100644 --- a/tests/v3d/grids.list +++ b/tests/v3d/grids.list @@ -15,3 +15,4 @@ 016 ivtk 017 mesh 018 point_cloud +019 manipulator diff --git a/tests/v3d/manipulator/rotate b/tests/v3d/manipulator/rotate new file mode 100644 index 0000000000..92f67fdbb2 --- /dev/null +++ b/tests/v3d/manipulator/rotate @@ -0,0 +1,142 @@ +puts "==================================" +puts "AIS_Manipulator - rotate an object" +puts "==================================" + +set anImage1 $imagedir/${casename}_1.png +set anImage2 $imagedir/${casename}_2.png +set anImage3 $imagedir/${casename}_3.png +set anImage4 $imagedir/${casename}_4.png +set anImage5 $imagedir/${casename}_5.png + +# ------------------------------------- +# create manipulated and helper objects +# ------------------------------------- + +pcylinder c1_1 5 10 +pcylinder c1_2 3 10 +pcylinder c2 10 20 +ttranslate c1_1 100 0 20 +ttranslate c1_2 100 0 20 +trotate c1_2 100 0 25 0 1 0 90 +trotate c1_2 100 0 25 0 0 1 10 +ttranslate c2 100 0 0 + +compound c1_1 c1_2 c1 + +# ------------------------------------ +# display manipulated objects (test 1) +# ------------------------------------ + +vdisplay c1 +vdisplay c2 +vsetdispmode 1 +vaxo +vfit + +# ------------------ +# attach manipulator +# ------------------ + +vmanipulator m -attach c1 -adjustPosition 1 -adjustSize 0 -enableModes 1 + +# ---------------------------------------------------- +# test rotation around x axis (object reference frame) +# ---------------------------------------------------- + +vmanipulator m -followRotation 1 + +set mouse_pick {201 092} +set mouse_drag {176 142} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage1 + +# ---------------------------------------------------- +# test rotation around y axis (object reference frame) +# ---------------------------------------------------- + +vmanipulator m -followRotation 1 + +set mouse_pick {173 137} +set mouse_drag {233 140} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage2 + +# ---------------------------------------------------- +# test rotation around z axis (object reference frame) +# ---------------------------------------------------- + +vmanipulator m -followRotation 1 + +set mouse_pick {200 094} +set mouse_drag {182 117} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage3 + +# ------------------------------------ +# display manipulated objects (test 2) +# ------------------------------------ + +vremove -all +vdisplay c1 +vdisplay c2 +vsetdispmode 1 +vaxo +vfit + +vmanipulator m -attach c1 -adjustPosition 1 -adjustSize 0 -enableModes 1 +vmanipulator m -followRotation 0 + +# --------------------------------------------------- +# test rotation around y axis (world reference frame) +# --------------------------------------------------- + +set mouse_pick {211 095} +set mouse_drag {230 127} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage4 + +# --------------------------------------------------- +# test rotation around z axis (world reference frame) +# --------------------------------------------------- + +set mouse_pick {225 143} +set mouse_drag {184 143} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage5 + +set to_dump_screen 0 \ No newline at end of file diff --git a/tests/v3d/manipulator/scale b/tests/v3d/manipulator/scale new file mode 100644 index 0000000000..85ddaa1c98 --- /dev/null +++ b/tests/v3d/manipulator/scale @@ -0,0 +1,63 @@ +puts "=================================" +puts "AIS_Manipulator - scale an object" +puts "=================================" + +set anImage1 $imagedir/${casename}_1.png +set anImage2 $imagedir/${casename}_2.png + +# ------------------------------------- +# create manipulated and helper objects +# ------------------------------------- + +pcylinder c1_1 5 10 +pcylinder c1_2 3 10 +pcylinder c2 10 20 +ttranslate c1_1 100 0 20 +ttranslate c1_2 100 0 20 +trotate c1_2 100 0 25 0 1 0 90 +trotate c1_2 100 0 25 0 0 1 10 +ttranslate c2 100 0 0 + +compound c1_1 c1_2 c1 + +# ------------------------------------ +# display manipulated objects (test 1) +# ------------------------------------ + +vdisplay c1 +vdisplay c2 +vsetdispmode 1 +vaxo +vfit + +# ------------------ +# attach manipulator +# ------------------ + +vmanipulator m -attach c1 -adjustPosition 1 -adjustSize 0 -enableModes 1 + +# -------------------------- +# test hilight and detection +# -------------------------- + +set mouse_pick {229 137} + +vmoveto {*}$mouse_pick +vdump $anImage1 + +# ------------------------- +# test scaling of an object +# ------------------------- + +set mouse_pick {229 137} +set mouse_drag {210 127} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vdump $anImage2 + +set to_dump_screen 0 diff --git a/tests/v3d/manipulator/translate b/tests/v3d/manipulator/translate new file mode 100644 index 0000000000..159651ee9d --- /dev/null +++ b/tests/v3d/manipulator/translate @@ -0,0 +1,150 @@ +puts "=====================================" +puts "AIS_Manipulator - translate an object" +puts "=====================================" + +set anImage1 $imagedir/${casename}_1.png +set anImage2 $imagedir/${casename}_2.png +set anImage3 $imagedir/${casename}_3.png +set anImage4 $imagedir/${casename}_4.png +set anImage5 $imagedir/${casename}_5.png + +# ------------------------------------- +# create manipulated and helper objects +# ------------------------------------- + +pcylinder c1 5 10 +pcylinder c2 10 20 +ttranslate c1 100 0 20 +ttranslate c2 100 0 0 +trotate c1 100 0 25 0 1 0 90 +trotate c1 100 0 25 0 0 1 10 + +# ------------------------------------- +# display manipulated objects (scene 1) +# ------------------------------------- + +vdisplay c1 +vdisplay c2 +vsetdispmode 1 +vaxo +vfit + +# ------------------ +# attach manipulator +# ------------------ + +vmanipulator m -attach c1 -adjustPosition 1 -adjustSize 0 -enableModes 1 +vmanipulator m -followRotation 1 +vmanipulator m -followTranslation 1 + +# ---------------------------------------------------- +# test x translation transform (world reference frame) +# ---------------------------------------------------- + +set mouse_pick {204 112} +set mouse_drag {204 156} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage1 + +# ---------------------------------------------------- +# test y translation transform (world reference frame) +# ---------------------------------------------------- + +set mouse_pick {215 160} +set mouse_drag {265 132} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage2 + +# ---------------------------------------------------- +# test z translation transform (world reference frame) +# ---------------------------------------------------- + +set mouse_pick {263 145} +set mouse_drag {127 065} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage3 + +# ------------------------------------- +# display manipulated objects (scene 2) +# ------------------------------------- + +vremove -all +vdisplay c1 +vdisplay c2 +vsetdispmode 1 +vaxo +vfit + +# ------------------------------------------- +# attach manipulator and rotate around z axis +# ------------------------------------------- + +vmanipulator m -attach c1 -adjustPosition 1 -adjustSize 0 -enableModes 1 +vmanipulator m -followRotation 1 +vmanipulator m -followTranslation 1 + +set mouse_pick {223 143} +set mouse_drag {181 141} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag + +# ---------------------------------------------------- +# test x translation transform (object reference frame) +# ---------------------------------------------------- + +set mouse_pick {199 131} +set mouse_drag {175 168} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage4 + +# ---------------------------------------------------- +# test y translation transform (object reference frame) +# ---------------------------------------------------- + +set mouse_pick {199 164} +set mouse_drag {246 177} + +vmoveto {*}$mouse_pick +vselect {*}$mouse_pick +vmanipulator m -startTransform {*}$mouse_pick +vmanipulator m -transform {*}$mouse_drag +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag +vdump $anImage5 + +set to_dump_screen 0 \ No newline at end of file diff --git a/tests/v3d/manipulator/zoom_persistence b/tests/v3d/manipulator/zoom_persistence new file mode 100644 index 0000000000..31bc3562fd --- /dev/null +++ b/tests/v3d/manipulator/zoom_persistence @@ -0,0 +1,87 @@ +puts "===============================================" +puts "AIS_Manipulator - check zoom persistence option" +puts "===============================================" + +set anImage1 $imagedir/${casename}_1.png +set anImage2 $imagedir/${casename}_2.png +set anImage3 $imagedir/${casename}_3.png +set anImage4 $imagedir/${casename}_4.png +set anImage5 $imagedir/${casename}_5.png +set anImage6 $imagedir/${casename}_6.png + +# ------------------------------------- +# create manipulated and helper objects +# ------------------------------------- + +box b1 0 0 0 20 20 20 +box b2 80 0 0 20 20 20 +vdisplay b1 +vdisplay b2 +vtrihedron tri +vsetdispmode 1 +vaxo +vfit + +# -------------------------------------------------------- +# create and test non-zoom persistent manipulator (test 1) +# -------------------------------------------------------- + +vmanipulator m1 -attach b1 -adjustPosition 1 -adjustSize 1 -enableModes 1 -zoomable 1 + +set mouse_pick_1 {84 135} +set mouse_pick_2 {29 103} +set mouse_pick_3 {29 103} +set mouse_drag_3 {121 126} + +# pick at default zoom +vmoveto 0 0 +vmoveto {*}$mouse_pick_1 +vdump $anImage1 + +# pick at changed zoom +vzoom 1.5 +vmoveto 0 0 +vmoveto {*}$mouse_pick_2 +vdump $anImage2 + +# drag object +vselect {*}$mouse_pick_3 +vmanipulator m1 -startTransform {*}$mouse_pick_3 +vmanipulator m1 -transform {*}$mouse_drag_3 +vmanipulator m1 -stopTransform +vselect 0 0 +vdump $anImage3 + +# ---------------------------------------------------- +# create and test zoom persistent manipulator (test 2) +# ---------------------------------------------------- + +vfit + +vmanipulator m2 -attach b2 -adjustPosition 1 -adjustSize 0 -enableModes 1 -zoomable 0 -size 100 + +set mouse_pick_1 {341 283} +set mouse_pick_2 {277 246} +set mouse_pick_3 {277 246} +set mouse_drag_3 {210 210} + +# pick at default zoom +vmoveto 0 0 +vmoveto {*}$mouse_pick_1 +vdump $anImage4 + +# pick at changed zoom +vzoom 0.5 +vmoveto 0 0 +vmoveto {*}$mouse_pick_2 +vdump $anImage5 + +# drag object +vselect {*}$mouse_pick_3 +vmanipulator m2 -startTransform {*}$mouse_pick_3 +vmanipulator m2 -transform {*}$mouse_drag_3 +vmanipulator m2 -stopTransform +vselect 0 0 +vdump $anImage6 + +set to_dump_screen 0 \ No newline at end of file