1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//! block, the smallest rigid body unit in the project, used to construct blobs

use bevy::prelude::*;
use bevy_rapier2d::prelude::*;

use crate::{componet::{ColliderFlag, BlobEntityIndex}, consts::{DEFAULT_DAMPING_LINEAR, DEFAULT_DAMPING_ANGULAR}};

#[derive(Component)]
pub struct CenterBlockFlag;

/// Anchor points that other joints can connect to.
#[derive(Component, Clone, Debug)]
pub struct BlockAnchors {
    pub top: Vec2,
    pub bottom: Vec2,
    pub left: Vec2,
    pub right: Vec2,
}

impl BlockAnchors {
    pub fn from_xy(dx: f32, dy: f32) -> Self {
        Self {
            top: Vec2 { x: 0.0, y: dy },
            bottom: Vec2 { x: 0.0, y: -dy },
            left: Vec2 { x: -dx, y: 0.0 },
            right: Vec2 { x: dx, y: 0.0 },
        }
    }
}

/// BlockDepth is a u32 which represent the depth of the block
/// in the blob tree
///
/// Depth determines the processing order of Neural Network
#[derive(Component, Clone, Debug)]
pub struct BlockDepth(pub u32);


/// ParentAnchor can only be 0(up), 1(down), 2(left), 3(right)
/// 
/// Considering using enum
#[derive(Component, Clone, Debug)]
pub struct ParentAnchor(pub Option<usize>);

/// id for relate Neuron
#[derive(Component, Clone, Debug)]
pub struct NeuronId{
    pub id:usize,
    pub parent_id:Option<usize>
}

impl Default for NeuronId {
    fn default() -> Self {
        Self { id: 0, parent_id: None }
    }
}

impl NeuronId {
    pub fn new(id:usize, parent_id:Option<usize>) -> Self {
        Self { id: id, parent_id: parent_id }
    }
}

/// JointInfor for joint sensors
#[derive(Component, Clone)]
pub struct JointInfo{
    pub ang_pos:f32,
    pub ang_velocity:f32,
}

impl JointInfo {
    pub fn update(&mut self,pos:f32,v:f32){
        self.ang_pos=pos;
        self.ang_velocity=v;
    }
}

/// PhysiBlockBundle is the smallest unit in this simulation.
/// It is the cubiod that construct blobs.
#[derive(Bundle, Clone)]
pub struct PhysiBlockBundle {
    // basic config
    pub sprite: SpriteBundle,
    pub collider: Collider,
    pub rigbody: RigidBody,
    pub event_flag: ActiveEvents,
    pub depth: BlockDepth,

    // physical config
    pub velocity: Velocity,
    pub massprop: ColliderMassProperties,
    pub friction: Friction,
    pub restitution: Restitution,
    pub damping: Damping,

    pub ex_force: ExternalForce,
    pub ex_impulse: ExternalImpulse,

    // helper componet for builder
    pub anchors: BlockAnchors,

    // connect to which side of parent
    pub parent_anchor: ParentAnchor,

    /// neuron id
    /// 
    /// id=0 is the default id, means random neuron output
    pub neuron_id: NeuronId,
    pub type_falg: ColliderFlag,
    pub joint_info: JointInfo
}

impl Default for PhysiBlockBundle {
    fn default() -> Self {
        let default_rad = 1.0;
        Self {
            sprite: SpriteBundle {
                sprite: Sprite {
                    color: Color::rgb(0.25, 0.25, 0.55),
                    custom_size: Some(Vec2 {
                        x: default_rad,
                        y: default_rad,
                    }),
                    ..default()
                },
                transform: Transform::default(),
                ..default()
            },
            neuron_id: NeuronId::default(),
            depth: BlockDepth(0),
            anchors: BlockAnchors::from_xy(default_rad, default_rad),
            collider: Collider::cuboid(default_rad / 2.0, default_rad / 2.0),
            rigbody: RigidBody::Dynamic,
            velocity: Velocity::default(),
            massprop: ColliderMassProperties::Density(1.0),
            friction: Friction::default(),
            restitution: Restitution::default(),
            damping: Damping{
                linear_damping: DEFAULT_DAMPING_LINEAR,
                angular_damping: DEFAULT_DAMPING_ANGULAR
            },
            ex_force: ExternalForce::default(),
            ex_impulse: ExternalImpulse::default(),
            // contact_force_events for sensor
            event_flag: ActiveEvents::CONTACT_FORCE_EVENTS,
            // default JointInfo is all 0
            joint_info: JointInfo { ang_pos: 0.0, ang_velocity: 0.0 },
            type_falg: ColliderFlag::BLOCK(BlobEntityIndex(None)),
            parent_anchor: ParentAnchor(None)
        }
    }
}

impl PhysiBlockBundle {
    pub fn from_xy_dx_dy(x: f32, y: f32, dx: f32, dy: f32) -> Self {
        Self {
            sprite: SpriteBundle {
                sprite: Sprite {
                    color: Color::rgb(0.25, 0.25, 0.55),
                    custom_size: Some(Vec2 {
                        x: 2.0 * dx,
                        y: 2.0 * dy,
                    }),
                    ..default()
                },
                transform: Transform::from_translation(Vec3::new(x, y, 0.0)),
                ..default()
            },
            collider: Collider::cuboid(dx, dy),
            anchors: BlockAnchors::from_xy(dx, dy),
            ..default()
        }
    }

    pub fn set_color(&mut self, color: Color) {
        self.sprite.sprite.color = color
    }

    pub fn with_color(mut self, color: Color) -> Self {
        self.sprite.sprite.color = color;
        self
    }

    pub fn with_density(mut self, density: f32) -> Self {
        self.massprop = ColliderMassProperties::Density(density);
        self
    }

    pub fn with_depth(mut self, depth: u32) -> Self {
        self.depth = BlockDepth(depth);
        self
    }

    pub fn with_nn_id(mut self, nn_id: usize, parent_nn_id: Option<usize>) -> Self{
        self.neuron_id = NeuronId{id: nn_id, parent_id: parent_nn_id};
        self
    }

    pub fn with_blob(mut self, blob_id: u32) -> Self{
        self.type_falg = ColliderFlag::BLOCK(BlobEntityIndex(Some(blob_id)));
        self
    }

    pub fn with_parent_anchor(mut self, parent_anchor:usize) -> Self{
        self.parent_anchor = ParentAnchor(Some(parent_anchor));
        self
    }
}