C++程序设计原理与实践 习题答案 第十八章 第18章习题答案

习题要求所设计的图形类

这些类比如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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值