
Ограничения
Программа использует сравнение с учётом погрешности (EPSILON =0,01)
Разработка интерфейса пользователя
O1: Задание: Дано N произвольных точек на плоскости. Найти среди них точки, являющиеся вершинами (образующими) фигур, обладающих следующими
свойствами: с максимальным числом точек в области (внутренней или строго
выделенной). Задание выполнить для правильной трапеции.
Автор: Группа: Дата: 24.12.24
O2: Ошибка: недостаточно точек для формирования пятиугольника.
O3: Недостаточно точек для формирования пятиугольника.
O4: Комбинация: (x , y) - Правильный. Точек внутри:
O5: Правильный пятиугольник: (x , y) (x , y) (x , y) (x , y) (x , y)
Точек внутри:
O6: Комбинация: (x , y) - Неправильный.
O7: Пятиугольник с максимальным количеством точек внутри (число):
O8: Ошибка открытия файлов!
O9: Начало обработки файла
O10: Ошибка: некорректное число точек.
O11: Ожидается n точек.
O12: Пропущена пустая строка.
O13: Считана точка:
O14: Пропущена строка:
O15: Предупреждение: Считано точек.
O16: Считанные точки ( )
O17: Обработка файла завершена.
O18: Ошибка: входной файл пуст.
O19: Пятиугольники с максимальным количеством точек внутри ()
Библиотеки
Внутреннее представление данных в программе
Функции
Представление алгоритма
Краткое пояснение выполняемых действий
Читаем данные из входного файла, содержащие координаты точек, и проводим их проверку и фильтрацию. Определяем границы области, в которой расположены точки, чтобы сократить дальнейший анализ. Каждую точка проверяется на уникальность и записываем в список уникальных координат. Анализируем точки для проверки возможности формирования правильных пятиугольников. Найденные пятиугольники сортируем и проверяем на соответствие требованиям (правильность, равные стороны и углы). Каждая точка дополнительно проверяется, входит ли она внутрь пятиугольника. Все действия и результаты записываются в протокол и итоговый файл.
Блоксхема
Для
первой функции:
Для
второй функции:

Для
третьей функции:
Для четвертой функции:
Для пятой функции:
Для шестой функции:
Для седьмой функции:
Для восьмой функции:
Для
девятой функции:
Д
ля
десятой функции:
Для одиннадцатой функции:
Для двенадцатой функции:
Для тринадцатой функции:
Текст программы #include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <sstream>
using namespace std;
const double PI = 3.141592653589793;
const double EPSILON = 0.01;
struct Point {
double x, y;
};
struct BoundingBox {
double minX, minY, maxX, maxY;
};
BoundingBox calculateBoundingBox(const Point polygon[], int size) {
BoundingBox box = { polygon[0].x, polygon[0].y, polygon[0].x, polygon[0].y };
for (int i = 1; i < size; ++i) {
box.minX = min(box.minX, polygon[i].x);
box.minY = min(box.minY, polygon[i].y);
box.maxX = max(box.maxX, polygon[i].x);
box.maxY = max(box.maxY, polygon[i].y);
}
return box;
}
bool isPointInBoundingBox(const BoundingBox& box, const Point& p) {
return p.x >= box.minX && p.x <= box.maxX && p.y >= box.minY && p.y <= box.maxY;
}
// Функция для преобразования строки в число
bool parseDouble(const char*& ptr, double& value) {
value = 0.0;
double fraction = 0.0, divisor = 1.0;
bool negative = false;
while (isspace(*ptr)) ptr++;
if (*ptr == '-' || *ptr == '+') negative = (*ptr++ == '-');
if (!isdigit(*ptr)) return false;
while (isdigit(*ptr)) value = value * 10 + (*ptr++ - '0');
if (*ptr == '.') {
ptr++;
while (isdigit(*ptr)) {
fraction = fraction * 10 + (*ptr++ - '0');
divisor *= 10;
}
value += fraction / divisor;
}
if ((*ptr == 'e' || *ptr == 'E') && isdigit(*(ptr + 1))) {
int exponent = 0;
bool expNegative = (*++ptr == '-') && ++ptr;
while (isdigit(*ptr)) exponent = exponent * 10 + (*ptr++ - '0');
value *= pow(10, expNegative ? -exponent : exponent);
}
value = negative ? -value : value;
return true;
}
// Функция для извлечения чисел из строки
int extractNumbers(const char* line, double numbers[], int maxCount) {
const char* ptr = line;
int count = 0;
while (*ptr && count < maxCount) {
double value;
if (parseDouble(ptr, value)) {
numbers[count++] = value;
}
else {
while (*ptr && !isdigit(*ptr) && *ptr != '-' && *ptr != '+') {
ptr++; // Пропускаем символы, которые не являются частью числа
}
}
}
return count;
}
bool customReadLine(ifstream& inputFile, char* buffer, size_t bufferSize) {
size_t i = 0;
char ch;
while (inputFile.get(ch)) {
if (ch == '\n' || i == bufferSize - 1) {
buffer[i] = '\0';
return true;
}
buffer[i++] = ch;
}
buffer[i] = '\0';
return i > 0;
}
bool isUniquePoint(const Point points[], int pointCount, double x, double y) {
for (int i = 0; i < pointCount; ++i)
if (points[i].x == x && points[i].y == y) return false;
return true;
}
inline double distance(const Point& p1, const Point& p2) {
return sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}
inline double angle(const Point& a, const Point& b, const Point& c) {
double abx = b.x - a.x;
double aby = b.y - a.y;
double cbx = b.x - c.x;
double cby = b.y - c.y;
double dotProduct = abx * cbx + aby * cby;
double magnitudeAB = sqrt(abx * abx + aby * aby);
double magnitudeCB = sqrt(cbx * cbx + cby * cby);
return acos(dotProduct / (magnitudeAB * magnitudeCB));
}
Point findCenter(const Point points[], int size) {
Point center = { 0, 0 };
for (int i = 0; i < size; ++i) {
center.x += points[i].x;
center.y += points[i].y;
}
center.x /= size;
center.y /= size;
return center;
}
void sortPointsClockwise(Point points[], int size, Point center) {
sort(points, points + size, [¢er](const Point& a, const Point& b) {
return atan2(a.y - center.y, a.x - center.x) < atan2(b.y - center.y, b.x - center.x);
});
}
bool isRegularPolygon(const Point points[], int size) {
double sideLength = distance(points[0], points[1]);
double angleValue = angle(points[size - 1], points[0], points[1]);
for (int i = 1; i < size; ++i) {
if (fabs(distance(points[i], points[(i + 1) % size]) - sideLength) > EPSILON ||
fabs(angle(points[i - 1], points[i], points[(i + 1) % size]) - angleValue) > EPSILON)
return false;
}
return true;
}
// Проверка принадлежности точки пятиугольнику через пересечение отрезков
bool isPointInsidePolygon(const Point polygon[], int size, const Point& p) {
int count = 0;
// Проверяем пересечения
for (int i = 0; i < size; ++i) {
int next = (i + 1) % size;
Point a = polygon[i], b = polygon[next];
// Проверяем, не совпадает ли точка p с одной из вершин
if (fabs(p.x - a.x) < EPSILON && fabs(p.y - a.y) < EPSILON) {
return false; // Игнорируем точки-вершины
}
// Проверка пересечения
if ((a.y > p.y) != (b.y > p.y)) {
double intersectionX = a.x + (p.y - a.y) * (b.x - a.x) / (b.y - a.y);
if (p.x < intersectionX) {
count++;
}
}
}
return count % 2 == 1; // Нечётное количество пересечений означает, что точка внутри
}
void generateCombinations(Point points[], int pointCount, ofstream& protocolFile, ofstream& outputFile) {
if (pointCount < 5) {
protocolFile << "Ошибка: недостаточно точек для формирования пятиугольника.\n";
outputFile << "Недостаточно точек для формирования пятиугольника.\n";
return;
}
Point combination[5];
int maxInsideCount = 0;
// Выделение памяти в куче
auto maxPolygons = new Point[100][5]; // Хранение до 100 пятиугольников
auto allInsidePoints = new Point[100][1000]; // Точки внутри пятиугольников
auto insidePointCounts = new int[100](); // Количество точек внутри каждого пятиугольника
int maxPolygonCount = 0;
// Список всех правильных пятиугольников
Point allPolygons[100][5];
int allPolygonCounts[100] = { 0 };
int totalPolygons = 0;
for (int i = 0; i < pointCount - 4; ++i) {
for (int j = i + 1; j < pointCount - 3; ++j) {
for (int k = j + 1; k < pointCount - 2; ++k) {
for (int l = k + 1; l < pointCount - 1; ++l) {
for (int m = l + 1; m < pointCount; ++m) {
combination[0] = points[i]; combination[1] = points[j];
combination[2] = points[k]; combination[3] = points[l];
combination[4] = points[m];
Point center = findCenter(combination, 5);
sortPointsClockwise(combination, 5, center);
protocolFile << "Комбинация: ";
for (int n = 0; n < 5; ++n)
protocolFile << "(" << combination[n].x << ", " << combination[n].y << ") ";
if (isRegularPolygon(combination, 5)) {
int insideCount = 0;
auto insidePoints = new Point[1000]; // Выделение памяти для точек внутри
BoundingBox box = calculateBoundingBox(combination, 5);
for (int p = 0; p < pointCount; ++p) {
if (!isPointInBoundingBox(box, points[p])) {
continue;
}
bool isVertex = false;
for (int v = 0; v < 5; ++v) {
if (fabs(points[p].x - combination[v].x) < EPSILON &&
fabs(points[p].y - combination[v].y) < EPSILON) {
isVertex = true;
break;
}
}
if (!isVertex && isPointInsidePolygon(combination, 5, points[p])) {
insidePoints[insideCount++] = points[p];
}
}
protocolFile << "- Правильный. Точек внутри: " << insideCount << ".\n";
protocolFile << "Точки внутри: ";
for (int n = 0; n < insideCount; ++n) {
protocolFile << "(" << insidePoints[n].x << ", " << insidePoints[n].y << ") ";
}
protocolFile << "\n";
outputFile << "Правильный пятиугольник:\n";
for (int n = 0; n < 5; ++n) {
outputFile << "(" << combination[n].x << ", " << combination[n].y << ")\n";
}
outputFile << "Точки внутри: ";
for (int n = 0; n < insideCount; ++n) {
outputFile << "(" << insidePoints[n].x << ", " << insidePoints[n].y << ") ";
}
outputFile << "\n\n";
// Добавление в список всех пятиугольников
if (totalPolygons < 100) {
for (int n = 0; n < 5; ++n) {
allPolygons[totalPolygons][n] = combination[n];
}
allPolygonCounts[totalPolygons] = insideCount;
totalPolygons++;
}
if (insideCount > maxInsideCount) {
maxInsideCount = insideCount;
maxPolygonCount = 0; // Сброс количества пятиугольников
copy(combination, combination + 5, maxPolygons[maxPolygonCount]);
copy(insidePoints, insidePoints + insideCount, allInsidePoints[maxPolygonCount]);
insidePointCounts[maxPolygonCount] = insideCount;
maxPolygonCount++;
}
else if (insideCount == maxInsideCount) {
if (maxPolygonCount < 100) {
copy(combination, combination + 5, maxPolygons[maxPolygonCount]);
copy(insidePoints, insidePoints + insideCount, allInsidePoints[maxPolygonCount]);
insidePointCounts[maxPolygonCount] = insideCount;
maxPolygonCount++;
}
}
delete[] insidePoints; // Очистка памяти
}
else {
protocolFile << "- Неправильный.\n";
}
}
}
}
}
}
// Вывод всех правильных пятиугольников
if (totalPolygons > 0) {
outputFile << "\nВсе найденные правильные пятиугольники:\n";
for (int i = 0; i < totalPolygons; ++i) {
outputFile << "Пятиугольник " << (i + 1) << ":\n";
for (int j = 0; j < 5; ++j) {
outputFile << "(" << allPolygons[i][j].x << ", " << allPolygons[i][j].y << ")\n";
}
outputFile << "\n";
}
}
// Вывод пятиугольников с максимальным количеством точек внутри
if (maxPolygonCount > 0) {
outputFile << "\nПятиугольники с максимальным количеством точек внутри (" << maxInsideCount << "):\n";
for (int i = 0; i < maxPolygonCount; ++i) {
if (insidePointCounts[i] == maxInsideCount) {
outputFile << "Пятиугольник " << (i + 1) << ":\n";
for (int j = 0; j < 5; ++j) {
outputFile << "(" << maxPolygons[i][j].x << ", " << maxPolygons[i][j].y << ")\n";
}
outputFile << "Точки внутри:\n";
for (int j = 0; j < insidePointCounts[i]; ++j) {
outputFile << "(" << allInsidePoints[i][j].x << ", " << allInsidePoints[i][j].y << ")\n";
}
outputFile << "\n";
}
}
}
// Очистка памяти
delete[] maxPolygons;
delete[] allInsidePoints;
delete[] insidePointCounts;
}
// Преобразование double в строку
string doubleToString(double value) {
ostringstream oss;
oss << value;
return oss.str();
}
void processFile(const char* inputFileName, const char* protocolFileName, const char* outputFileName) {
ifstream inputFile(inputFileName);
ofstream protocolFile(protocolFileName), outputFile(outputFileName);
if (!inputFile || !protocolFile || !outputFile) {
cout << "Ошибка открытия файлов!" << endl;
return;
}
protocolFile << "Начало обработки файла.\n";
// Проверка на пустой входной файл
if (inputFile.peek() == ifstream::traits_type::eof()) {
protocolFile << "Ошибка: входной файл пуст.\n";
outputFile << "Ошибка: входной файл пуст.\n";
return;
}
int pointCount = 0;
inputFile >> pointCount;
inputFile.ignore();
if (pointCount <= 0) {
protocolFile << "Ошибка: некорректное число точек.\n";
return;
}
protocolFile << "Ожидается " << pointCount << " точек.\n";
Point points[1000];
char buffer[256];
double x, y;
int validPoints = 0;
while (customReadLine(inputFile, buffer, sizeof(buffer)) && validPoints < pointCount) {
if (buffer[0] == '\0') {
protocolFile << "Пропущена пустая строка.\n";
continue;
}
double numbers[2];
int numCount = extractNumbers(buffer, numbers, 2);
if (numCount == 2 && isUniquePoint(points, validPoints, numbers[0], numbers[1])) {
points[validPoints++] = { numbers[0], numbers[1] };
protocolFile << "Считана точка: (" << numbers[0] << "; " << numbers[1] << ").\n";
}
else {
protocolFile << "Пропущена строка: " << buffer << "\n";
}
}
// Проверяем, все ли точки считаны
protocolFile << (validPoints < pointCount ?
"Предупреждение: Считано " + doubleToString(validPoints) + " точек.\n" :
"Все точки успешно считаны.\n");
// Записываем считанные точки в output
outputFile << "Считанные точки (" << validPoints << "):\n";
for (int i = 0; i < validPoints; ++i) {
outputFile << "(" << points[i].x << ", " << points[i].y << ")\n";
}
outputFile << "\n";
// Генерируем комбинации
generateCombinations(points, validPoints, protocolFile, outputFile);
protocolFile << "Обработка файла завершена.\n";
}
int main() {
setlocale(LC_ALL, "ru");
cout << "Задание: Дано N произвольных точек на плоскости.Найти среди них точки, являющиеся вершинами(образующими) фигур, обладающих следующими"
<< "свойствами: с максимальным числом точек в области(внутренней или строго выделенной). Задание выполнить для правильного пятиугольника.\n"
<< "Автор: Группа: \n"
<< "Дата: 24.12.24\n";
setlocale(LC_ALL, "ru");
processFile("points.txt", "protocol.txt", "output.txt");
system("output.txt");
}Результаты работы программы
Для такого контрольного примера:
60
24.5545 50.7653
21.5338 33.3924
37.1229 25.151
49.7783 37.4304
42.0106 53.2609
26.2703 36.8875
48.4698 36.8386
38.4208 51.6524
40.5137 29.515
7.58742 -13.2878
6.3257 -24.9756
17.0516 -29.7873
24.9422 -21.0733
19.0931 -10.876
17.3489 -13.9453
13.7082 -13.8299
12.7799 -16.7323
-27.8957 21.1366
-28.2762 9.38704
-17.2192 5.39441
-10.0052 14.6764
-16.6037 24.4056
-15.2194 17.0064
-23.5404 8.84598
-15.9147 11.3077
-32.3793 -13.5292
-31.8816 -31.1558
-14.964 -36.1293
-5.00597 -21.5767
-15.7692 -7.60902
-8.20552 -24.862
-15.0724 -15.8552
-12.2522 -17.1529
-5.9625 -22.3805
-32.0376 -18.5743
Output:
protocol:
(много
подбных выводов)
продолжение перечисления всех комбинаций и найденых правильных пятиугольников.
Конец файла.
Если из данных точек недостаточно для построения пятиугольника:
Если в файле нет данных: