📄 canvas.cpp
字号:
#include "mathutils.h"
#include "canvas.h"
#include "CMUgraphics.h"
#include "image.h"
#include "auxil.h"
#include "canvasiterator.h"
#include <typeinfo>
#include <sstream>
#include <fstream>
#include <cmath>
Box::Box(int xul, int yul, int xlr, int ylr)
: myLeft(xul, yul),
myRight(xlr, ylr)
{
}
Box::Box(const Point& ul, const Point& lr)
: myLeft(ul),
myRight(lr)
{
}
Box::Box()
: myLeft(0,0),
myRight(0,0)
{
}
const Box& Box::operator += (const Box& rhs)
{
myLeft.x = min(myLeft.x, rhs.myLeft.x);
myLeft.y = min(myLeft.y, rhs.myLeft.y);
myRight.x = max(myRight.x, rhs.myRight.x);
myRight.y = max(myRight.y, rhs.myRight.y);
return *this;
}
Box operator + (const Box& lhs, const Box& rhs)
{
Box copy(lhs);
copy += rhs;
return copy;
}
Point Box::getUL() const
{
return myLeft;
}
Point Box::getLR() const
{
return myRight;
}
double Box::width() const
{
return myRight.x - myLeft.x;
}
double Box::height() const
{
return myRight.y - myLeft.y;
}
bool Box::contains(const Point& p) const
{
Point ul = getUL();
Point ur = getLR();
return ul.x <= p.x && p.x <= ur.x &&
ul.y <= p.y && p.y <= ur.y;
}
bool Box::intersects(const Box& b) const
{
Point LL = b.getUL(); LL.y = b.getLR().y;
Point UR = b.getLR(); LL.x = b.getUL().x;
Point myLL = getUL(); myLL.y = getLR().y;
Point myUR = getLR(); myUR.x = getUL().x;
return contains(LL) || contains(UR) ||
contains(b.getUL()) || contains(b.getLR()) ||
b.contains(myLL) || b.contains(myUR) ||
b.contains(myLeft) || b.contains(myRight);
}
string Box::tostring() const
{
ostringstream out;
out << "[ " << getUL() << ", " << getLR() << " ]";
return out.str();
}
ostream& operator << (ostream& os, const Box& b)
{
// os << "[ " << b.getUL() << ", " << b.getLR() << " ]";
os << b.tostring();
return os;
}
int BaseCanvas::ourCount = 0;
const int BaseCanvas::BBARHEIGHT = 20;
BaseCanvas::BaseCanvas(int w, int h, int x, int y)
: myWindow(new window(w,h,x,y)),
myHeight(h),
myFilled(true),
myCoords(BaseCanvas::top_origin)
{
myWindow->SetBuffering(false);
myWindow->ChangeTitle("Tapestry Canvas");
myCount = ourCount;
ourCount++;
if (myCount == 0)
{
SetColor(CanvasColor::BLACK);
DrawString("click with mouse to begin",Point(0,h/2));
int x,y;
myWindow->WaitMouseClick(x,y);
Clear();
SetColor(CanvasColor::BLACK);
}
}
double BaseCanvas::ycoord(double d)
{
if (myCoords == BaseCanvas::top_origin)
{ return d;
}
else
{ return height() - d;
}
}
Point BaseCanvas::ycoord(const Point& p)
{
return Point(p.x,ycoord(p.y));
}
void BaseCanvas::MakeBBar()
{
SetColor(CanvasColor::BLACK);
DrawLine(Point(0,height()-BBARHEIGHT),Point(width(),height()-BBARHEIGHT));
SetColor(myColor);
myHeight = height() - BBARHEIGHT;
}
BaseCanvas::~BaseCanvas()
{
// delete myBackground;
ourCount--;
// delete myWindow;
}
int BaseCanvas::height()
{
return myHeight; // myWindow->GetHeight();
}
int BaseCanvas::width()
{
return myWindow->GetWidth();
}
void BaseCanvas::Print()
{
myWindow->Print();
}
AnimatedCanvas::AnimatedCanvas(int w, int h, int x, int y, bool isBuffered)
: BaseCanvas(w,h,x,y),
myShapes(),
myShapeCount(0),
myButtonCount(0),
myBackground(0),
myClickPoint(-1,-1),
myKey(0),
myIsBuffered(isBuffered),
myIsRunning(false)
{
myShapes.reserve(8); // space for some shapes to start
myWindow->SetBuffering(myIsBuffered);
}
AnimatedCanvas::~AnimatedCanvas()
{
int k;
for(k=0; k < myShapes.size(); k++)
{
// delete myShapes[k];
}
}
void AnimatedCanvas::repaint()
{
if (myIsBuffered)
{
Clear();
if (myBackground != 0)
{
myWindow->DrawImage(myBackground,0,0,width(),height());
}
}
int k;
poll();
Point p = getClick();
if( ! myKey.isnothing())
{
for(k=0; k < myShapeCount; k++)
{
Keyable * ks = dynamic_cast<Keyable *>(myShapes[k]);
if (ks != 0)
{
ks->processKey(myKey,*this);
}
}
}
if (p.x != -1)
{
for(k=0; k < myShapeCount; k++)
{
Mouseable * ms = dynamic_cast<Mouseable *>(myShapes[k]);
if (ms != 0)
{
ms->processClick(p,*this);
}
}
}
for(k=0; k < myShapeCount; k++)
{
myShapes[k]->draw(*this);
}
myIsRunning = false;
int limit = myDeadShapes.size();
for(k=0; k < limit; k++)
{
removeShape(myDeadShapes[k]);
}
myDeadShapes.clear();
limit = myLiveShapes.size();
for(k=0; k < limit; k++)
{
addShape(myLiveShapes[k]);
}
myLiveShapes.clear();
myIsRunning = true;
myWindow->UpdateBuffer();
}
void AnimatedCanvas::setBackground(image& im)
{
myBackground= &im;
}
void AnimatedCanvas::addShape(Shape * s)
{
if (myIsRunning)
{
myLiveShapes.push_back(s);
return;
}
myShapes.push_back(s);
myShapeCount++;
}
void AnimatedCanvas::addShape(Shape& s)
{
addShape(s.clone());
}
void AnimatedCanvas::addShape(Button& b)
{
addShape((Button *) b.clone());
}
void AnimatedCanvas::addShape(Button * b)
{
addShape((Shape *) b);
if (myButtonCount == 0)
{
MakeBBar();
}
b->setLocation(Point(myButtonCount, ycoord(height())));
myButtonCount += b->bbox().width() + 5;
}
void AnimatedCanvas::removeShape(Shape * s)
{
if (myIsRunning)
{
myDeadShapes.push_back(s);
return;
}
int k;
for(k=0; k < myShapeCount; k++)
{
if (myShapes[k]->id() == s->id())
{
myShapes[k] = myShapes[myShapeCount-1];
myShapes.pop_back();
myShapeCount--;
return;
}
}
}
void AnimatedCanvas::removeShape(Shape& s)
{
removeShape(&s);
}
void BaseCanvas::SetFrame()
{
myFilled = false;
SetColor(myColor);
}
void BaseCanvas::SetFilled()
{
myFilled = true;
SetColor(myColor);
}
void BaseCanvas::SetColor(const color&c )
{
myColor = c;
myWindow->SetPen(c,0);
if (myFilled)
{
myWindow->SetBrush(c);
}
else
{
myWindow->SetBrush(WHITE);
}
}
void BaseCanvas::Clear()
{
SetColor(WHITE);
myWindow->DrawRectangle(0,0,width(),height());
}
void BaseCanvas::DrawPixel(int x, int y)
{
DrawPixel(Point(x,y));
}
void BaseCanvas::DrawPixel(const Point& p)
{
myWindow->DrawPixel(p.x,p.y);
}
CanvasColor BaseCanvas::GetPixel(const Point& p) const
{
return CanvasColor(myWindow->GetColor(static_cast<int>(p.x),
static_cast<int>(p.y)));
}
void BaseCanvas::DrawLine(int x1, int y1, int x2, int y2)
{
DrawLine(Point(x1,y1), Point(x2,y2));
}
void BaseCanvas::DrawLine(const Point& p1, const Point& p2)
{
//myWindow->DrawLine(p1.x, p1.y, p2.x+1, p2.y+1);
Process();
myWindow->DrawLine(p1.x,p1.y,p2.x,p2.y);
}
void BaseCanvas::DrawRectangle(int x1, int y1, int x2, int y2)
{
DrawRectangle(Point(x1,y1),Point(x2,y2));
}
void BaseCanvas::DrawRectangle(const Point& p1, const Point& p2)
{
Process();
myWindow->DrawRectangle(p1.x,p1.y,p2.x,p2.y);
}
void BaseCanvas::DrawCircle(int x, int y, int radius)
{
DrawCircle(Point(x,y),radius);
}
void BaseCanvas::DrawCircle(const Point& center, int radius)
{
Process();
myWindow->DrawCircle(center.x,center.y,radius);
}
void BaseCanvas::DrawEllipse(int x1, int y1, int x2, int y2)
{
DrawEllipse(Point(x1,y1),Point(x2,y2));
}
void BaseCanvas::DrawEllipse(const Point& p1, const Point& p2)
{
Process();
myWindow->DrawEllipse(p1.x,p1.y,p2.x,p2.y);
}
void BaseCanvas::DrawTriangle(const Point& p1, const Point& p2, const Point& p3)
{
tvector<Point> t;
t.push_back(p1);
t.push_back(p2);
t.push_back(p3);
DrawPolygon(t,3);
}
void BaseCanvas::DrawPolygon(const tvector<Point>& a, int numPoints)
{
const int SIZE = 100;
static int MAX = SIZE;
static int x[SIZE];
static int y[SIZE];
static int * xp = x;
static int * yp = y;
Process();
if (numPoints > MAX)
{
xp = new int[numPoints];
yp = new int[numPoints];
MAX = numPoints;
}
int k;
for(k=0; k < numPoints; k++)
{
xp[k] = a[k].x;
yp[k] = a[k].y;
}
myWindow->DrawPolygon(xp,yp,numPoints);
}
void BaseCanvas::DrawImage(image& im, int x, int y, double scale)
{
Process();
myWindow->DrawImage(im,x,y, im.GetWidth()*scale, im.GetHeight()*scale);
}
void BaseCanvas::DrawImage(image& im, const Point& p, double scale)
{
DrawImage(im,p.x,p.y,scale);
}
void BaseCanvas::DrawPieWedge(const Point& p, int radius, double startRad, double endRad)
{
myWindow->DrawArc(p.x, p.y, p.x+2*radius, p.y+2*radius,
startRad,endRad, myFilled ? FILLED : FRAME,RADIANS);
}
void BaseCanvas::DrawString(const string& s, int x, int y, int fontsize)
{
Process();
myWindow->SetFont(fontsize,BOLD,SWISS);
myWindow->DrawString(x,y,s);
}
void BaseCanvas::DrawString(const string& s, const Point& p, int fontsize)
{
DrawString(s,p.x,p.y,fontsize);
}
void BaseCanvas::GetStringSize(int & w, int & h, const string& s)
{
myWindow->GetStringSize(w,h,s.c_str());
}
void BaseCanvas::SetTitle(const string& s)
{
myWindow->ChangeTitle(const_cast<char *>(s.c_str()));
}
void BaseCanvas::Process()
{
}
IteratorRef<Shape> * AnimatedCanvas::makeIterator()
{
return new CanvasIterator(myShapes,myShapeCount);
}
void AnimatedCanvas::poll()
{
clicktype click;
keytype press;
//myWindow->FlushMouseQueue();
int x,y;
char ch;
click = myWindow->GetMouseClick(x,y);
Point p(x,y);
press = myWindow->GetKeyPress(ch);
if (click != NO_CLICK)
{
myClickPoint = p;
}
else
{
myClickPoint = Point(-1,-1);
}
if (press == NO_KEYPRESS)
{
myKey = Key(ch,Key::none);
}
else
{
switch(press)
{
case ESCAPE:
myKey = Key(ch,Key::escape);
break;
case ASCII:
myKey = Key(ch,Key::ascii);
break;
case FUNCTION:
myKey = Key(ch,Key::function);
break;
case ARROW:
myKey = Key(ch,Key::arrow);
break;
default:
myKey = Key(ch,Key::ascii);
break;
}
}
}
void AnimatedCanvas::run(int steps,int pause)
{
myIsRunning = true;
for(int k=0; k < steps; k++)
{
repaint();
Pause(pause);
}
myIsRunning = false;
}
void AnimatedCanvas::runUntilEscape(int pause)
{
myIsRunning = true;
while (true)
{
repaint();
if (myKey.isescape()) break;
Pause(pause);
}
myIsRunning = false;
}
Point AnimatedCanvas::getClick()
{
return myClickPoint;
}
int Shape::ourCount = 0;
Shape::Shape()
{
myCount = ourCount;
ourCount++;
}
bool Shape::contains(const Point& p) const
{
return bbox().contains(p);
}
bool Shape::overlaps(const Shape& s) const
{
return bbox().intersects(s.bbox());
}
Shape * Shape::clone()
{
cerr << "error, called Shape::clone()" << endl;
return 0; // intentionally return NULL/0, clients should override
}
string Shape::tostring() const
{
ostringstream out;
out << typeid(*this).name() << " " << id() << " " << bbox();
return out.str();
}
CircleShape::CircleShape(const Point& p, double r, color c)
: myPoint(p),
myRadius(r),
myColor(c)
{
}
CircleShape::CircleShape(const CircleShape& c)
: myPoint(c.myPoint),
myRadius(c.myRadius),
myColor(c.myColor)
{
}
Box CircleShape::bbox() const
{
return Box (myPoint.x - myRadius, myPoint.y - myRadius,
myPoint.x + myRadius, myPoint.y + myRadius);
}
void CircleShape::draw(AnimatedCanvas& c)
{
c.SetColor(myColor);
c.DrawCircle(myPoint.x, myPoint.y, myRadius);
}
Shape * CircleShape::clone()
{
CircleShape * c = new CircleShape(*this);
return c;
}
void CircleShape::setLocation(const Point& p)
{
myPoint = p;
}
Point CircleShape::getLocation() const
{
return myPoint;
}
string CircleShape::tostring() const
{
return string("circle ") + bbox().tostring();
}
EllipseShape::EllipseShape(const Point& ul, const Point& lr, color c)
: myPoint(ul),
myBox(ul,lr),
myColor(c)
{
}
void EllipseShape::draw(AnimatedCanvas& c)
{
c.SetColor(myColor);
Point ul = myBox.getUL();
Point lr = myBox.getLR();
c.DrawEllipse(ul.x,ul.y,lr.x,lr.y);
}
void EllipseShape::setLocation(const Point& p)
{
Point ul = myBox.getUL();
Point lr = myBox.getLR();
//myBox = Box(p,Point(lr.x + (p.x - ul.x), lr.y + (p.y - ul.y)));
myBox = Box(p,Point(p.x+myBox.width(),p.y+myBox.height()));
myPoint = p;
}
Point EllipseShape::getLocation() const
{
return myPoint;
}
Box EllipseShape::bbox() const
{
return myBox;
}
Shape * EllipseShape::clone()
{
EllipseShape * e = new EllipseShape(myBox.getUL(),myBox.getLR(),myColor);
return e;
}
string EllipseShape::tostring() const
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -