init_angle = 0;
xform_valid = false;
+ supergear = 0;
+
mesh = 0;
}
delete mesh;
}
+void Gear::attach(Gear *g)
+{
+ if(g->supergear) {
+ if(g->supergear == this) {
+ return;
+ }
+ g->supergear->detach(g);
+ }
+ g->supergear = this;
+ subgears.push_back(g);
+
+ // make co-axial
+ g->axis = axis;
+ g->pos.x = pos.x;
+ g->pos.y = pos.y;
+}
+
+bool Gear::detach(Gear *g)
+{
+ int nsubgears = (int)subgears.size();
+ for(int i=0; i<nsubgears; i++) {
+ if(subgears[i] == g) {
+ subgears.erase(subgears.begin() + i);
+ g->supergear = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+Gear *Gear::get_super() const
+{
+ return supergear;
+}
+
void Gear::set_angular_offset(float offs)
{
init_angle = offs;
void Gear::set_position(const Vec3 &pos)
{
- this->pos = pos;
- xform_valid = false;
+ if(!supergear) {
+ this->pos = pos;
+ xform_valid = false;
+ } else {
+ if(fabs(this->pos.z - pos.z) > 1e-5) {
+ this->pos.z = pos.z;
+ xform_valid = false;
+ }
+ }
}
const Vec3 &Gear::get_position() const
Vec3 Gear::get_global_position() const
{
- return pos; // TODO
-}
-
-Vec3 Gear::get_planar_position() const
-{
- Mat4 inv_xform = transpose(get_dir_matrix());
- return inv_xform * pos;
+ const Mat4 &m = get_matrix();
+ return m * Vec3(0, 0, 0);
}
void Gear::set_angle(float angle)
float Gear::get_vis_rotation() const
{
- float fix_crooked_teeth = get_angular_pitch() * 3.0 / 8.0;
- return fmod(init_angle + fix_crooked_teeth + angle, M_PI * 2.0);
+ return fmod(init_angle + angle, M_PI * 2.0);
}
const Mat4 &Gear::get_matrix() const
mesh->explode();
mesh->calc_face_normals();
+ float fix_tooth_up = get_angular_pitch() * 3.0 / 8.0;
+
Mat4 rot;
rot.rotation_x(M_PI / 2.0);
+ rot.rotate_z(fix_tooth_up);
mesh->apply_xform(rot, rot);
mesh->set_vis_vecsize(6.0);
xform = dir_xform;
xform.rotate_z(get_vis_rotation());
xform.translate(pos);
+
+ axel_xform = dir_xform;
+ axel_xform.translate(pos);
}
private:
Mesh *mesh;
- mutable Mat4 xform, dir_xform;
+ mutable Mat4 xform, dir_xform, axel_xform;
mutable bool xform_valid;
void calc_matrix() const;
float bevel; // bevel size
+ Gear *supergear;
+ std::vector<Gear*> subgears;
std::vector<GearPin> pins;
std::vector<GearSlot> slots;
Gear();
~Gear();
+ void attach(Gear *g);
+ bool detach(Gear *g);
+ Gear *get_super() const;
+
void set_angular_offset(float offs);
float get_angular_offset() const;
Vec3 ptdir = pt - ray.origin;
float t = dot(normal, ptdir) / ndotdir;
+ hit->dist = t;
hit->pos = ray.origin + ray.dir * t;
hit->normal = normal;
hit->obj = this;
void Machine::add_gear(Gear *g)
{
+ if(gearidx.find(g) != gearidx.end()) {
+ return; // already have this gear
+ }
+ gearidx[g] = gears.size();
gears.push_back(g);
meshing_valid = false;
}
// we're going to need the planar position of each gear on its plane, so let's cache it
Vec3 *ppos = (Vec3*)alloca(ngears * sizeof *ppos);
for(int i=0; i<ngears; i++) {
- ppos[i] = gears[i]->get_planar_position();
+ ppos[i] = gears[i]->get_position();
}
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(i == j || gears[i]->get_super() == gears[j] || gears[j]->get_super() == gears[i]) {
+ // don't attempt meshing if it's the same gear, or they are attached to each other
+ 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
// fix the initial angles so that teeth mesh as best as possible
// should work in one pass as long as the gear train is not impossible
for(int i=0; i<ngears; i++) {
- float rnd = gears[i]->angle + gears[i]->get_angular_pitch() / 2.0;
+ /*float rnd = gears[i]->angle + gears[i]->get_angular_pitch() / 2.0;
float snap = rnd - fmod(rnd, gears[i]->get_angular_pitch());
- gears[i]->set_angle(snap);
+ gears[i]->set_angle(snap);*/
gears[i]->set_angular_offset(0);
}
}
}
}
+
+ /*
+ printf("meshing graph\n");
+ for(int i=0; i<ngears; i++) {
+ putchar(' ');
+ for(int j=0; j<ngears; j++) {
+ printf("| %d ", meshing[i][j] ? 1 : 0);
+ }
+ printf("|\n");
+ }
+ */
}
void Machine::update_gear(int idx, float angle)
{
+ Gear *gear = gears[idx];
+
if(visited[idx]) {
- if(delta_angle(angle, gears[idx]->angle) > 0.25 / gears[idx]->nteeth) {
+ if(delta_angle(angle, gear->angle) > 0.25 / gear->nteeth) {
fprintf(stderr, "warning: trying to transmit different values to gear %s (%d)\n",
- gears[idx]->name.c_str(), idx);
- gears[idx]->angle = 0;
+ gear->name.c_str(), idx);
+ gear->angle = 0;
}
return;
}
- gears[idx]->set_angle(angle);
+ gear->set_angle(angle);
visited[idx] = true;
+ // propagate to meshing gears (depth-first)
int ngears = (int)gears.size();
for(int i=0; i<ngears; i++) {
if(!meshing[idx][i]) continue;
assert(idx != i);
- float ratio = -(float)gears[idx]->nteeth / (float)gears[i]->nteeth;
+ float ratio = -(float)gear->nteeth / (float)gears[i]->nteeth;
update_gear(i, angle * ratio);
}
+
+ // propagate to rigidly attached gears
+ if(gear->supergear) {
+ int supidx = gearidx[gear->supergear];
+ update_gear(supidx, angle);
+ }
+
+ int nsub = (int)gear->subgears.size();
+ for(int i=0; i<nsub; i++) {
+ int subidx = gearidx[gear->subgears[i]];
+ update_gear(subidx, angle);
+ }
}
void Machine::update(float dt)
#define MACHINE_H_
#include <vector>
+#include <map>
#include "gear.h"
struct Motor {
class Machine {
private:
std::vector<Gear*> gears;
+ std::map<Gear*, int> gearidx;
bool **meshing;
bool meshing_valid;
bool *visited; /* used for update_gear */
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
Mesh::use_custom_sdr_attr = false;
gear3->gen_mesh();
machine->add_gear(gear3);
+ Gear *subgear = new Gear;
+ subgear->set_teeth(10, pitch);
+ subgear->pos = Vec3(0, 0, (gear2->thickness + subgear->thickness) / 2 + 1);
+ subgear->gen_mesh();
+ gear2->attach(subgear);
+ machine->add_gear(subgear);
+
machine->add_motor(0, 1.0);
start_time = glutGet(GLUT_ELAPSED_TIME);
hover_gear = pick_gear(prev_mx, prev_my);
}
+static void set_light(int idx, const Vec3 &pos, const Vec3 &color)
+{
+ unsigned int lt = GL_LIGHT0 + idx;
+ float posv[] = { pos.x, pos.y, pos.z, 1 };
+ float colv[] = { color.x, color.y, color.z, 1 };
+
+ glEnable(lt);
+ glLightfv(lt, GL_POSITION, posv);
+ glLightfv(lt, GL_DIFFUSE, colv);
+ glLightfv(lt, GL_SPECULAR, colv);
+}
+
static void display()
{
unsigned int msec = glutGet(GLUT_ELAPSED_TIME) - start_time;
glRotatef(cam_phi, 1, 0, 0);
glRotatef(cam_theta, 0, 1, 0);
+ set_light(0, Vec3(-50, 75, 100), Vec3(1.0, 0.8, 0.7) * 0.8);
+ set_light(1, Vec3(100, 0, 30), Vec3(0.6, 0.7, 1.0) * 0.6);
+ set_light(2, Vec3(-10, -10, 60), Vec3(0.8, 1.0, 0.8) * 0.3);
+
update(dt);
draw_gears();