// -----------------------------------------------------------------
// file: turtle_ps.C
// Version: $Revision: 1.5 $ from $Date: 1998/12/03 17:33:32 $
// -----------------------------------------------------------------
// provides a simple function-based turtle-graphic interface
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace IFM_NAMESPACE {
const int coordwidth = 512;
const int borderwidth = 40;
// types for arithmetic stuff:
typedef int INT;
typedef double FT;
struct TurtlePoint {
FT x, y;
TurtlePoint( FT xx, FT yy) : x( xx), y ( yy) {}
};
struct Turtle {
// turtle commands
static const int forward = 0;
static const int left = 1;
static const int right = 2;
// defines the turtle commands:
struct Command;
// default con- and destructor:
Turtle();
~Turtle();
// execute a command:
void operator()( int c, int steps = 1);
// return turtle coordinates:
FT x() const;
FT y() const;
FT xmax() const;
FT xmin() const;
FT ymax() const;
FT ymin() const;
private:
INT Turtle::round( FT r);
FT Turtle::map_x( FT x);
FT Turtle::map_y( FT y);
bool pen;
bool used;
FT _x, _y, _phi, _xmin, _xmax, _ymin, _ymax, _xcw, _ycw;
// to store the coordinates after any forward cmd:
typedef std::deque< TurtlePoint > Cont;
Cont positions;
// draw function:
void draw();
};
// member functions of class Turtle
Turtle::Turtle()
: pen( false), used( false), _x( 0), _y( 0), _phi( 0),
_xmin( 0), _xmax( 0), _ymin( 0), _ymax( 0)
{ positions.push_back( TurtlePoint( 0, 0)); }
INT
Turtle::round( FT r) {
if ( r < floor( r) + 0.5)
return INT( floor( r));
else
return INT( ceil( r));
}
FT
Turtle::map_x( FT x) {
assert( x >= _xmin && x <= _xmax);
return borderwidth +
(_xmax == _xmin ? 0 :
round( (x - _xmin) / (_xmax - _xmin) * _xcw));
}
FT
Turtle::map_y( FT y) {
assert( y >= _ymin && y <= _ymax);
return borderwidth + _ycw -
(_ymax == _ymin ? 0 :
round( (y - _ymin) / (_ymax - _ymin) * _ycw));
}
void
Turtle::draw() {
std::cout << "%!PS-Adobe-2.0\n"
<< "%%Creator: turtle_ps / Michael Hoffmann\n"
<< "%%Title: Turtle Graphics\n"
<< "%%Pages: 1\n"
<< "%%PageOrder: Ascend\n"
<< "%%BoundingBox: 0 0 "
<< round(_xcw + 2 * borderwidth) << " "
<< round(_ycw + 2 * borderwidth) << "\n"
<< "%%EndComments\n";
Cont::iterator i = positions.begin();
TurtlePoint p = *i;
while ( ++i != positions.end()) {
std::cout << round( map_x( p.x)) << " "
<< round( map_y( p.y)) << " moveto "
<< round( map_x( (*i).x)) << " "
<< round( map_y( (*i).y)) << " lineto stroke\n";
p = *i;
}
std::cout << "showpage\n%% EOF" << std::endl;
}
Turtle::~Turtle()
{
if ( used) {
// compute coordinate width:
if ( xmax() - xmin() > ymax() - ymin()) {
_xcw = coordwidth;
if ( ymax() == ymin())
_ycw = 0;
else
_ycw = coordwidth * (ymax() - ymin()) / (xmax() - xmin());
} else {
if ( ymax() == ymin()) {
_ycw = 0;
_xcw = 0;
} else {
_ycw = coordwidth;
if ( xmax() == xmin())
_xcw = 0;
else
_xcw = coordwidth * (xmax() - xmin()) / (ymax() - ymin());
}
}
// draw picture:
std::cerr << "----------------------------------------------------\n"
<< "One moment, please ..."
<< std::endl;
draw();
// Wait for mouse-click/handle expose events:
std::cerr << "----------------------------------------------------\n"
<< "Drawing complete.\n"
<< "----------------------------------------------------"
<< std::endl;
}
}
void
Turtle::operator()( int c, int steps)
{
used = true;
switch( c) {
case forward:
_x += steps * cos( _phi / 180 * M_PI);
_y += steps * sin( _phi / 180 * M_PI);
_xmin = std::min( _xmin, _x);
_xmax = std::max( _xmax, _x);
_ymin = std::min( _ymin, _y);
_ymax = std::max( _ymax, _y);
positions.push_back( TurtlePoint( _x, _y));
break;
case right:
_phi += steps;
while ( _phi > 360)
_phi -= 360;
break;
case left:
_phi -= steps;
while ( _phi < 0)
_phi += 360;
break;
}
}
// return turtle coordinates:
FT Turtle::x() const { return _x; }
FT Turtle::y() const { return _y; }
FT Turtle::xmax() const { return _xmax; }
FT Turtle::xmin() const { return _xmin; }
FT Turtle::ymax() const { return _ymax; }
FT Turtle::ymin() const { return _ymin; }
// static stuff for simple function interface:
Turtle the_turtle;
void forward(unsigned int n_steps)
// POST: turtle has moved n_steps steps in its current direction.
{ the_turtle( Turtle::forward, n_steps); }
void left(int deg)
// POST: turtle has turned left by deg degrees.
{ the_turtle( Turtle::left, deg); }
void right(int deg)
// POST: turtle has turned right by deg degrees.
{ the_turtle( Turtle::right, deg); }
} // namespace IFM_NAMESPACE
// EOF