Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
1 семестр / Пояснительная записка курсовик.docx
Скачиваний:
0
Добавлен:
28.03.2025
Размер:
1.32 Mб
Скачать

Ограничения

Программа использует сравнение с учётом погрешности (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, [&center](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: (много подбных выводов)

продолжение перечисления всех комбинаций и найденых правильных пятиугольников.

Конец файла.

Если из данных точек недостаточно для построения пятиугольника:

Если в файле нет данных: