const bool R3Segment:: operator==(const R3Segment& segment) const { // Return whether segment is equal if (Start() != segment.Start()) return false; if (End() != segment.End()) return false; return true; }
double R3Distance(const R3Ray& ray, const R3Segment& segment) { // There's got to be a better way ??? // Get vectors in more convenient form const R3Vector v1 = ray.Vector(); const R3Vector v2 = segment.Vector(); // Compute useful intermediate values const double v1v1 = 1.0; // v1.Dot(v1); const double v2v2 = 1.0; // v2.Dot(v2); double v1v2 = v1.Dot(v2); double denom = v1v2*v1v2 - v1v1*v2v2; // Check if ray and segment are parallel if (denom == 0) { // Not right ??? // Look at directions of vectors, then check relative starts and stops return R3Distance(segment.Line(), ray.Line()); } else { // Find closest points const R3Vector p1 = ray.Start().Vector(); const R3Vector p2 = segment.Start().Vector(); double p1v1 = v1.Dot(p1); double p2v2 = v2.Dot(p2); double p1v2 = v2.Dot(p1); double p2v1 = v1.Dot(p2); double ray_t = (v1v2*p2v2 + v2v2*p1v1 - v1v2*p1v2 - v2v2*p2v1) / denom; double segment_t = (v1v2*p1v1 + v1v1*p2v2 - v1v2*p2v1 - v1v1*p1v2) / denom; R3Point ray_point = (ray_t <= 0.0) ? ray.Start() : ray.Point(ray_t); R3Point segment_point = (segment_t <= 0.0) ? segment.Start() : (segment_t >= segment.Length()) ? segment.End() : segment.Ray().Point(segment_t); double distance = R3Distance(ray_point, segment_point); return distance; } }
double R3Distance(const R3Point& point, const R3Segment& segment) { // Check if start point is closest R3Vector v1 = point - segment.Start(); double dir1 = v1.Dot(segment.Vector()); if (dir1 < 0) return v1.Length(); // Check if end point is closest R3Vector v2 = point - segment.End(); double dir2 = v2.Dot(segment.Vector()); if (dir2 < 0) return v2.Length(); // Return distance from point to segment line return R3Distance(point, segment.Line()); }
double R3SignedDistance(const R3Plane& plane, const R3Segment& segment) { // Return signed distance from plane to segment double d1 = R3SignedDistance(plane, segment.Start()); if (d1 > 0) { // Start point is above plane double d2 = R3SignedDistance(plane, segment.End()); if (d2 > 0) return ((d1 > d2) ? d2 : d1); else return 0.0; } else if (d1 < 0) { // Start point is below plane double d2 = R3SignedDistance(plane, segment.End()); if (d2 < 0) return ((d1 > d2) ? d1 : d2); else return 0.0; } else { // Start point is on plane return 0.0; } }
//////////////////////////////////////////////////////////// // Generating Particles //////////////////////////////////////////////////////////// void GenerateParticles(R3Scene *scene, double current_time, double delta_time) { // Generate new particles for every source R3ParticleSource* source; for (int i = 0; i < scene->NParticleSources(); i++) { source = scene->ParticleSource(i); int num_particles = source->elapsed_time * source->rate; if ((num_particles) >= 1) { source->elapsed_time = 0; for (int m = 0; m < num_particles; m++) { if (source->shape->type == R3_SEGMENT_SHAPE) { R3Segment* seg = source->shape->segment; R3Point pos = seg->Start() + RandomNumber() * (seg->End() - seg->Start()); R3Vector dir = seg->Vector(); dir.Cross(R3Vector(RandomNumber() - .5, RandomNumber() - .5, RandomNumber() - .5)); dir.Normalize(); R3Particle* particle = new R3Particle(); particle->position = pos; particle->velocity = source->velocity * dir; particle->mass = source->mass; particle->fixed = source->fixed; particle->drag = source->drag; particle->elasticity = source->elasticity; particle->lifetime = source->lifetime; particle->material = source->material; scene->particles.push_back(particle); } if (source->shape->type == R3_BOX_SHAPE) { R3Particle* particle = generate_random_box_particle(source); scene->particles.push_back(particle); } else if (source->shape->type == R3_MESH_SHAPE) { R3Mesh* mesh = source->shape->mesh; double area_sum = 0.0; double face_prob[mesh->faces.size()]; for (unsigned int i = 0; i < mesh->faces.size(); i++) { face_prob[i] = mesh->faces[i]->Area(); area_sum += face_prob[i]; } for (unsigned int i = 0; i < mesh->faces.size(); i++) face_prob[i] /= area_sum; int source_face = discrete(face_prob, mesh->faces.size()); int num_verts = mesh->faces[source_face]->vertices.size(); R3Point pos = R3Point(0,0,0); R3Vector dir = R3Vector(0,0,0); if (num_verts == 3) { double a = 0; double b = 0; double c; while (a + b <= 1) { a = RandomNumber(); b = RandomNumber(); } a = 1 - a; b = 1 - b; c = 1 - a - b; pos = a * mesh->faces[source_face]->vertices[0]->position + b * mesh->faces[source_face]->vertices[1]->position + c * mesh->faces[source_face]->vertices[2]->position; mesh->faces[source_face]->vertices[0]->UpdateNormal(); mesh->faces[source_face]->vertices[1]->UpdateNormal(); mesh->faces[source_face]->vertices[2]->UpdateNormal(); dir = a * mesh->faces[source_face]->vertices[0]->normal + b * mesh->faces[source_face]->vertices[0]->normal + c * mesh->faces[source_face]->vertices[0]->normal; } else { int num_verts = mesh->faces[source_face]->vertices.size(); double vert_sum = 0.0; double vert_prob[num_verts]; for (int i = 0; i < num_verts; i++) { vert_prob[i] = RandomNumber(); vert_sum += vert_prob[i]; } R3Point pos = R3Point(0,0,0); R3Vector dir = R3Vector(0,0,0); for (int i = 0; i < num_verts; i++) { vert_prob[i] /= vert_sum; pos += vert_prob[i] * mesh->faces[source_face]->vertices[i]->position; mesh->faces[source_face]->vertices[i]->UpdateNormal(); dir += vert_prob[i] * mesh->faces[source_face]->vertices[i]->normal; } } dir.Normalize(); R3Particle* particle = new R3Particle(); particle->position = pos; particle->velocity = source->velocity * dir; particle->mass = source->mass; particle->fixed = source->fixed; particle->drag = source->drag; particle->elasticity = source->elasticity; particle->lifetime = source->lifetime; particle->material = source->material; scene->particles.push_back(particle); } else if (source->shape->type == R3_SPHERE_SHAPE) { R3Sphere* sphere = source->shape->sphere; double radius = sphere->Radius(); R3Point center = sphere->Center(); double z = (RandomNumber() * 2 - 1); double t = RandomNumber() * 2 * PI; double r = sqrt(1.0 - z*z); double x = r * cos(t) * radius; double y = r * sin(t) * radius; R3Point pos = R3Point(center.X() + x, center.Y() + y, center.Z() + z*radius); R3Vector dir = (pos - center); dir.Normalize(); R3Particle* particle = new R3Particle(); particle->position = pos; particle->velocity = source->velocity * dir; particle->mass = source->mass; particle->fixed = source->fixed; particle->drag = source->drag; particle->elasticity = source->elasticity; particle->lifetime = source->lifetime; particle->material = source->material; scene->particles.push_back(particle); } } } else source->elapsed_time += delta_time; } }