Skip to content

Commit 3000519

Browse files
committed
New nodes: 'Reciprocal', 'Angle Between', and 'Angle To'
1 parent f1e8ebe commit 3000519

File tree

1 file changed

+58
-0
lines changed
  • node-graph/nodes/math/src

1 file changed

+58
-0
lines changed

node-graph/nodes/math/src/lib.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,19 @@ where
142142
numerator / denominator
143143
}
144144

145+
/// The reciprocal operation (`1/x`) calculates the multiplicative inverse of a number.
146+
///
147+
/// Produces 0 if the input is 0.
148+
#[node_macro::node(category("Math: Arithmetic"))]
149+
fn reciprocal<T: num_traits::float::Float>(
150+
_: impl Ctx,
151+
/// The number for which the reciprocal is calculated.
152+
#[implementations(f64, f32)]
153+
value: T,
154+
) -> T {
155+
if value == T::from(0.).unwrap() { T::from(0.).unwrap() } else { T::from(1.).unwrap() / value }
156+
}
157+
145158
/// The modulo operation (`%`) calculates the remainder from the division of two scalar numbers or vectors.
146159
///
147160
/// The sign of the result shares the sign of the numerator unless *Always Positive* is enabled.
@@ -780,6 +793,51 @@ fn dot_product(
780793
}
781794
}
782795

796+
/// Calculates the angle swept between two vectors.
797+
///
798+
/// The value is always positive and ranges from 0° (both vectors point the same direction) to 180° (both vectors point opposite directions).
799+
#[node_macro::node(category("Math: Vector"))]
800+
fn angle_between(_: impl Ctx, vector_a: DVec2, vector_b: DVec2, radians: bool) -> f64 {
801+
let dot_product = vector_a.normalize_or_zero().dot(vector_b.normalize_or_zero());
802+
let angle = dot_product.acos();
803+
if radians { angle } else { angle.to_degrees() }
804+
}
805+
806+
pub trait ToPosition {
807+
fn to_position(self) -> DVec2;
808+
}
809+
impl ToPosition for DVec2 {
810+
fn to_position(self) -> DVec2 {
811+
self
812+
}
813+
}
814+
impl ToPosition for DAffine2 {
815+
fn to_position(self) -> DVec2 {
816+
self.translation
817+
}
818+
}
819+
820+
/// Calculates the angle needed for a rightward-facing object placed at the observer position to turn so it points toward the target position.
821+
#[node_macro::node(category("Math: Vector"))]
822+
fn angle_to<T: ToPosition, U: ToPosition>(
823+
_: impl Ctx,
824+
/// The position from which the angle is measured.
825+
#[implementations(DVec2, DAffine2, DVec2, DAffine2)]
826+
observer: T,
827+
/// The position toward which the angle is measured.
828+
#[expose]
829+
#[implementations(DVec2, DVec2, DAffine2, DAffine2)]
830+
target: U,
831+
/// Whether the resulting angle should be given in as radians instead of degrees.
832+
radians: bool,
833+
) -> f64 {
834+
let from = observer.to_position();
835+
let to = target.to_position();
836+
let delta = to - from;
837+
let angle = delta.y.atan2(delta.x);
838+
if radians { angle } else { angle.to_degrees() }
839+
}
840+
783841
// TODO: Rename to "Magnitude"
784842
/// The magnitude operator (`‖x‖`) calculates the length of a vec2, which is the distance from the base to the tip of the arrow represented by the vector.
785843
#[node_macro::node(category("Math: Vector"))]

0 commit comments

Comments
 (0)