1 module grape.geometry; 2 3 import grape.math; 4 import std.stdio; 5 import std.algorithm; 6 import std.array; 7 8 struct CoordinateSystem { 9 public: 10 CoordinateSystem opBinary(string op)(Vec3 vec3) if (op == "+") { 11 CoordinateSystem result; 12 result.set_position( _list[0].vec3 + vec3, 13 _list[1].vec3 + vec3, 14 _list[2].vec3 + vec3 ); 15 return result; 16 } 17 18 CoordinateSystem opBinaryRight(string op)(Vec3 vec3) if (op == "+") { 19 return opBinary!op(vec3); 20 } 21 22 ref CoordinateSystem opOpAssign(string op)(Vec3 vec3) if (op == "+") { 23 _list[0].set(_list[0].vec3 + vec3); 24 _list[1].set(_list[1].vec3 + vec3); 25 _list[2].set(_list[2].vec3 + vec3); 26 return this; 27 } 28 29 void set_position(Vec3 x, Vec3 y, Vec3 z) { 30 _list = [ Quat(x), Quat(y), Quat(z) ]; 31 } 32 33 void set_position(Quat x, Quat y, Quat z) { 34 _list = [ x, y, z ]; 35 } 36 37 void rotate(Quat rotQuat) { 38 _list = map!(pos => rotQuat.conjugate * pos * rotQuat)(_list).array; 39 } 40 41 @property { 42 Vec3 x() { 43 return _list[0].vec3; 44 } 45 46 Vec3 y() { 47 return _list[1].vec3; 48 } 49 50 Vec3 z() { 51 return _list[2].vec3; 52 } 53 } 54 55 private: 56 Quat[] _list = [ Quat(Vec3(1, 0, 0)), 57 Quat(Vec3(0, 1, 0)), 58 Quat(Vec3(0, 0, 1)) ]; 59 } 60 61 // TODO atomic 62 class Geometry { 63 public: 64 void set_position(Vec3 vec3) { 65 auto distance = vec3 - _origin.vec3; 66 67 _origin.set(_origin.vec3 + distance); 68 _vertices = map!(x => x + distance)(_vertices).array; 69 } 70 71 void forward(in float distance) { 72 auto distanceVec3 = _localCS.x * distance; 73 move_impl(distanceVec3); 74 } 75 76 void back(in float distance) { 77 auto distanceVec3 = _localCS.x * (-distance); 78 move_impl(distanceVec3); 79 } 80 81 void up(in float distance) { 82 auto distanceVec3 = _localCS.y * distance; 83 move_impl(distanceVec3); 84 } 85 86 void down(in float distance) { 87 auto distanceVec3 = _localCS.y * (-distance); 88 move_impl(distanceVec3); 89 } 90 91 void right(in float distance) { 92 auto distanceVec3 = _localCS.z * distance; 93 move_impl(distanceVec3); 94 } 95 96 void left(in float distance) { 97 auto distanceVec3 = _localCS.z * (-distance); 98 move_impl(distanceVec3); 99 } 100 101 void pitch(in float rad) { 102 rotate_impl(_localCS.x, rad, _origin.vec3); 103 } 104 105 void yaw(in float rad) { 106 rotate_impl(_localCS.y, rad, _origin.vec3); 107 } 108 109 void roll(in float rad) { 110 rotate_impl(_localCS.z, rad, _origin.vec3); 111 } 112 113 // 任意の直線の方向に移動 114 void translate(Vec3 axis, in float distance) { 115 auto distanceVec3 = axis * distance; 116 move_impl(distanceVec3); 117 } 118 119 // 任意の点(pos)を通る直線(axis)を中心軸に回転 120 void rotate(in Vec3 axis, in float rad, in Vec3 pos=Vec3(0, 0, 0)) { 121 rotate_impl(axis, rad, pos); 122 } 123 124 void scale(in float ratio) { 125 foreach (ref vertex; _vertices) { 126 vertex = vertex * ratio; 127 } 128 } 129 130 @property { 131 Quat origin() { 132 return _origin; 133 } 134 135 Vec3[] vertices() { 136 return _vertices; 137 } 138 139 int[] indices() { 140 return _indices; 141 } 142 143 Vec3[] normals() { 144 return _normals; 145 } 146 } 147 148 protected: 149 void move_impl(in Vec3 distanceVec3) { 150 foreach (ref vertex; _vertices) { 151 vertex += distanceVec3; 152 } 153 _origin.set(_origin.vec3 + distanceVec3); 154 } 155 156 void rotate_impl(in Vec3 axis, in float rad, in Vec3 pos) { 157 void delegate() impl = { 158 auto rotQuat = Quat(axis, rad); 159 160 // _originの回転 161 if (pos != _origin.vec3) _origin = rotQuat.conjugate * _origin * rotQuat; 162 163 // _localCSの回転 164 _localCS.rotate(rotQuat); 165 166 // _verticesの回転 167 auto tmp = map!(vec3 => Quat(vec3))(_vertices); 168 _vertices = map!(pos => (rotQuat.conjugate * pos * rotQuat).vec3)(tmp).array; 169 170 // _normalsの回転 171 auto tmp2 = map!(vec3 => Quat(vec3))(_normals); 172 _normals = map!(pos => (rotQuat.conjugate * pos * rotQuat).vec3)(tmp2).array; 173 }; 174 175 _vertices = map!(x => x - pos)(_vertices).array; 176 impl(); 177 _vertices = map!(x => x + pos)(_vertices).array; 178 } 179 180 CoordinateSystem _localCS; 181 Quat _origin = Quat(Vec3(0, 0, 0)); 182 Vec3[] _vertices; 183 int[] _indices; 184 Vec3[] _normals; 185 } 186 187 class BoxGeometry : Geometry { 188 public: 189 this(in float width, in float height, in float depth) { 190 auto x = width / 2; 191 auto y = height / 2; 192 auto z = depth / 2; 193 194 _vertices = [ Vec3(x, -y, -z), 195 Vec3(x, -y, z), 196 Vec3(-x, -y, z), 197 Vec3(-x, -y, -z), 198 Vec3(x, y, -z), 199 Vec3(x, y, z), 200 Vec3(-x, y, z), 201 Vec3(-x, y, -z) ]; 202 _indices = [ 0, 1, 2, 0, 2, 3, 203 0, 1, 4, 1, 4, 5, 204 1, 2, 5, 2, 5, 6, 205 0, 3, 4, 3, 4, 7, 206 4, 5, 6, 4, 6, 7, 207 2, 3, 7, 2, 7, 6 ]; 208 _normals = [ Vec3(1.0, -1.0, -1.0), 209 Vec3(1.0, -1.0, 1.0), 210 Vec3(-1.0, -1.0, 1.0), 211 Vec3(-1.0, -1.0, -1.0), 212 Vec3(1.0, 1.0, -1.0), 213 Vec3(1.0, 1.0, 1.0), 214 Vec3(-1.0, 1.0, 1.0), 215 Vec3(-1.0, 1.0, -1.0) ]; 216 } 217 218 this(in float width, in float height, in float depth, in int widthSegments=1, in int heightSegments=1, in int depthSegments=1) { 219 this(width, height, depth); 220 } 221 } 222 223 class PlaneGeometry : Geometry { 224 public: 225 this(in float width, in float height, in int widthSegments=1, in int heightSegments=1) { 226 auto x = width / 2; 227 auto y = height / 2; 228 229 _vertices = [ Vec3(-x, y, 0), 230 Vec3(x, y, 0), 231 Vec3(x, -y, 0), 232 Vec3(-x, -y, 0) ]; 233 _indices = [ 0, 1, 2, 0, 2, 3 ]; 234 } 235 } 236 237 class CustomGeometry : Geometry { 238 public: 239 this(Vec3[] vertices=[], int[] indices=[], Vec3[] normals=[]) { 240 _vertices = vertices; 241 _indices = indices; 242 _normals = normals; 243 } 244 } 245 246 unittest { 247 import std.range : zip; 248 249 bool nearly_equal(Vec3 a, Vec3 b) { 250 foreach (v; zip(a.coord, b.coord)) 251 if (v[0] - v[1] > 0.001) return false; 252 return true; 253 } 254 255 auto geometry = new BoxGeometry(1, 1, 1); 256 assert(geometry.origin.vec3 == Vec3(0, 0, 0)); 257 assert(geometry.vertices == [ Vec3([0.5, -0.5, -0.5]), Vec3([0.5, -0.5, 0.5]), Vec3([-0.5, -0.5, 0.5]), Vec3([-0.5, -0.5, -0.5]), Vec3([0.5, 0.5, -0.5]), Vec3([0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, -0.5])]); 258 259 geometry.set_position(Vec3(1, 0, 0)); 260 assert(geometry.origin.vec3 == Vec3(1, 0, 0)); 261 assert(geometry.vertices == [ Vec3([1.5, -0.5, -0.5]), Vec3([1.5, -0.5, 0.5]), Vec3([0.5, -0.5, 0.5]), Vec3([0.5, -0.5, -0.5]), Vec3([1.5, 0.5, -0.5]), Vec3([1.5, 0.5, 0.5]), Vec3([0.5, 0.5, 0.5]), Vec3([0.5, 0.5, -0.5])]); 262 263 geometry.set_position(Vec3(0, 0, 0)); 264 geometry.forward(1.0); 265 assert(geometry.origin.vec3 == Vec3(1, 0, 0)); 266 assert(geometry.vertices == [ Vec3([1.5, -0.5, -0.5]), Vec3([1.5, -0.5, 0.5]), Vec3([0.5, -0.5, 0.5]), Vec3([0.5, -0.5, -0.5]), Vec3([1.5, 0.5, -0.5]), Vec3([1.5, 0.5, 0.5]), Vec3([0.5, 0.5, 0.5]), Vec3([0.5, 0.5, -0.5])]); 267 geometry.back(1.0); 268 assert(geometry.origin.vec3 == Vec3(0, 0, 0)); 269 assert(geometry.vertices == [ Vec3([0.5, -0.5, -0.5]), Vec3([0.5, -0.5, 0.5]), Vec3([-0.5, -0.5, 0.5]), Vec3([-0.5, -0.5, -0.5]), Vec3([0.5, 0.5, -0.5]), Vec3([0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, -0.5])]); 270 geometry.right(1.0); 271 assert(geometry.origin.vec3 == Vec3(0, 0, 1)); 272 assert(geometry.vertices == [ Vec3([0.5, -0.5, 0.5]), Vec3([0.5, -0.5, 1.5]), Vec3([-0.5, -0.5, 1.5]), Vec3([-0.5, -0.5, 0.5]), Vec3([0.5, 0.5, 0.5]), Vec3([0.5, 0.5, 1.5]), Vec3([-0.5, 0.5, 1.5]), Vec3([-0.5, 0.5, 0.5])]); 273 geometry.left(1.0); 274 assert(geometry.origin.vec3 == Vec3(0, 0, 0)); 275 assert(geometry.vertices == [ Vec3([0.5, -0.5, -0.5]), Vec3([0.5, -0.5, 0.5]), Vec3([-0.5, -0.5, 0.5]), Vec3([-0.5, -0.5, -0.5]), Vec3([0.5, 0.5, -0.5]), Vec3([0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, -0.5])]); 276 geometry.up(1.0); 277 assert(geometry.origin.vec3 == Vec3(0, 1, 0)); 278 assert(geometry.vertices == [ Vec3([0.5, 0.5, -0.5]), Vec3([0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, -0.5]), Vec3([0.5, 1.5, -0.5]), Vec3([0.5, 1.5, 0.5]), Vec3([-0.5, 1.5, 0.5]), Vec3([-0.5, 1.5, -0.5])]); 279 geometry.down(1.0); 280 assert(geometry.origin.vec3 == Vec3(0, 0, 0)); 281 assert(geometry.vertices == [ Vec3([0.5, -0.5, -0.5]), Vec3([0.5, -0.5, 0.5]), Vec3([-0.5, -0.5, 0.5]), Vec3([-0.5, -0.5, -0.5]), Vec3([0.5, 0.5, -0.5]), Vec3([0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, 0.5]), Vec3([-0.5, 0.5, -0.5])]); 282 283 284 /* 285 geometry.rotate(Vec3(0, 1, 0), PI); 286 assert(nearly_equal(geometry.origin.vec3, Vec3(-1, 0, 0))); 287 288 geometry.pitch(PI_2); 289 geometry.yaw(PI_2); 290 geometry.roll(PI_2); 291 geometry.rotate(Vec3(0, 1, 0), PI, Vec3(1, 1, 1)); 292 */ 293 } 294