home *** CD-ROM | disk | FTP | other *** search
- /*
- * Turtle.C - definitions for 3D turtle.
- *
- * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
- * University of Berne, Switzerland
- * All rights reserved.
- *
- * This software may be freely copied, modified, and redistributed
- * provided that this copyright notice is preserved on all copies.
- *
- * You may not distribute this software, in whole or in part, as part of
- * any commercial product without the express consent of the authors.
- *
- * There is no warranty or other guarantee of fitness of this software
- * for any purpose. It is provided solely "as is".
- *
- */
-
- #include <stdlib.h>
- #include <values.h>
- #include "Turtle.h"
- #include "TransMatrix.h"
- #include "Error.h"
- #include "Ray.h"
-
- //___________________________________________________________ Tropism
-
- Tropism::Tropism(real x, real y, real z, real w)
- : F(x, y, z), weight(w), apply(0)
- {
- if (F.zero())
- F = Vector(0,0,-1);
- F.normalize();
- }
-
- //___________________________________________________________ Turtle
-
- /* init of turtle:
- *
- * *
- * / \ H
- * |
- * |
- * L |
- * / _________|
- * \ /
- * / U
- * \ /
- * *
- */
-
- Turtle::Turtle()
- : P(0,0,0), lastP(0,0,0), H(0,0,1), L(0,-1,0), U(1,0,0),
- tropism(0,0,-1,0.5),
- hullActivated(0), hull(NULL), reflectanceFactor(1), stopOnHit(0)
- {
- width = 1;
- lastWidth = -1; // no move has been previously done
-
- b.expand(P);
- }
-
- Turtle::Turtle(const Turtle& t)
- :b(t.b),
- P(t.P), lastP(t.lastP),
- H(t.H), L(t.L), U(t.U),
- width(t.width), lastWidth(t.lastWidth),
- tropism(t.tropism),
- color(t.color), lastColor(t.lastColor),
- texture(t.texture), lastTexture(t.lastTexture),
- hullActivated(t.hullActivated),
- stopOnHit(t.stopOnHit),
- hull(t.hull),
- reflectanceFactor(t.reflectanceFactor),
- closestObject(t.closestObject),
- distanceToClosestObject(t.distanceToClosestObject)
- {}
-
- Turtle::~Turtle()
- {}
-
- /*
- * forward moves the turtle in the current direction according to
- * the formula:
- *
- * P' = P + step*H
- */
-
- int Turtle::forward(real step)
- {
- lastWidth = width;
- lastP = P;
- lastColor = color;
- lastTexture = texture;
-
- if (hullActivated)
- return forwardWithRespectToHull(step);
- else {
- P += step*H;
- applyTropism();
- b.expand(P);
- return 0;
- }
- }
-
- /*
- * Moves the turtle in the current direction with respect to the
- * activated hull. If the turtle hits the hull it changes direction.
- * This is repeated until step == 0.
- */
-
- int Turtle::forwardWithRespectToHull(real step)
- {
- hull->intersect(Ray(P, H), distanceToClosestObject, closestObject);
-
- while (step > 0) {
- if (distanceToClosestObject > step) {
- P += H*step;
- b.expand(P);
- applyTropism();
- distanceToClosestObject -= step;
- break;
- }
- else {
- P += H*distanceToClosestObject;
- b.expand(P);
-
- if (stopOnHit)
- return 1;
-
- bounce();
- applyTropism();
- step -= distanceToClosestObject;
- hull->intersect(Ray(P, H), distanceToClosestObject, closestObject);
- }
- }
-
- return 0;
- }
-
- /*
- * Reflect turtle at the current closest object -> changes H, U
- */
-
- void Turtle::bounce()
- {
- /*
- * Reflect turtle at position P. The result is a new heading (H)
- * and a changed up vector (U). The left vector (L) does not change
- * (a reflected ray stays in the same plane).
- */
-
- Vector normal = closestObject->getNormal(P);
-
- H = H-2.*((normal^H)*normal)*reflectanceFactor;
- H.normalize();
- U = H*L;
- }
-
- /*
- * pitch rotates H, L, U around L according to the formula
- *
- * [ cos(a) 0 -sin(a) ]
- * [ ]
- * [H' L' U'] = [ H L U ] * [ 0 1 0 ]
- * [ ]
- * [ sin(a) 0 cos(a) ]
- */
-
- void Turtle::pitch(real a)
- {
- Vector tmp(H);
- real sin_a, cos_a;
-
- SinCos(a, sin_a, cos_a);
-
- H = H*cos_a + U*sin_a;
- H.normalize();
- U = U*cos_a - tmp*sin_a;
- }
-
- /*
- * turn rotates H, L, U around U according to the formula
- *
- * [ cos(a) sin(a) 0 ]
- * [ ]
- * [H' L' U'] = [ H L U ] * [ - sin(a) cos(a) 0 ]
- * [ ]
- * [ 0 0 1 ]
- */
-
- void Turtle::turn(real a)
- {
- Vector tmp(H);
- real sin_a, cos_a;
-
- SinCos(a, sin_a, cos_a);
-
- H = H*cos_a - L*sin_a;
- H.normalize();
- L = tmp*sin_a + L*cos_a;
- }
-
- /*
- * roll rotates H, L, U around H according to the formula
- *
- * [ 1 0 0 ]
- * [ ]
- * [H' L' U'] = [ H L U ] * [ 0 cos(a) sin(a) ]
- * [ ]
- * [ 0 -sin(a) cos(a) ]
- */
-
- void Turtle::roll(real a)
- {
- Vector tmp(L);
- real sin_a, cos_a;
-
- SinCos(a, sin_a, cos_a);
-
- L = L*cos_a - U*sin_a;
- U = tmp*sin_a + U*cos_a;
- }
-
- /*
- * reverse spins the turtle around 180 degrees
- */
-
- void Turtle::reverse()
- {
- H = -H;
- L = -L;
- }
-
- void Turtle::rotate_vertical()
- {
- const real tolerance = 1e-4;
- static Vector gravity(0,0,-1);
- Vector tmp = gravity * H;
-
- if (tmp.length() < tolerance)
- return;
-
- L = tmp.normalized();
- U = H*L;
- }
-
- void Turtle::setWeight(real w)
- {
- tropism.weight = w;
- if (equal(tropism.weight, 0) || tropism.F.zero())
- tropism.apply = 0;
- else
- tropism.apply = 1;
- }
-
- void Turtle::setTropism(real x, real y, real z)
- {
- tropism.F = Vector(x, y, z);
-
- if (!tropism.F.zero())
- tropism.F.normalize();
-
- if (equal(tropism.weight, 0) || tropism.F.zero())
- tropism.apply = 0;
- else
- tropism.apply = 1;
- }
-
- ostream& operator<<(ostream& os, const Turtle& t)
- {
- os << "P: " << t.P << "\n"
- << "H: " << t.H << "\n"
- << "U: " << t.U << "\n"
- << "L: " << t.L << "\n";
- return os;
- }
-
- /*
- * Apply the given tropism vector to the turtle.
- */
-
- void Turtle::applyTropism()
- {
- static TransMatrix rot;
-
- /*
- * Should tropism be applied.
- */
- if (!tropism.apply)
- return;
-
- Vector rotvec(H*tropism.F);
- real alpha = acos(H^tropism.F)*tropism.weight*rotvec.length();
-
- /*
- * Limit the rotation.
- */
- if (alpha > M_PI/6) alpha = M_PI/6;
- if (alpha < -M_PI/6) alpha = -M_PI/6;
-
- if (!equal(alpha,0) && !rotvec.zero()) {
- rot.setRotate(rotvec, alpha);
- H = H*rot; H.normalize();
- L = L*rot; L.normalize();
- U = H*L;
- }
- }
-
-