Calculating the Angle Between Two Points
Windows only
Problem
For two sets of 3D vectors, you can use the method demonstrated in Calculate the Angle Between Two Vectors to calculate the angle between them. The results for both are always the same - 45 degree in this case. For example:
But what if you need a result in which one is 45 degrees the other is 315 degrees?
Solution
The following example code demonstrates how to calculate the angle between two 3D points, given a common base point.
/* Description: Calculates the angle between two points that lie on a given plane. Parameters: plane - [in] The plane on which the points lie basept - [in] The base point refpt1 - [in] The first reference point refpt2 - [in] The second reference point radians - [out] The angle in radians Returns: TRUE if successful, FALSE otherwise. */ static bool CalculatePlaneAngle( const ON_Plane& plane, const ON_3dPoint& basept, const ON_3dPoint& refpt1, const ON_3dPoint& refpt2, double& radians ) { // Make sure the points are on the plane double tolerance = 0.000001; double dist = 0.0; dist = plane.plane_equation.ValueAt( basept ); if( fabs(dist) > tolerance ) return false; dist = plane.plane_equation.ValueAt( refpt1 ); if( fabs(dist) > tolerance ) return false; dist = plane.plane_equation.ValueAt( refpt2 ); if( fabs(dist) > tolerance ) return false; // Make sure base and reference points are not equal if( basept == refpt1 | basept == refpt2 ) return false; // Calculate angle between vectors ON_3dVector v = refpt2 - basept; v.Unitize(); ON_3dVector zerov = refpt1 - basept; zerov.Unitize(); double dot = ON_DotProduct( zerov, v ); dot = RHINO_CLAMP( dot, -1.0, 1.0 ); double angle = acos( dot ); // Calculate a new y-axis based on the plane's // zaxis and our zero vector v = ON_CrossProduct( plane.zaxis, zerov ); v.Unitize(); // Create a plane using our y-axis a the normal ON_Plane yplane; yplane.CreateFromNormal( basept, v ); // Figure out which side of this plane that refpt2 is on dist = yplane.plane_equation.ValueAt( refpt2 ); if( dist < 0.0 ) angle = (ON_PI * 2.0) - angle; radians = angle; return true; }
You can use the above function as follows…
CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context ) { CRhinoView* view = RhinoApp().ActiveView(); if( 0 == view ) return failure; ON_Plane plane = view->ActiveViewport().ConstructionPlane().m_plane; ON_3dPoint basept, refpt1, refpt2; CRhinoGetPoint gp; gp.SetCommandPrompt( L"Base point" ); gp.Constrain( plane ); gp.GetPoint(); if( gp.CommandResult() != success ) return gp.CommandResult(); basept = gp.Point(); gp.SetCommandPrompt( L"First angle point" ); gp.SetBasePoint( basept ); gp.DrawLineFromPoint( basept, TRUE ); gp.GetPoint(); if( gp.CommandResult() != success ) return gp.CommandResult(); refpt1 = gp.Point(); gp.SetCommandPrompt( L"Second angle point" ); gp.SetBasePoint( basept ); gp.DrawLineFromPoint( basept, TRUE ); gp.GetPoint(); if( gp.CommandResult() != success ) return gp.CommandResult(); refpt2 = gp.Point(); double angle = 0.0; if( CalculatePlaneAngle(plane, basept, refpt1, refpt2, angle) ) RhinoApp().Print( L"Angle = %.3f degrees.\n", angle * (180.0 / ON_PI) ); return success; }