use ordered_float::*;
use axgeom::*;
use dists;
#[derive(Copy, Clone, Debug)]
pub struct BotProp {
pub radius: Dist,
pub collision_push: f32,
pub collision_drag: f32,
pub minimum_dis_sqr: f32,
pub viscousity_coeff: f32,
}
impl BotProp {
#[inline(always)]
pub fn create_bbox_i32(&self, pos: Vec2<i32>) -> Rect<i32> {
let p = pos;
let r = self.radius.dis() as i32;
Rect::new(p.x - r, p.x + r, p.y - r, p.y + r)
}
#[inline(always)]
pub fn create_bbox(&self, pos: Vec2<f32>) -> Rect<f32> {
let p = pos;
let r = self.radius.dis();
Rect::new(p.x - r, p.x + r, p.y - r, p.y + r)
}
#[inline(always)]
pub fn create_bbox_nan(&self, pos: Vec2<f32>) -> Rect<NotNan<f32>> {
self.create_bbox(pos).inner_try_into().unwrap()
}
#[inline(always)]
pub fn liquid(&self, a: &mut Bot, b: &mut Bot) {
let diff = b.pos - a.pos;
let dis_sqr = diff.magnitude2();
if dis_sqr < 0.0001 {
a.acc += vec2(0.1, 0.0);
b.acc -= vec2(0.1, 0.0);
return;
}
if dis_sqr >= self.radius.dis2_squared() {
return;
}
let dis = dis_sqr.sqrt();
let d = 1.0 - (dis / (self.radius.dis2()));
let spring_force_mag = -(d - 0.5) * 0.02;
let velociy_diff = b.vel - a.vel;
let damping_ratio = 0.0002;
let spring_dampen = velociy_diff.dot(diff) * (1. / dis) * damping_ratio;
let spring_force = diff * (1. / dis) * (spring_force_mag + spring_dampen);
a.acc += spring_force;
b.acc -= spring_force;
}
pub fn collide(&self, bota: &mut Bot, botb: &mut Bot) {
#[inline(always)]
pub fn handle_repel(input: f32) -> f32 {
let a = 3.0 * input * input;
a.min(1.0)
}
let prop = self;
let offset = bota.pos - botb.pos;
let dis_sqr = offset.magnitude2();
if dis_sqr >= prop.radius.dis2_squared() {
return;
}
if dis_sqr < 0.00001 {
bota.acc += vec2(0.1, 0.1);
botb.acc -= vec2(0.1, 0.1);
return;
}
let sum_rad = prop.radius.dis2();
let disinv = 1.0 / dis_sqr.sqrt();
let dd = 1.0 - 1.0 / (sum_rad * disinv);
let ammount_touching = handle_repel(dd);
let push_mag = ammount_touching * prop.collision_push;
let velocity_diff = bota.vel - botb.vel;
let drag = -prop.collision_drag * ammount_touching * velocity_diff.dot(offset);
let push1 = drag + push_mag;
let push2 = -drag - push_mag;
let push_force1 = offset * (push1 * disinv);
let push_force2 = offset * (push2 * disinv);
let viscous = velocity_diff * (-prop.viscousity_coeff * ammount_touching);
bota.acc += push_force1;
bota.acc += viscous;
botb.acc += push_force2;
botb.acc += viscous;
}
#[inline(always)]
pub fn collide_mouse(&self, bot: &mut Bot, mouse: &Mouse) {
let prop = self;
let offset = *mouse.get_midpoint() - bot.pos;
let dis_sqr = offset.magnitude2();
let sum_rad = mouse.get_radius() + prop.radius.dis();
if dis_sqr < sum_rad * sum_rad {
let dis = dis_sqr.sqrt();
if dis < 0.0001 {
return;
}
let vv = (sum_rad - dis) / sum_rad;
let vv = vv * vv;
let vv2 = (5.0 * vv).min(1.0);
let push_mag = vv2 * mouse.mouse_prop.force;
let push_force = offset * (push_mag / dis);
bot.acc += -push_force;
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct Bot {
pub pos: Vec2<f32>,
pub vel: Vec2<f32>,
pub acc: Vec2<f32>,
}
impl crate::BorderCollideTrait for Bot {
type N = f32;
#[inline(always)]
fn pos_vel_mut(&mut self) -> (&mut Vec2<f32>, &mut Vec2<f32>) {
(&mut self.pos, &mut self.vel)
}
}
impl Bot {
#[inline(always)]
pub fn move_to_point(&mut self,target:Vec2<f32>,radius:f32) -> bool
{
let mut force = ((target-self.pos)*0.02).truncate_at(1.0) - self.vel;
self.acc+=force.truncate_at(0.01);
let speed=self.vel.magnitude();
let k=speed.min(radius)*0.9;
let position_check = (target-self.pos).magnitude()+k<=radius;
position_check }
#[inline(always)]
pub fn update(&mut self){
let bot=self;
bot.pos+=bot.vel;
bot.vel+=bot.acc;
bot.acc=vec2(0.0,0.0);
}
#[inline(always)]
pub fn create_bbox(&self, bot_scene: &BotProp) -> Rect<f32> {
let p = self.pos;
let r = bot_scene.radius.dis();
Rect::new(p.x - r, p.x + r, p.y - r, p.y + r)
}
#[inline(always)]
pub fn create_bbox_nan(&self, bot_scene: &BotProp) -> Rect<NotNan<f32>> {
self.create_bbox(bot_scene).inner_try_into().unwrap()
}
#[inline(always)]
pub fn new(pos: Vec2<f32>) -> Bot {
let vel = vec2(0.0, 0.0);
let acc = vec2(0.0, 0.0);
Bot { pos, vel, acc }
}
#[inline(always)]
pub fn push_away(&mut self, b: &mut Self, radius: f32, max_amount: f32) {
let mut diff = b.pos - self.pos;
let dis = diff.magnitude2().sqrt();
if dis < 0.000_001 {
return;
}
let mag = max_amount.min(radius * 2.0 - dis);
if mag < 0.0 {
return;
}
diff *= mag / dis;
self.acc -= diff;
b.acc += diff;
{}
}
}
#[derive(Copy, Clone, Debug)]
pub struct MouseProp {
pub radius: Dist,
pub force: f32,
}
#[derive(Copy, Clone, Debug)]
pub struct Mouse {
pub mouse_prop: MouseProp,
pub midpoint: Vec2<f32>,
pub rect: axgeom::Rect<f32>,
}
impl Mouse {
#[inline(always)]
pub fn new(midpoint: Vec2<f32>, mouse_prop: MouseProp) -> Mouse {
let r = vec2same(mouse_prop.radius.dis());
Mouse {
mouse_prop,
midpoint,
rect: Rect::from_point(midpoint, r),
}
}
#[inline(always)]
pub fn get_rect(&self) -> &axgeom::Rect<f32> {
&self.rect
}
#[inline(always)]
pub fn get_midpoint(&self) -> &Vec2<f32> {
&self.midpoint
}
#[inline(always)]
pub fn get_radius(&self) -> f32 {
self.mouse_prop.radius.dis()
}
#[inline(always)]
pub fn move_to(&mut self, pos: Vec2<f32>) {
self.midpoint = pos;
let p = self.midpoint;
let r = self.mouse_prop.radius.dis();
let r = axgeom::Rect::new(p.x - r, p.x + r, p.y - r, p.y + r);
self.rect = r;
}
}
#[derive(Copy, Clone, Debug)]
pub struct Dist {
dis: f32,
dis2: f32,
dis2_squared: f32,
}
impl Dist {
#[inline(always)]
pub fn new(dis: f32) -> Dist {
let k = dis * 2.0;
Dist {
dis,
dis2: k,
dis2_squared: k.powi(2),
}
}
#[inline(always)]
pub fn dis(&self) -> f32 {
self.dis
}
#[inline(always)]
pub fn dis2(&self) -> f32 {
self.dis2
}
#[inline(always)]
pub fn dis2_squared(&self) -> f32 {
self.dis2_squared
}
}
pub struct BotScene<T> {
pub bot_prop: BotProp,
pub bots: Vec<T>,
}
#[derive(Copy, Clone, Debug)]
pub struct BotSceneBuilder {
grow: f32,
radius: f32,
num: usize,
bot_radius: f32,
}
impl BotSceneBuilder {
pub fn new(num: usize) -> BotSceneBuilder {
BotSceneBuilder {
grow: 0.2,
radius: 17.0,
num,
bot_radius: 5.0,
}
}
pub fn with_grow(&mut self, grow: f32) -> &mut Self {
self.grow = grow;
self
}
pub fn with_num(&mut self, num: usize) -> &mut Self {
self.num = num;
self
}
pub fn with_radius_of(&mut self, radius: f32) -> &mut Self {
self.radius = radius;
self
}
pub fn build_specialized<T>(&mut self, mut func: impl FnMut(Vec2<f32>) -> T) -> BotScene<T> {
let spiral = dists::spiral::Spiral::new([0.0, 0.0], self.radius, self.grow);
let bots: Vec<T> = spiral.take(self.num).map(|pos| func(pos)).collect();
let bot_prop = BotProp {
radius: Dist::new(self.bot_radius),
collision_push: 0.1,
collision_drag: 0.1,
minimum_dis_sqr: 0.0001,
viscousity_coeff: 0.1,
};
BotScene { bot_prop, bots }
}
pub fn build(&mut self) -> BotScene<Bot> {
let spiral = dists::spiral::Spiral::new([0.0, 0.0], self.radius, self.grow);
let bots: Vec<Bot> = spiral.take(self.num).map(|pos| Bot::new(pos)).collect();
let bot_prop = BotProp {
radius: Dist::new(self.bot_radius),
collision_push: 0.1,
collision_drag: 0.1,
minimum_dis_sqr: 0.0001,
viscousity_coeff: 0.1,
};
BotScene { bot_prop, bots }
}
}