diff --git a/src/V3d/V3d_View.cdl b/src/V3d/V3d_View.cdl index 2bc996a509..2e13ad8613 100644 --- a/src/V3d/V3d_View.cdl +++ b/src/V3d/V3d_View.cdl @@ -1337,7 +1337,7 @@ is -- the objects contained in the view is static private; - Gravity ( me; X,Y,Z : out Coordinate ) returns Integer + Gravity ( me; X,Y,Z : out Coordinate ) ---Purpose: Returns the Objects number and the gravity center -- of ALL viewable points in the view is static private; diff --git a/src/V3d/V3d_View.cxx b/src/V3d/V3d_View.cxx index 5d16ad0e9a..d261682333 100644 --- a/src/V3d/V3d_View.cxx +++ b/src/V3d/V3d_View.cxx @@ -151,6 +151,11 @@ To solve the problem (for lack of a better solution) I make 2 passes. #define DEUXPI (2. * M_PI) +namespace +{ + static const Standard_Integer THE_NB_BOUND_POINTS = 8; +} + //============================================================================= //function : Constructor //purpose : @@ -2090,61 +2095,112 @@ Standard_Integer V3d_View::MinMax(Standard_Real& Xmin, //function : Gravity //purpose : //======================================================================= -Standard_Integer V3d_View::Gravity(Standard_Real& X, Standard_Real& Y, Standard_Real& Z) const +void V3d_View::Gravity (Standard_Real& theX, + Standard_Real& theY, + Standard_Real& theZ) const { - Standard_Real Xmin,Ymin,Zmin,Xmax,Ymax,Zmax; - Standard_Integer Nstruct,Npoint ; - Graphic3d_MapOfStructure MySetOfStructures; + Graphic3d_MapOfStructure aSetOfStructures; + MyView->DisplayedStructures (aSetOfStructures); - MyView->DisplayedStructures (MySetOfStructures); - Nstruct = MySetOfStructures.Extent() ; - - Graphic3d_MapIteratorOfMapOfStructure MyIterator(MySetOfStructures) ; - - Npoint = 0 ; X = Y = Z = 0. ; - for (; MyIterator.More(); MyIterator.Next()) + Standard_Boolean hasSelection = Standard_False; + for (Graphic3d_MapIteratorOfMapOfStructure aStructIter (aSetOfStructures); + aStructIter.More(); aStructIter.Next()) { - const Handle(Graphic3d_Structure)& aStruct = MyIterator.Key(); - if (!aStruct->IsEmpty()) + if (aStructIter.Key()->IsHighlighted() + && aStructIter.Key()->IsVisible()) { - Bnd_Box aBox = aStruct->MinMaxValues(); + hasSelection = Standard_True; + break; + } + } - // Check bounding box for validness + Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax; + Standard_Integer aNbPoints = 0; + gp_XYZ aResult (0.0, 0.0, 0.0); + for (Graphic3d_MapIteratorOfMapOfStructure aStructIter (aSetOfStructures); + aStructIter.More(); aStructIter.Next()) + { + const Handle(Graphic3d_Structure)& aStruct = aStructIter.Key(); + if (!aStruct->IsVisible() + || (hasSelection && !aStruct->IsHighlighted()) + || aStruct->IsEmpty()) + { + continue; + } + + Bnd_Box aBox = aStruct->MinMaxValues(); + if (aBox.IsVoid()) + { + continue; + } + + // use camera projection to find gravity point + aBox.Get (Xmin, Ymin, Zmin, + Xmax, Ymax, Zmax); + gp_Pnt aPnts[THE_NB_BOUND_POINTS] = + { + gp_Pnt (Xmin, Ymin, Zmin), gp_Pnt (Xmin, Ymin, Zmax), + gp_Pnt (Xmin, Ymax, Zmin), gp_Pnt (Xmin, Ymax, Zmax), + gp_Pnt (Xmax, Ymin, Zmin), gp_Pnt (Xmax, Ymin, Zmax), + gp_Pnt (Xmax, Ymax, Zmin), gp_Pnt (Xmax, Ymax, Zmax) + }; + + for (Standard_Integer aPntIt = 0; aPntIt < THE_NB_BOUND_POINTS; ++aPntIt) + { + const gp_Pnt& aBndPnt = aPnts[aPntIt]; + const gp_Pnt aProjected = myCamera->Project (aBndPnt); + if (Abs (aProjected.X()) <= 1.0 + && Abs (aProjected.Y()) <= 1.0) + { + aResult += aBndPnt.XYZ(); + ++aNbPoints; + } + } + } + + if (aNbPoints == 0) + { + for (Graphic3d_MapIteratorOfMapOfStructure aStructIter (aSetOfStructures); + aStructIter.More(); aStructIter.Next()) + { + const Handle(Graphic3d_Structure)& aStruct = aStructIter.Key(); + if (aStruct->IsEmpty()) + { + continue; + } + + Bnd_Box aBox = aStruct->MinMaxValues(); if (aBox.IsVoid()) { continue; } - // use camera projection to find gravity point - aBox.Get (Xmin,Ymin,Zmin,Xmax,Ymax,Zmax); - gp_Pnt aPnts[8] = { + aBox.Get (Xmin, Ymin, Zmin, + Xmax, Ymax, Zmax); + gp_Pnt aPnts[THE_NB_BOUND_POINTS] = + { gp_Pnt (Xmin, Ymin, Zmin), gp_Pnt (Xmin, Ymin, Zmax), gp_Pnt (Xmin, Ymax, Zmin), gp_Pnt (Xmin, Ymax, Zmax), gp_Pnt (Xmax, Ymin, Zmin), gp_Pnt (Xmax, Ymin, Zmax), - gp_Pnt (Xmax, Ymax, Zmin), gp_Pnt (Xmax, Ymax, Zmax) }; + gp_Pnt (Xmax, Ymax, Zmin), gp_Pnt (Xmax, Ymax, Zmax) + }; - for (Standard_Integer aPntIt = 0; aPntIt < 8; ++aPntIt) + for (Standard_Integer aPntIt = 0; aPntIt < THE_NB_BOUND_POINTS; ++aPntIt) { const gp_Pnt& aBndPnt = aPnts[aPntIt]; - - gp_Pnt aProjected = myCamera->Project (aBndPnt); - const Standard_Real& U = aProjected.X(); - const Standard_Real& V = aProjected.Y(); - if (Abs(U) <= 1.0 && Abs(V) <= 1.0) - { - Npoint++; - X += aBndPnt.X(); - Y += aBndPnt.Y(); - Z += aBndPnt.Z(); - } + aResult += aBndPnt.XYZ(); + ++aNbPoints; } } } - if( Npoint > 0 ) { - X /= Npoint ; Y /= Npoint ; Z /= Npoint ; - } - return Nstruct ; + if (aNbPoints > 0) + { + aResult /= aNbPoints; + } + theX = aResult.X(); + theY = aResult.Y(); + theZ = aResult.Z(); } //======================================================================= diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 395e3d99b8..42012a0c9b 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -2950,22 +2950,84 @@ static int VTestZBuffTrihedron(Draw_Interpretor& di, Standard_Integer argc, cons //purpose : Camera Rotating //============================================================================== -static int VRotate( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) { - Handle(V3d_View) V3dView = ViewerTest::CurrentView(); - if ( V3dView.IsNull() ) { +static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec) +{ + Handle(V3d_View) aView = ViewerTest::CurrentView(); + if (aView.IsNull()) + { + std::cout << "No active view!\n"; return 1; } - if ( argc == 4 ) { - V3dView->Rotate( Draw::Atof(argv[1]), Draw::Atof(argv[2]), Draw::Atof(argv[3]) ); - return 0; - } else if ( argc == 7 ) { - V3dView->Rotate( Draw::Atof(argv[1]), Draw::Atof(argv[2]), Draw::Atof(argv[3]), Draw::Atof(argv[4]), Draw::Atof(argv[5]), Draw::Atof(argv[6]) ); - return 0; - } else { - di << argv[0] << " Invalid number of arguments" << "\n"; - return 1; + Standard_Boolean hasFlags = Standard_False; + for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter) + { + Standard_CString anArg (theArgVec[anArgIter]); + TCollection_AsciiString aFlag (anArg); + aFlag.LowerCase(); + if (aFlag == "-mousestart" + || aFlag == "-mousefrom") + { + hasFlags = Standard_True; + if (anArgIter + 2 >= theArgNb) + { + std::cout << "Error: wrong syntax at '" << anArg << "'\n"; + return 1; + } + + Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]); + Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]); + aView->StartRotation (anX, anY); + } + else if (aFlag == "-mousemove") + { + hasFlags = Standard_True; + if (anArgIter + 2 >= theArgNb) + { + std::cout << "Error: wrong syntax at '" << anArg << "'\n"; + return 1; + } + + Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]); + Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]); + aView->Rotation (anX, anY); + } + else if (theArgNb != 4 + && theArgNb != 7) + { + std::cout << "Error: wrong syntax at '" << anArg << "'\n"; + return 1; + } } + + if (hasFlags) + { + return 0; + } + else if (theArgNb == 4) + { + Standard_Real anAX = Draw::Atof (theArgVec[1]); + Standard_Real anAY = Draw::Atof (theArgVec[2]); + Standard_Real anAZ = Draw::Atof (theArgVec[3]); + aView->Rotate (anAX, anAY, anAZ); + return 0; + } + else if (theArgNb == 7) + { + Standard_Real anAX = Draw::Atof (theArgVec[1]); + Standard_Real anAY = Draw::Atof (theArgVec[2]); + Standard_Real anAZ = Draw::Atof (theArgVec[3]); + + Standard_Real anX = Draw::Atof (theArgVec[4]); + Standard_Real anY = Draw::Atof (theArgVec[5]); + Standard_Real anZ = Draw::Atof (theArgVec[6]); + + aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ); + return 0; + } + + std::cout << "Error: Invalid number of arguments\n"; + return 1; } //============================================================================== @@ -7249,7 +7311,11 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) " : Displays a V3d_ZBUFFER'ed or V3d_WIREFRAME'd trihedron", __FILE__,VTestZBuffTrihedron,group); theCommands.Add("vrotate", - "vrotate : vrotate AX AY AZ [X Y Z]", + "vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]" + "\n : Option -mouseStart starts rotation according to the mouse position" + "\n : Option -mouseMove continues rotation with angle computed" + "\n : from last and new mouse position." + "\n : vrotate AX AY AZ [X Y Z]", __FILE__,VRotate,group); theCommands.Add("vzoom", "vzoom : vzoom coef", diff --git a/tests/bugs/vis/bug25723 b/tests/bugs/vis/bug25723 new file mode 100644 index 0000000000..f725c5e85c --- /dev/null +++ b/tests/bugs/vis/bug25723 @@ -0,0 +1,50 @@ +puts "============" +puts "OCC25723" +puts "Calculate the center of rotation taking into account structure visibility" +puts "============" +puts "" + +set x_start_sel_coord 100 +set y_start_sel_coord 100 + +set x_end_sel_coord 400 +set y_end_sel_coord 400 + +set x_mouse_start_coord 100 +set y_mouse_start_coord 100 + +set x_mouse_move_coord 300 +set y_mouse_move_coord 300 + +set x_check_coord 220 +set y_check_coord 50 + +box b1 0 0 0 10 10 10 +box b2 0 0 20 10 10 10 +box b3 0 0 -20 10 10 10 +box b4 0 0 40 10 10 10 + +vinit View1 +vclear +vaxo +vsetdispmode 1 + +# turn on solid selection +vselmode 6 1 +vdisplay b1 b2 b3 b4 +vfit + +# select solid +vselect ${x_start_sel_coord} ${y_start_sel_coord} ${x_end_sel_coord} ${y_end_sel_coord} + +# hide selected solids +verase + +# rotation +vrotate -mouseStart ${x_mouse_start_coord} ${y_mouse_start_coord} -mouseMove ${x_mouse_move_coord} ${y_mouse_move_coord} + +if {"[vreadpixel ${x_check_coord} ${y_check_coord} rgb name]" != "GOLDENROD2"} { + puts "Error: Rotation is not correct" +} + +set only_screen 1 diff --git a/tests/bugs/vis/bug25723_1 b/tests/bugs/vis/bug25723_1 new file mode 100644 index 0000000000..ef12838523 --- /dev/null +++ b/tests/bugs/vis/bug25723_1 @@ -0,0 +1,48 @@ +puts "============" +puts "OCC25723" +puts "Calculate the center of rotation taking into account active selection" +puts "============" +puts "" + +set x_sel_coord 220 +set y_sel_coord 50 + +set x_mouse_start_coord 100 +set y_mouse_start_coord 100 + +set x_mouse_move_coord 300 +set y_mouse_move_coord 300 + +set x_check_coord 220 +set y_check_coord 50 + +box b1 0 0 0 10 10 10 +box b2 0 0 20 10 10 10 +box b3 0 0 -20 10 10 10 +box b4 0 0 40 10 10 10 + +vinit View1 +vclear +vaxo +vsetdispmode 1 + +# turn on solid selection +vselmode 6 1 +vdisplay b1 b2 b3 b4 +vfit + +# select one (red) solid +vselect ${x_sel_coord} ${y_sel_coord} + +# start rotation +vrotate -mouseStart ${x_mouse_start_coord} ${y_mouse_start_coord} -mouseMove ${x_mouse_move_coord} ${y_mouse_move_coord} + +# unselect +vselect 0 0 + +# check color +if {"[vreadpixel ${x_check_coord} ${y_check_coord} rgb name]" != "GOLDENROD2"} { + puts "Error : Rotation is not correct" +} + +set only_screen 1