use serde_json::{json, Value};
pub fn penrose(center_x: f64, center_y: f64, size: f64) -> Value {
let s = size;
let v1_x = center_x;
let v1_y = center_y - s * 0.577;
let v2_x = center_x - s * 0.5;
let v2_y = center_y + s * 0.289;
let v3_x = center_x + s * 0.5;
let v3_y = center_y + s * 0.289;
let thick = s * 0.15;
let lines = vec![
json!([
v1_x - thick * 0.3,
v1_y - thick * 0.5,
v2_x + thick * 0.5,
v2_y - thick * 0.3,
]),
json!([
v1_x + thick * 0.3,
v1_y - thick * 0.5,
v2_x - thick * 0.5,
v2_y + thick * 0.3,
]),
json!([
v2_x + thick * 0.5,
v2_y - thick * 0.3,
v3_x - thick * 0.5,
v3_y - thick * 0.3,
]),
json!([
v2_x + thick * 0.5,
v2_y + thick * 0.3,
v3_x - thick * 0.5,
v3_y + thick * 0.3,
]),
json!([
v3_x + thick * 0.3,
v3_y - thick * 0.5,
v1_x + thick * 0.3,
v1_y + thick * 0.5,
]),
json!([
v3_x - thick * 0.3,
v3_y + thick * 0.5,
v1_x - thick * 0.3,
v1_y + thick * 0.5,
]),
json!([
v1_x - thick * 0.3,
v1_y - thick * 0.5,
v1_x - thick * 0.3,
v1_y + thick * 0.5,
]),
json!([
v1_x + thick * 0.3,
v1_y - thick * 0.5,
v1_x + thick * 0.3,
v1_y + thick * 0.5,
]),
json!([
v2_x - thick * 0.5,
v2_y - thick * 0.3,
v2_x - thick * 0.5,
v2_y + thick * 0.3,
]),
json!([
v2_x + thick * 0.5,
v2_y - thick * 0.3,
v2_x + thick * 0.5,
v2_y + thick * 0.3,
]),
json!([
v3_x - thick * 0.5,
v3_y - thick * 0.3,
v3_x - thick * 0.5,
v3_y + thick * 0.3,
]),
json!([
v3_x + thick * 0.5,
v3_y - thick * 0.3,
v3_x + thick * 0.5,
v3_y + thick * 0.3,
]),
];
json!(lines)
}
pub fn impossible_cube(center_x: f64, center_y: f64, size: f64) -> Value {
let s = size * 0.5;
let f_bl_x = center_x - s; let f_bl_y = center_y + s;
let f_br_x = center_x + s; let f_br_y = center_y + s;
let f_tl_x = center_x - s; let f_tl_y = center_y - s;
let f_tr_x = center_x + s; let f_tr_y = center_y - s;
let offset = s * 0.6;
let b_bl_x = center_x - s + offset; let b_bl_y = center_y + s - offset;
let b_br_x = center_x + s + offset; let b_br_y = center_y + s - offset;
let b_tl_x = center_x - s + offset; let b_tl_y = center_y - s - offset;
let b_tr_x = center_x + s + offset; let b_tr_y = center_y - s - offset;
let lines = vec![
json!([f_bl_x, f_bl_y, f_br_x, f_br_y]), json!([f_br_x, f_br_y, f_tr_x, f_tr_y]), json!([f_tr_x, f_tr_y, f_tl_x, f_tl_y]), json!([f_tl_x, f_tl_y, f_bl_x, f_bl_y]), json!([b_bl_x, b_bl_y, b_br_x, b_br_y]), json!([b_br_x, b_br_y, b_tr_x, b_tr_y]), json!([b_tr_x, b_tr_y, b_tl_x, b_tl_y]), json!([b_tl_x, b_tl_y, b_bl_x, b_bl_y]), json!([f_bl_x, f_bl_y, b_bl_x, b_bl_y]),
json!([f_br_x, f_br_y, b_br_x, b_br_y]),
json!([f_tl_x, f_tl_y, b_tl_x, b_tl_y]),
json!([f_tr_x, f_tr_y, b_tr_x, b_tr_y]),
json!([f_bl_x + s * 0.3, f_bl_y, b_bl_x - s * 0.3, b_bl_y]),
json!([f_tr_x - s * 0.3, f_tr_y, b_tr_x + s * 0.3, b_tr_y]),
];
json!(lines)
}
pub fn spiral(center_x: f64, center_y: f64, turns: i32, radius: f64, points: i32) -> Value {
let mut points_arr = Vec::new();
let total_points = turns * points;
for i in 0..total_points {
let t = (i as f64) / (total_points as f64); let angle = t * turns as f64 * 2.0 * std::f64::consts::PI;
let r = t * radius;
let x = center_x + r * angle.cos();
let y = center_y + r * angle.sin();
points_arr.push(json!([x, y]));
}
json!(points_arr)
}
pub fn muller_lyer(center_x: f64, center_y: f64, length: f64) -> Value {
let half = length / 2.0;
let arrow_size = length * 0.15;
let mut lines = Vec::new();
let y1 = center_y - length * 0.3;
lines.push(json!([center_x - half, y1, center_x + half, y1]));
lines.push(json!([
center_x - half,
y1,
center_x - half + arrow_size,
y1 - arrow_size * 0.6
]));
lines.push(json!([
center_x - half,
y1,
center_x - half + arrow_size,
y1 + arrow_size * 0.6
]));
lines.push(json!([
center_x + half,
y1,
center_x + half - arrow_size,
y1 - arrow_size * 0.6
]));
lines.push(json!([
center_x + half,
y1,
center_x + half - arrow_size,
y1 + arrow_size * 0.6
]));
let y2 = center_y + length * 0.3;
lines.push(json!([center_x - half, y2, center_x + half, y2]));
lines.push(json!([
center_x - half,
y2,
center_x - half - arrow_size,
y2 - arrow_size * 0.6
]));
lines.push(json!([
center_x - half,
y2,
center_x - half - arrow_size,
y2 + arrow_size * 0.6
]));
lines.push(json!([
center_x + half,
y2,
center_x + half + arrow_size,
y2 - arrow_size * 0.6
]));
lines.push(json!([
center_x + half,
y2,
center_x + half + arrow_size,
y2 + arrow_size * 0.6
]));
json!(lines)
}
pub fn ponzo(
center_x: f64,
center_y: f64,
height: f64,
width_top: f64,
width_bottom: f64,
) -> Value {
let mut lines = Vec::new();
let top_y = center_y - height / 2.0;
let bottom_y = center_y + height / 2.0;
lines.push(json!([
center_x - width_top / 2.0,
top_y,
center_x - width_bottom / 2.0,
bottom_y
]));
lines.push(json!([
center_x + width_top / 2.0,
top_y,
center_x + width_bottom / 2.0,
bottom_y
]));
let top_line_width = width_top * 0.8;
let bottom_line_width = width_bottom * 0.8;
lines.push(json!([
center_x - top_line_width / 2.0,
top_y + height * 0.2,
center_x + top_line_width / 2.0,
top_y + height * 0.2
]));
lines.push(json!([
center_x - bottom_line_width / 2.0,
bottom_y - height * 0.2,
center_x + bottom_line_width / 2.0,
bottom_y - height * 0.2
]));
let mid_y = (top_y + bottom_y) / 2.0;
let mid_line_width = (width_top + width_bottom) * 0.4;
lines.push(json!([
center_x - mid_line_width / 2.0,
mid_y,
center_x + mid_line_width / 2.0,
mid_y
]));
lines.push(json!([
center_x - mid_line_width / 2.0 * 0.5,
mid_y + height * 0.15,
center_x + mid_line_width / 2.0 * 0.5,
mid_y + height * 0.15
]));
json!(lines)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_penrose_returns_lines() {
let result = penrose(400.0, 300.0, 100.0);
let lines = result.as_array().unwrap();
assert!(!lines.is_empty());
assert!(lines.len() >= 10);
let first_line = lines[0].as_array().unwrap();
assert_eq!(first_line.len(), 4);
}
#[test]
fn test_impossible_cube_returns_lines() {
let result = impossible_cube(400.0, 300.0, 100.0);
let lines = result.as_array().unwrap();
assert!(!lines.is_empty());
assert!(lines.len() >= 12);
let first_line = lines[0].as_array().unwrap();
assert_eq!(first_line.len(), 4);
}
#[test]
fn test_spiral_returns_points() {
let result = spiral(400.0, 300.0, 3, 100.0, 20);
let points = result.as_array().unwrap();
assert_eq!(points.len(), 60);
let first_point = points[0].as_array().unwrap();
assert_eq!(first_point.len(), 2); }
#[test]
fn test_muller_lyer_returns_lines() {
let result = muller_lyer(400.0, 300.0, 200.0);
let lines = result.as_array().unwrap();
assert_eq!(lines.len(), 10);
let first_line = lines[0].as_array().unwrap();
assert_eq!(first_line.len(), 4);
}
#[test]
fn test_ponzo_returns_lines() {
let result = ponzo(400.0, 300.0, 300.0, 100.0, 300.0);
let lines = result.as_array().unwrap();
assert_eq!(lines.len(), 6);
let first_line = lines[0].as_array().unwrap();
assert_eq!(first_line.len(), 4);
}
#[test]
fn test_spiral_center_point() {
let result = spiral(400.0, 300.0, 1, 100.0, 10);
let points = result.as_array().unwrap();
let first_point = points[0].as_array().unwrap();
let x = first_point[0].as_f64().unwrap();
let y = first_point[1].as_f64().unwrap();
assert!((x - 400.0).abs() < 1.0); assert!((y - 300.0).abs() < 1.0);
}
#[test]
fn test_spiral_outer_point() {
let result = spiral(400.0, 300.0, 1, 100.0, 10);
let points = result.as_array().unwrap();
let last_point = points[points.len() - 1].as_array().unwrap();
let x = last_point[0].as_f64().unwrap();
let y = last_point[1].as_f64().unwrap();
let dist = ((x - 400.0).powi(2) + (y - 300.0).powi(2)).sqrt();
assert!(dist > 80.0 && dist < 120.0); }
}