【C++ 程序】 tvj::Polygon类 (多边形类)

代码

Polygon.h

/*
 * Project: Polygon Class
 * File: Polygon.h
 * ------------------
 *
 * @author: Teddy van Jerry
 *
 * @version: 2021/01/03
 * - initial version
 */

 ///
 // NOTE:	
 //   The class name Polygon can be misinterpreted
 // as a function defined in C++ standard library.
 //   So remember to use the namespace tvj.
 ///

#pragma once
#define _POLYGON_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include  // std::istringstream
#include 

// used when debugging
// #define DEBUG

struct Point
{
	double X = 0;
	double Y = 0;
};

namespace tvj
{
	class Polygon
	{
		friend std::istream& operator>> (std::istream& in, tvj::Polygon& pol);

	public:

		// Constuctors will be released in later versions.

		//Polygon(Point[]);

		//Polygon(std::vector);

		double perimeter();

		double area();

		unsigned edgeNumber();

	private:
		std::vector<Point> Pt;

		double C = 0; // perimeter

		double S = 0; // area

		bool legal(double xi, double yi);

		// add to C when new points added
		double _C_(double xi, double yi);

		// add to S when new points added
		double _S_(double xi, double yi);
	};

	// input numbers into a vector and test whether it is 'end'
	std::vector<double> cinvec_d(std::istream& input, int& index)
	{
		std::string cin_d;
		std::getline(input, cin_d);
		std::vector<double> vint;
		if (cin_d == "end")
		{
			index = 1; // 'end' is inputted
			return vint;
		}

		// change string into double
		std::istringstream is(cin_d);
		double i;
		while (is >> i)
			vint.push_back(i);
		return vint;
	}

	// used to test whether there are crosses in sides
	bool Polygon::legal(double xi, double yi)
	{
		double epsilon = 1E-12; // allowing for precision in calculation
		if (this->Pt.size() >= 3)
		{
			for (int i = 1; i != this->Pt.size() - 1; i++)
			{
				for (int j = 0; j != i; j++)
				{
					// define
					double x1 = Pt[i].X, y1 = Pt[i].Y;
					double x2 = Pt[j].X, y2 = Pt[j].Y;
					double x3 = (Pt.cend() - 1)->X, y3 = (Pt.cend() - 1)->Y;
					double x4 = xi, y4 = yi;
					double x_t = 0, y_t; // intersection
					double denominator, numerator;

					// test (using maths methods)
					denominator = (y2 - y1) * (x4 - x3) - (y4 - y3) * (x2 - x1);
					numerator = (y3 - y1) * (x4 - x3) * (x2 - x1) + x1 * (y2 - y1) * (x4 - x3) - x3 * (y4 - y3) * (x2 - x1);
					if (fabs(denominator) < epsilon);
					// The requirement has been lowered.
					/*
					{
						if (fabs((yi - y1) * (xi - x2) - (yi - y2) * (xi - x1)) < epsilon) return false;
					}
					*/
					else // fabs(denominator) >= epsilon
					{
						x_t = numerator / denominator;

						// The next two lines are used when debugging
						#ifdef DEBUG
							std::cout << "\n" << i << "/" << x1 << " " << x_t << " " << j << "/" << x2
								<< "\n  " << x3 << "   " << x4 << std::endl;
						#endif // !DEBUG				

						// This part should be dealt with very carefully
						// If x1=x2 or x3=x4, we cannot use x as the sole criterion
						// because we cannot see whether the intersection is in the line
						// so we have to use y this time
						if (x1 == x2)
						{
							y_t = (y4 - y3) / (x4 - x3) * (x_t - x3) + y3;
							if ((y_t - y1) * (y_t - y2) < epsilon && (x_t - x3) * (x_t - x4) < epsilon) return false;
						}
						else if (x3 == x4)
						{
							y_t = (y2 - y1) / (x2 - x1) * (x_t - x1) + y1;
							if ((x_t - x1) * (x_t - x2) < epsilon && (y_t - y3) * (y_t - y4) < epsilon) return false;
						}
						else if ((x_t - x1) * (x_t - x2) < epsilon && (x_t - x3) * (x_t - x4) < epsilon) return false;
					}
				}
			}
		}
		else if (Pt.size() == 2)
		{
			// if they coincide
			if ((fabs(yi - Pt[1].Y) < epsilon && fabs(xi - Pt[1].X) < epsilon)
				|| (fabs(yi - Pt[0].Y) < epsilon && fabs(xi - Pt[0].X) < epsilon)) return false;
		}
		else if (Pt.size() == 1)
		{
			// if they coincide
			if (fabs(Pt[0].X - xi) < epsilon && fabs(Pt[0].Y - yi) < epsilon) return false;
		}
		return true;
	}

	// perimeter
	double Polygon::_C_(double xi, double yi)
	{
		if (Pt.size() >= 2)
			return sqrt((xi - (Pt.cend() - 2)->X) * (xi - (Pt.cend() - 2)->X) + (yi - (Pt.cend() - 2)->Y) * (yi - (Pt.cend() - 2)->Y));
		else return 0;
	}

	// area
	double Polygon::_S_(double xi, double yi)
	{
		if (Pt.size() >= 2)
			// This is a maths formula.
			return (xi * ((Pt.cend() - 2)->Y) / 2 - yi * ((Pt.cend() - 2)->X) / 2);
		else return 0;
	}

	double Polygon::perimeter()
	{
		return this->C;
	}

	double Polygon::area()
	{
		return fabs(this->S);
	}

	unsigned Polygon::edgeNumber()
	{
		return this->Pt.size();
	}

	// the class:: used here is to avoid Polygon being interpreted as a function defined in Windows.h
	std::istream& operator>> (std::istream& in, tvj::Polygon& pol)
	{
		int Index = 0;
		while (1)
		{
			std::vector<double> row = cinvec_d(in, Index);
			if (Index != 0)
			{
				// add the last one
				pol.C += sqrt((pol.Pt[0].X - (pol.Pt.cend() - 1)->X) * (pol.Pt[0].X - (pol.Pt.cend() - 1)->X)
					+ (pol.Pt[0].Y - (pol.Pt.cend() - 1)->Y) * (pol.Pt[0].Y - (pol.Pt.cend() - 1)->Y));
				pol.S += pol.Pt[0].X * (pol.Pt.cend() - 1)->Y / 2 - pol.Pt[0].Y * (pol.Pt.cend() - 1)->X / 2;
				break;
			}
			if (row.size() == 2 && pol.legal(row[0], row[1]))
			{
				Point this_point{ row[0], row[1] };
				pol.Pt.push_back(this_point);
				pol.C += pol._C_(row[0], row[1]);
				pol.S += pol._S_(row[0], row[1]);
			}
			else
			{
				// It may have crossed lines or do not have exactly two numbers.
				MessageBox(NULL, L"Illegal input of a coordinate.\nTry again!", L"Error", MB_ICONERROR);
			}
		}
		return in;
	}
}

// Copyright: 2021 Teddy van Jerry

测试主函数

main.cpp

#include "Polygon.h"
using namespace std;

int main()
{
	tvj::Polygon Test1;

	// input
	cout << "Please input the coordinates of the polygon one in a line:" << endl;
	cin >> Test1;

	// output
	cout << "\n-----------------------" << endl;
	cout << "Edge Number: " << Test1.edgeNumber() << endl;
	cout << "  Perimeter: " << Test1.perimeter() << endl;
	cout << "       Area: " << Test1.area() << endl;
	cout << "-----------------------\nALL RIGHTS RESERVED (C) 2021 Teddy van Jerry" << endl;
	return 0;
}

// Copyright: 2021 Teddy van Jerry

输出示例

正确数据的时候:
【C++ 程序】 tvj::Polygon类 (多边形类)_第1张图片
输入数据存在交点的时候。
【C++ 程序】 tvj::Polygon类 (多边形类)_第2张图片

分析

  • 使用详见头文件的 Note。
  • 本头文件由我的博客 【C++ 程序】 多边形面积周长问题 改写而来。

ALL RIGHTS RESERVED © 2021 Teddy van Jerry
欢迎转载,转载请注明出处。


See also

Teddy van Jerry 的导航页

你可能感兴趣的:(【C++】,自编程序,c++,多边形,Polygon,类,头文件)