第十八章:图形类 习题答案
- 习题要求所设计的图形类
- 18.1 Arc
- 18.2 Box
- 18.3 Arrow
- 18.4 Rect Compass
- 18.5 Circle and Ellipse Compass
- 18.6 Structure Diagram
- 18.7 RGB Chart
- 18.8 and 18.9 Regular Hexagon
- 18.10 Regular Polygon
- 18.11 Elipse with Axis
- 18.12 Circle and Mark Moving
- 18.13 Color Matrix
- 18.14 and 18.15 Draw Octagon with Right Triangle
- 18.16 and 18.17 Hexagon Tile
- 18.18
- 18.19
习题要求所设计的图形类
这些类比如Arc、Box、Arrow,等等,都放在 My_shape 名称空间中了。
下面是类的实现
My_shape.h
#include "../../GUI/Point.h"
#include<vector>
#include "../../GUI/fltk.h"
#include"../../GUI/Graph.h"
#include "../../GUI/std_lib_facilities.h"
namespace My_shape {
using Graph_lib::Shape;
using Graph_lib::Point;
using Graph_lib::Color;
using Graph_lib::Line;
using Graph_lib::Rectangle;
using Graph_lib::Circle;
using Graph_lib::Ellipse;
using Graph_lib::Text;
using Graph_lib::Font;
using Graph_lib::Closed_polyline;
constexpr double PI = 3.1415926;
struct Arc : Shape {
public:
//圆心、到圆心的最大和最小距离,绘制的起始和结束角度(用度数表示,最大0-360度)
Arc(Point p, int ww, int hh, double bg, double ed);
void draw_lines() const;
Point center() const { return{ point(0).x + w, point(0).y + h }; }
Point focus1() const { return{ center().x + int(sqrt(double(w * w - h * h))), center().y }; }
Point focus2() const { return{ center().x - int(sqrt(double(w * w - h * h))), center().y }; }
void set_major(int ww) { w = ww; }
int major() const { return w; }
void set_minor(int hh) { h = hh; }
int minor() const { return h; }
void set_arc_begin(double b);
void set_arc_end(double e);
private:
int w;
int h;
double begin;
double end;
};
//-----------------------------------------------------------------------------------------------
struct Box : Shape {
Box(Point p, int ww, int hh);
Box(Point p, int ww, int hh, int rr);
void draw_lines() const;
int height()const { return h; }
int width()const { return w; }
int radius()const { return r; }
private:
int w;
int h;
int r;
};
struct Arrow : Line {
//Arrow(Point p1, Point p2);
using Line::Line; //使用Line的构造函数
void draw_lines() const;
private:
static constexpr double rad = 0.2617994; //15.0 / 180.0 * PI, 角度15度
static constexpr double length = 30;
};
//----------------------------------------------------------------------------------------------
Point n(Rectangle& r);
Point s(Rectangle& r);
Point e(Rectangle& r);
Point w(Rectangle& r);
Point ne(Rectangle& r);
Point nw(Rectangle& r);
Point se(Rectangle& r);
Point sw(Rectangle& r);
Point center(Rectangle& r);
Point n(Circle& c);
Point s(Circle& c);
Point e(Circle& c);
Point w(Circle& c);
Point ne(Circle& c);
Point nw(Circle& c);
Point se(Circle& c);
Point sw(Circle& c);
Point center(Circle& c);
Point n(Ellipse& e);
Point s(Ellipse& e);
Point e(Ellipse& e);
Point w(Ellipse& e);
Point ne(Ellipse& e);
Point nw(Ellipse& e);
Point se(Ellipse& e);
Point sw(Ellipse& e);
Point center(Ellipse& e);
Point n(Box& b);
Point s(Box& b);
Point e(Box& b);
Point w(Box& b);
Point ne(Box& b);
Point nw(Box& b);
Point se(Box& b);
Point sw(Box& b);
Point center(Box& b);
//------------------------------------------------------------------------------
struct Text_box : Box{
Text_box(Point pp, int ww, int hh, const string& ss)
:Box{ pp,ww,hh }, lab{ ss }{ }
void draw_lines() const;
//void set_color(Color col);
void set_label(const string& s) { lab = s; }
string label() const { return lab; }
void set_font(Font f) { fnt = f; }
Font font() const { return Font(fnt); }
void set_font_size(int s) { fnt_sz = s; }
int font_size() const { return fnt_sz; }
private:
string lab; // label
Font fnt{ fl_font() };
int fnt_sz{ (14 < fl_size()) ? fl_size() : 14 }; // at least 14 point
};
//----------------------------------------------------------------------------------
struct Regular_hexagon : Closed_polyline {
Regular_hexagon(Point cen, int dist);
Point center() const;
int dist() const;
private:
int d;
};
//----------------------------------------------------------------------------------
struct Regular_polygon : Closed_polyline {
Regular_polygon(Point cen, int n_edges, int dist);
Point center() const;
int n_edges() const;
int dist() const;
private:
int n;
int d;
};
//----------------------------------------------------------------------------------
struct Right_triangle : Closed_polyline {
Right_triangle(Point p, int a, int b); // initialize w/o rotation
Right_triangle(Point p, int a, int b, double o);
private:
int a; // side a
int b; // side b
double o = 0; // orientation
double c = 90; // compliment of orientation
};
//----------------------------------------------------------------------------------
struct Star : Closed_polyline {
Star(Point cc, int np, int dist);
Point center() const;
int num_points() const { return n; }
int distance() const { return d; }
private:
int n; // number of points
int d; // radius of bounding circle
};
}
My_shape.cpp
#include"My_Shape.h"
using Graph_lib::Color;
namespace My_shape {
Arc::Arc(Point p, int ww, int hh, double bg, double ed)
:w{ ww }, h{ hh }, begin{ bg }, end{ ed }
{
if (ed <= bg)
error("second angle in arc must be larger than first angle");
add(Point{ p.x - ww, p.y - hh });
}
void Arc::draw_lines() const
{
if (fill_color().visibility()) { // fill
fl_color(fill_color().as_int());
fl_pie(point(0).x, point(0).y, w + w - 1, h + h - 1, begin, end);
fl_color(color().as_int()); // reset color
}
if (color().visibility()) {
fl_color(color().as_int());
fl_arc(point(0).x, point(0).y, w + w, h + h, begin, end);
}
}
void Arc::set_arc_begin(double b)
{
if (b >= end)
error("first angle in arc must be smaller than first angle");
begin = b;
}
void Arc::set_arc_end(double e)
{
if (e <= begin)
error("second angle in arc must be larger than first angle");
end = e;
}
//-----------------------------------------------------------
Box::Box(Point pp, int ww, int hh)
:w{ww},h{hh}
{
if(ww <= 0 || hh <= 0)
error("Bad rectangle: non-positive width or height");
add(pp);
int rr = ww < hh ? ww : hh;
r = rr / 4;
}
Box::Box(Point pp, int ww, int hh, int rr)
:w{ ww }, h{ hh },r{rr}
{
if (ww <= 0 || hh <= 0)
error("Bad rectangle: non-positive width or height");
if(rr <= 0)
error("Bad box corner radius: non-positive radius ");
if (rr > (ww < hh ? ww / 2 : hh / 2))
error("box corner radius too large");
add(pp);
}
void Box::draw_lines() const
{
Point pp = point(0); //基准左上角点
if (color().visibility())
{
//draw four straight lines
fl_line(pp.x + r, pp.y, pp.x + w - r, pp.y); //two horizontal lines
fl_line(pp.x + r, pp.y + h, pp.x + w - r, pp.y + h);
fl_line(pp.x, pp.y + r, pp.x, pp.y + h - r); //two vertical lines
fl_line(pp.x + w, pp.y + r, pp.x + w, pp.y + h - r);
//draw four arcs
fl_arc(pp.x, pp.y, r + r, r + r, 90, 180);
fl_arc(pp.x, pp.y + h - r - r, r + r, r + r, 180, 270);
fl_arc(pp.x + w - r - r, pp.y + h - r - r, r + r, r + r, 270, 360);
fl_arc(pp.x + w - r - r, pp.y, r + r, r + r, 0, 90);
}
if (fill_color().visibility())
{
//fill three rectangles
fl_color(fill_color().as_int());
fl_rectf(pp.x + r, pp.y, w - r - r, h);
fl_rectf(pp.x, pp.y + r, r, h - r - r);
fl_rectf(pp.x + w - r, pp.y + r, r, h - r - r);
//fill four corners
fl_pie(pp.x, pp.y, r + r, r + r, 90, 180);
fl_pie(pp.x, pp.y + h - r - r, r + r, r + r, 180, 270);
fl_pie(pp.x + w - r - r, pp.y + h - r - r, r + r, r + r, 270, 360);
fl_pie(pp.x + w - r - r, pp.y, r + r, r + r, 0, 90);
}
}
//----------------------------------------------------------------------------
void Arrow::draw_lines() const
//箭头画在点p2上
{
if(color().visibility())
{
Point p1 = point(0);
Point p2 = point(1);
//draw line
fl_line(p1.x, p1.y, p2.x, p2.y);
//draw arrow
double x = p1.x - p2.x;
double y = p2.y - p1.y;
double lrad;
if (x == 0)
{
if (y == 0)
error("Bad Arrow line");
else if (y > 0)
lrad = PI / 2;
else
lrad = PI * 1.5;
}
else
lrad = atan2(y, x);
if (lrad < 0)
lrad += 2 * PI;
double arad1 = lrad - rad;
double arad2 = lrad + rad;
if (arad1 < 0)
arad1 += 2 * PI;
if (arad2 >= 2 * PI)
arad2 -= 2 * PI;
int x1 = p2.x + length * cos(arad1);
int y1 = p2.y - length * sin(arad1);
int x2 = p2.x + length * cos(arad2);
int y2 = p2.y - length * sin(arad2);
fl_line(p2.x, p2.y, x1, y1);
fl_line(p2.x, p2.y, x2, y2);
}
}
//---------------------------------------------------------------------------
Point n(Rectangle& r)
{
int x = r.point(0).x + r.width() / 2;
int y = r.point(0).y;
return Point{ x,y };
}
Point s(Rectangle& r)
{
int x = r.point(0).x + r.width() / 2;
int y = r.point(0).y + r.height();
return Point{ x,y };
}
Point e(Rectangle& r)
{
int x = r.point(0).x + r.width();
int y = r.point(0).y + r.height() / 2;
return Point{ x,y };
}
Point w(Rectangle& r)
{
int x = r.point(0).x;
int y = r.point(0).y + r.height() / 2;
return Point{ x,y };
}
Point ne(Rectangle& r)
{
int x = r.point(0).x + r.width();
int y = r.point(0).y;
return Point{ x,y };
}
Point nw(Rectangle& r)
{
return r.point(0);
}
Point se(Rectangle& r)
{
int x = r.point(0).x + r.width();
int y = r.point(0).y + r.height();
return Point{ x,y };
}
Point sw(Rectangle& r)
{
int x = r.point(0).x;
int y = r.point(0).y + r.height();
return Point{ x,y };
}
Point center(Rectangle& r)
{
int x = r.point(0).x + r.width() / 2;
int y = r.point(0).y + r.height() / 2;
return Point{ x,y };
}
//----------------------------------------------------
Point n(Circle& c)
{
int x = c.point(0).x + c.radius();
int y = c.point(0).y;
return Point{ x,y };
}
Point s(Circle& c)
{
int x = c.point(0).x + c.radius();
int y = c.point(0).y + 2 * c.radius();
return Point{ x,y };
}
Point e(Circle& c)
{
int x = c.point(0).x + 2 * c.radius();
int y = c.point(0).y + c.radius();
return Point{ x,y };
}
Point w(Circle& c)
{
int x = c.point(0).x;
int y = c.point(0).y + c.radius();
return Point{ x,y };
}
Point ne(Circle& c)
{
int x = c.center().x + c.radius() * cos(PI * 45 / 180);
int y = c.center().y - c.radius() * sin(PI * 45 / 180);
return Point{ x,y };
}
Point nw(Circle& c)
{
int x = c.center().x + c.radius() * cos(PI * 135 / 180);
int y = c.center().y - c.radius() * sin(PI * 135 / 180);
return Point{ x,y };
}
Point se(Circle& c)
{
int x = c.center().x + c.radius() * cos(PI * 315 / 180);
int y = c.center().y - c.radius() * sin(PI * 315 / 180);
return Point{ x,y };
}
Point sw(Circle& c)
{
int x = c.center().x + c.radius() * cos(PI * 225 / 180);
int y = c.center().y - c.radius() * sin(PI * 225 / 180);
return Point{ x,y };
}
Point center(Circle& c)
{
return c.center();
}
//----------------------------------------------------
Point n(Ellipse& e)
{
int x = e.center().x;
int y = e.center().y - e.minor();
return Point{ x,y };
}
Point s(Ellipse& e)
{
int x = e.center().x;
int y = e.center().y + e.minor();
return Point{ x,y };
}
Point e(Ellipse& e)
{
int x = e.center().x + e.major();
int y = e.center().y;
return Point{ x,y };
}
Point w(Ellipse& e)
{
int x = e.center().x - e.major();
int y = e.center().y;
return Point{ x,y };
}
/*
这里求椭圆四个斜方向:
若焦点在 x 轴,那么斜方向的点是在焦点的正上下方的椭圆线上
若焦点在 y 轴,那么斜方向的点是在焦点的正左右方的椭圆线上
a为长轴,b为短轴,c为焦点距离圆心的长度
c = a^2 - b^2,将其代入椭圆公式可以求得斜方向的高度(长度)
*/
Point ne(Ellipse& e)
{
int a = e.major();
int b = e.minor();
Point f1 = e.focus1();
int x{ 0 }, y{ 0 };
if (a >= b) // 焦点在 x 轴
{
int h = pow(b, 2) / a;
x = f1.x;
y = f1.y - h;
}
else
{ //焦点在 y 轴
int l = pow(a, 2) / b;
x = f1.x + l;
y = f1.y;
}
return Point{ x,y };
}
Point nw(Ellipse& e)
{
int a = e.major();
int b = e.minor();
int x{ 0 }, y{ 0 };
if (a >= b) // 焦点在 x 轴
{
Point f2 = e.focus2();
int h = pow(b, 2) / a;
x = f2.x;
y = f2.y - h;
}
else
{ //焦点在 y 轴
Point f1 = e.focus1();
int l = pow(a, 2) / b;
x = f1.x - l;
y = f1.y;
}
return Point{ x,y };
}
Point se(Ellipse& e)
{
int a = e.major();
int b = e.minor();
int x{ 0 }, y{ 0 };
if (a >= b) // 焦点在 x 轴
{
Point f1 = e.focus1();
int h = pow(b, 2) / a;
x = f1.x;
y = f1.y + h;
}
else
{ //焦点在 y 轴
Point f2 = e.focus2();
int l = pow(a, 2) / b;
x = f2.x + l;
y = f2.y;
}
return Point{ x,y };
}
Point sw(Ellipse& e)
{
int a = e.major();
int b = e.minor();
Point f2 = e.focus2();
int x{ 0 }, y{ 0 };
if (a >= b) // 焦点在 x 轴
{
int h = pow(b, 2) / a;
x = f2.x;
y = f2.y + h;
}
else
{ //焦点在 y 轴
int l = pow(a, 2) / b;
x = f2.x - l;
y = f2.y;
}
return Point{ x,y };
}
Point center(Ellipse& e)
{
return e.center();
}
//-----------------------------------------------------------
Point n(Box& b)
{
int x = b.point(0).x + b.width() / 2;
int y = b.point(0).y;
return Point{ x,y };
}
Point s(Box& b)
{
int x = b.point(0).x + b.width() / 2;
int y = b.point(0).y + b.height();
return Point{ x,y };
}
Point e(Box& b)
{
int x = b.point(0).x + b.width();
int y = b.point(0).y + b.height() / 2;
return Point{ x,y };
}
Point w(Box& b)
{
int x = b.point(0).x;
int y = b.point(0).y + b.height() / 2;
return Point{ x,y };
}
Point ne(Box& b)
{
int x = b.point(0).x;
int y = b.point(0).y + b.height();
return Point{ x,y };
}
Point nw(Box& b)
{
return b.point(0);
}
Point se(Box& b)
{
int x = b.point(0).x + b.width();
int y = b.point(0).y + b.height();
return Point{ x,y };
}
Point sw(Box& b)
{
int x = b.point(0).x;
int y = b.point(0).y + b.height();
return Point{ x,y };
}
Point center(Box& b)
{
int x = b.point(0).x + b.width() / 2;
int y = b.point(0).y + b.height() / 2;
return Point{ x,y };
}
//------------------------------------------------------------
void Text_box::draw_lines() const
{
const int dx = 5;
const int dy = 15;
Box::draw_lines();
fl_draw(lab.c_str(), point(0).x + dx, point(0).y + dy);
}
//-------------------------------------------------------------------
Regular_hexagon::Regular_hexagon(Point cen, int dist)
:d{dist}
{
if (dist <= 0)
error("Bad regular hexagon: the distance from center to corners is non-positive");
for (int i = 0; i < 6; ++i)
{
int x = cen.x + d * cos(PI * i * 60.0 / 180.0);
int y = cen.y + d * sin(PI * i * 60.0 / 180.0);
add(Point{ x,y });
}
}
Point Regular_hexagon::center() const
{
return Point{ point(0).x - dist(), point(0).y };
}
int Regular_hexagon::dist() const
{
return d;
}
//-------------------------------------------------------------------
Regular_polygon::Regular_polygon(Point cen, int n_edges, int dist)
: n{ n_edges },d { dist }
{
if (n_edges < 3)
error("Bad regular polygon: number of edges less than three");
if (dist <= 0)
error("Bad regular hexagon: the distance from center to corners is non-positive");
double rot_ang = PI * 2.0 / n; //旋转角,弧度
for (int i = 0; i < n; ++i)
{
int x = cen.x + d * cos(i * rot_ang);
int y = cen.y + d * sin(i * rot_ang);
add(Point{ x,y });
}
}
Point Regular_polygon::center() const
{
return Point{ point(0).x - dist(), point(0).y };
}
int Regular_polygon::n_edges() const
{
return n;
}
int Regular_polygon::dist() const
{
return d;
}
//----------------------------------------------------------------------------------
/*
|\
| \
b | \
| \
|____\
a
p 是直角的顶点,a 和 b 分别是两条直角边的边长
o = orient, 是直角边 a 相对于 x 轴的角度
*/
Right_triangle::Right_triangle(Point p, int aa, int bb)
: a{ aa }, b{ bb }
{
add(p);
add(Point{ p.x + a, p.y });
add(Point{ p.x, p.y - b });
}
Right_triangle::Right_triangle(Point p, int aa, int bb, double oo)
: a{ aa }, b{ bb }, o{ oo }, c{ 90 + oo }
{
add(p);
int x = p.x + cos(o * PI / 180) * a;
int y = p.y - sin(o * PI / 180) * a;
add(Point{ x, y });
x = p.x + cos(c * PI / 180) * b;
y = p.y - sin(c * PI / 180) * b;
add(Point{ x, y });
}
//----------------------------------------------------------------------------------
Star::Star(Point cc, int np, int dist)
: n{ np }, d{ dist }
{
if (np < 3)
error("Bad Star: number of points less than three");
if (dist <= 0)
error("Bad Star: the distance from center to corners is non-positive");
double radian = PI * 90.0 / 180.0; //top mid
double step = 2 * PI / np;
int x{ 0 }, y{ 0 };
for (int i = 0; i < np; ++i) {
//先画星型的外面的突出点
x = cc.x + cos(radian) * dist;
y = cc.y - sin(radian) * dist;
add(Point{ x, y });
//再画凹点
radian += step / 2;
x = cc.x + cos(radian) * (dist / 2.0);
y = cc.y - sin(radian) * (dist / 2.0);
add(Point{ x, y });
radian += step / 2;
}
}
Point Star::center() const
{
int x = point(0).x;
int y = point(0).y + d;
return Point{ x,y };
}
}
18.1 Arc
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using My_shape::Arc;
Point tl{ 100,100 };
Simple_window win{ tl, 1200, 800, "My window" };
Arc arc1{ Point{200,200},50,50,0,180 };
arc1.set_color(Color::black);
win.attach(arc1);
struct Arc arc2{ Point{300,300},50,50,90,180 };
arc2.set_color(Color::red);
win.attach(arc2);
struct Arc arc3 { Point{ 400,400 }, 150, 70, 180, 270 };
arc3.set_color(Color::blue);
win.attach(arc3);
win.wait_for_button();
arc1.set_arc_begin(90);
arc2.set_arc_end(360);
arc3.set_arc_begin(120);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.2 Box
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using My_shape::Box;
Point tl{ 100,100 };
Simple_window win{ tl, 1200, 800, "My window" };
Box box1{ Point{200,200}, 200,150 };
Box box2{ Point{500,200}, 200,150, 15 };
Box box3{ Point{500,400}, 200,150, 30 };
box1.set_color(Color::red);
box2.set_color(Color::green);
box3.set_color(Color::blue);
box2.set_fill_color(Color::white);
win.attach(box1);
win.attach(box2);
win.attach(box3);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.3 Arrow
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using My_shape::Arrow;
Point tl{ 100,100 };
Simple_window win{ tl, 1200, 800, "My window" };
Arrow ar1{ Point{100,100}, Point{100,200} };
Arrow ar2{ Point{200,200}, Point{200,100} };
ar1.set_color(Color::red);
ar2.set_color(Color::blue);
win.attach(ar1);
win.attach(ar2);
Arrow ar3{ Point{300,100}, Point{400,100} };
Arrow ar4{ Point{400,200}, Point{300,200} };
ar3.set_color(Color::green);
ar4.set_color(Color::yellow);
win.attach(ar3);
win.attach(ar4);
Arrow ar5{ Point{200,250}, Point{100,260} };
Arrow ar6{ Point{200,361}, Point{100,350} };
ar5.set_color(Color::red);
ar6.set_color(Color::blue);
win.attach(ar5);
win.attach(ar6);
Arrow ar7{ Point{300,250}, Point{350,300} };
Arrow ar8{ Point{400,350}, Point{450,250} };
ar7.set_color(Color::green);
ar8.set_color(Color::yellow);
win.attach(ar7);
win.attach(ar8);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.4 Rect Compass
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1200, 800, "My window" };
Graph_lib::Rectangle r{ Point{200,200}, 400,300 };
r.set_color(Color::black);
win.attach(r);
Marks pp{ "x" };
pp.add(n(r));
pp.add(s(r));
pp.add(w(r));
pp.add(e(r));
pp.add(nw(r));
pp.add(ne(r));
pp.add(sw(r));
pp.add(se(r));
pp.add(center(r));
win.attach(pp);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.5 Circle and Ellipse Compass
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1000, "My window" };
Graph_lib::Circle c1{ Point{1100,400}, 300 };
c1.set_color(Color::blue);
win.attach(c1);
Marks pc{ "x" };
pc.add(n(c1));
pc.add(s(c1));
pc.add(w(c1));
pc.add(e(c1));
pc.add(nw(c1));
pc.add(ne(c1));
pc.add(sw(c1));
pc.add(se(c1));
pc.add(center(c1));
win.attach(pc);
Graph_lib::Ellipse e1{ Point{400,400}, 300,200 };
e1.set_color(Color::red);
win.attach(e1);
Marks pp{ "x" };
pp.add(n(e1));
pp.add(s(e1));
pp.add(w(e1));
pp.add(e(e1));
pp.add(nw(e1));
pp.add(ne(e1));
pp.add(sw(e1));
pp.add(se(e1));
pp.add(center(e1));
pp.add(e1.focus1());
pp.add(e1.focus2());
win.attach(pp);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.6 Structure Diagram
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1000, 800, "My window" };
Text_box shape{ Point{50, 50}, 100, 50, "Shape" };
shape.set_color(Color::black);
win.attach(shape);
Text_box rect{ Point{50, 200}, 100, 50, "Rectangle" };
rect.set_color(Color::black);
win.attach(rect);
Text_box tb{ Point{50, 300}, 100, 50, "Textbox" };
tb.set_color(Color::black);
win.attach(tb);
Text_box circ{ Point{200, 200}, 100, 50, "Circle" };
circ.set_color(Color::black);
win.attach(circ);
Arrow a1{ n(rect), s(shape) };
a1.set_color(Color::black);
win.attach(a1);
Arrow a2{ n(tb), s(rect) };
a2.set_color(Color::black);
win.attach(a2);
Arrow a3{ nw(circ), se(shape) };
a3.set_color(Color::black);
win.attach(a3);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.7 RGB Chart
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
using namespace Graph_lib;
int main()
try
{
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "RGB Chart" };
const int w { 20 };
const int h { 4 };
const int color_max = 0xF;
//RGB每一个颜色8bit,对应0x00-0xFF
const int color_step = 0xF;
Vector_ref<Graph_lib::Rectangle> rects;
for(int i = 0; i <= color_max; ++i)
for(int j = 0; j <= color_max; ++j)
for (int k = 0; k <= color_max; ++k)
{
rects.push_back(new Graph_lib::Rectangle{ Point{w * k,h * (i * color_max + j)}, w,h });
rects[rects.size() - 1].set_fill_color(fl_rgb_color(color_step * i, color_step * j, color_step * k));
rects[rects.size() - 1].set_color(Color{ Color::white, Color::invisible });
win.attach(rects[rects.size() - 1]);
}
win.wait_for_button();
for (int i = 0; i < rects.size(); ++i)
win.detach(rects[i]);
//下面是模仿Stroustrup个人网站中PPP2的Support页中的RGB Chart
const int box_h = 22;
const int box_w = 88;
Vector_ref<Graph_lib::Rectangle> boxes;
Vector_ref<Text> labels;
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
for (int k = 0; k < 6; ++k) {
boxes.push_back(new Graph_lib::Rectangle(Point{ k * box_w, i * 6 * box_h + j * box_h }, box_w, box_h));
boxes[boxes.size() - 1].set_fill_color(fl_rgb_color(51 * i, 51 * j, 51 * k));
boxes[boxes.size() - 1].set_color(Color(Color::white));
win.attach(boxes[boxes.size() - 1]);
ostringstream oss;
oss << hex << uppercase << setfill('0') << left << '#' <<
setw(2) << 51 * i << setw(2) << 51 * j << setw(2) << 51 * k;
labels.push_back(new Text(Point{ k * box_w + 4, i * 6 * box_h + j * box_h + 16 }, oss.str().c_str()));
if (j < 3)
labels[labels.size() - 1].set_color(Color::white);
else
labels[labels.size() - 1].set_color(Color::black);
win.attach(labels[labels.size() - 1]);
}
}
}
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.8 and 18.9 Regular Hexagon
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "Regular Hexagon" };
Regular_hexagon rh{ Point{100,100}, 100 };
rh.set_color(Color::black);
win.attach(rh);
const int x_hex = 100;
const int y_hex = 300;
const int dist = 100;
Vector_ref<Regular_hexagon> hexs;
int x_step = 300;
int y_step = dist * sin(PI * 60.0 / 180.0);
for (int i = 0; i < 4; ++i)
{
int x = x_hex + (i % 2) * 1.5 * dist;
int y = y_hex + i * y_step;
for (int j = 0; j < 4; ++j)
{
hexs.push_back(new Regular_hexagon{ Point{x,y}, dist });
auto last = hexs.size() - 1;
hexs[last].set_color(Color::blue);
win.attach(hexs[last]);
x += x_step;
}
}
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.10 Regular Polygon
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "Regular polygon" };
Regular_polygon rh{ Point{100,100}, 6, 100 };
rh.set_color(Color::black);
win.attach(rh);
win.wait_for_button();
Vector_ref<Regular_polygon> vpoly;
for (int i = 3; i < 10; ++i) {
vpoly.push_back(new Regular_polygon(Point{ 200 + 20 * i, 200 + 20 * i }, i, 250 - 5 * i));
vpoly[vpoly.size() - 1].set_style(Line_style(Line_style::solid, 4));
vpoly[vpoly.size() - 1].set_color(Color::blue);
vpoly[vpoly.size() - 1].set_fill_color(i * 30 % 255);
win.attach(vpoly[vpoly.size() - 1]);
win.wait_for_button();
}
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.11 Elipse with Axis
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "Ellipse Axis" };
Point cc{ 600,400 }; //圆心
int a = 300 / 2;
int b = 200 / 2;
Graph_lib::Ellipse e{ cc, a,b };
e.set_color(Color::red);
win.attach(e);
const int axis_xlen = 400;
const int axis_ylen = 300;
const int axis_step = 10;
Axis xa{ Axis::x, Point{cc.x - axis_xlen / 2, cc.y},axis_xlen, axis_xlen / axis_step,"x axis" };
Axis ya{ Axis::y, Point{cc.x, cc.y + axis_ylen / 2},axis_ylen, axis_ylen / axis_step,"y axis" };
xa.set_color(Color::black);
ya.set_color(Color::black);
win.attach(xa);
win.attach(ya);
win.put_on_top(e);
Point f1{ e.focus1() };
Point f2{ e.focus2() };
Marks ms{ "o" };
ms.add(f1);
ms.add(f2);
ms.set_color(Color{ Color::red, Color::invisible});
win.attach(ms);
//根据椭圆公式:x^2 / a^2 + y^2 / b^2 = 1,可以求出任意角度的椭圆上的点的坐标
double angle = 45.0;
int px = e.center().x + a * cos(PI * angle / 180);
int py = e.center().y - b * sin(PI * angle / 180);
Point p{ px,py };
Lines ls;//{ p,f1,p,f2 };
ls.add(p,f1);
ls.add(p,f2);
ls.set_color(Color::blue);
ls.set_style(Line_style{ Line_style::dash, 3 });
win.attach(ls);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.12 Circle and Mark Moving
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "Circle Marking Moving" };
Point cc{ 600,400 }; //圆心
const int r = 200;
Circle c{ cc, r };
c.set_color(Color::red);
win.attach(c);
constexpr int n = 12;
constexpr double radian_step = 2 * PI / n; //2 * pi / 12
Mark m{ e(c), 'x' }; //从圆的“东侧”,即0度开始
m.set_color(Color::blue);
win.attach(m);
int i = 1;
do {
win.wait_for_button();
int x = cc.x + r * cos(radian_step * i);
int y = cc.y - r * sin(radian_step * i);
int dx = x - m.point(0).x;
int dy = y - m.point(0).y;
m.move(dx, dy);
++i;
} while (i < n);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.13 Color Matrix
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
using Graph_lib::Rectangle;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "Color Matrix" };
const int width{ 20 };
const int height{ 20 };
Vector_ref<Rectangle> vr;
for(int i = 0; i < 16; ++i)
for (int j = 0; j < 16; ++j)
{
vr.push_back(new Rectangle{ Point{i * width,j * height},width,height });
auto last = vr.size() - 1;
vr[last].set_fill_color(Color{ i * 16 + j });
vr[last].set_color(Color{ Color::black,Color::invisible });
win.attach(vr[last]);
}
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.14 and 18.15 Draw Octagon with Right Triangle
这题很有意思,直角三角形类的设计和正八边形的绘制花了我不少时间
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "Right Triangle" };
Point next{ 200, 250 };
int a = 100;
int b = 100;
double o = 0;
Vector_ref <Right_triangle> vr;
for (int i = 0; i < 8; ++i) {
vr.push_back(new Right_triangle{ next, a, b, o });
vr[vr.size() - 1].set_fill_color(Color(i));
win.attach(vr[vr.size() - 1]);
//逆时针
o += 45;
next.x += cos((o - 90) * PI / 180) * b;
next.y -= sin((o - 90) * PI / 180) * b;
//顺时针
/*next.x += cos((90 + o) * PI / 180) * b;
next.y -= sin((90 + o) * PI / 180) * b;
o -= 45;*/
win.wait_for_button();
}
for (int i = 0; i < vr.size(); ++i)
win.detach(vr[i]);
vr.~Vector_ref();
//fulfill the window
Vector_ref <Right_triangle> vr2;
const int x_win = 0;
const int y_win = 0;
const int x_n = 15;
const int y_n = 8;
const int x_step = win.x_max() / x_n;
const int y_step = win.y_max() / y_n;
int x{ x_win }, y{ y_win };
for (int i = 0; i < y_n; ++i)
{
x = x_win;
for (int j = 0; j < x_n; ++j)
{
vr2.push_back(new Right_triangle{ Point{x,y}, y_step, x_step,-90 });
vr2[vr2.size() - 1].set_fill_color(Color(i * 16 + j));
win.attach(vr2[vr2.size() - 1]);
vr2.push_back(new Right_triangle{ Point{x + x_step,y + y_step}, y_step, x_step,90 });
vr2[vr2.size() - 1].set_fill_color(Color(i * 16 + j + 1));
win.attach(vr2[vr2.size() - 1]);
x += x_step;
}
y += y_step;
}
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.16 and 18.17 Hexagon Tile
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "Hexagon Tile" };
Vector_ref<Regular_hexagon> hexs;
const int dist = 100;
const int x_hex = 0;
const int y_hex = 0;
int x_step = dist * 3;
int y_step = dist * sin(PI * 60.0 / 180.0);
const int x_n = win.x_max() / x_step + 1;
const int y_n = win.y_max() / y_step + 1;
for (int i = 0; i < y_n; ++i)
{
int x = x_hex + (i % 2) * 1.5 * dist; //x = x_hex + (i % 2) * (1 + cos(PI * 60 / 180)) * dist;
int y = y_hex + i * y_step;
for (int j = 0; j < x_n; ++j)
{
hexs.push_back(new Regular_hexagon{ Point{x,y}, dist });
auto last = hexs.size() - 1;
hexs[last].set_color(Color::invisible);
hexs[last].set_fill_color(Color{ (i * x_n + j) % 8 }); //18.17
win.attach(hexs[last]);
x += x_step;
}
}
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}
18.18
这道题我没有实现,具体的实现见 Graph.cpp 中,Polygon 类的实现方法。
附上 判断两条线是否相交的方法
Polygon 类 的实现方法和链接中提到的方法有些区别,我主要是没看懂 line_intersect() 函数最后返回结果中 除以 denom 的意思,如果你知道的话,请不吝赐教,谢谢啦。
18.19
#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"
#include"My_Shape.h"
using namespace Graph_lib;
int main()
try
{
using namespace My_shape;
Point tl{ 100,100 };
Simple_window win{ tl, 1500, 1024, "Star" };
Star s1{ Point{300, 200}, 5, 100 };
s1.set_fill_color(Color::red);
win.attach(s1);
Star s2{ Point{100, 100}, 7, 50 };
s2.set_color(Color::blue);
s2.set_fill_color(Color::white);
s2.set_style(Line_style(Line_style::dash, 2));
win.attach(s2);
Star s3{ Point{400, 300}, 10, 60 };
s3.set_color(Color::dark_green);
win.attach(s3);
Star s4{ Point{350, 100}, 8, 40 };
s4.set_color(Color::invisible);
s4.set_fill_color(Color::magenta);
win.attach(s4);
win.wait_for_button();
return 0;
}
catch (exception& e)
{
cerr << "Exception: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred\n";
return 2;
}