Converting an Array2 to Polar Coordinates - rust

I am struggling to convert an Array2 of Cartesian Coordinates to Polar Coordinates. The two columns of each row have to be mutated based on each others values, and I can't figure out how to make it.
After different trials, I implemented the following code, but I think it is a dead end:
use ndarray::{array, Axis};
use num_traits::float::Float;
fn main() {
let mut coords = array![[1., 0.], [1. / 2., (3.).sqrt() / 2.0], [0., 1.]];
for mut row in coords.axis_iter_mut(Axis(0)) {
let col_0 = row.get(0).unwrap();
let col_1 = row.get(1).unwrap();
let mut row_polar_coord = array![
(col_0.powi(2) + col_1.powi(2)).sqrt(),
(col_1 / col_0).atan()
];
//row = row_polar_coord;
// Error: mismatched types
// expected struct `ndarray::ArrayBase<ndarray::ViewRepr<&mut {float}>, _>`
// found struct `ndarray::ArrayBase<ndarray::OwnedRepr<{float}>, _>`
row = row_polar_coord.view_mut();
// Diagnostics:
// `row_polar_coord` does not live long enough
// borrowed value does not live long enough
}
}
How should be handled these kinds of transformations in ndarray?

I would suggest not using an ndarray to store the real and imaginary part of your values but a tuple. This has way less overhead.
For inplace mutation you can use map_inplace():
use ndarray::{array, Axis};
fn main() {
let mut coords = array![(1_f32, 0_f32), (1. / 2., (3_f32).sqrt() / 2.0), (0., 1.)];
coords.map_inplace(|(a,b)| {
let c = (a.powi(2) + b.powi(2)).sqrt();
let d = (*b / *a).atan();
*a = c;
*b = d;
});
print!("{:?}", coords);
}
When you really need to stick to this input you can do
use ndarray::{array, Axis};
fn main() {
let mut coords = array![[1_f32, 0_f32], [1. / 2., (3_f32).sqrt() / 2.0], [0., 1.]];
coords.axis_iter_mut(Axis(0)).for_each(|mut x| {
let a : f32 = *x.get(0).unwrap();
let b : f32 = *x.get(1).unwrap();
x[0] = (a.powi(2) + b.powi(2)).sqrt();
x[1] = (b / a).atan();
});
print!("{:?}", coords);
}

Related

How to interpolate between fixed values in a 2D grid for biome-generation?

I am currently implementing biome-generation in my game and I want to make the type of a biome dependent on humidity and temperature values that are generated from gradual noise.
different Biomes should have different heights and without interpolation this would result in abrupt height differences on biome borders as expected.
What I tried was to get the 2 neighbour biomes in the grid too and measure the blend-percentage of each biome.
Later I then get the 3 different height values from the biomes and multiply each with it's respective blend value.
Here is the simplified and stripped code, which I use to fetch biomes:
const BIOME_GRID_SIZE: usize = 2;
const BIOME_INDEX_SIZE: usize = BIOME_GRID_SIZE - 1;
const BIOME_GRID: [[Biomes; BIOME_GRID_SIZE]; BIOME_GRID_SIZE] =
[
[Biomes::Mountains, Biomes::Forest],
[Biomes::Desert , Biomes::Mesa ],
];
fn get_height(coord: [i64; 2], noise: &Noise) -> i64 {
let temperature = (noise.get_2d(coord) + 0.5).clamp(0.0, 1.0);
let humidity = (noise.get_2d(coord /* + some offset */) + 0.5).clamp(0.0, 1.0);
let x = BIOME_GRID_SIZE as f64 * humidity;
let y = BIOME_GRID_SIZE as f64 * temperature;
let x_frac = (x.fract() - 0.5) * 2.0;
let y_frac = (y.fract() - 0.5) * 2.0;
let x_blending = x_frac.abs();
let y_blending = y_frac.abs();
let own_blending = 2.0 - x_blending - y_blending;
// direction of neighbour biomes
let x_direction = x_frac.signum() as isize;
let y_direction = y_frac.signum() as isize;
let x_index = (x.trunc() as isize).clamp(0, BIOME_INDEX_SIZE as isize);
let y_index = (y.trunc() as isize).clamp(0, BIOME_INDEX_SIZE as isize);
let biomes = get_biomes(x_index, y_index, x_direction, y_direction);
blend(
coord,
noise,
biomes,
[
own_blending,
x_blending,
y_blending,
]
),
}
// get main and neighbour biomes
fn get_biomes(x: isize, y: isize, x_direction: isize, y_direction: isize) -> [Biomes; 3] {
let mut biomes = [Biomes::Ocean; 3];
for (i, (d_x, d_y)) in [(0, 0), (x_direction, 0), (0, y_direction)].iter().enumerate() {
let x_index = (x + d_x).clamp(0, BIOME_INDEX_SIZE as isize) as usize;
let y_index = (y + d_y).clamp(0, BIOME_INDEX_SIZE as isize) as usize;
let biome = BIOME_GRID[x_index][y_index];
biomes[i] = biome;
}
biomes
}
pub fn blend(
coord: [i64; 2],
noise: &Noise,
biomes: [Biomes; 4],
blending: [f64; 4],
) -> i64 {
let heights: Vec<f64> = biomes
.iter()
.map(|x| x.get().height(coord, noise) as f64)
.collect();
let height = heights[0] * blending[0] + heights[1] * blending[1] + heights[2] * blending[2];
let height = height as i64;
height
}
This works well in some cases, in the other it fails completely.
I am unsure, if 2 neighbours are enough and how to properly get the blend values.
Is there a better solution to this problem?
In general for bilinear blending you would use four points. If I understand your code correctly that would be the four height maps for each biome.
You then lerp across one axis (e.g. humidity) for the two pairs with the same other axis, and then lerp the two blended values again with the other axis (e.g. temperature).

Operator overloading with vectors: cannot add vector of complex numbers

I'm trying to implement the Add trait for a Vector type that I defined.
use std::ops::Add;
use num::traits::Float;
#[derive(PartialEq, Debug, Clone)]
pub struct Vector<T>(Vec<T>);
impl<T: Float> Add for Vector<T> {
type Output = Vector<T>;
fn add(self, w: Self) -> Self::Output {
let dim = self.0.len();
let mut t = vec![T::zero(); dim];
for i in 0..dim {
t[i] = self.0[i] + w.0[i];
}
Vector(t)
}
}
Adding vector of float values works fine.
let v = Vector(vec![1., 2., 3.]);
let w = Vector(vec![1., 2., 6.]);
let result = v + w;
println!("{:?}", result);
However, when I try to add a vector of complex numbers, it doesn't work. Also, the error is a little vague.
let x = Complex::new(1., 3.);
let y = Complex::new(9., -1.);
let z = Complex::new(0.32, 81.);
let v: Vector<Complex<f32>> = Vector(vec![x, y, z]);
// cannot add `vector::Vector<num::Complex<f32>>` to `vector::Vector<num::Complex<f32>>`rustc(E0369)
let result = v + v;
Am I missing something about the Add implementation? How would I enable the add operation for vector of complex numbers?
Link to code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c5d3b0314968fa261287a19be4ad9536
So, I think the reason my code doesn't work is because num::traits::Float is not the right type to use. The reason being is that it has too many methods.
To make it work, I defined a trait Num, which is "narrower" compared to Float.
pub trait Num: Add + Zero + Clone + Copy {}
impl<T> Num for T where T: Add + Zero + Clone + Copy {}
Then, use that trait instead of Float.
impl<T: Num> Add for Vector<T> {
type Output = Vector<T>;
fn add(self, w: Self) -> Self::Output {
let dim = self.0.len();
let mut t = vec![T::zero(); dim];
for i in 0..dim {
t[i] = self.0[i] + w.0[i];
}
Vector(t)
}
}
With the above change, adding vector of floats and complex numbers now works.
// Adding vector of floats works.
let v = Vector(vec![1., 2., 3.]);
let w = Vector(vec![1., 2., 6.]);
let result = v + w;
println!("{:?}", result);
let x = Complex::new(1., 3.);
let y = Complex::new(9., -1.);
let z = Complex::new(0.32, 81.);
let v: Vector<Complex<f32>> = Vector(vec![x, y, z]);
let w: Vector<Complex<f32>> = Vector(vec![x, y, z]);
// Adding vector of complex numbers also works!
let result = v + w;
println!("{:?}", result);
On the side note, I'm also implementing other traits (Sub, Div, Mul, etc.) and having a different issue, but that's another thing.
Link to playground
Thanks #RobinZigmond and #Dogbert!

How can I create bezier like curves instead of lines between multiple points?

This is a relatively complex task for me and I am not fully able to sum it up in the title.
But the problem is this:
I created a audio visualizer that converts raw audio data to a Vec<f32> where the elements in the vector are ordered by ascending frequency starting with 0hz and ending with 20_000hz
But now I have to normalize the vector so that the frequencies are not spaced in a linear way but logarithmically, which is more like how the human hearing works. here is the function that does this:
fn normalize(buffer: Vec<f32>, volume: f32) -> Vec<f32> {
let mut output_buffer: Vec<f32> = vec![0.0; buffer.len()];
let mut start_pos: usize = 0;
let mut end_pos: usize = 0;
for i in 0..buffer.len() {
// FIRST HALF
let offset: f32 = (buffer.len() as f32 / (i + 1) as f32).sqrt();
if ((i as f32 * offset) as usize) < output_buffer.len() {
// normalized position
let pos: usize = (i as f32 * offset) as usize;
// stores positions needed for filling
start_pos = end_pos;
end_pos = pos;
let y = buffer[i];
// prevent volume loss, that could occur because of 'crunching' of higher freqs
// by only setting the value of buffer if y is bigger
if output_buffer[pos] < y {
output_buffer[pos] = y;
}
}
// SECOND HALF
// linear filling of the values between
if end_pos - start_pos > 1 && (end_pos - 1) < output_buffer.len() {
for s_p in (start_pos + 1)..end_pos {
let percentage: f32 = (s_p - start_pos) as f32 / ((end_pos - 1) - start_pos) as f32;
let mut y: f32 = 0.0;
//(output_buffer[s_p] * (1.0 - percentage) ) + (output_buffer[end_pos] * percentage);
y += output_buffer[start_pos] * (1.0 - percentage);
y += output_buffer[end_pos] * percentage;
output_buffer[s_p] = y;
}
}
}
output_buffer
}
In the first half I am reallocating the values of the buffer to be logarithmic, but with this method a lot of values especially in the low frequency range get skipped and then it looks like this: unfilled
|
| |
| |
| | | |
| | | |||
| | | | |||
+----+---+--+-+++
Because of that I found a way to fill in the the gaps in the second half.
now it looks like this: filled
|
:|: |
::|:: :|:
:::|::: ::|:| |
::::|:::|::|:|||
|::::|:::|::|:|||
+----+---+--+-+++
I reduced the amount of bars for the sake of visualisation, the real implementation has about 10 time more 'bars' so the linearity is much more visible there.
So my final problem is that instead of straight lines in between the points I want to create curves, which represent sound much better.
I need to be able to access the 'y' coordinate value of any point of the curve.
Is there any way to do this, or am I doing this totally wrong?
I created audioviz that does all of this processing and where the code is from and audiolizer an application that makes use this libary combined with a GUI.
Splines does solve my exact problem.
here is my implementation with added resolution control and volume normalisation, that may not be neccessary:
use splines::{Interpolation, Key, Spline};
fn normalize(buffer: Vec<f32>, volume: f32, resolution: f32) -> Vec<f32> {
let mut output_buffer: Vec<f32> = vec![0.0; (buffer.len() as f32 * resolution ) as usize ];
let mut pos_index: Vec<(usize, f32)> = Vec::new();
for i in 0..buffer.len() {
let offset: f32 = (output_buffer.len() as f32 / (i + 1) as f32 * resolution).sqrt();
if ((i as f32 * offset) as usize) < output_buffer.len() {
// space normalisation
let pos: usize = (i as f32 * offset) as usize;
// volume normalisation
let volume_offset: f32 = (output_buffer.len() as f32 / (pos + 1) as f32).sqrt();
let y = buffer[i] / volume_offset.powi(3) * 0.01;
pos_index.push( ((pos as f32) as usize, y) );
}
}
// Interpolation
let mut points: Vec<Key<f32, f32>> = Vec::new();
for val in pos_index.iter() {
let x = val.0 as f32;
let y = val.1 * volume;
points.push(Key::new(x, y, Interpolation::Bezier(0.5)));
}
let spline = Spline::from_vec(points);
for i in 0..output_buffer.len() {
let v = match spline.sample(i as f32) {
Some(v) => v,
None => 0.0,
};
output_buffer[i] = v;
}
output_buffer
}

What do letters enclosed by two single quotes next to a function argument mean?

I tried using LAPACK bindings for Rust when I came over some syntax that I could not find anything about.
The example code from https://github.com/stainless-steel/lapack:
let n = 3;
let mut a = vec![3.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 1.0, 3.0];
let mut w = vec![0.0; n];
let mut work = vec![0.0; 4 * n];
let lwork = 4 * n as isize;
let mut info = 0;
lapack::dsyev(b'V', b'U', n, &mut a, n, &mut w, &mut work, lwork, &mut info);
for (one, another) in w.iter().zip(&[2.0, 2.0, 5.0]) {
assert!((one - another).abs() < 1e-14);
}
What does b'V' and b'U' mean?
b'A' means to create a byte literal. Specifically, it will be a u8 containing the ASCII value of the character:
fn main() {
let what = b'a';
println!("{}", what);
// let () = what;
}
The commented line shows you how to find the type.
b"hello" is similar, but produces a reference to an array of u8, a byte string:
fn main() {
let what = b"hello";
println!("{:?}", what);
// let () = what;
}
Things like this are documented in the Syntax Index which is currently only available in the nightly version of the docs.
It creates a u8 value with the ASCII value of the char between quote.
For ASCII literals, it's the same as writing 'V' as u8.
Also, the b prefix on a double quoted string will create a byte array containing the UTF8 content of the string.
let s: &[u8; 11] = b"Hello world";

Explicitly stating the type of vector length for references

I'm trying to get my head around Rust and I'm being faced with a probably obvious error.
I have found a method which computes the dot product of two vectors and I want to implement it so that I do not need to consume the vectors to do so. Right now it looks like the following:
pub fn dot(&u: Vec<f32>, &v: Vec<f32>) -> f32 {
let len = cmp::min(u.len(), v.len());
let mut xs = &u[..len];
let mut ys = &v[..len];
let mut s = 0.;
let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) =
(0., 0., 0., 0., 0., 0., 0., 0.);
while xs.len() >= 8 {
p0 += xs[0] * ys[0];
p1 += xs[1] * ys[1];
p2 += xs[2] * ys[2];
p3 += xs[3] * ys[3];
p4 += xs[4] * ys[4];
p5 += xs[5] * ys[5];
p6 += xs[6] * ys[6];
p7 += xs[7] * ys[7];
xs = &xs[8..];
ys = &ys[8..];
}
s += p0 + p4;
s += p1 + p5;
s += p2 + p6;
s += p3 + p7;
for i in 0..xs.len() {
s += xs[i] * ys[i];
}
s
}
The problem occurs in the first line of the function body: the compiler cannot infer the type of u.len() as u is a reference.
How can I work around this? Is it possible to explicitly state the type?
The problem as stated does not exist. The error the above code produces is:
<anon>:3:16: 3:18 error: mismatched types:
expected `collections::vec::Vec<f32>`,
found `&_`
(expected struct `collections::vec::Vec`,
found &-ptr) [E0308]
<anon>:3 pub fn dot(&u: Vec<f32>, &v: Vec<f32>) -> f32 {
^~
<anon>:3:16: 3:18 help: see the detailed explanation for E0308
&u: Vec<f32> cannot work; this says that u should be bound to the contents of a pointer... which is impossible given the parameter is of type Vec<f32>. I suspect you meant to say u: &Vec<f32>.
But you shouldn't do that, either. There's effectively no reason to ever pass a &Vec<_> when you can just pass a &[_] instead, which will work for more types. So what you really want is u: &[f32].
Once you fix both arguments, the code compiles with no errors.

Resources