Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add l-systems #30

Merged
merged 3 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Hello, World!
- [ ] parse a limited number of shapes from svg files (WIP).
- [x] add more organic ways to generate images, such as voronoi diagrams
- [ ] adapt composition things to work with voronoi diagrams
- [ ] experiment with L-systems.
- [x] experiment with L-systems.
- [ ] add noise generator
- [ ] add camera input, so the generated art can be a reaction to what already is on paper.
- [ ] project layout that allows for easy transitions between creating art work with lots of predefined functions, writing custom parts for the frame work and switching between different works of art.
Expand All @@ -29,9 +29,21 @@ Hello, World!

## Changes, Thoughts and Learnings (newest first)

### October 29th, 2023

I added a basic implementation of L-Systems, as described here [https://paulbourke.net/fractals/lsys/]. I omitted rules about filled polygons, and will add more rules about shapes that are already present in the lib. There is also a need for more randomness in the parameters.
<figure>
<img
src="https://github.com/Mirabellensaft/sanguine/blob/main/output/images/image_00016.png"
width="300"
height="300"
alt="A generated Tree">
<figcaption>A generated Tree.</figcaption>
</figure>

### October 15th, 2023

New shape dropped. Circloid.
New shape dropped. The Circloid.
<figure>
<img
src="https://github.com/Mirabellensaft/sanguine/blob/main/output/images/image_00014.png"
Expand Down
1 change: 1 addition & 0 deletions output/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ svg = "0.14.0"
sanguine_lib = { path = "../sanguine_lib" }
voronator = "0.2.1"
chrono = "0.4.31"
lsystem = "0.2.1"


Binary file added output/images/image_00016.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions output/src/work/lsys_1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use lsystem::{LSystem, MapRules};
use sanguine_lib::resources::layout::grid::Grid;
use sanguine_lib::resources::lsystems::{State, SystemState};
use sanguine_lib::resources::shapes::point::Point;

use std::f32::consts::PI;
use svg::node::element::Group;

pub fn form_group(work: Grid) -> Group {
let graph = Group::new();

// Set rules for the L-System
let mut rules = MapRules::new();
rules.set_str('F', "FF");
rules.set_str('X', "F-[[X]+X]+F[+FX]-X");
let axiom = "X".chars().collect();
let lsystem = LSystem::new(rules, axiom);
let iteration = 7;

// Set starting properties
let start = Point::new(600.0, 1200.0);
let length = 20.0;
let length_increment = 20.0;
let turning_angle = (PI / 2.0) / 3.0;
let turning_angle_increment = 20.0;
let current_direction = 3.0 * (PI / 2.0);
let reverse = false;

let state = State::new(
start,
length,
length_increment,
turning_angle,
turning_angle_increment,
current_direction,
reverse,
);

let system_state = SystemState::new(state);
system_state.form_system(graph, iteration, lsystem)
}
1 change: 1 addition & 0 deletions output/src/work/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod blocks;
pub mod lsys_1;
pub mod mush;
pub mod mushroom;
pub mod star_burst;
Expand Down
1 change: 1 addition & 0 deletions sanguine_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ svg = "0.14.0"
usvg = "0.36.0"
geo = "0.27.0"
voronator = "0.2.1"
lsystem = "0.2.1"


193 changes: 193 additions & 0 deletions sanguine_lib/src/resources/lsystems/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
use crate::resources::shapes::point::Point;
use crate::resources::shapes::{circle::Circle, line::Line};
use lsystem::{LSystem, MapRules};
use std::f32::consts::PI;
use svg::node::element::Group;
use svg::Node;

/// This module implements applicable rules for L Systems described here https://paulbourke.net/fractals/lsys/.

/// This struct captures the current state of the Drawing. It is first defined with the starting properties.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct State {
start: Point,
length: f32,
length_increment: f32,
/// Angles in radians
turning_angle: f32,
turning_angle_increment: f32,

current_direction: f32,
/// default: false
reverse: bool,
}

impl State {
pub fn new(
start: Point,
length: f32,
length_increment: f32,
turning_angle: f32,
turning_angle_increment: f32,
current_direction: f32,
reverse: bool,
) -> Self {
let state = State {
start: start,
length: length,
length_increment: length_increment,

turning_angle: turning_angle,
turning_angle_increment: turning_angle_increment,

current_direction: current_direction,
reverse: reverse,
};
state
}
}

/// This Type serves as a stack for the different states, so it is possible to go back to a certain point.
pub struct SystemState(Vec<Vec<State>>);

impl SystemState {
pub fn new(state: State) -> Self {
let mut system_state: Vec<Vec<State>> = Vec::new();
let vec = vec![state];
system_state.push(vec);
SystemState(system_state)
}
/// Gets the last added state.
fn get_state(&self) -> State {
let index = self.0.len() - 1;
let state_keep = &self.0[index];
let state = state_keep[state_keep.len() - 1];
state
}

/// Updates the system with the new state
fn update_state(&mut self, state: State) {
let length = self.0.len() - 1;
let state_keep = &mut self.0[length];
state_keep.push(state);
}

/// Turns the string of chars that represent rules into a graphical representation.
pub fn form_system(
mut self,
mut graph: Group,
iteration: usize,

mut lsystem: LSystem<char, MapRules<char>>,
) -> Group {
let mut out: Vec<char> = Vec::new();
for _i in 1..iteration {
out = lsystem.next().unwrap();
}

for item in out {
match item {
'F' => {
let mut state = self.get_state();

let x = state.length * f32::cos(state.current_direction);
let y = state.length * f32::sin(state.current_direction);
let end = Point::new(state.start.x + x, state.start.y + y);
let line = Line::new(state.start, end);
graph.append(line.draw());
state.start = end;
self.update_state(state);
}

'f' => {
let mut state = self.get_state();
let x = state.length * f32::cos(state.current_direction);
let y = state.length * f32::sin(state.current_direction);
let end = Point::new(state.start.x + x, state.start.y + y);
state.start = end;
self.update_state(state);
}

'-' => {
let mut state = self.get_state();
if state.reverse == true {
state.current_direction = state.current_direction + state.turning_angle;
} else {
state.current_direction = state.current_direction - state.turning_angle;
}
self.update_state(state);
}
'+' => {
let mut state = self.get_state();
if state.reverse == true {
state.current_direction = state.current_direction - state.turning_angle;
} else {
state.current_direction = state.current_direction + state.turning_angle;
}
self.update_state(state);
}

'|' => {
let mut state = self.get_state();
state.current_direction = state.current_direction + PI;
self.update_state(state);
}

'[' => {
let state = self.get_state();
let vec = vec![state];
self.0.push(vec);
}

']' => {
self.0.pop().unwrap();
}
'@' => {
// dot
let state = self.get_state();
let circle = Circle::new(state.start, 5.0);
graph.append(circle.draw());
self.update_state(state);
}
'>' => {
// increase line length
let mut state = self.get_state();
state.length = state.length + state.length_increment;
self.update_state(state);
}
'<' => {
// decrease line length;
let mut state = self.get_state();
state.length = state.length - state.length_increment;
self.update_state(state);
}

'&' => {
// swap meaning of + and -
let mut state = self.get_state();
if state.reverse == false {
state.reverse = true;
} else {
state.reverse = false;
}
self.update_state(state);
}
'(' => {
// decrease turning angle;
let mut state = self.get_state();
state.turning_angle = state.turning_angle - state.turning_angle_increment;
self.update_state(state);
}
')' => {
// increase turning angle;
let mut state = self.get_state();
state.turning_angle = state.turning_angle - state.turning_angle_increment;
self.update_state(state);
}
_ => (),
}
}

graph
}
}
1 change: 1 addition & 0 deletions sanguine_lib/src/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ pub mod shapes;
pub mod exclusion;

pub mod errors;
pub mod lsystems;
Loading