Crates.io | ring360 |
lib.rs | ring360 |
version | 0.2.14 |
source | src |
created_at | 2024-02-25 12:10:09.725687 |
updated_at | 2024-11-05 23:12:48.701261 |
description | Simple wrapper type for 64-bit floats representing degrees around a circle. It has operator overloads for addition and subtraction, calculates the shortest angles and implements the core trigonometric functions. |
homepage | |
repository | https://github.com/neilg63/ring360 |
max_upload_size | |
id | 1152411 |
size | 24,445 |
This crate provides a versatile wrapper struct for representing degrees in a circular range, designed around 64-bit floats. The primary type, Ring360
, supports intuitive degree manipulation with +
and -
operators, and provides directional calculations for the shortest angle between two degrees. This angle calculation returns a positive value for clockwise movement and a negative value for counterclockwise, making it ideal for applications where direction matters. Additionally, an abs()
method can be used to get the absolute shortest distance regardless of direction.
Ring360
is implemented as a tuple struct, encapsulating an f64
value with methods for accessing degrees()
, rotations()
, and value()
. For example, Ring360(400.0)
would have a raw value of 400.0
, representing 40º
in degrees with 1
rotation.
Values are kept within a circular 360º range, so negative values are automatically converted to their positive counterparts in the opposite direction (e.g., -60º
is represented as 300º
). Recognizing that geographic coordinates often use a ±180º range, the crate includes GIS-compatible conversions. The to_360_gis()
method converts ±180º to the 360º format, and Ring360::from_gis(lng180: f64)
performs the reverse conversion. This way, the crate seamlessly adapts to GIS systems such as QGIS, where angles between 180º and 360º are often expressed in a ±180º format.
These conversions preserve the actual angle (e.g., -60º
in ±180º converts directly to 300º
), though they may adjust the rotation count. Standard methods like to_360()
and degrees()
offer consistent handling of degrees within the 360º range.
/// Add and/or subtract degrees on a circle
/// The degree value represents the longitude, while the intrinsic f64 value
/// represents the angle travelled around the circumference
let longitude_1 = 74.7.to_360(); // or Ring360(74.7);
let longitude_2 = 291.4.to_360();
let longitude_3 = 126.1.to_360();
let result_1 = longitude_1 + longitude_2 + longitude_3;
println!(
"Degrees: {:.1}º, intrinsic value is {:.1}, rotations: {}",
result_1.degrees(),
result_1.value(),
result_1.rotations()
);
/// Should read: Degrees: 132.2º, intrinsic value is 492.2, rotations: 1
let result_2 = longitude_1 - longitude_2 + longitude_3;
println!("Degree value: {}º", result_2);
/// Should read: Degree value: 269.4º
/// Declare two degrees on the GIS scale
let gis_lng_1 = 143.32;
let gis_lng_2 = -111.4;
/// Shift ±180 degrees to a 0º to 360º scale
let lng_360_1 = gis_lng_1.to_360_gis(); // or Ring360::rom_gis(74.7);
let lng_360_2 = gis_lng_2.to_360_gis();
let angle_3 = lng_360_1.angle(lng_360_2);
println!("The longitudinal distance between {} and {} is {}", lng_360_1.to_gis(), lng_360_2.to_gis(), angle_3);
/// The longitudinal distance between 143.32 and -111.4 is 105.28
let value_1 = 74.7;
let value_2 = 291.4;
let longitude_1 = value_1.to_360();
let longitude_2 = value_2.to_360();
let result_1_f64 = (longitude_1 + longitude_2).degrees();
println!(
"{}º + {}º equals {}º",
longitude_1,
longitude_2,
result_1_f64
);
These are not implemented directly for degrees as Ring360 values, but only with primitive f64 values via the multiply() and divide() methods.
let value_1 = 74.7;
let factor = 4.0;
let result_1 = value_1.to_360().multiply(factor);
println!(
"{}º multiplied by {} equals {}º",
value_1,
factor,
result_1
);
let result_2 = value_1.to_360().divide(factor);
println!(
"{}º divided by {} equals {}",
value_1,
factor,
result_2
);
The angle() and angle_f64() methods calculate the shortest angle in degrees between two longitudes in a circle. Negative values indicate an anticlockwise offset from A to B, e.g. from 340º to 320º would be negative, while 350º to 10º would be positive.
let value_1 = 297.4;
let longitude_1 = value_1.to_360();
let value_2: f64 = 36.2;
let longitude_2 = value_2.to_360();
let result_1 = longitude_1.angle(longitude_2);
let result_2 = longitude_1.angle_f64(value_2);
println!(
"Both results should be the same: {} == {}",
result_2,
result_1
);
The angle_abs()
and angle_f64_abs()
methods calculate the absolute angle in degrees in a clockwise direction between two longitudes in a circle. Values over 180.0 represent more than half a turn. For f64
value you may use .angle_360_abs(other_value: f64)
.
let value_1 = 270.0;
let longitude_1 = value_1.to_360();
let value_2: f64 = 30.0;
let longitude_2 = value_2.to_360();
let result_1 = longitude_1.angle_abs(longitude_2);
let result_2 = longitude_2.angle_abs(longitude_1);
println!(
"The angles may be anywhere in the 0 to 359.9999º range: {} and {}",
result_2,
result_1
);
let value_1 = 45.0;
let degree_1 = value_1.to_360();
println!(
"The sine of {}º is {:.12}",
degree_1.degrees(),
degree_1.sin()
);
// Should print: The sine of 45º is 0.707106781187
let value_2 = 60.0;
let degree_2 = value_2.to_360();
println!(
"The cosine of {}º is {:.1}",
degree_2.degrees(),
degree_2.cos()
);
// Should print: The cosine of 60º is 0.5
This is implemented only for f64 with the following methods:
This is crate is in development, but implements all core features.
angle_f64_abs()
and angle_360_abs()
methodsThe following methods have been added to Ring360
The core trigonometric methods, sin(), cos(), tan(), asin(), acos() and atan() are calculated from degrees without explicitly converting to radians first:
The following deprecated methods were removed from version 0.2.5:
angle_f64()
method and added a new static method minus_half_turn()
(-180).