C++ 描述任意多边形的类及计算其面积和周长

 

 

这是一个可以在平面坐标系中表示任意多边形并且计算其面积和周长的类。不过目前只能在第一象限计算。使用时较简便,只要把多边形的各个顶点传进去就可以了(不用按顺序)

(其中面积的计算是参考https://blog.csdn.net/hemmingway/article/details/7814494的公式)

 

程序中附带包含了point 类,line 类。

      point 类:

               计算点点距离的函数:

double distancebetweenpoint(const point &a, const point &b);

 

               计算点到线距离的成员函数:

double distancetoline(const line &line)const;

 

 

       line 类:

               获得直线标准方程的函数:

void getStandardEquation(double &A, double &B, double &C)const;//get the standard equation of line( Ax+By+C=0)

 

               计算直线长度的成员函数:

 

double length()const;

               判断两条直线是否相交的成员函数:

              

bool line::iflinemeet(const line &other)const//return a bool value represent whether this line meets the other line (1 stand for yes, 0 for no)

 

 

 

(第一次用不是很会排版)

 

 

以下是使用样例:

	point a(3, 6), b(3, 3), c(0, 5),d(5,5),e(10,5),f(5,8),g(10,8);
	point v[4] = { e,f,g,d};
	polygon m(4, v);
	cout << "  area is " << m.area() << "  perimeter is " << m.perimeter()<

 

area(面积)和perimeter(周长)是double类型的。

 

 

 

以下是头文件中类的声明等等:

#pragma once
#include
using namespace std;

#define PI 3.1415926535
enum errortype { noside,cantcalculate };//the type in exceptions class which may occured in shape's functions


class line;
class point;
class error;

//the exception class
class error {
private:
	errortype eor;
public:
	error(errortype e) :eor(e) {}//constructor
	const errortype what()const { return eor; }//for inquiry
};

//class point used to represent a point in a rectangular coordinate system
class point {
	friend double distancebetweenpoint(const point &a, const point &b);//calculate the distance between two difference point(which isn't a member function of point)
public:
	double x;
	double y;
	point(double setx = 0, double sety = 0) { x = setx; y = sety; }//constructor
	double distancetoline(const line &line)const;//calculate the distance between this point and a line
	bool operator==(const point &ro)const;//compare by the x and y of the point
	void show()const { cout << "(" << x << "," << y << ")"; }//a simple output function for test
};

const point O(0, 0);//the origin in the rectangular coordinate system

//class line used to represent a line in a rectangular coordinate system
//with two different point, which may used to derive a class vector(for now, the difference between start point and end point doesn't make any sense)
class line {
	friend bool compareSlope(const line &l, const line &r);//compare(>) two lines' slope( no numercially, but geometrically)
public:
	point start;
	point end;
	line():start(0,0),end(1,0){}//default constructor which construct the line which go through (0,0) and (1,0)
	line(point startpoint, point endpoint) { start = startpoint; end = endpoint; }//constructor( construct with any two point on the line)
	void getStandardEquation(double &A, double &B, double &C)const;//get the standard equation of line( Ax+By+C=0)
	double length()const;//return the length of line
	bool iflinemeet(const line &other)const;//return a bool value represent whether this line meets the other line (1 stand for yes, 0 for no(coincide situation included))
};

//class polygon can represent arbitrary planar polygon in the rectangular coordinate system( in the first quadrant)
class polygon {
protected:
	point originalvertex;//the vertex of polygon which is the closest to original point
	//( if this shape doesn't have any vertex, then originalvertex is the center point of the shape
	point *vertexes;//save the vertexes of the polygon( the order of the vertexes follow the anti-clockwise and begin in orginalvertex)
	line *sides;//save the sides of the polygon( follow the same rule of the vertexes) 
	unsigned int sidenum;//the number of the polygon's sides
	void setoriginalvertex(point ov);//reset the originalvertex of the polygon

public:
	polygon( unsigned int numofside=0);//contructor which only set number of sides, thus its *sides and *vertexes is null pointer(originalvertex is (0,0))
	polygon(point Uoriginalvertex,unsigned int numofside = 0);//contructor which set number of sides and originalvertex, thus its *sides and *vertexes is null pointer
	polygon(unsigned int numofside, point vertex[]) throw(error);//contructor, whose parameter is a point array saved the vertexes of the polygon
	//if numofside is 0, function will throw a exception( within the exception class is the error type "noside")
	~polygon();//destructor
	polygon(const polygon &obj);//copy constructor
	point getoriginalvertex()const;//return the originalvertex
	int getnumofsides()const;//return the sides' number of  ploygon
	virtual double area()const throw(error);//return polygon's area( if polygon has no vertexes, this function will throw exception( within the exception class is the error type "cantcalculate")
	virtual double perimeter()const throw(error);//return polygon's perimeter( if polygon has no sides, this function will throw exception( within the exception class is the error type "cantcalculate")
	virtual void show()const {//a simple output function for test
		cout << "original vertex is "; originalvertex.show(); cout << " number of sides is"
			<< sidenum;
	}
};
bool compareSlope(const line &l, const line &r);

 

具体的实现文件:

 

#include"Shape.h"
#include

//class point {

bool point::operator==(const point &ro)const {
	if (x == ro.x&&y == ro.y) {
		return true;
	}
	else {
		return false;
	}
}

double distancebetweenpoint(const point &a, const point &b)//calculate the distance between two difference point
{
	double x = (a.x - b.x);
	double y = (a.y - b.y);
	x = pow(x, 2);
	y = pow(y, 2);
	double dis = sqrt(x + y);
	return dis;
}

double point::distancetoline(const line &line)const//calculate the distance between this point and line
{
	double A, B, C;
	line.getStandardEquation(A, B, C);
	C = -C;
	
	//calculate the distance
	double dis =abs( (A*x + B*y + C) / sqrt(A*A + B*B));
	return dis;
}

//class line {

void line::getStandardEquation(double &A, double &B, double &C)const {
	//give the line's equation
	double dy1 = end.y - start.y;
	double dx1 = end.x - start.x;
	A = dy1; B = -dx1; C = start.y*dx1 - start.x*dy1;
	C = -C;
	return;
}

double line::length()const {//return the length of line
	return distancebetweenpoint(start, end);
}

bool line::iflinemeet(const line &other)const//return a bool value represent whether this line meets the other line (1 stand for yes, 0 for no)
{
	if (end.xother.end.x || start.y>other.end.y)
	{
		return 0;
	}
	//get the line's equation
	double A1, B1, C1;
	getStandardEquation(A1, B1, C1);

	//get the line's equation
	double A2, B2, C2;
	other.getStandardEquation(A2, B2, C2);

	if ((A1 / A2) == (B1 / B2)) {
		if (C1 != C2) 
			return 0;
		else 
			return 1;
	}

	double rx, ry;//calculate the meet point
	ry = (C1*A2 / A1 - C2) / (B2 - A2*B1 / A1);
	rx = ((-1)*C2 + (-1)*B2*ry) / A2;

	if (rxend.x || rx>other.end.x ||
		ryend.y || ry>other.end.y) {
		return 0;
	}
	return 1;

}

//class shape {

polygon::polygon(const polygon &obj) {
	sidenum = obj.sidenum;
	originalvertex = obj.originalvertex;
	if (!obj.vertexes) {
		vertexes = nullptr;
	}
	else {
		vertexes = new point[obj.sidenum];
		for (int i = 0; i < sidenum; i++) {
			vertexes[i] = obj.vertexes[i];
		}
	}
	if (!obj.sides) {
		sides = nullptr;
	}
	else {
		sides = new line[obj.sidenum];
		for (int i = 0; i < sidenum; i++) {
			sides[i] = obj.sides[i];
		}
	}
}

double polygon::perimeter()const {
	if (!sides) {//the shape's can't be represent/calculate this way
		throw error(cantcalculate);
	}
	double perimeter = 0;
	for (int i = 0; i < sidenum; i++) {
		perimeter += sides[i].length();
	}
	return perimeter;
}

//the way of calculate the area is refered from the website below:
//https://blog.csdn.net/hemmingway/article/details/7814494
double polygon::area()const {
	if (!vertexes) {//the shape has no vertex
		throw error(cantcalculate);
	}
	double s=0;
	int n = sidenum - 1;
	for (int i = 0; i <= n - 1; i++) {
		s += (vertexes[i].x - vertexes[0].x)*(vertexes[i + 1].y - vertexes[0].y) - (vertexes[i].y - vertexes[0].y)*(vertexes[i + 1].x - vertexes[0].x);
	}
	s = abs(s) / 2;
	return s;
}

void polygon::setoriginalvertex(point ov) {
	originalvertex = ov;
}

int polygon::getnumofsides()const {
	return sidenum;
}

point polygon::getoriginalvertex()const {
	return originalvertex;
}

polygon::~polygon() {
	if (vertexes != nullptr) {
		delete[]vertexes;
	}
	if (sides != nullptr) {
		delete[]sides;
	}
}

polygon::polygon(point Uoriginalvertex, unsigned int numofside ):vertexes(nullptr),sides(nullptr),sidenum(numofside),originalvertex(Uoriginalvertex) {}

polygon::polygon(unsigned int numofside):sidenum(numofside),vertexes(nullptr),sides(nullptr),originalvertex(O) {}

bool compareSlope(const line &l, const line &r) {//compare(>) two lines' slope( no numercially, but geometrically)
	bool flagl, flagr;
	flagl = flagr = 0;
	if (l.end.x == l.start.x)//whether the slope is existed
		flagl = 1;
	if (r.end.x == r.start.x)
		flagr = 1;
	if (flagl&&flagr)
		return 0;

	if (flagl) {
		double k = (r.end.y - r.start.y) / (r.end.x - r.start.x);
		if (k >= 0)
			return 1;
		else
			return 0;
	}
	if (flagr) {
		double k = (l.end.y - l.start.y) / (l.end.x - l.start.x);
		if (k >= 0)
			return 0;
		else
			return 1;
	}
	double kr = (r.end.y - r.start.y) / (r.end.x - r.start.x);
	double kl = (l.end.y - l.start.y) / (l.end.x - l.start.x);
	if (kl >= 0 ) {
		if (kr >= 0)
			return kl > kr;
		else
			return 0;
	}
	if (kl < 0) {
		if (kr < 0)
			return kl > kr;
		else
			return 1;
	}
}

bool aTempCompareFunctionfor_polygonConstructor(double kl, double kr) {
	if (kl >= 0) {
		if (kr >= 0)
			return kl > kr;
		else
			return 0;
	}
	if (kl < 0) {
		if (kr < 0)
			return kl > kr;
		else
			return 1;
	}
}

polygon::polygon(unsigned int numofside, point vertex[]) {
	if (numofside == 0) {
		throw error(errortype(0));
	}

	//find the originalvertex
	sidenum = numofside; double min = distancebetweenpoint(O, vertex[0]);
	for (int i = 0; i < numofside; i++) {
		if (distancebetweenpoint(O, vertex[i]) <= min) {
			originalvertex = vertex[i];
		}
	}

	//set the vertexes in anti-clock order( only make sense when all the vertexes are in the first quadrant )
	class dot {//use a list structure to reorder
	public:
		point v;
		double k;//the slope of the line which go through the original vertex and this point
		bool flag;//whether the point is the original vertex
		dot *next;
		dot() = default;
		dot(point vertex, point original) :v(vertex),  next(nullptr), flag(0) {
			if (vertex.x == original.x) {//the slope doesn't exist, so I use a really big numerical value to represent it
				k = 1000000000000;
				if (vertex.y == original.y)
					flag = 1;
			}
			else {
				k = (vertex.y - original.y) / (vertex.x - original.x);
			}
		}
		dot& operator=(const dot &ro) { v = ro.v;  k = ro.k; next = ro.next; flag = ro.flag; }
		dot(const dot &ro) { v = ro.v; k = ro.k; next = nullptr; flag = ro.flag;	}
	};
	typedef dot* dotp;

	int i=1;
	dot *head = new dot(vertex[0],originalvertex);//create the head node
	while (head->flag) {
		delete head;
		head = new dot(vertex[i], originalvertex);
		i++;
	}
	
	dot *p1, *b1; b1 = head; 
	for ( ; i < numofside; i++) {//create the list
		p1 = new dot(vertex[i], originalvertex);
		if (p1->flag) { delete p1; continue; }
		b1->next = p1;
		b1 = p1;
	}

	//the reorder operation
	int num = sidenum-1;
	dotp *arr = new dotp[num];
	dotp b, p, *t, *todelete;
	t = new dotp;//这里只是为了堵住编译器的嘴
	todelete = t;
	b = p = head;

	for ( i = 0; i < num; i++) {
		arr[i] = p;
		p = p->next;
	}

	for (int j = 0; jk;
				t = &arr[i];
			}
			if (!aTempCompareFunctionfor_polygonConstructor(arr[i]->k, temp)){
				temp = arr[i]->k;
				t = &arr[i];
			}
		}
		dotp lin = arr[j];
		arr[j] = *t;
		*t = lin;
	}

	head = arr[0];
	b = head;
	for ( i = 1; i < num; i++) {
		b->next = arr[i];
		b = arr[i];
	}
	b->next = nullptr;


	//create the polygon's vertexes and sides
	vertexes = new point[sidenum];
	sides = new line[sidenum];
	vertexes[0] = originalvertex;
	p1 =  head;
	for ( i = 1; i < num+1; i++) {
		vertexes[i] = p1->v;
		line ts(vertexes[i - 1], vertexes[i]);
		sides[i-1] = ts;
		p1 = p1->next;
	}
	line ts(vertexes[sidenum - 1], vertexes[0]);
	sides[sidenum - 1] = ts;

	//clean up
	delete todelete;
	for ( i = 0; i < num; i++) {
		p = head->next;
		delete head;
		head = p;
	}
}

 

你可能感兴趣的:(C++ 描述任意多边形的类及计算其面积和周长)