📄 graphics.cpp
字号:
#endif
void graphics::circle (int x, int y, int radius)
{
requiregraphics ();
activecolor (pforeground);
lastx= x + radius;
lasty= y;
transform_y (y);
if (radius == 0)
{
impl_plot_mask (x, y);
return;
}
// sq2_2 is sin (pi/4)
#ifdef M_SQRT2
static const double sq2_2= M_SQRT2 / 2.0;
#else
static const double sq2_2= sqrt (2.0) / 2.0;
#endif
//int r= int (radius * sq2_2 + .5) + 1;
int r= int (radius * sq2_2 + 1.0);
int rr= int (sqrt (radius * radius - r * r) + .5);
int dim= r;
if (rr >= r) ++dim;
#ifdef DEBUG_CIRCLE
cerr << "Circle: " << radius << ", " << r << endl;
#endif
util::auto_buffer <int> p (dim);
// Bresenham algorithm.
for (int i= 0, j= radius, d= 1 - radius; i < dim; ++i)
{
p [i]= j;
if (d < 0)
d+= 2 * i + 3;
else
{
d+= 2 * (i - j) + 5;
--j;
}
}
rr= p [r - 1] - 1;
ASSERT (rr <= dim - 1);
// The first point in each quadrant is plotted independently.
// In the first quadrant is omitted, we plot it at the end.
#ifdef DEBUG_CIRCLE
graphics::setcolor (4);
#endif
for (int j= 1; j < r; ++j)
{
//do_line (x + p [j], y - j);
impl_plot_mask (x + p [j], y - j);
pausec ();
}
#ifdef DEBUG_CIRCLE
graphics::setcolor (0);
#endif
for (int i= rr; i > 0; --i)
{
//do_line (x + i, y - p [i] );
impl_plot_mask (x + i, y - p [i] );
pausec ();
}
//do_line (x, y - radius);
#ifdef DEBUG_CIRCLE
graphics::setcolor (4);
#endif
impl_plot_mask (x, y - radius);
for (int i= 1; i < r; ++i)
{
//do_line (x - i, y - p [i] );
impl_plot_mask (x - i, y - p [i] );
pausec ();
}
#ifdef DEBUG_CIRCLE
graphics::setcolor (0);
#endif
for (int j= rr; j > 0; --j)
{
//do_line (x - p [j], y - j);
impl_plot_mask (x - p [j], y - j);
pausec ();
}
//do_line (x - radius, y);
#ifdef DEBUG_CIRCLE
graphics::setcolor (4);
#endif
impl_plot_mask (x - radius, y);
for (int j= 1; j < r; ++j)
{
//do_line (x - p [j], y + j);
impl_plot_mask (x - p [j], y + j);
pausec ();
}
#ifdef DEBUG_CIRCLE
graphics::setcolor (0);
#endif
for (int i= rr; i > 0; --i)
{
//do_line (x - i, y + p [i] );
impl_plot_mask (x - i, y + p [i] );
pausec ();
}
//do_line (x, y + radius);
impl_plot_mask (x, y + radius);
#ifdef DEBUG_CIRCLE
graphics::setcolor (4);
#endif
for (int i= 1; i < r; ++i)
{
//do_line (x + i, y + p [i] );
impl_plot_mask (x + i, y + p [i] );
pausec ();
}
#ifdef DEBUG_CIRCLE
graphics::setcolor (0);
#endif
for (int j= rr; j > 0; --j)
{
//do_line (x + p [j], y + j);
impl_plot_mask (x + p [j], y + j);
pausec ();
}
//do_line (x + radius, y);
#ifdef DEBUG_CIRCLE
graphics::setcolor (4);
#endif
impl_plot_mask (x + radius, y);
}
namespace {
inline void get_point_on_arc (int r, BlNumber a, int & out_x, int & out_y)
{
BlNumber s= sin (a) * r, c= cos (a) * r;
out_x= static_cast <int> (c < 0 ? c - .5 : c + .5);
out_y= static_cast <int> (s < 0 ? s - .5 : s + .5);
}
inline int get_quadrant (int x, int y)
{
if (x >= 0)
{
if (y >= 0)
return 0;
else
return 3;
}
else
{
if (y > 0)
return 1;
else
return 2;
}
}
}
void graphics::arccircle (int x, int y, int radius,
BlNumber arcbeg, BlNumber arcend)
{
/*
The code for this function and his auxiliarys
is taken from the Allegro library.
Many thanks.
*/
requiregraphics ();
activecolor (pforeground);
//#define DEBUG_ARCCIRCLE
#ifdef DEBUG_ARCCIRCLE
cerr << "arccircle: " << x << ", " << y << ", " << radius << ", " <<
arcbeg << ", " << arcend << endl;
#endif
transform_y (y);
int px, py; // Current position and auxiliary.
get_point_on_arc (radius, arcend, px, py);
const int ex= px, ey= py; // End position.
get_point_on_arc (radius, arcbeg, px, py);
const int sx= px, sy= py; // Start position.
// Current position start at start position.
const int sq= get_quadrant (sx, sy); // Start quadrant.
// Calculate end quadrant, considering that end point
// must be after start point.
int q= get_quadrant (ex, ey);
if (sq > q)
// Quadrant end must be greater or equal.
q+= 4;
else if (sq == q && arcbeg > arcend)
// If equal, consider the angle.
q+= 4;
const int qe= q;
q= sq; // Current cuadrant.
#ifdef DEBUG_ARCCIRCLE
cerr << "Quadrant from " << sq << " to " << qe << endl;
#endif
// Direction of movement.
int dy = ( ( (q + 1) & 2) == 0) ? 1 : -1;
int dx= ( (q & 2) == 0) ? -1 : 1;
const int rr= radius * radius;
int xx= px * px;
int yy= py * py - rr;
while (true)
{
// Change quadrant when needed, adjusting directions.
if ( (q & 1) == 0)
{
if (px == 0)
{
if (qe == q)
break;
++q;
dy= -dy;
}
}
else
{
if (py == 0)
{
if (qe == q)
break;
++q;
dx= -dx;
}
}
// If we are in the end quadrant, check if at the end position.
if (qe == q)
{
int det= 0;
if (dy > 0)
{
if (py >= ey)
++det;
}
else
{
if (py <= ey)
++det;
}
if (dx > 0)
{
if (px >= ex)
++det;
}
else
{
if (px <= ex)
++det;
}
if (det == 2)
break;
}
impl_plot_mask (x + px, y - py);
int xx_new= (px + dx) * (px + dx);
int yy_new= (py + dy) * (py + dy) - rr;
int rr1= xx_new + yy;
int rr2= xx_new + yy_new;
int rr3= xx + yy_new;
if (rr1 < 0) rr1= -rr1;
if (rr2 < 0) rr2= -rr2;
if (rr3 < 0) rr3= -rr3;
if (rr3 >= std::min (rr1, rr2) )
{
px+= dx;
xx= xx_new;
}
if (rr1 > std::min (rr2, rr3) )
{
py+= dy;
yy= yy_new;
}
}
if (px != sx || py != sy || sq == qe)
impl_plot_mask (x + px, y - py);
}
void graphics::mask (int m)
{
requiregraphics ();
maskvalue= static_cast <unsigned char> (m);
maskpos= 0;
}
void graphics::maskdrawfirstpoint (bool f)
{
requiregraphics ();
maskdrawfirst= f;
}
namespace {
char skipblank (const char * & s)
{
char c;
while ( (c= * s) == ' ' || c == '\t')
++s;
return c;
}
int getnum (const char * & s)
{
int r= 0;
char c;
if (! isdigit (* s) )
throw ErrSyntax;
while ( isdigit (c= * s) )
{
r*= 10;
r+= c - '0';
++s;
}
//cerr << r;
return r;
}
enum TypeMove { MoveAbs, MovePos, MoveNeg };
TypeMove gettypemove (const char * & s)
{
TypeMove tm= MoveAbs;
char c= skipblank (s);
switch (c)
{
case '+':
//cerr << '+';
tm= MovePos;
++s;
skipblank (s);
break;
case '-':
//cerr << '-';
tm= MoveNeg;
++s;
skipblank (s);
break;
}
return tm;
}
inline void adjust (int & value, TypeMove t, int last)
{
switch (t)
{
case MoveAbs:
break;
case MovePos:
value= last + value;
break;
case MoveNeg:
value= last - value;
break;
}
}
} // namespace
void graphics::draw (const std::string & str)
{
requiregraphics ();
const char * s= str.c_str ();
char c;
int i;
while ( (c= skipblank (s) ) != '\0')
{
//cerr << c;
++s;
bool nopaint= false;
if (c == 'B')
{
c= skipblank (s);
//cerr << c;
++s;
nopaint= true;
}
switch (c)
{
case 'M':
{
TypeMove mx= gettypemove (s);
int x= getnum (s);
adjust (x, mx, lastx);
c= skipblank (s);
if (c != ',')
throw ErrSyntax;
//cerr << ',';
++s;
TypeMove my= gettypemove (s);
int y= getnum (s);
adjust (y, my, lasty);
if (nopaint)
graphics::move (x, y);
else
graphics::line (x, y);
}
break;
case 'U':
skipblank (s);
i= getnum (s);
if (nopaint)
graphics::move (lastx, lasty - i);
else
graphics::line (lastx, lasty - i);
break;
case 'D':
skipblank (s);
i= getnum (s);
if (nopaint)
graphics::move (lastx, lasty + i);
else
graphics::line (lastx, lasty + i);
break;
case 'R':
skipblank (s);
i= getnum (s);
if (nopaint)
graphics::move (lastx + i, lasty);
else
graphics::line (lastx + i, lasty);
break;
case 'L':
skipblank (s);
i= getnum (s);
if (nopaint)
graphics::move (lastx - i, lasty);
else
graphics::line (lastx - i, lasty);
break;
case 'E':
skipblank (s);
i= getnum (s);
if (nopaint)
graphics::move (lastx + i, lasty - i);
else
graphics::line (lastx + i, lasty - i);
break;
case 'F':
skipblank (s);
i= getnum (s);
if (nopaint)
graphics::move (lastx + i, lasty + i);
else
graphics::line (lastx + i, lasty + i);
break;
case 'G':
skipblank (s);
i= getnum (s);
if (nopaint)
graphics::move (lastx - i, lasty + i);
else
graphics::line (lastx - i, lasty + i);
break;
case 'H':
skipblank (s);
i= getnum (s);
if (nopaint)
graphics::move (lastx - i, lasty - i);
else
graphics::line (lastx - i, lasty - i);
break;
case 'C':
c= skipblank (s);
if (! isdigit (c) )
throw ErrSyntax;
graphics::setcolor (c - '0');
++s;
break;
case 'X':
{
std::string x;
while ( (c= *s) != ';' && c != '\0')
{
x+= c;
++s;
}
if (c != ';')
throw ErrSyntax;
++s;
if (typeofvar (x) != VarString)
throw ErrMismatch;
std::string xx= evaluatevarstring (x);
draw (xx);
}
break;
case ';':
break;
default:
throw ErrSyntax;
}
}
//cerr << endl;
}
graphics::Point graphics::getlast ()
{
return Point (lastx, lasty);
}
std::string graphics::getkey ()
{
idle ();
if (queuekey.empty () )
return std::string ();
#if 0
std::string str= queuekey.front ();
queuekey.pop ();
return str;
#else
return queuekey.pop ();
#endif
}
namespace {
int zone= 8;
class BlWindow {
public:
BlWindow ()
{
setdefault ();
defaultcolors ();
}
BlWindow (int x1, int x2, int y1, int y2)
{
set (x1, x2, y1, y2);
defaultcolors ();
}
void setdefault ()
{
set (0, maxtcol - 1, 0, maxtrow - 1);
}
void set (int x1, int x2, int y1, int y2)
{
if (x1 > x2) std::swap (x1, x2);
if (y1 > y2) std::swap (y1, y2);
orgx= x1; orgy= y1;
width= x2 - x1 + 1;
height= y2 - y1 + 1;
x= y= 0;
}
void defaultcolors ()
{
foreground= default_foreground;
background= default_background;
}
int getwidth () { return width; }
void gotoxy (int x, int y)
{
this->x= x; this->y= y;
}
void tab (size_t n)
{
int col (n - 1);
if (x >= col)
{
do {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -