]> OCCT Git - occt.git/commitdiff
0032055: Draw Harness, ViewerTest - add more vmanipulator position adjusting options
authorkgv <kgv@opencascade.com>
Wed, 13 Jan 2021 18:22:00 +0000 (21:22 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 14 Jan 2021 16:21:54 +0000 (19:21 +0300)
Draw::ParseOnOffIterator() - added auxiliary wrapper over Draw::ParseOnOff() for more compact syntax.
strncasecmp() definition for msvc compilers has been moved to Standard_CString for consistency with strcasecmp().
vmanipulator command has been refactored to use more straightforward parser.

vmanipulator now accepts "-adjustPosition {0|center|location|shapeLocation}" options
adjusting position to object's AABB center (existed before), object's local transformation or TopoDS_Shape location.

src/Draw/Draw.cxx
src/Draw/Draw.hxx
src/RWStl/RWStl_Reader.cxx
src/Standard/Standard_CString.hxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/v3d/manipulator/shape_location [new file with mode: 0644]

index 3b1a1650727398d300c80bdea3061a4fc122d561..957aec927a9b58fa7b9d557b562d861e3c024594 100644 (file)
@@ -958,3 +958,34 @@ Standard_Boolean Draw::ParseOnOff (Standard_CString  theArg,
   }
   return Standard_False;
 }
+
+//=======================================================================
+//function : ParseOnOffIterator
+//purpose  :
+//=======================================================================
+Standard_Boolean Draw::ParseOnOffIterator (Standard_Integer  theArgsNb,
+                                           const char**      theArgVec,
+                                           Standard_Integer& theArgIter)
+{
+  Standard_Boolean isOn = Standard_True;
+  if (theArgIter + 1 < theArgsNb
+   && Draw::ParseOnOff (theArgVec[theArgIter + 1], isOn))
+  {
+    ++theArgIter;
+  }
+  return isOn;
+}
+
+//=======================================================================
+//function : ParseOnOffNoIterator
+//purpose  :
+//=======================================================================
+Standard_Boolean Draw::ParseOnOffNoIterator (Standard_Integer  theArgsNb,
+                                             const char**      theArgVec,
+                                             Standard_Integer& theArgIter)
+{
+  Standard_Boolean toReverse = strncasecmp (theArgVec[theArgIter], "no", 2) == 0
+                            || strncasecmp (theArgVec[theArgIter], "-no", 3) == 0;
+  Standard_Boolean isOn = Draw::ParseOnOffIterator (theArgsNb, theArgVec, theArgIter);
+  return toReverse ? !isOn : isOn;
+}
index e8cbffe4ff2cf3bc8463bb9c03d547bde80ca17a..1b37fe0befe3a08a385f403c564a76681d2ac285 100644 (file)
@@ -179,6 +179,39 @@ public: //! @name argument parsing tools
   Standard_EXPORT static Standard_Boolean ParseOnOff (Standard_CString  theArg,
                                                       Standard_Boolean& theIsOn);
 
+  //! Parses boolean argument at specified iterator position with optional on/off coming next.
+  //!
+  //! Usage code sample for command argument in form "cmd -usefeature [on|off|1|0]=on":
+  //! @code
+  //!   for (int anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
+  //!   {
+  //!     if (strcasecmp (theArgVec[anArgIter], "-usefeature") == 0)
+  //!     {
+  //!       bool toUseFeature = Draw::ParseOnOffIterator (theNbArgs, theArgVec, anArgIter);
+  //!       // process feature
+  //!     }
+  //!   }
+  //! @endcode
+  //!
+  //! @param theArgsNb [in] overall number of arguments
+  //! @param theArgVec [in] vector of arguments
+  //! @param theArgIter [in] [out] argument position to parse
+  //! @return flag value
+  Standard_EXPORT static Standard_Boolean ParseOnOffIterator (Standard_Integer  theArgsNb,
+                                                              const char**      theArgVec,
+                                                              Standard_Integer& theArgIter);
+
+  //! Parses boolean argument at specified iterator position with optional on/off coming next.
+  //! Similar to ParseOnOffIterator() but also reverses returned value if argument name starts with "no" prefix.
+  //! E.g. if nominal argument is "cmd -usefeature [on|off|1|0]=on", then "-nousefeature" argument will return FALSE.
+  //! @param theArgsNb [in] overall number of arguments
+  //! @param theArgVec [in] vector of arguments
+  //! @param theArgIter [in] [out] argument position to parse
+  //! @return flag value
+  Standard_EXPORT static Standard_Boolean ParseOnOffNoIterator (Standard_Integer  theArgsNb,
+                                                                const char**      theArgVec,
+                                                                Standard_Integer& theArgIter);
+
 public:
 
   //! Returns last graphic selection description.
index b29bd3e01086c2da4b3bf93bf54e282a4ed7dde5..b7f939ef7cc87dd2e0dd60426b34ffa2e8f740c4 100644 (file)
@@ -256,14 +256,10 @@ Standard_Boolean RWStl_Reader::IsAscii (Standard_IStream& theStream,
   #define GETPOS(aPos) ((int64_t)aPos)
 #endif
 
-# if defined(_MSC_VER) && ! defined(strncasecmp)
-#  define strncasecmp _strnicmp
-# endif
-
 static inline bool str_starts_with (const char* theStr, const char* theWord, int theN)
 {
   while (isspace (*theStr) && *theStr != '\0') theStr++;
-  return !strncasecmp (theStr, theWord, theN); 
+  return !strncasecmp (theStr, theWord, theN);
 }
 
 static bool ReadVertex (const char* theStr, double& theX, double& theY, double& theZ)
index 3513016ad81bbd0b1e13c9fad13436e5839569aa..4f5b353618f5efa40e5d6472564875744ef25626 100644 (file)
 #include <stdio.h>
 #include <string.h>
 
-# if defined(_MSC_VER) && ! defined(strcasecmp)
-#  define strcasecmp _stricmp
-# endif
+#if defined(_MSC_VER)
+  #if !defined(strcasecmp)
+    #define strcasecmp _stricmp
+  #endif
+  #if !defined(strncasecmp)
+    #define strncasecmp _strnicmp
+  #endif
+#endif
 
 // C++ only definitions
 #ifdef __cplusplus
index 2bdabea3875da6fd466754550350f746e6d7fca8..52a772266e9fef88d8fc2020988ee992e0d23328 100644 (file)
@@ -12889,6 +12889,27 @@ static Standard_Integer VXRotate (Draw_Interpretor& di,
   return 0;
 }
 
+namespace
+{
+  //! Structure for setting AIS_Manipulator::SetPart() property.
+  struct ManipAxisModeOnOff
+  {
+    Standard_Integer    Axis;
+    AIS_ManipulatorMode Mode;
+    Standard_Boolean    ToEnable;
+
+    ManipAxisModeOnOff() : Axis (-1), Mode (AIS_MM_None), ToEnable (false) {}
+  };
+
+  enum ManipAjustPosition
+  {
+    ManipAjustPosition_Off,
+    ManipAjustPosition_Center,
+    ManipAjustPosition_Location,
+    ManipAjustPosition_ShapeLocation,
+  };
+}
+
 //===============================================================================================
 //function : VManipulator
 //purpose  :
@@ -12908,170 +12929,359 @@ static int VManipulator (Draw_Interpretor& theDi,
 
   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
   Standard_Integer anArgIter = 1;
+  Handle(AIS_Manipulator) aManipulator;
+  ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
+  TCollection_AsciiString aName;
+  // parameters
+  Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1, toFollowDragging = -1, isZoomable = -1;
+  Standard_Real aGap = -1.0, aSize = -1.0;
+  NCollection_Sequence<ManipAxisModeOnOff> aParts;
+  gp_XYZ aLocation (RealLast(), RealLast(), RealLast()), aVDir, anXDir;
+  //
+  bool toDetach = false;
+  AIS_Manipulator::OptionsForAttach anAttachOptions;
+  Handle(AIS_InteractiveObject) anAttachObject;
+  Handle(V3d_View) aViewAffinity;
+  ManipAjustPosition anAttachPos = ManipAjustPosition_Off;
+  //
+  Graphic3d_Vec2i aMousePosFrom(IntegerLast(), IntegerLast());
+  Graphic3d_Vec2i aMousePosTo  (IntegerLast(), IntegerLast());
+  Standard_Integer toStopMouseTransform = -1;
+  // explicit transformation
+  gp_Trsf aTrsf;
+  gp_XYZ aTmpXYZ;
+  Standard_Real aTmpReal = 0.0;
+  gp_XYZ aRotPnt, aRotAxis;
   for (; anArgIter < theArgsNb; ++anArgIter)
   {
-    anUpdateTool.parseRedrawMode (theArgVec[anArgIter]);
-  }
-
-  ViewerTest_CmdParser aCmd;
-  aCmd.SetDescription ("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 ("view",           "... {active | [view name]} - define view in which manipulator will be displayed, 'all' by default");
-  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 ("followDragging",    "... {0|1} - set following dragging transform");
-  aCmd.AddOption ("gap",               "... value - set gap between sub-parts");
-  aCmd.AddOption ("part",              "... axis mode {0|1} - set visual part");
-  aCmd.AddOption ("parts",             "... all axes 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);
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anUpdateTool.parseRedrawMode (anArg))
+    {
+      continue;
+    }
+    else if (anArg == "-help")
+    {
+      theDi.PrintHelp (theArgVec[0]);
+      return 0;
+    }
+    //
+    else if (anArg == "-autoactivate"
+          || anArg == "-noautoactivate")
+    {
+      toAutoActivate = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
+    }
+    else if (anArg == "-followtranslation"
+          || anArg == "-nofollowtranslation")
+    {
+      toFollowTranslation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
+    }
+    else if (anArg == "-followrotation"
+          || anArg == "-nofollowrotation")
+    {
+      toFollowRotation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
+    }
+    else if (anArg == "-followdragging"
+          || anArg == "-nofollowdragging")
+    {
+      toFollowDragging = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
+    }
+    else if (anArg == "-gap"
+          && anArgIter + 1 < theArgsNb
+          && Draw::ParseReal (theArgVec[anArgIter + 1], aGap)
+          && aGap >= 0.0)
+    {
+      ++anArgIter;
+    }
+    else if (anArg == "-size"
+          && anArgIter + 1 < theArgsNb
+          && Draw::ParseReal (theArgVec[anArgIter + 1], aSize)
+          && aSize > 0.0)
+    {
+      ++anArgIter;
+    }
+    else if ((anArg == "-part"  && anArgIter + 3 < theArgsNb)
+          || (anArg == "-parts" && anArgIter + 2 < theArgsNb))
+    {
+      ManipAxisModeOnOff aPart;
+      Standard_Integer aMode = 0;
+      if (anArg == "-part")
+      {
+        if (!Draw::ParseInteger (theArgVec[++anArgIter], aPart.Axis)
+          || aPart.Axis < 0 || aPart.Axis > 3)
+        {
+          Message::SendFail() << "Syntax error: -part axis '" << theArgVec[anArgIter] << "' is out of range [1, 3]";
+          return 1;
+        }
+      }
+      if (!Draw::ParseInteger (theArgVec[++anArgIter], aMode)
+        || aMode < 1 || aMode > 4)
+      {
+        Message::SendFail() << "Syntax error: -part mode '" << theArgVec[anArgIter] << "' is out of range [1, 4]";
+        return 1;
+      }
+      if (!Draw::ParseOnOff (theArgVec[++anArgIter], aPart.ToEnable))
+      {
+        Message::SendFail() << "Syntax error: -part value on/off '" << theArgVec[anArgIter] << "' is incorrect";
+        return 1;
+      }
+      aPart.Mode = static_cast<AIS_ManipulatorMode> (aMode);
+      aParts.Append (aPart);
+    }
+    else if (anArg == "-pos"
+          && anArgIter + 3 < theArgsNb
+          && parseXYZ (theArgVec + anArgIter + 1, aLocation))
+    {
+      anArgIter += 3;
+      if (anArgIter + 3 < theArgsNb
+       && parseXYZ (theArgVec + anArgIter + 1, aVDir)
+       && aVDir.Modulus() > Precision::Confusion())
+      {
+        anArgIter += 3;
+      }
+      if (anArgIter + 3 < theArgsNb
+       && parseXYZ (theArgVec + anArgIter + 1, anXDir)
+       && anXDir.Modulus() > Precision::Confusion())
+      {
+        anArgIter += 3;
+      }
+    }
+    else if (anArg == "-zoomable"
+          || anArg == "-notzoomable")
+    {
+      isZoomable = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
+    }
+    //
+    else if (anArg == "-adjustposition"
+          || anArg == "-noadjustposition")
+    {
+      anAttachPos = ManipAjustPosition_Center;
+      if (anArgIter + 1 < theArgsNb)
+      {
+        TCollection_AsciiString aPosName (theArgVec[++anArgIter]);
+        aPosName.LowerCase();
+        if (aPosName == "0")
+        {
+          anAttachPos = ManipAjustPosition_Off;
+        }
+        else if (aPosName == "1"
+              || aPosName == "center")
+        {
+          anAttachPos = ManipAjustPosition_Center;
+        }
+        else if (aPosName == "transformation"
+              || aPosName == "trsf"
+              || aPosName == "location"
+              || aPosName == "loc")
+        {
+          anAttachPos = ManipAjustPosition_Location;
+        }
+        else if (aPosName == "shapelocation"
+              || aPosName == "shapeloc")
+        {
+          anAttachPos = ManipAjustPosition_ShapeLocation;
+        }
+        else
+        {
+          --anArgIter;
+        }
+      }
+      anAttachOptions.SetAdjustPosition (anAttachPos == ManipAjustPosition_Center);
+    }
+    else if (anArg == "-adjustsize"
+          || anArg == "-noadjustsize")
+    {
+      anAttachOptions.SetAdjustSize (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
+    }
+    else if (anArg == "-enablemodes"
+          || anArg == "-enablemodes")
+    {
+      anAttachOptions.SetEnableModes (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
+    }
+    //
+    else if (anArg == "-starttransform"
+          && anArgIter + 2 < theArgsNb
+          && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosFrom.x())
+          && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosFrom.y()))
+    {
+      anArgIter += 2;
+    }
+    else if (anArg == "-transform"
+          && anArgIter + 2 < theArgsNb
+          && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosTo.x())
+          && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosTo.y()))
+    {
+      anArgIter += 2;
+    }
+    else if (anArg == "-stoptransform")
+    {
+      toStopMouseTransform = 1;
+      if (anArgIter + 1 < theArgsNb
+       && TCollection_AsciiString::IsSameString (theArgVec[anArgIter + 1], "abort", false))
+      {
+        ++anArgIter;
+        toStopMouseTransform = 0;
+      }
+    }
+    //
+    else if (anArg == "-move"
+          && anArgIter + 3 < theArgsNb
+          && parseXYZ (theArgVec + anArgIter + 1, aTmpXYZ))
+    {
+      anArgIter += 3;
+      aTrsf.SetTranslationPart (aTmpXYZ);
+    }
+    else if (anArg == "-scale"
+          && anArgIter + 1 < theArgsNb
+          && Draw::ParseReal (theArgVec[anArgIter + 1], aTmpReal))
+    {
+      ++anArgIter;
+      aTrsf.SetScale (gp_Pnt(), aTmpReal);
+    }
+    else if (anArg == "-rotate"
+          && anArgIter + 7 < theArgsNb
+          && parseXYZ (theArgVec + anArgIter + 1, aRotPnt)
+          && parseXYZ (theArgVec + anArgIter + 4, aRotAxis)
+          && Draw::ParseReal (theArgVec[anArgIter + 7], aTmpReal))
+    {
+      anArgIter += 7;
+      aTrsf.SetRotation (gp_Ax1 (gp_Pnt (aRotPnt), gp_Dir (aRotAxis)), aTmpReal);
+    }
+    //
+    else if (anArg == "-detach")
+    {
+      toDetach = true;
+    }
+    else if (anArg == "-attach"
+          && anArgIter + 1 < theArgsNb)
+    {
+      TCollection_AsciiString anObjName (theArgVec[++anArgIter]);
+      if (!aMapAIS.Find2 (anObjName, anAttachObject))
+      {
+        Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' does not exist";
+        return 1;
+      }
 
-  if (aCmd.HasOption ("help"))
-  {
-    theDi.PrintHelp (theArgVec[0]);
-    return 0;
+      for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS); anIter.More(); anIter.Next())
+      {
+        Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
+        if (!aManip.IsNull()
+          && aManip->IsAttached()
+          && aManip->Object() == anAttachObject)
+        {
+          Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' already has manipulator";
+          return 1;
+        }
+      }
+    }
+    else if (anArg == "-view"
+          && anArgIter + 1 < theArgsNb
+          && aViewAffinity.IsNull())
+    {
+      TCollection_AsciiString aViewString (theArgVec[++anArgIter]);
+      if (aViewString == "active")
+      {
+        aViewAffinity = ViewerTest::CurrentView();
+      }
+      else // Check view name
+      {
+        ViewerTest_Names aViewNames (aViewString);
+        if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
+        {
+          Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
+          return 1;
+        }
+        aViewAffinity = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
+        if (aViewAffinity.IsNull())
+        {
+          Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
+          return 1;
+        }
+      }
+    }
+    else if (aName.IsEmpty())
+    {
+      aName = theArgVec[anArgIter];
+      if (!aMapAIS.IsBound2 (aName))
+      {
+        aManipulator = new AIS_Manipulator();
+        aManipulator->SetModeActivationOnDetection (true);
+        aMapAIS.Bind (aManipulator, aName);
+      }
+      else
+      {
+        aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
+        if (aManipulator.IsNull())
+        {
+          Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
+          return 1;
+        }
+      }
+    }
+    else
+    {
+      theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
+    }
   }
 
-  ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
-
-  TCollection_AsciiString aName (aCmd.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0).c_str());
-
   if (aName.IsEmpty())
   {
     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
     return 1;
   }
-
-  // ----------------------------------
-  // detach existing manipulator object
-  // ----------------------------------
-
-  if (aCmd.HasOption ("detach"))
-  {
-    if (!aMapAIS.IsBound2 (aName))
-    {
-      Message::SendFail() << "Syntax error: could not find \"" << aName << "\" AIS object";
-      return 1;
-    }
-
-    Handle(AIS_Manipulator) aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
-    if (aManipulator.IsNull())
-    {
-      Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
-      return 1;
-    }
-
-    aManipulator->Detach();
-    aMapAIS.UnBind2 (aName);
-    ViewerTest::GetAISContext()->Remove (aManipulator, Standard_True);
-
-    return 0;
-  }
-
-  // -----------------------------------------------
-  // find or create manipulator if it does not exist
-  // -----------------------------------------------
-
-  Handle(AIS_Manipulator) aManipulator;
-  if (!aMapAIS.IsBound2 (aName))
+  if (!toDetach
+    && aManipulator.IsNull())
   {
-    std::cout << theArgVec[0] << ": AIS object \"" << aName << "\" has been created.\n";
-
     aManipulator = new AIS_Manipulator();
     aManipulator->SetModeActivationOnDetection (true);
     aMapAIS.Bind (aManipulator, aName);
   }
-  else
-  {
-    aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
-    if (aManipulator.IsNull())
-    {
-      Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
-      return 1;
-    }
-  }
 
   // -----------------------------------------
   // change properties of manipulator instance
   // -----------------------------------------
 
-  if (aCmd.HasOption ("autoActivate", 1, Standard_True))
+  if (toAutoActivate != -1)
   {
-    aManipulator->SetModeActivationOnDetection (aCmd.ArgBool ("autoActivate"));
+    aManipulator->SetModeActivationOnDetection (toAutoActivate == 1);
   }
-  if (aCmd.HasOption ("followTranslation", 1, Standard_True))
+  if (toFollowTranslation != -1)
   {
-    aManipulator->ChangeTransformBehavior().SetFollowTranslation (aCmd.ArgBool ("followTranslation"));
+    aManipulator->ChangeTransformBehavior().SetFollowTranslation (toFollowTranslation == 1);
   }
-  if (aCmd.HasOption ("followRotation", 1, Standard_True))
+  if (toFollowRotation != -1)
   {
-    aManipulator->ChangeTransformBehavior().SetFollowRotation (aCmd.ArgBool ("followRotation"));
+    aManipulator->ChangeTransformBehavior().SetFollowRotation (toFollowRotation == 1);
   }
-  if (aCmd.HasOption("followDragging", 1, Standard_True))
+  if (toFollowDragging != -1)
   {
-    aManipulator->ChangeTransformBehavior().SetFollowDragging(aCmd.ArgBool("followDragging"));
+    aManipulator->ChangeTransformBehavior().SetFollowDragging (toFollowDragging == 1);
   }
-  if (aCmd.HasOption ("gap", 1, Standard_True))
+  if (aGap >= 0.0f)
   {
-    aManipulator->SetGap (aCmd.ArgFloat ("gap"));
+    aManipulator->SetGap ((float )aGap);
   }
-  if (aCmd.HasOption ("part", 3, Standard_True))
+
+  for (NCollection_Sequence<ManipAxisModeOnOff>::Iterator aPartIter (aParts); aPartIter.More(); aPartIter.Next())
   {
-    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 > 4)
+    const ManipAxisModeOnOff& aPart = aPartIter.Value();
+    if (aPart.Axis == -1)
     {
-      Message::SendFail ("Syntax error: mode value should be in range [1, 4]");
-      return 1;
+      aManipulator->SetPart (aPart.Mode, aPart.ToEnable);
     }
-
-    aManipulator->SetPart (anAxis, static_cast<AIS_ManipulatorMode> (aMode), aOnOff);
-  }
-  if (aCmd.HasOption("parts", 2, Standard_True))
-  {
-    Standard_Integer aMode = aCmd.ArgInt("parts", 0);
-    Standard_Boolean aOnOff = aCmd.ArgBool("parts", 1);
-    if (aMode < 1 || aMode > 4)
+    else
     {
-      Message::SendFail ("Syntax error: mode value should be in range [1, 4]");
-      return 1;
+      aManipulator->SetPart (aPart.Axis, aPart.Mode, aPart.ToEnable);
     }
-
-    aManipulator->SetPart(static_cast<AIS_ManipulatorMode>(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))
+  if (aSize > 0.0)
   {
-    aManipulator->SetSize (aCmd.ArgFloat ("size"));
+    aManipulator->SetSize ((float )aSize);
   }
-  if (aCmd.HasOption ("zoomable", 1, Standard_True))
+  if (isZoomable != -1)
   {
-    aManipulator->SetZoomPersistence (!aCmd.ArgBool ("zoomable"));
+    aManipulator->SetZoomPersistence (isZoomable == 0);
 
     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
     {
@@ -13080,132 +13290,124 @@ static int VManipulator (Draw_Interpretor& theDi,
     }
   }
 
+  // ----------------------------------
+  // detach existing manipulator object
+  // ----------------------------------
+
+  if (toDetach)
+  {
+    aManipulator->Detach();
+    aMapAIS.UnBind2 (aName);
+    ViewerTest::GetAISContext()->Remove (aManipulator, false);
+  }
+
   // ---------------------------------------------------
   // attach, detach or access manipulator from an object
   // ---------------------------------------------------
 
-  if (aCmd.HasOption ("attach"))
+  if (!anAttachObject.IsNull())
   {
-    // 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());
-    Handle(AIS_InteractiveObject) anObject;
-    if (!aMapAIS.Find2 (anObjName, anObject))
-    {
-      Message::SendFail() << "Syntax error: AIS object \"" << anObjName << "\" does not exist";
-      return 1;
-    }
-
-    for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS);
+    aManipulator->Attach (anAttachObject, anAttachOptions);
+  }
+  if (!aViewAffinity.IsNull())
+  {
+    for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
          anIter.More(); anIter.Next())
     {
-      Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
-      if (!aManip.IsNull()
-       && aManip->IsAttached()
-       && aManip->Object() == anObject)
-      {
-        Message::SendFail() << "Syntax error: AIS object \"" << anObjName << "\" already has manipulator";
-        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"));
+      ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), false);
     }
+    ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aViewAffinity, true);
+  }
 
-    aManipulator->Attach (anObject, anOptions);
-
-    // Check view option
-    if (aCmd.HasOption ("view"))
+  if (anAttachPos != ManipAjustPosition_Off
+   && aManipulator->IsAttached()
+   && (anAttachObject.IsNull() || anAttachPos != ManipAjustPosition_Center))
+  {
+    gp_Ax2 aPosition = gp::XOY();
+    const gp_Trsf aBaseTrsf = aManipulator->Object()->LocalTransformation();
+    switch (anAttachPos)
     {
-      if (!aCmd.HasOption ("view", 1, Standard_True))
+      case ManipAjustPosition_Off:
       {
-        return 1;
+        break;
       }
-      TCollection_AsciiString aViewString (aCmd.Arg ("view", 0).c_str());
-      Handle(V3d_View) aView;
-      if (aViewString.IsEqual ("active"))
+      case ManipAjustPosition_Location:
       {
-        aView = ViewerTest::CurrentView();
+        aPosition = gp::XOY().Transformed (aBaseTrsf);
+        break;
       }
-      else // Check view name
+      case ManipAjustPosition_ShapeLocation:
       {
-        ViewerTest_Names aViewNames (aViewString);
-        if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
+        if (Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (aManipulator->Object()))
         {
-          Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
-          return 1;
+          aPosition = gp::XOY().Transformed (aBaseTrsf * aShapePrs->Shape().Location());
         }
-        aView = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
-        if (aView.IsNull())
+        else
         {
-          Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
+          Message::SendFail() << "Syntax error: manipulator is not attached to shape";
           return 1;
         }
+        break;
       }
-      for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
-        anIter (ViewerTest_myViews); anIter.More(); anIter.Next())
+      case ManipAjustPosition_Center:
       {
-        ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), Standard_False);
+        Bnd_Box aBox;
+        for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*aManipulator->Objects()); anObjIter.More(); anObjIter.Next())
+        {
+          Bnd_Box anObjBox;
+          anObjIter.Value()->BoundingBox (anObjBox);
+          aBox.Add (anObjBox);
+        }
+        aBox = aBox.FinitePart();
+        if (!aBox.IsVoid())
+        {
+          const gp_Pnt aCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) * 0.5;
+          aPosition.SetLocation (aCenter);
+        }
+        break;
       }
-      ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aView, Standard_True);
     }
+    aManipulator->SetPosition (aPosition);
+  }
+  if (!Precision::IsInfinite (aLocation.X()))
+  {
+    if (aVDir.Modulus() <= Precision::Confusion())
+    {
+      aVDir = aManipulator->Position().Direction().XYZ();
+    }
+    if (anXDir.Modulus() <= Precision::Confusion())
+    {
+      anXDir = aManipulator->Position().XDirection().XYZ();
+    }
+    aManipulator->SetPosition (gp_Ax2 (gp_Pnt (aLocation), gp_Dir (aVDir), gp_Dir (anXDir)));
   }
 
   // --------------------------------------
   // apply transformation using manipulator
   // --------------------------------------
 
-  if (aCmd.HasOption ("startTransform", 2, Standard_True))
+  if (aMousePosFrom.x() != IntegerLast())
   {
-    aManipulator->StartTransform (aCmd.ArgInt ("startTransform", 0), aCmd.ArgInt ("startTransform", 1), ViewerTest::CurrentView());
+    aManipulator->StartTransform (aMousePosFrom.x(), aMousePosFrom.y(), ViewerTest::CurrentView());
   }
-  if (aCmd.HasOption ("transform", 2, Standard_True))
+  if (aMousePosTo.x() != IntegerLast())
   {
-    aManipulator->Transform (aCmd.ArgInt ("transform", 0), aCmd.ArgInt ("transform", 1), ViewerTest::CurrentView());
+    aManipulator->Transform (aMousePosTo.x(), aMousePosTo.y(), ViewerTest::CurrentView());
   }
-  if (aCmd.HasOption ("stopTransform"))
+  if (toStopMouseTransform != -1)
   {
-    Standard_Boolean toApply = !aCmd.HasOption ("stopTransform", 1) || (aCmd.Arg ("stopTransform", 0) != "abort");
-
-    aManipulator->StopTransform (toApply);
+    aManipulator->StopTransform (toStopMouseTransform == 1);
   }
 
-  gp_Trsf aT;
-  if (aCmd.HasOption ("move", 3, Standard_True))
-  {
-    aT.SetTranslationPart (aCmd.ArgVec ("move"));
-  }
-  if (aCmd.HasOption ("rotate", 7, Standard_True))
+  if (aTrsf.Form() != gp_Identity)
   {
-    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"));
+    aManipulator->Transform (aTrsf);
   }
 
-  if (aT.Form() != gp_Identity)
+  if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
   {
-    aManipulator->Transform (aT);
+    ViewerTest::GetAISContext()->Redisplay (aManipulator, true);
   }
-
-  ViewerTest::GetAISContext()->Redisplay (aManipulator, Standard_True);
-
   return 0;
 }
 
@@ -15009,7 +15211,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
       "\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      '-adjustPosition {0|center|location|shapeLocation}' adjust position when attaching"
       "\n      '-adjustSize     {0|1}'             adjust size when attaching"
       "\n      '-enableModes    {0|1}'             enable modes when attaching"
       "\n      '-view  {active | [name of view]}'  display manipulator only in defined view,"
diff --git a/tests/v3d/manipulator/shape_location b/tests/v3d/manipulator/shape_location
new file mode 100644 (file)
index 0000000..94cd440
--- /dev/null
@@ -0,0 +1,18 @@
+puts "==============================================="
+puts "0032055: Draw Harness, ViewerTest - add more vmanipulator position adjusting options"
+puts "==============================================="
+
+pload MODELING VISUALIZATION
+box b 0 0 0 1 2 3
+ttranslate b 1 0 0
+vclear
+vinit View1
+vdisplay -dispMode 1 b
+vlocation b -location 5 0 0 -rotate 5 0 0 0 0 1 30
+vpoint p 0 0 0
+vfit
+vmanipulator m -attach b -adjustPosition 0
+vmanipulator m -adjustPosition shapeLocation
+
+vdump $imagedir/${casename}.png
+set to_dump_screen 0