Converting vectors to angles

To see this code in action, visit the vectorAngleConversion project. This is a simple project that sets up a Point object that contains a vector and a variable called angle:

private Point vectorLength = new Point(); private double angle;

A value that represents a vector is assigned to the vectorLength variable, and the angle of the vector is calculated and output to a TextBlock:

vectorLength.X = 5; vectorLength.Y = 5;

double radians = Math.Atan2(vectorLength.Y, vectorLength.X); angle = Convert.ToIntl6(l80 / Math.PI * radians); msgBlock.Text = angle + "";

The result produced by this bit of code is 45, which is the correct angle (in degrees) for a vector of 5,5. Go ahead and play with the values of the vectorLength variable, and run the program to see what kind of results you get. Don't worry if you see a few results that surprise you—we'll be visiting these two math functions again later.

Let's take a look at a project that graphically illustrates the math. This project allows a user to adjust the endpoints of a line. As the endpoints are adjusted, the application calculates the length of the vector that the line creates, calculates the angle of that vector, and applies the angle to a separate line object as a sanity check for the calculations. All the code we're about to discuss is available in the vectorAngles project.

The MainPage.xaml file for this project contains four sliders and several TextBlock objects that are used to provide user feedback. In addition, there is a Path object that is used to draw a simple line. The default orientation for the line is horizontal.

In the MainPage.xaml.es file, the objects needed in the project are declared. The first one is the user-adjustable line, called myLine. The next two objects are Point objects, pi and p2, and are used to store the endpoints of the myline object. The last two declarations are similar to those illustrated in the previous project—vectorLength is used to determine the length of the line as a user manipulates it, and angle is used to store the angle of the line.

private Line myLine = new Line(); private Point pi = new Point(); private Point p2 = new Point(); private Point vectorLength = new Point(); private double angle;

The code starts by assigning some default values to the pi and p2 Point objects:

Next, the values in the pi and p2 Point objects are used to create starting and ending points for the myline object. In Silverlight, a line is defined by two pairs of coordinates: the start point and the endpoint. They are referenced as Xl,Yl and X2,Y2. Once values are assigned to the myline object, the line's

StrokeThickness and Color are set.

myLine.StrokeThickness = 1;

SolidColorBrush stroke = new SolidColorBrush();

stroke.Color = Colors.Black;

myLine.Stroke = stroke;

Prior to adding the line to the canvas, a function called doAngle() is called with the code doAngle();. This function uses the start point and endpoint of the myline object to determine the length of the vector created by the line. You should recognize the next couple of lines of code from the previous example—this is where the vector created by the line is converted into an angle.

The testLineAngle object is our sanity check—this object will be rotated the number of degrees calculated by our code, and the angle of the line should match the angle of the myline object, assuming the code is functioning correctly. The values are converted to integers for display as they are output to the canvas.

private void doAngle() {

vectorLength.X = myLine.X2 - myLine.Xl; vectorLength.Y = myLine.Y2 - myLine.Yl;

double radians = Math.Atan2(vectorLength.Y, vectorLength.X); angle = Convert.ToIntl6(l80 / Math.PI * radians); testLineAngle.Angle = angle; msgBlock.Text = "Vector X,Y: " +

Convert.ToIntl6(vectorLength.X) + " + Convert.ToIntl6(vectorLength.Y) + "\nAngle: " + angle;

Now that the initial state of the line has been used to determine the angle and the screen output is current, the line is added to the LayoutRoot Canvas:

LayoutRoot.Children.Add(myLine);

Next, the maximum limits for the sliders are set. The sliders will be used to allow a user to change the starting and ending points of the myline object, and the application will not allow either point's x value to be greater than the width of the canvas or either point's y value to be greater than the height of the canvas.

plXSlider.Maximum = p2XSlider.Maximum = LayoutRoot.Width; plYSlider.Maximum = p2YSlider.Maximum = LayoutRoot.Height;

Each of the four sliders is then preset to the default value for the endpoints of myLine, and the text that displays the current value for each slider is updated:

plXSlider.Value = myLine.Xl plYSlider.Value = myLine.Yl p2XSlider.Value = myLine.X2

p2YSlider.Value = myLine.Y2

msgPlXSlider.Text = "Point 1 X

msgPlYSlider.Text = "Point 1 Y

msgP2XSlider.Text = "Point 2 X

msgP2YSlider.Text = "Point 2 Y

+ (Intl6)myLine.Xl + (Intl6)myLine.Yl + (Intl6)myLine.X2 + (Intl6)myLine.Y2

With all of the preliminary setup out of the way, the application then sets up an event listener for each slider's ValueChanged event. This event will be raised when a slider is manipulated by a user.

plXSlider.ValueChanged += new RoutedPropertyChangedEventHandler^-

<double>(plXSlider_ValueChanged); plYSlider.ValueChanged += new RoutedPropertyChangedEventHandler^-

<double>(plYSlider_ValueChanged); p2XSlider.ValueChanged += new RoutedPropertyChangedEventHandler^-

<double>(p2XSlider_ValueChanged); p2YSlider.ValueChanged += new RoutedPropertyChangedEventHandler^-

<double>(p2YSlider_ValueChanged);

The event handler code for each of the four sliders is fairly similar. The value of the slider is used to update the corresponding point of the myline object. The text that shows the slider's value to the user is updated, and the doAngle() function is called to update the angle output on the screen.

private void plXSlider_ValueChanged(object sender,

RoutedPropertyChangedEventArgs<double> e)

myLine.Xl = plXSlider.Value; msgPlXSlider.Text = "Point IX: "+

Convert.ToIntl6(plXSlider.Value);

doAngle();

The pi y slider event handler is shown in the following listing. Notice that the functionally it is identical except that it references a different point of the myline object, and outputs text to a different TextBlock.

private void plYSlider_ValueChanged(object sender,

RoutedPropertyChangedEventArgs<double> e)

myLine.Yl = plYSlider.Value;

msgPlYSlider.Text = "Point lY:"+

Convert.ToIntl6(plYSlider.Value);

doAngle();

The sliders for p2 follow the same pattern. When the program runs, you can use the sliders to adjust the endpoints of the line object, and the code will calculate the length of the vector that is created by the line.

The vector length is used to calculate the angle of the line, which is then applied to the line object near the bottom of the screen. Aside from slight differences due to the conversion to an integer data type and the imprecision that introduces, you should see that the code is doing what it is supposed to, as shown in Figure 5-14. Pretty cool, huh?

Point 1 X:

171

:—

Point 1 Y:

163

=£K

Point 2 X:

650

Point 2 Y:

349

Vector X,Y: 479, 1 86

Angle: 21

Figure 5-14. The vectorAngle project allows you to modify the endpoints of a line as it calculates the angle in real time.

Figure 5-14. The vectorAngle project allows you to modify the endpoints of a line as it calculates the angle in real time.

You've seen a pretty broad variety of ways to manipulate objects using vectors. You know how to make objects move using vectors, and you know how to make objects rotate by using vectors. Let's take a look at how you can separate the acceleration vector of an object from the directional vector.

0 0

Post a comment

  • Receive news updates via email from this site