diff --git a/collider.cpp b/collider.cpp index 1588c86..5e58217 100644 --- a/collider.cpp +++ b/collider.cpp @@ -3,41 +3,11 @@ #include "collider.h" -Real Collider::distance_to_triangle(const Triangle &triangle, const Vector3 &pos, const Vector3 &dir) { - const Vector3 &n = triangle.normal; - const Vector3 &a = triangle.vertices[0]; - const Vector3 &b = triangle.vertices[1]; - const Vector3 &c = triangle.vertices[2]; - - Real d = n * dir; - if (fabs(d) < 1e-5) return INFINITY; - if ((b - a).len() < 1e-5) return INFINITY; - if ((c - b).len() < 1e-5) return INFINITY; - if ((a - c).len() < 1e-5) return INFINITY; - - d = 1/d; - //Real angle = fabs(atan(d)); - Real l = (a - pos)*n*d; - - Vector3 p = pos + dir*l; - //Vector3 dp = n.cross(dir.cross(n)); - - //Real th = 0, ch = 0, co = 0; - //tool.calc_collision(angle, th, ch, co); - //Real dist = sqrt(ch*ch + co*co); - - Vector3 pp = p;// + dp*dist; - if (n.cross(b - a)*(pp - a) < 0) return INFINITY; - if (n.cross(c - b)*(pp - b) < 0) return INFINITY; - if (n.cross(a - c)*(pp - c) < 0) return INFINITY; - - return l;// - th; -} - -Real Collider::distance_to_model(const Vector3 &pos, const Vector3 &dir) { +Real Collider::distance_to_model(const Vector3 &pos, const Vector3 &dir) const { + Shape *shape = tool.create_collision_shape(pos, dir); Real distance = INFINITY; for(TriangleList::const_iterator i = model.triangles.begin(); i != model.triangles.end(); ++i) - distance = std::min(distance, distance_to_triangle(*i, pos, dir)); + distance = std::min(distance, shape->distance_to_triangle(*i)); return distance; } diff --git a/collider.h b/collider.h index 36273da..c47b958 100644 --- a/collider.h +++ b/collider.h @@ -15,8 +15,8 @@ public: Collider(const Model &model, const Tool &tool): model(model), tool(tool) { } - Real distance_to_triangle(const Triangle &triangle, const Vector3 &pos, const Vector3 &dir); - Real distance_to_model(const Vector3 &pos, const Vector3 &dir); + Real distance_to_triangle(const Triangle &triangle, const Vector3 &pos, const Vector3 &dir) const; + Real distance_to_model(const Vector3 &pos, const Vector3 &dir) const; }; diff --git a/generator.cpp b/generator.cpp new file mode 100644 index 0000000..06c6622 --- /dev/null +++ b/generator.cpp @@ -0,0 +1,192 @@ + +#include +#include + +#include "generator.h" + + +void GeneratorRowsZAX::tool_up(Track &track, Real safe_z) const { + if (track.points.empty()) return; + + const TrackPoint &prev = track.points.back(); + if (prev.position.z == safe_z) return; + + TrackPoint p; + p.position = prev.position; + p.position.z = safe_z; + p.angle = prev.angle; + p.speed = move_speed/60.0; + + track.points.push_back(p); +} + +void GeneratorRowsZAX::tool_feed(Track &track, Real safe_z, Real z1, Real z, Real a, Real x) const { + TrackPoint p; + p.position = Vector3(x, 0, safe_z); + p.angle = a*180.0/M_PI; + + if (track.points.empty() || track.points.back().position.z == safe_z) { + p.speed = move_speed/60.0; + track.points.push_back(p); + + if (safe_z > z1 && z1 > z) { + p.position.z = z1; + track.points.push_back(p); + } + } + + p.position.z = z; + p.speed = feed_speed/60.0; + track.points.push_back(p); +} + + +void GeneratorRowsZAX::touch( + const Collider &collider, + Track &track, + Real safe_z, Real z1, Real z0, + Real a, Real x ) const +{ + Vector3 dir(0, sin(a), -cos(a)); + Vector3 pos(x, 0, 0); + + Real z = collider.distance_to_model(pos, dir); + if (std::isinf(z)) { + tool_up(track, safe_z); + } else { + z = std::max(-z, z0); + if (z > z1) + tool_up(track, safe_z); + else + tool_feed(track, safe_z, z1, z, a, x); + } +} + + + +bool GeneratorRowsZAX::generate(const Collider &collider, Track &track) const { + track.points.clear(); + + const Real precision = 1e-3; + + if (collider.model.triangles.empty()) return false; + + if (step_z != 0 && step_z <= precision) return false; + if (step_a <= precision) return false; + if (step_x <= precision) return false; + if (feed_speed <= precision) return false; + if (move_speed <= precision) return false; + + std::cout << "GeneratorRowsZAX::generate" << std::endl; + + unsigned long long max_count = 100ull*1024*1024/sizeof(track.points.front()); + + Real min_x = this->min_x; + Real max_x = this->max_x; + Real min_z = 0; + Real max_z = 0; + Real safe_z = this->safe_z; + + const TriangleList &triangles = collider.model.triangles; + + // calc bounds + Real bx0 = INFINITY, bx1 = -INFINITY, bz1 = 0; + for(TriangleList::const_iterator i = triangles.begin(); i != triangles.end(); ++i) { + for(int j = 0; j < 3; ++j) { + const Vector3 &v = i->vertices[j]; + const Real z = sqrt(v.y*v.y + v.z*v.z); + bx0 = std::min(bx0, v.x); + bx1 = std::max(bx1, v.x); + bz1 = std::max(bz1, z); + } + } + + bx0 += collider.tool.get_radius(); + bx1 -= collider.tool.get_radius(); + if (bx1 + precision <= bx0 || bz1 + precision <= 0) { + std::cout << "GeneratorRowsZAX::generate: zero bound" << std::endl; + return false; + } + + if (max_x <= min_x) { + min_x = bx0; + max_x = bx1; + } else { + min_x = std::max(min_x, bx0); + max_x = std::min(max_x, bx1); + } + if (max_x + precision <= min_x) return false; + + min_z = std::max(min_z, Real(0)); + max_z = std::max(max_z, bz1); + safe_z = std::max(safe_z, max_z + 1); + + int count_z = step_z ? std::max(1, (int)ceil((max_z - min_z)/step_z - precision)) : 1; + int count_x = std::max(1, (int)ceil((max_x - min_x)/step_x - precision)) + 1; + + bool forward_a = true; + bool forward_x = true; + Real z1 = bz1 + precision; + for(int iz = 0; iz < count_z; ++iz) { + Real z0 = count_z <= 1 ? min_z : max_z - iz*(max_z - min_z)/(count_z - 1); + + int count_a = 3; + if (z1 > precision) + count_a = std::max(count_a, (int)ceil(2*M_PI*z1/step_a - precision)); + Real sa = 2*M_PI/count_a; + + int count_aa = 0; + if (z1 > precision) + count_aa = (int)ceil(sa*z1/step_x - precision); + + for(int ia = 0; ia < count_a; ++ia) { + int iia = forward_a ? ia : count_a - ia - 1; + Real a = iia*sa; + + if (ia > 0) for(int iaa = 1; iaa < count_aa; ++iaa) { + Real aa = sa - sa*iaa/count_a; + aa = forward_a ? a - aa : a + aa; + Real x = forward_x ? min_x : max_x; + touch(collider, track, safe_z, z1, z0, aa, x); + if (track.points.size() >= max_count) break; + } + + for(int ix = 0; ix < count_x; ++ix) { + int iix = forward_x ? ix : count_x - ix - 1; + Real x = min_x + iix*(max_x - min_x)/(count_x - 1); + touch(collider, track, safe_z, z1, z0, a, x); + if (track.points.size() >= max_count) break; + } + + forward_x = !forward_x; + if (track.points.size() >= max_count) break; + std::cout << "." << std::flush; + } + + forward_a = !forward_a; + z1 = z0; + if (track.points.size() >= max_count) break; + std::cout << std::endl << std::flush; + } + + tool_up(track, safe_z); + + if (track.points.size() >= max_count) { + std::cout << "GeneratorRowsZAX::generate: reached memory limit" << std::endl; + return false; + } + + if (track.points.size() <= 1) { + std::cout << "GeneratorRowsZAX::generate: generated track is empty" << std::endl; + return false; + } + + track.split(1, 0, 0); + track.calc_length(); + track.split(0, 0.1, 0); + + std::cout << "GeneratorRowsZAX::generate: track dureation " << (track.points.back().time/60) << std::endl; + std::cout << "GeneratorRowsZAX::generate: done" << std::endl; + return true; +} + diff --git a/generator.h b/generator.h new file mode 100644 index 0000000..b48d84a --- /dev/null +++ b/generator.h @@ -0,0 +1,52 @@ + +#ifndef GENERATOR_H +#define GENERATOR_H + + +#include "track.h" +#include "collider.h" + + +class Generator { +public: + virtual ~Generator() { } + virtual bool generate(const Collider &collider, Track &track) const = 0; +}; + +class GeneratorRowsZAX: public Generator { +public: + Real step_z; + Real step_a; + Real step_x; + + Real min_x; + Real max_x; + Real min_z; + Real max_z; + Real safe_z; + + Real feed_speed; + Real move_speed; + + explicit GeneratorRowsZAX(): + step_z(1), + step_a(1), + step_x(0.1), + min_x(), + max_x(), + min_z(), + max_z(), + safe_z(), + feed_speed(600), + move_speed(1500) + { } + + void tool_up(Track &track, Real safe_z) const; + void tool_feed(Track &track, Real safe_z, Real z1, Real z, Real a, Real x) const; + void touch(const Collider &collider, Track &track, Real safe_z, Real z1, Real z0, Real a, Real x) const; + + bool generate(const Collider &collider, Track &track) const override; +}; + + +#endif diff --git a/geometry.cpp b/geometry.cpp index 79ee487..d5932d8 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -2,3 +2,100 @@ #include "geometry.h" +Matrix4 Matrix4::operator*(const Matrix4 &m) const { + return Matrix4( + m00*m.m00 + m10*m.m01 + m20*m.m02 + m30*m.m02, + m01*m.m00 + m11*m.m01 + m21*m.m02 + m31*m.m02, + m02*m.m00 + m12*m.m01 + m22*m.m02 + m32*m.m02, + m03*m.m00 + m13*m.m01 + m23*m.m02 + m33*m.m02, + + m00*m.m10 + m10*m.m11 + m20*m.m12 + m30*m.m12, + m01*m.m10 + m11*m.m11 + m21*m.m12 + m31*m.m12, + m02*m.m10 + m12*m.m11 + m22*m.m12 + m32*m.m12, + m03*m.m10 + m13*m.m11 + m23*m.m12 + m33*m.m12, + + m00*m.m20 + m10*m.m21 + m20*m.m22 + m30*m.m22, + m01*m.m20 + m11*m.m21 + m21*m.m22 + m31*m.m22, + m02*m.m20 + m12*m.m21 + m22*m.m22 + m32*m.m22, + m03*m.m20 + m13*m.m21 + m23*m.m22 + m33*m.m22, + + m00*m.m30 + m10*m.m31 + m20*m.m32 + m30*m.m32, + m01*m.m30 + m11*m.m31 + m21*m.m32 + m31*m.m32, + m02*m.m30 + m12*m.m31 + m22*m.m32 + m32*m.m32, + m03*m.m30 + m13*m.m31 + m23*m.m32 + m33*m.m32 ); +} + +Real Matrix4::det() const { + return m00 * (m11*(m22*m33 - m23*m32) + m12*(m23*m31 - m21*m33) + m13*(m21*m32 - m22*m31)) + + m01 * (m01*(m23*m32 - m22*m33) + m02*(m21*m33 - m23*m31) + m03*(m22*m31 - m21*m32)) + + m02 * (m01*(m12*m33 - m13*m32) + m02*(m13*m31 - m11*m33) + m03*(m11*m32 - m12*m31)) + + m03 * (m01*(m13*m22 - m12*m23) + m02*(m11*m23 - m13*m21) + m03*(m12*m21 - m11*m22)); +} + +Matrix4 Matrix4::inv() const { + Matrix4 r; + r.m00 = m11*(m22*m33 - m23*m32) + m12*(m23*m31 - m21*m33) + m13*(m21*m32 - m22*m31); + r.m10 = m10*(m23*m32 - m22*m33) + m12*(m20*m33 - m23*m30) + m13*(m22*m30 - m20*m32); + r.m20 = m10*(m21*m33 - m23*m31) + m11*(m23*m30 - m20*m33) + m13*(m20*m31 - m21*m30); + r.m30 = m10*(m22*m31 - m21*m32) + m11*(m20*m32 - m22*m30) + m12*(m21*m30 - m20*m31); + + double det = m00*r.m00 + m01*r.m10 + m02*r.m20 + m03*r.m30; + if (fabs(det) <= precision) return zero(); + det = 1/det; + r.m00 *= det; + r.m10 *= det; + r.m20 *= det; + r.m30 *= det; + + r.m01 = det*(m01*(m23*m32 - m22*m33) + m02*(m21*m33 - m23*m31) + m03*(m22*m31 - m21*m32)); + r.m11 = det*(m00*(m22*m33 - m23*m32) + m02*(m23*m30 - m20*m33) + m03*(m20*m32 - m22*m30)); + r.m21 = det*(m00*(m23*m31 - m21*m33) + m01*(m20*m33 - m23*m30) + m03*(m21*m30 - m20*m31)); + r.m31 = det*(m00*(m21*m32 - m22*m31) + m01*(m22*m30 - m20*m32) + m02*(m20*m31 - m21*m30)); + r.m02 = det*(m01*(m12*m33 - m13*m32) + m02*(m13*m31 - m11*m33) + m03*(m11*m32 - m12*m31)); + r.m12 = det*(m00*(m13*m32 - m12*m33) + m02*(m10*m33 - m13*m30) + m03*(m12*m30 - m10*m32)); + r.m22 = det*(m00*(m11*m33 - m13*m31) + m01*(m13*m30 - m10*m33) + m03*(m10*m31 - m11*m30)); + r.m32 = det*(m00*(m12*m31 - m11*m32) + m01*(m10*m32 - m12*m30) + m02*(m11*m30 - m10*m31)); + r.m03 = det*(m01*(m13*m22 - m12*m23) + m02*(m11*m23 - m13*m21) + m03*(m12*m21 - m11*m22)); + r.m13 = det*(m00*(m12*m23 - m13*m22) + m02*(m13*m20 - m10*m23) + m03*(m10*m22 - m12*m20)); + r.m23 = det*(m00*(m13*m21 - m11*m23) + m01*(m10*m23 - m13*m20) + m03*(m11*m20 - m10*m21)); + r.m33 = det*(m00*(m11*m22 - m12*m21) + m01*(m12*m20 - m10*m22) + m02*(m10*m21 - m11*m20)); + return r; +} + +Matrix4 Matrix4::zero() { + return Matrix4( + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 ); +} + +Matrix4 Matrix4::translation(const Vector3 &translate) { + return Matrix4( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + translate.x, translate.y, translate.z, 1 ); +} + +Matrix4 Matrix4::scaling(const Vector3 &scale) { + return Matrix4( + scale.x, 0, 0, 0, + 0, scale.y, 0, 0, + 0, 0, scale.z, 0, + 0, 0, 0, 1 ); +} + +Matrix4 Matrix4::rotation(const Vector3 &axis, Real angle) { + Real len = axis.len(); + if (len < precision) return Matrix4(); + Real s = sin(angle); + Real c = cos(angle); + Vector3 a = axis/len; + Vector3 ac = a*(1 - c); + return Matrix4( + a.x*ac.x + c , a.y*ac.x + a.z*s, a.z*ac.x - a.y*s, 0, + a.x*ac.y - a.z*s, a.y*ac.y + c , a.z*ac.y + a.x*s, 0, + a.x*ac.z + a.y*s, a.y*ac.z - a.x*s, a.z*ac.z + c , 0, + 0 , 0 , 0 , 1 ); +} diff --git a/geometry.h b/geometry.h index 7ff2c95..a6d4924 100644 --- a/geometry.h +++ b/geometry.h @@ -8,6 +8,40 @@ typedef double Real; +const Real precision = 1e-5; + +inline int solve(Real* roots, Real k0, Real k1) { + if (fabs(k1) <= precision) return 0; + if (roots) roots[0] = -k0/k1; + return 1; +} + +inline int solve(Real* roots, Real k0, Real k1, Real k2) { + if (fabs(k1) <= precision) return solve(roots, k0, k1); + Real D = k1*k1 - 4*k2*k0; + if (fabs(k1) <= precision) { + if (roots) roots[0] = -0.5*k1/k2; + return 1; + } else + if (D > 0) { + if (roots) { + Real a = sqrt(D); + Real b = -0.5/k2; + roots[0] = (k1 - a)*b; + roots[1] = (k1 + a)*b; + } + return 2; + } + return 0; +} + + +inline Real sign(Real x, Real precision) { + return x < -precision ? -1 + : x > precision ? 1 + : 0; +} + class Vector2 { public: @@ -44,12 +78,19 @@ public: { return x*v.x + y*v.y + z*v.z; } Vector3 operator*(Real k) const { return Vector3(x*k, y*k, z*k); } + Vector3 operator/(Real k) const + { return *this*(1/k); } Vector3 cross(const Vector3 &v) const { return Vector3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x); } + Vector3 perp() const + { return fabs(y) > fabs(x) ? Vector3(0, z, -y) : Vector3(-z, 0, x); } Real len_sqr() const { return x*x + y*y + z*z; } Real len() const { return sqrt(len_sqr()); } + + Vector3 norm() const + { Real l = len(); return l > precision ? *this/l : Vector3(); } }; @@ -66,4 +107,55 @@ public: }; +class Matrix4 { +public: + union { + struct { + Real m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33; + }; + struct { Real m[4][4]; }; + struct { Real a[16]; }; + }; + + explicit Matrix4( + Real m00 = 1, Real m01 = 0, Real m02 = 0, Real m03 = 0, + Real m10 = 0, Real m11 = 1, Real m12 = 0, Real m13 = 0, + Real m20 = 0, Real m21 = 0, Real m22 = 1, Real m23 = 0, + Real m30 = 0, Real m31 = 0, Real m32 = 0, Real m33 = 1 + ): + m00(m00), m01(m01), m02(m02), m03(m03), + m10(m10), m11(m11), m12(m12), m13(m13), + m20(m20), m21(m21), m22(m22), m23(m23), + m30(m30), m31(m31), m32(m32), m33(m33) + { } + + Vector4 operator*(const Vector4 &v) const { + return Vector4( + m00*v.x + m10*v.y + m20*v.z + m30*v.w, + m01*v.x + m11*v.y + m21*v.z + m31*v.w, + m02*v.x + m12*v.y + m22*v.z + m32*v.w, + m03*v.x + m13*v.y + m23*v.z + m33*v.w ); + } + + Vector3 transform(const Vector3 &v, Real w = 1) const { + return Vector3( + m00*v.x + m10*v.y + m20*v.z + m30*w, + m01*v.x + m11*v.y + m21*v.z + m31*w, + m02*v.x + m12*v.y + m22*v.z + m32*w ); + } + + Matrix4 operator*(const Matrix4 &m) const; + + Real det() const; + Matrix4 inv() const; + + static Matrix4 zero(); + static Matrix4 translation(const Vector3 &translate); + static Matrix4 scaling(const Vector3 &scale); + static Matrix4 rotation(const Vector3 &axis, Real angle); +}; + #endif diff --git a/loader.cpp b/loader.cpp index 5f8af6b..c0caa2c 100644 --- a/loader.cpp +++ b/loader.cpp @@ -197,28 +197,35 @@ public: char header[80] = {}; unsigned int count = 0; - float triangle_data[3+3*3] = {}; + float normal[3] = {}; + float vertices[3][3] = {}; unsigned short attribute = 0; Triangle t; bool success = false; + int degenerated_count = 0; if (read(header) && read(count)) { success = true; for(unsigned int i = 0; i < count; ++i) { - if (!read(triangle_data) || !read(attribute)) + if (!read(normal) || !read(vertices) || !read(attribute)) { success = false; break; } - for(int i = 0; i < 3; ++i) { - t.normal.c[i] = triangle_data[i]; - for(int j = 0; j < 3; ++j) - t.vertices[j].c[i] = triangle_data[3 + j*3 + i]; - } - model.triangles.push_back(t); + for(int j = 0; j < 3; ++j) + for(int k = 0; k < 3; ++k) + t.vertices[j].c[k] = vertices[j][k]; + if (t.check(1e-10)) + model.triangles.push_back(t); + else + ++degenerated_count; } } fclose(f); - model.transform(Vector3(1000, 1000, 1000)); + if (degenerated_count) + std::cout << "skipped degenerated triangles: " << degenerated_count << std::endl; + std::cout << "loaded triangles: " << model.triangles.size() << std::endl; + model.normalize(); + model.transform(Matrix4::scaling(Vector3(1000, 1000, 1000))); std::cout << "loaded: " << filename << std::endl; return success; diff --git a/main.cpp b/main.cpp index 57a5a97..2b8e5d8 100644 --- a/main.cpp +++ b/main.cpp @@ -11,6 +11,7 @@ #include "tool.h" #include "loader.h" #include "collider.h" +#include "generator.h" class Main { @@ -70,6 +71,8 @@ public: glEnable(GL_POINT_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + + glEnable(GL_NORMALIZE); glEnable(GL_LIGHT0); float light0[] = {1, 1, 1, 0}; @@ -161,8 +164,8 @@ public: scene->offset.z *= pow(2, event.motion.yrel/100.0); } if (event.motion.state & SDL_BUTTON_MMASK) { - scene->offset.x += event.motion.xrel; - scene->offset.y += event.motion.yrel; + scene->offset.x += 0.1*event.motion.xrel; + scene->offset.y -= 0.1*event.motion.yrel; } } } @@ -186,6 +189,8 @@ int main(int argc, char **argv) Main app; if (!app.init()) return -1; + bool load_track = false; + Model model; SimulatorXYZA simulator_xyza(400, 360); FlatTool tool(1.5); @@ -198,11 +203,22 @@ int main(int argc, char **argv) Loader::load(app.scene->track, argv[1]); app.scene->simulator = &simulator_xyza; app.scene->simulator->simulate(app.scene->track, tool); + load_track = true; } if (argc > 2 && std::string(argv[2]) != ".") { Loader::load(model, argv[2]); app.scene->model = &model; + if (!load_track) { + GeneratorRowsZAX generator; + generator.step_z = 1.5; + generator.step_a = 2*0.9*tool.radius; + generator.step_x = 0.5; + generator.generate(collider, app.scene->track); + app.scene->simulator = &simulator_xyza; + app.scene->simulator->simulate(app.scene->track, tool); + //app.scene->model = 0; + } } app.scene->tool = &tool; diff --git a/model.cpp b/model.cpp index 755c4dc..9a80231 100644 --- a/model.cpp +++ b/model.cpp @@ -4,21 +4,17 @@ #include "model.h" -void Model::transform(const Vector3 &scale, const Vector3 &move) { - for(TriangleList::iterator i = triangles.begin(); i != triangles.end(); ++i) { - for(int j = 0; j < 3; ++j) { - i->normal.c[j] *= scale.c[j]; - for(int k = 0; k < 3; ++k) { - i->vertices[k].c[j] *= scale.c[j]; - i->vertices[k].c[j] += move.c[j]; - } - } - Real nl = i->normal.len(); - nl = nl > 1e-5 ? 1/nl : 0.0; - i->normal = i->normal * nl; - } +void Model::normalize() { + for(TriangleList::iterator i = triangles.begin(); i != triangles.end(); ++i) + i->normalize(); } +void Model::transform(const Matrix4 &matrix) { + for(TriangleList::iterator i = triangles.begin(); i != triangles.end(); ++i) + for(int j = 0; j < 3; ++j) + i->vertices[j] = matrix.transform( i->vertices[j] ); + normalize(); +} void Model::draw() const { glEnable(GL_LIGHTING); diff --git a/model.h b/model.h index be6d1de..36c2ab0 100644 --- a/model.h +++ b/model.h @@ -12,6 +12,11 @@ class Triangle { public: Vector3 vertices[3]; Vector3 normal; + + void normalize() + { normal = (vertices[2] - vertices[0]).cross(vertices[1] - vertices[0]).norm(); } + bool check(Real precision) const + { return (vertices[2] - vertices[0]).cross(vertices[1] - vertices[0]).len_sqr() > precision*precision; } }; typedef std::vector TriangleList; @@ -24,7 +29,8 @@ public: Model(const Vector4 &color = Vector4(0.5, 0.5, 0.5, 0.5)): color(color) { } - void transform(const Vector3 &scale, const Vector3 &move = Vector3()); + void normalize(); + void transform(const Matrix4 &matrix); void draw() const; }; diff --git a/scene.cpp b/scene.cpp index b891fa0..a5212f1 100644 --- a/scene.cpp +++ b/scene.cpp @@ -71,10 +71,23 @@ void Scene::update(Real dt) { if (time_speed > 0) time_speed = 0; } - if (simulator) { - int index = track.index_by_time(time); - if (index >= 0) simulator->scroll_to(index); + int index = track.index_by_time(time); + if (index > 0) { + /* + const TrackPoint &p0 = track.points[index-1]; + const TrackPoint &p1 = track.points[index]; + Real l = p1.duration > 1e-5 ? (p0.time - time)/p1.duration : 0.5; + TrackPoint p = TrackPoint::median(l, p0, p1); + + Real a = p.angle*(M_PI/180); + Real s = sin(a); + Real c = cos(a); + tool_pos = p.real_pos; + tool_dir = Vector3(0, p.position.z*s, -p.position.z*c).norm(); + */ + if (simulator) simulator->scroll_to(index); } + } Real Scene::random() diff --git a/shape.cpp b/shape.cpp new file mode 100644 index 0000000..d70b006 --- /dev/null +++ b/shape.cpp @@ -0,0 +1,65 @@ + +#include "shape.h" + + +CilinderShape::CilinderShape(Real radius, const Vector3 &pos, const Vector3 &dir) { + Vector3 vx = dir.perp().norm(); + Vector3 vy = vx.cross(dir); + matrix = Matrix4( + vx.x*radius, vx.y*radius, vx.z*radius, 0, + vy.x*radius, vy.y*radius, vy.z*radius, 0, + dir.x , dir.y , dir.z , 0, + pos.x , pos.y , pos.z , 1 ).inv(); +} + +Real CilinderShape::distance_to_triangle(const Triangle &triangle) const { + Real dist = INFINITY; + + Vector3 v[3], d[3]; + Real A[3], B[3], C[3]; + for(int i = 0; i < 3; ++i) { + v[i] = matrix.transform( triangle.vertices[i] ); + C[i] = v[i].x*v[i].x + v[i].y*v[i].y - 1; + + // collision with vertex + if (C[i] <= precision) + dist = std::min(dist, v[i].z); + } + + for(int i = 0; i < 3; ++i) { + d[i] = v[(i+1)%3] - v[i]; + A[i] = d[i].x*d[i].x + d[i].y*d[i].y; + B[i] = 2*(d[i].x*v[i].x + d[i].y*v[i].y); + + // collision with edge + Real roots[2]; + int count = solve(roots, C[i], B[i], A[i]); + for(int j = 0; j < count; ++j) + if (roots[j] >= -precision && roots[j] <= 1 + precision) + dist = std::min(dist, d[i].z*roots[j] + v[i].z); + } + + // collision with plane + Vector3 perp = d[1].cross(d[2]); + if (perp.z < 0) perp = Vector3(-perp.x, -perp.y, -perp.z); + if (perp.z > precision) { + // nearest plane touch point + Vector3 p(0, 0, perp*v[0]/perp.z); + Real xy = sqrt(perp.x*perp.x + perp.y*perp.y); + if (xy > precision) { + Real dxy = 1/xy; + p.x = perp.x*dxy; + p.y = perp.y*dxy; + p.z -= xy/perp.z; + } + + // is touch point inside tringle + Real s = sign( perp.cross(d[0])*(p - v[0]), 0.1*precision ); + if ( s + && s == sign( perp.cross(d[1])*(p - v[1]), 0.1*precision ) + && s == sign( perp.cross(d[2])*(p - v[2]), 0.1*precision ) ) + dist = std::min(dist, p.z); + } + + return dist; +} diff --git a/shape.h b/shape.h new file mode 100644 index 0000000..8a59027 --- /dev/null +++ b/shape.h @@ -0,0 +1,24 @@ + +#ifndef SHAPE_H +#define SHAPE_H + + +#include "geometry.h" +#include "model.h" + + +class Shape { +public: + virtual ~Shape() { } + virtual Real distance_to_triangle(const Triangle &triangle) const = 0; +}; + +class CilinderShape: public Shape { +public: + Matrix4 matrix; + CilinderShape(Real radius, const Vector3 &pos, const Vector3 &dir); + Real distance_to_triangle(const Triangle &triangle) const override; +}; + + +#endif diff --git a/tool.cpp b/tool.cpp index 5d8ff1e..51e2f8d 100644 --- a/tool.cpp +++ b/tool.cpp @@ -9,8 +9,8 @@ void FlatTool::draw(const Vector3 &pos, const Vector3 &dir) const { const Real len = 10*radius; glPushMatrix(); - glEnable(GL_NORMALIZE); glEnable(GL_LIGHTING); + glColor4d(1, 1, 0, 0.25); glTranslated(pos.x, pos.y, pos.z); Vector3 vx = dir.cross(Vector3(dir.y, dir.z, dir.x)); @@ -30,8 +30,8 @@ void FlatTool::draw(const Vector3 &pos, const Vector3 &dir) const { Real c = cos(a); Real s = sin(a); glNormal3b(c, s, 0); - glVertex3d(c, s, 0); - glVertex3d(c, s, -len); + glVertex3d(c*radius, s*radius, 0); + glVertex3d(c*radius, s*radius, -len); } glEnd(); @@ -39,7 +39,7 @@ void FlatTool::draw(const Vector3 &pos, const Vector3 &dir) const { glNormal3b(0, 0, 1); for(int i = 0; i < segments; ++i) { Real a = 2*M_PI*i/segments; - glVertex3d(cos(a), sin(a), 0); + glVertex3d(cos(a)*radius, sin(a)*radius, 0); } glEnd(); @@ -47,11 +47,10 @@ void FlatTool::draw(const Vector3 &pos, const Vector3 &dir) const { glNormal3b(0, 0, -1); for(int i = 0; i < segments; ++i) { Real a = 2*M_PI*i/segments; - glVertex3d(cos(a), sin(a), -len); + glVertex3d(cos(a)*radius, sin(a)*radius, -len); } glEnd(); glDisable(GL_LIGHTING); - glDisable(GL_NORMALIZE); glPopMatrix(); } diff --git a/tool.h b/tool.h index b506c07..19c31f4 100644 --- a/tool.h +++ b/tool.h @@ -6,6 +6,7 @@ #include #include "raster.h" +#include "shape.h" class Tool { @@ -15,7 +16,7 @@ public: virtual Real get_height(Real offset) const = 0; // must be >= 0 virtual void calc_collision( - Real plane_angle, + Real plane_k, Real &tool_height, Real &collision_height, Real &collision_offset ) const = 0; @@ -27,6 +28,8 @@ public: return sqrt(distance*distance + v.y*v.y) + get_height(v.len()); } + virtual Shape* create_collision_shape(const Vector3 &pos, const Vector3 &dir) const = 0; + virtual void draw(const Vector3 &pos, const Vector3 &dir) const = 0; }; @@ -44,7 +47,7 @@ public: { return fabs(offset) <= fabs(radius) ? 0 : INFINITY; } void calc_collision( - Real plane_angle, + Real plane_k, Real &tool_height, Real &collision_height, Real &collision_offset @@ -53,14 +56,9 @@ public: tool_height = 0; collision_height = 0; collision_offset = 0; - return; - Real a = fabs(0.5*M_PI - plane_angle); - if (a >= 0.5*M_PI - 1e-5) return; - Real t = tan(a); - if (t <= 1e-5) return; - - tool_height = collision_height = radius/t; + if (plane_k <= 1e-5) return; + tool_height = collision_height = radius*plane_k; collision_offset = radius; } @@ -72,6 +70,10 @@ public: return t2 <= r2 ? sqrt(distance*distance + t2) : INFINITY; } + Shape* create_collision_shape(const Vector3 &pos, const Vector3 &dir) const override { + return new CilinderShape(radius, pos, dir); + } + void draw(const Vector3 &pos, const Vector3 &dir) const override; };