The angle between two vectors and The orientation from one Vector point to another Vector point

Hi rust community!
I want to create a program which will define the angle between two vectors !
Is cgmath the way to do that ?

Typing something like "angle between two vectors" or "angle between two vectors 3d" into google is the way to do that.

Of course if you add "rust" to your search term you soon find a Crate to help. For example: https://docs.rs/ami/0.13.0/ami/struct.Vector.html

3 Likes
use cgmath::Rad; 

pub struct Vector {

pub x: f32,
pub y: f32,

}

impl Vector {

pub fn angle(self, rhs: Self) -> f32 {
	(self.dot(rhs) / self.length()).acos()	

}

}

fn main() {



}

Am I in a good way ? :smiley:

Hi, if you're planning on using cgmath, use InnerSpace::angle. This is implemented for Vector3, so you can use it through that.

Can you give me an example code with the InnerSpace::angle ?

use cgmath::{prelude::*, Vector3};

fn main() {
    let v1 = Vector3::new(0.3, 1.0, 0.5);
    let v2 = Vector3::new(1.0, 0.5, 0.9);

    println!("v1: {:?}", v1);
    println!("v2: {:?}", v2);
    println!("angle: {:?}", v1.angle(v2));
}

v1: Vector3 [0.3, 1.0, 0.5]
v2: Vector3 [1.0, 0.5, 0.9]
angle: 0.7191634638561107 rad
2 Likes

Oh this is even better !!

i was trying this one ;

 use cgmath::Rad;
use cgmath::prelude::*;

fn main() {

let angle: Rad<f32> = Rad::acos(0.5);
println!("{:?}", angle)
}

I was just playing around , thank you parasyte :smiley:

and here it convert it to degrees;

use cgmath::{prelude::*, Vector3};

fn main() {

let mut pointx: Vec<f32> = Vec::new();

pointx.push(20.0);
pointx.push(1.0);
pointx.push(0.0);

let mut pointy: Vec<f32> = Vec::new();

pointy.push(1.0);
pointy.push(40.0);
pointy.push(0.0);

let pointx = Vector3::new(pointx[0], pointx[1], pointx[2]);
let pointy = Vector3::new(pointy[0], pointy[1], pointy[2]);	

println!("angle: {:?}", pointx.angle(pointy) * 180.0 / 3.14159);
}

Deg<S> implements From<Rad<S>> so you can just do:

use cgmath::Deg;

println!("angle: {:?}", Deg::from(pointx.angle(pointy)));
2 Likes

And for the distance between two values .. like in nalgebra is quiet simple;

use nalgebra::distance;

(point1.coordinates() - point2.coordinates()).norm()

Is the Point3 method for the distance in cgmath ? ; https://docs.rs/cgmath/0.17.0/cgmath/struct.Point3.html

That nalgebra example actually calculates the normal vector from point1 to point2. In cgmath, you calculate the distance between two points using MetricSpace::distance, like so:

let p1 = Vector3 {
    x: 32.0,
    y: 14.0, 
    z: -3.0
};
let p2 = Vector3 {
    x: -5.6,
    y: 8.9,
    z: 0.0,
};
let dist = p1.distance(p2);

See below, @marcianx's post.

1 Like

ohh this is exactly what i did before 2 minutes, so i am correct thank you Optimist !!
Check out my code;

Input;

use cgmath::{prelude::*, Vector3, Deg};

fn main() {

let mut pointx: Vec<f32> = Vec::new();

pointx.push(20.0);
pointx.push(1.0);
pointx.push(0.0);

let mut pointy: Vec<f32> = Vec::new();

pointy.push(1.0);
pointy.push(40.0);
pointy.push(0.0);

let mut pointz: Vec<f32> = Vec::new();

pointz.push(-60.0);
pointz.push(-1.0);
pointz.push(0.0);

let point1 = Vector3::new(pointx[0], pointx[1], pointx[2]);
let point2 = Vector3::new(pointy[0], pointy[1], pointy[2]);	
let point3 = Vector3::new(pointz[0], pointz[1], pointz[2]);



println!("Angle of Point1 & Point2 & Point3 is: {:?}", Deg::from(point1.angle(point2) + 
point2.angle(point3)));
println!("Distance between Point1 to Point2 is: {:?}", point1.distance(point2))
}

Ouput;

Angle of Point1 & Point2 & Point3 is: 178.09244°
Distance between Point1 to Point2 is: 43.382023

Hey, you don't have to create a Vec to be able to create a Vector3:

//Constructor:
let point_a = Vector3 {
     x: 10.0,
     y: 20.0,
     z: 30.0,
};
//Using an array:
let point_b: Vector3<f32> = [40.0, 50.0, 60.0].into();
1 Like

am Yeah this is better :smiley: Now the most extreme i want to do is the orientation,
If i walk from point 1 to point 2,do I have to turn left,right or straight on,to get to point 3. Can rotation method help me do this; https://docs.rs/cgmath/0.17.0/cgmath/trait.Rotation.html

That sounds a lot like the Orientation::of() function from the arcs crate. The crate is MIT licensed, so feel free to browse the source or copy code.

These sorts of algorithms aren't necessarily specific to a single crate or the Rust language, I've had to do a lot of computational geometry things for work and resources like this geeks-for-geeks page are super useful!

3 Likes

Ok i did it, check out my code;

use cgmath::{prelude::*, Vector3, Deg};
use  arcs::{Point, Orientation};

fn main() {

   //Constructor   
  let point_a = Vector3 {
  x: 20.0,
  y: 1.0,
  z: 0.0,
};

let point_b = Vector3 {
x: 1.0,
y: 40.0,
z: 0.0,
};

let point_c = Vector3 {
x: -60.0,
y: -1.0,
z:  0.0,
};

//Angle
println!("Angle of Point A & Point B is: {:?}", Deg::from(point_a.angle(point_b)));
println!("Angle of Point B & Point C is: {:?}", Deg::from(point_b.angle(point_c)));   
println!("Angle of Point A & Point B & Point C is: {:?}", 
Deg::from(point_a.angle(point_b) + point_b.angle(point_c)));

//Distance
println!("Distance between Point A to Point B is: {:?}", point_a.distance(point_b));
println!("Distance between Point B to point C is: {:?}", point_b.distance(point_c));
println!("Distacne between Point A to Point C is: {:?}", point_a.distance(point_c));

let first = Point::new(20.0, 1.0);
let second = Point::new(1.0, 40.0);
let third = Point::new(-60.0, -1.0);

let value = (second.y - first.y) * (third.x - second.x)
            - (second.x - first.x) * (third.y - second.y);
            
            if value > 0.0 {
            println!("Go right");
            } else if value < 0.0 {
            println!("Go left");
            } else {
            println!("Go Straight on");
            }

}

The output is : Go left .
It looks correct, but actually i want the orientation from point 2 to point 3, so i have to change the value calculations

nalgebra's norm actually does compute the norm (= magnitude) of the vector from point1 to point2. This is the same as the distance between the two points.

(Also, a little nit: I suppose you meant to write "normalized" vector? The normal vector to a 3D vector is not well-defined -- there's a whole plane that's normal to a 3D vector.)

2 Likes

Ah, interesting, and yes I did mean to write normalized vector. I have edited my post above.

1 Like

I want the result for the orientation from second point to third point ;

let _first = Point::new(20.0, 1.0);
let second = Point::new(1.0, 40.0);
let third = Point::new(-60.0, -1.0);

let value =  (second.x - third.x) * (second.y - third.y);
            println!("Orientation Value: {}", value);
            
            if value > 0.0 {
            //arcs::Orientation::Clockwise
            println!("Walking from Point A to Point B && after turn Left to reach Point C!");
            } else if value < 0.0 {
            //arcs::Orientation::Anticlockwise
            println!("Walking from Point A to Point B && after turn Right to reach Point C!");
            } else {
            //arcs::Orientation::Collinear
            println!("Walking from Point A to Point B && after Go Straight on to reach Point C!");
            }

is the value correct ?
Or maybe i should change the value calculations to (second.x - first.x) * (second.x - third.x).. ?

So, I don't remember much of linear algebra, but, I believe that this code should suffice:

let reference_point = Point3(...);
let first_target = Point3(...);
let second_target = Point3(...);

let first_vector = first_target - reference_point;
let second_vector = second_target - first_target;
let up = Vector3 {
    x: 0.,
    y: 1.,
    z: 0.,
};
let cross = up.cross(first_vector.normalize()).normalize();
let dot = cross.dot(second_vector.normalize());

if dot == 1.0 {
    println!("Go left");
} else if dot == 0.0 {
    println!("Go forward or backward or up or down");
} else if dot == -1.0 {
    println!("Go right");
}

This with some kind of a buffer could work.

1 Like