Merge pull request #1 from shadow8t4/development

Most features are working from the original.
Next steps are to generate and map the noise generated height values and clean up and modularize input parameters.
This commit is contained in:
Alex Huddleston 2017-11-18 15:30:24 -06:00 committed by GitHub Enterprise
commit 06c99b00f4
3 changed files with 14643 additions and 3 deletions

View file

@ -9,3 +9,4 @@ license = "MIT"
[dependencies]
obj = "0.8"
noise = "0.4"
cgmath = "0.15.0"

14440
data/noice.obj Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,23 @@
// REralCity
// Alex Huddleston / Jeremy Martin
extern crate obj;
extern crate noise;
extern crate cgmath;
use std::io::Result;
use std::path::Path;
use obj::{Obj, SimplePolygon};
use std::f32::consts::PI;
use std::fs::File;
use std::io::Write;
use obj::{Obj, SimplePolygon, IndexTuple};
use noise::Fbm;
use noise::Seedable;
use noise::MultiFractal;
use noise::NoiseModule;
use cgmath::Vector3;
use cgmath::ElementWise;
use cgmath::Array;
// A function called test that takes in 1 32-bit integer
// and returns a 32-bit integer.
@ -27,13 +41,198 @@ fn test(x: i32) -> i32 {
}
*/
fn distance_a_to_b(ax: f64, ay: f64, bx: f64, by: f64) -> f64 {
((bx - ax) * (bx - ax) + (by - ay) * (by - ay)).sqrt()
}
fn noise_map(seed: usize, oct: usize, freq: f64, lacu: f64, pers: f64) -> Fbm<f64> {
Fbm::new()
.set_seed(seed)
.set_octaves(oct)
.set_frequency(freq)
.set_lacunarity(lacu)
.set_persistence(pers)
}
fn return_at(x: f64, y: f64, fbmnoise: &Fbm<f64>) -> f64 {
let n = 20.0 * fbmnoise.get([x, y]);
let n = n - n.floor();
let m = distance_a_to_b(x, y, 0.5, 0.5);
return (m * 0.15) + (n * 0.85);
}
fn find_l_w(obj: &Obj<SimplePolygon>) -> (f32, f32) {
if let Some(first) = obj.position.first() {
let initial = (first[0], first[1], first[0], first[1]);
let min_maxes = obj.position.iter().fold(initial, |mut acc, point| {
if acc.0 > point[0] {
acc.0 = point[0];
} else if acc.2 < point[0] {
acc.2 = point[0];
}
if acc.1 > point[1] {
acc.1 = point[1];
} else if acc.3 < point[1] {
acc.3 = point[1];
}
acc
});
(min_maxes.2 - min_maxes.0, min_maxes.3 - min_maxes.1)
} else {
(0.0, 0.0)
}
}
/*
* The current layer is how many iterations you are from the center,
* the count is how far around the square you've gone on the current layer.
* This outputs the angle at which to place the new duplicate relative
* to the initial input obj's position.
*/
fn calculate_angle(current_duplicate: i32, current_layer: i32) -> f32 {
(current_duplicate / (2 * current_layer)) as f32 * (0.5 * PI)
}
fn calculate_translation(current_layer: i32, length: f32, width: f32, angle: f32) -> Vector3<f32> {
Vector3::new(length * angle.cos(), width * angle.sin(), 0.0)
}
fn duplicate(
positions: Vec<Vector3<f32>>,
translation: Vector3<f32>,
height_vec: Vector3<f32>,
) -> Vec<Vector3<f32>> {
positions
.iter()
.map(|point| {
//height_vec.mul_element_wise(point.clone()) + translation
point.clone() + translation
})
.collect()
}
fn generate_city(
positions: Vec<Vector3<f32>>,
layers: i32,
spacing: f32,
length: f32,
width: f32,
) -> Vec<Vector3<f32>> {
let length = length + spacing;
let width = width + spacing;
let mut temp = Vector3::new(0.0, 0.0, 0.0);
//let mut coord = Vector3::new(0.0, 0.0, 0.0);
(1..layers).fold(positions.clone(), |acc_positions, current_layer| {
temp.x = -length * (current_layer as f32);
temp.y = -width * (current_layer as f32);
(0..(current_layer * 8)).fold(acc_positions, |mut acc_positions, current_duplicate| {
let angle = calculate_angle(current_duplicate, current_layer);
let translation = calculate_translation(current_layer, length, width, angle);
temp += translation;
let height_vec = Vector3::new(1.0, 1.0, 1.0);
let x = Vector3::new(1.0, 1.0, 1.0);
acc_positions.extend(duplicate(positions.clone(), temp, height_vec));
acc_positions
})
})
}
fn copy_faces(
faces: Vec<Vec<IndexTuple>>,
n_positions: usize,
layers: usize,
) -> Vec<Vec<IndexTuple>> {
(0..(2 * layers - 1).pow(2)).fold(Vec::new(), |mut acc_faces, current_value| {
let offset = n_positions * current_value + 1;
acc_faces.extend(faces.iter().map(|current_face| {
current_face
.iter()
.map(|index_tuple| {
IndexTuple(
index_tuple.0 + offset,
index_tuple.1.map(|i| i + offset),
index_tuple.2.map(|j| j + offset),
)
})
.collect()
}));
acc_faces
})
}
fn save(filename: &Path, positions: Vec<Vector3<f32>>, faces: Vec<Vec<IndexTuple>>) {
let mut file = File::create(filename).unwrap();
for pos in positions {
write!(file, "v {} {} {}\n", pos[0], pos[1], pos[2]).unwrap();
}
for face in faces {
write!(file, "f");
for value in face {
write!(file, " {}/", value.0).unwrap();
if let Some(i) = value.1 {
write!(file, "{}", i).unwrap();
}
write!(file, "/").unwrap();
if let Some(j) = value.2 {
write!(file, "{}", j).unwrap();
}
}
write!(file, "\n").unwrap();
}
}
fn main() {
let path = Path::new("data/teapot.obj");
let path = Path::new("data/test.obj");
let maybe_obj: Result<Obj<SimplePolygon>> = Obj::load(&path);
if let Ok(obj) = maybe_obj {
println!("Postiion: {:?}", obj.position);
println!("Position: {:?}", obj.position);
let layers = 10;
let spacing = 1.0;
let (length, width) = find_l_w(&obj);
println!("Length: {} Width: {}", length, width);
let input_positions = obj.position
.iter()
.map(|point| Vector3::new(point[0], point[1], point[2]))
.collect();
let output_positions = generate_city(input_positions, layers, spacing, length, width);
println!("Objects: {:?}", obj.objects[0].groups[0].polys[0]);
// I have two faces, blurry's the one I'm not.
let output_faces = copy_faces(
obj.objects[0].groups[0].polys.clone(),
obj.position.len(),
layers as usize,
);
save(Path::new("data/noice.obj"), output_positions, output_faces);
}
/*
else if Err(error) = maybe_obj {