home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
oct93
/
graphics
/
graphtal.lha
/
Graphtal
/
Turtle.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-17
|
7KB
|
310 lines
/*
* 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;
}
}