这是一个可以在平面坐标系中表示
任意多边形并且计算其面积和周长的类。
不过目前只能在第一象限计算。使用时较简便,只要把多边形的各个顶点传进去就可以了
(不用按顺序)。
(其中面积的计算是参考
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()<<endl;
area(面积)和perimeter(周长)是double类型的。
以下是头文件中类的声明等等:
#pragma once #include<iostream> 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<cmath> //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.x<other.start.x || end.y<other.start.y || start.x>other.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 (rx<start.x || rx<other.start.x || rx>end.x || rx>other.end.x || ry<start.y || ry<other.start.y || ry>end.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; j<num; j++) { double temp; for (int i = j; i<num; i++) { if (i == j) { temp = arr[i]->k; 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; } }