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