meshing calculation for co-planar gears
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Sat, 17 Sep 2016 03:28:00 +0000 (06:28 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Sat, 17 Sep 2016 03:28:00 +0000 (06:28 +0300)
src/app.cc [new file with mode: 0644]
src/app.h [new file with mode: 0644]
src/gear.cc
src/gear.h
src/machine.cc
src/main.cc

diff --git a/src/app.cc b/src/app.cc
new file mode 100644 (file)
index 0000000..6125823
--- /dev/null
@@ -0,0 +1,3 @@
+#include "app.h"
+
+bool opt_gear_wireframe;
diff --git a/src/app.h b/src/app.h
new file mode 100644 (file)
index 0000000..926c2d2
--- /dev/null
+++ b/src/app.h
@@ -0,0 +1,6 @@
+#ifndef APP_H_
+#define APP_H_
+
+extern bool opt_gear_wireframe;
+
+#endif // APP_H_
index 03a3b7d..6ce9d8a 100644 (file)
@@ -1,6 +1,7 @@
 #include <GL/glew.h>
 #include "gear.h"
 #include "meshgen.h"
+#include "app.h"
 
 Gear::Gear()
        : axis(0, 0, 1)
@@ -13,6 +14,7 @@ Gear::Gear()
        thickness = 5;
        bevel = 1.5;
        init_angle = 0;
+       xform_valid = false;
 
        mesh = 0;
 }
@@ -30,11 +32,62 @@ void Gear::set_teeth(int nt, float tooth_pitch)
        init_angle = get_angular_pitch() * 3.0 / 8.0;
 }
 
-float Gear::get_rotation() const
+void Gear::set_axis(const Vec3 &axis)
+{
+       this->axis = normalize(axis);
+       xform_valid = false;
+}
+
+void Gear::set_position(const Vec3 &pos)
+{
+       this->pos = pos;
+       xform_valid = false;
+}
+
+const Vec3 &Gear::get_position() const
+{
+       return pos;
+}
+
+Vec3 Gear::get_global_position() const
+{
+       return pos;     // TODO
+}
+
+void Gear::set_angle(float angle)
+{
+       this->angle = angle;
+       xform_valid = false;
+}
+
+float Gear::get_angle() const
+{
+       return angle;
+}
+
+float Gear::get_vis_rotation() const
 {
        return fmod(init_angle + angle, M_PI * 2.0);
 }
 
+const Mat4 &Gear::get_matrix() const
+{
+       if(!xform_valid) {
+               calc_matrix();
+               xform_valid = true;
+       }
+       return xform;
+}
+
+const Mat4 &Gear::get_dir_matrix() const
+{
+       if(!xform_valid) {
+               calc_matrix();
+               xform_valid = true;
+       }
+       return xform;
+}
+
 float Gear::get_angular_pitch() const
 {
        return 2.0 * M_PI / (float)nteeth;
@@ -49,24 +102,34 @@ void Gear::draw() const
        }
        calc_matrix();
 
+       glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
+
        glPushMatrix();
        glMultMatrixf(xform[0]);
 
+       if(opt_gear_wireframe) {
+               glPolygonOffset(1, 1);
+               glEnable(GL_POLYGON_OFFSET_FILL);
+       }
+
        mesh->draw();
 
-       glPushAttrib(GL_ENABLE_BIT);
        glDisable(GL_LIGHTING);
 
+       if(opt_gear_wireframe) {
+               glColor3f(0.2, 0.4, 1.0);
+               mesh->draw_wire();
+       }
+
        glLineWidth(2.0);
        glBegin(GL_LINES);
        glColor3f(0, 0, 1);
        glVertex3f(0, 0, -10);
        glVertex3f(0, 0, 10);
        glEnd();
-       glLineWidth(1.0);
-       glPopAttrib();
 
        glPopMatrix();
+       glPopAttrib();
 }
 
 static Vec2 rev_pos(float u, float v, void *cls)
@@ -130,7 +193,9 @@ void Gear::calc_matrix() const
        Vec3 right = normalize(cross(up, axis));
        up = cross(axis, right);
 
-       xform = Mat4(right, up, axis);
-       xform.rotate_z(get_rotation());
+       dir_xform = Mat4(right, up, axis);
+
+       xform = dir_xform;
+       xform.rotate_z(get_vis_rotation());
        xform.translate(pos);
 }
index 12d9ba2..281e77f 100644 (file)
@@ -39,26 +39,31 @@ class Gear {
 private:
        Mesh *mesh;
 
-       mutable Mat4 xform;
+       mutable Mat4 xform, dir_xform;
+       mutable bool xform_valid;
        void calc_matrix() const;
 
        float contour(float u);
 
 public:
+
+       /* TODO hide most of this shit, especially the stuff which invalidate
+        * the transformation matrices
+        */
        std::string name;
-       Vec3 pos, axis; /* implicitly defines a plane eqn. */
-       float pdist;    /* derived: distance of plane from origin */
+       Vec3 pos, axis; // implicitly defines a plane eqn.
+       float pdist;    // derived: distance of plane from origin
 
-       float init_angle;       /* initial starting angle */
-       float angle;    /* current angle of the gear */
+       float init_angle;       // initial starting angle
+       float angle;    // current angle of the gear
 
-       int nteeth;             /* number of teeth */
+       int nteeth;             // number of teeth
 
-       float radius;   /* total radius of the gear, including teeth */
-       float teeth_length;     /* how far teeth extend past the radius */
-       float thickness;        /* thickness of the gear along the Z axis */
+       float radius;   // total radius of the gear, including teeth
+       float teeth_length;     // how far teeth extend past the radius
+       float thickness;        // thickness of the gear along the Z axis
 
-       float bevel;    /* bevel size */
+       float bevel;    // bevel size
 
        std::vector<GearPin> pins;
        std::vector<GearSlot> slots;
@@ -69,8 +74,17 @@ public:
        // sets the supplied number of teeth, and calculates the radius
        // of the gear, to achieve the required tooth pitch
        void set_teeth(int nt, float tooth_pitch);
+       void set_axis(const Vec3 &axis);
+       void set_position(const Vec3 &pos);
+       const Vec3 &get_position() const;
+       Vec3 get_global_position() const;       // taking parent gear into account
+
+       void set_angle(float angle);
+       float get_angle() const;
 
-       float get_rotation() const;
+       float get_vis_rotation() const;
+       const Mat4 &get_matrix() const;
+       const Mat4 &get_dir_matrix() const;
 
        // returns the angle (in radians) from one tooth to the next
        float get_angular_pitch() const;
index 716fc89..1a78452 100644 (file)
@@ -5,7 +5,6 @@
 #include "machine.h"
 
 static float delta_angle(float a, float b);
-static float signed_delta_angle(float a, float b);
 
 Machine::Machine()
 {
@@ -21,9 +20,7 @@ Machine::~Machine()
        }
 
        if(meshing) {
-               for(int i=0; i<ngears; i++) {
-                       delete [] meshing[i];
-               }
+               delete [] meshing[0];
                delete [] meshing;
        }
        delete [] visited;
@@ -48,8 +45,10 @@ void Machine::calc_meshing()
 
        if(!meshing) {
                meshing = new bool*[ngears];
-               for(int i=0; i<ngears; i++) {
-                       meshing[i] = new bool[ngears];
+               meshing[0] = new bool[ngears * ngears];
+
+               for(int i=1; i<ngears; i++) {
+                       meshing[i] = meshing[i - 1] + ngears;
                }
        }
 
@@ -57,12 +56,43 @@ void Machine::calc_meshing()
                visited = new bool[ngears];
        }
 
-       // let's mesh everything together just for shits and giggles
+       // we're going to need the inverse of each gear's matrix, so let's cache it here
+       Mat4 *inv_xform = (Mat4*)alloca(ngears * sizeof *inv_xform);
        for(int i=0; i<ngears; i++) {
-               for(int j=0; j<ngears; j++) {
-                       meshing[i][j] = abs(i - j) & 1 ? true : false;
-                       if(meshing[i][j]) {
-                               printf("connecting %d - %d\n", i, j);
+               inv_xform[i] = transpose(gears[i]->get_dir_matrix());
+       }
+
+       for(int i=0; i<ngears; i++) {
+               for(int j=i; j<ngears; j++) {
+                       meshing[i][j] = meshing[j][i] = false;
+
+                       if(i == j) continue;
+
+                       if(1.0 - fabs(dot(gears[i]->axis, gears[j]->axis)) < 1e-5) {
+                               // co-planar, just check Z range after inverse-transforming to the XY plane
+                               Vec3 pos_i = inv_xform[i] * gears[i]->get_position();
+                               Vec3 pos_j = inv_xform[j] * gears[j]->get_position();
+
+                               if(fabs(pos_i.z - pos_j.z) > (gears[i]->thickness + gears[j]->thickness) / 2.0) {
+                                       continue;
+                               }
+                               // Z interval match, check distance
+                               float dsq = length_sq(pos_i.xy() - pos_j.xy());
+
+                               float outer_rad_sum = gears[i]->radius + gears[j]->radius;
+                               float inner_rad_sum = outer_rad_sum - gears[i]->teeth_length - gears[j]->teeth_length;
+
+                               if(dsq <= outer_rad_sum * outer_rad_sum && dsq >= inner_rad_sum * inner_rad_sum) {
+                                       printf("connecting co-planar gears %d - %d\n", i, j);
+                                       meshing[i][j] = meshing[j][i] = true;
+                               }
+
+                       } else {
+                               /* TODO: not co-planar
+                                * - calc line of intersection between the two planes
+                                * - find distance of each gear to that line
+                                * - profit...
+                                */
                        }
                }
        }
@@ -74,8 +104,6 @@ void Machine::calc_meshing()
                        if(meshing[i][j]) {
                                assert(i != j);
 
-                               float tarc = gears[i]->get_angular_pitch(); // assumed to be the same for meshing gears
-
                                float frac_i = fmod(gears[i]->init_angle / gears[i]->get_angular_pitch() + 1.0, 1.0);
                                float frac_j = fmod(gears[j]->init_angle / gears[j]->get_angular_pitch() + 1.0, 1.0);
                                float delta = frac_j - frac_i;
@@ -97,7 +125,7 @@ void Machine::update_gear(int idx, float angle)
                return;
        }
 
-       gears[idx]->angle = angle;
+       gears[idx]->set_angle(angle);
        visited[idx] = true;
 
        int ngears = (int)gears.size();
@@ -137,15 +165,3 @@ static float delta_angle(float a, float b)
        float bpi = fmod(b + M_PI, 2.0 * M_PI);
        return std::min(fabs(a - b), fabs(api - bpi));
 }
-
-
-static float signed_delta_angle(float a, float b)
-{
-       float api = fmod(a + M_PI, 2.0 * M_PI);
-       float bpi = fmod(b + M_PI, 2.0 * M_PI);
-
-       if(fabs(a - b) < fabs(api - bpi)) {
-               return a - b;
-       }
-       return api - bpi;
-}
index b5d430b..7efc114 100644 (file)
@@ -7,6 +7,7 @@
 #else
 #include <GL/glut.h>
 #endif
+#include "app.h"
 #include "machine.h"
 
 bool init();
@@ -19,7 +20,7 @@ void keyb(unsigned char key, int x, int y);
 void mouse(int bn, int st, int x, int y);
 void motion(int x, int y);
 
-static float cam_dist = 2;
+static float cam_dist = 0.5;
 static float cam_theta, cam_phi;
 static int prev_mx, prev_my;
 static bool bnstate[8];
@@ -127,7 +128,7 @@ void idle()
 
 void draw_gears()
 {
-       /* world scale is in meters, gears are in millimeters, sclae by 1/1000 */
+       /* world scale is in meters, gears are in millimeters, scale by 1/1000 */
        glPushMatrix();
        glScalef(0.001, 0.001, 0.001);
 
@@ -142,7 +143,7 @@ void reshape(int x, int y)
 
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
-       gluPerspective(50.0, (float)x / (float)y, 0.05, 100.0);
+       gluPerspective(50.0, (float)x / (float)y, 0.01, 100.0);
 }
 
 void keyb(unsigned char key, int x, int y)
@@ -150,6 +151,11 @@ void keyb(unsigned char key, int x, int y)
        switch(key) {
        case 27:
                exit(0);
+
+       case 'w':
+               opt_gear_wireframe = !opt_gear_wireframe;
+               glutPostRedisplay();
+               break;
        }
 }