#include #include #include using namespace std; namespace fml { vec3 LineSegment::integrate(vec3 (*integrand)(vec3 s, vec3 ds), scalar dl) const { vec3 diff = this->b - this->a, sum = 0; scalar len = diff.magnitude(); vec3 diffnorm = diff / len, s = this->a, ds = diffnorm * dl; scalar l; for(l = 0; l < len; l += dl, s += ds) sum += integrand(s, ds); if(l < len) sum += integrand(s, diffnorm * (len - l)); return sum; } vec3 Arc::integrate(vec3 (*integrand)(vec3 s, vec3 ds), scalar dl) const { //cout << "Integrating loop of length " << this->angle << " radians" << endl; scalar r = this->radius.magnitude(), dtheta = dl / r; //cout << "R = " << r << ", dtheta = " << dtheta << endl; quat rot = quat::from_angleaxis(dtheta, normal); //cout << "rot = " << rot << ", crot = " << crot << endl; scalar len = this->angle * r, l; vec3 sum = 0; quat radius = this->radius; for(l = 0; l < len; l += dl) { vec3 ds = this->normal.cross(radius).normalize() * dl; sum += integrand(this->center + radius, ds); radius = radius.rotateby(rot); } if(l < len) { dl = len - l; dtheta = dl / r; vec3 ds = this->normal.cross(radius).normalize() * dl; sum += integrand(this->center + radius, ds); } return sum; } vec3 Spiral::integrate(vec3 (*integrand)(vec3 s, vec3 ds), scalar dl) const { //cout << "Integrating loop of length " << this->angle << " radians" << endl; scalar r = this->radius.magnitude(), dtheta = dl / r; //cout << "R = " << r << ", dtheta = " << dtheta << endl; quat rot = quat::from_angleaxis(dtheta, normal); //cout << "rot = " << rot << ", crot = " << crot << endl; /* only flat (doesn't include stretched length) */ scalar len = this->angle * r, l; vec3 sum = 0; quat radius = this->radius; /* how far along the axis we've moved */ vec3 axis = 0; /* we add this axial component each iteration */ vec3 dp = this->normal * dtheta * pitch / (2 * M_PI); for(l = 0; l < len; l += dl, axis += dp) { vec3 ds = this->normal.cross(radius).normalize() * dl + dp; sum += integrand(this->origin + axis + radius, ds); /* rotate by dtheta about normal */ radius = radius.rotateby(rot); } if(l < len) { dl = len - l; dtheta = dl / r; dp = this->normal * dtheta * pitch / (2 * M_PI); vec3 ds = this->normal.cross(radius).normalize() * dl + dp; sum += integrand(this->origin + axis + radius, ds); } return sum; } vec3 Toroid::integrate(vec3 (*integrand)(vec3 s, vec3 ds), scalar dl) const { /* this applies to the minor rotation */ scalar minor_r = this->minor_r; scalar major_r = this->major_radius.magnitude(); /* how far parallel to the major median each dl takes us */ scalar pitch_length = this->pitch * major_r; scalar dpar = this->pitch * dl / (2 * M_PI * sqrt(minor_r * minor_r + pitch_length * pitch_length)) * major_r; /* how far each dl rotates the major vector */ scalar major_dtheta = dpar / major_r; /* how long perpendicular to the major median each dl takes us (from * Pythagoras) */ scalar dper = sqrt(dl * dl - dpar * dpar); scalar minor_dtheta = dper / minor_r; /* minor normal is binormal to major normal and radius */ vec3 minor_normal = this->major_normal.cross(this->major_radius).normalize(); /* quaternion describing rotation of minor vector */ quat minor_rot = quat::from_angleaxis(minor_dtheta, minor_normal); quat major_rot = quat::from_angleaxis(major_dtheta, major_normal); vec3 sum = 0; quat major_radius = this->major_radius; quat minor_radius = this->major_radius.normalize() * this->minor_r; //cout << "minor_dtheta = " << minor_dtheta << endl; //cout << "minor_dper = " << dper << endl; //cout << "dl = " << dl << endl; //cout << "dpar = " << dpar << endl; //cout << "pitch = " << this->pitch << endl; for(scalar theta = 0; theta < this->major_angle; theta += major_dtheta) { vec3 dpar_vec = minor_normal * dpar; vec3 ds = minor_normal.cross(minor_radius).normalize() * dper + dpar_vec; sum += integrand(this->origin + major_radius + minor_radius, ds); /* we need to rotate some vectors: first the major radius and * minor normal about the major normal, and then the minor * radius */ /* we also need to rotate the minor radius rotation quaternion * about the origin */ major_radius = major_radius.rotateby(major_rot); minor_normal = minor_normal.rotateby(major_rot); minor_radius = minor_radius.rotateby(minor_rot); minor_rot = quat::from_angleaxis(minor_dtheta, minor_normal); //minor_rot = major_rot * minor_rot; //minor_crot = minor_rot.conjugate(); //cout << "Minor radius is " << minor_radius << endl; //cout << "Minor rot quat is " << minor_rot << endl; } #if 0 if(l < len) { dl = len - l; dtheta = dl / r; rot = quat::from_angleaxis(dtheta, normal); crot = rot.conjugate(); dp = this->normal * dtheta * pitch / (2 * M_PI); vec3 ds = this->normal.cross(radius).normalize() * dl + dp; sum += integrand(this->origin + axis + radius, ds); } #endif return sum; } }