import json import tkinter as tk import numpy as np from shapely.geometry import Polygon, Point import tripy import math # Загрузка координат из JSON файла with open('regions.json', 'r') as file: data = json.load(file) # Извлечение координат coordinates = data['features'][1]['geometry']['coordinates'][0] # Функция для запроса количества точек у пользователя def get_number_of_points(): num_points = int(input("Введите количество точек: ")) return num_points # Функция для генерации точки внутри треугольника с учетом минимального расстояния def generate_point_in_triangle_with_distance(triangle, existing_points, min_distance, polygon, max_attempts=100): # Генерирует случайную точку внутри треугольника с использованием барицентрических координат. for _ in range(max_attempts): r1, r2 = np.random.random(2) sqrt_r1 = np.sqrt(r1) a, b, c = triangle point = ( (1 - sqrt_r1) * np.array(a) + sqrt_r1 * (1 - r2) * np.array(b) + sqrt_r1 * r2 * np.array(c) ) point = Point(point) # Проверка, что точка находится на достаточном расстоянии от других точек и границ многоугольника if all(point.distance(existing_point) >= min_distance for existing_point in existing_points) and \ point.distance(polygon.boundary) >= min_distance: return point return None def distribute_points_on_polygon_with_Seidal(coords, num_points): # Создание многоугольника с использованием библиотеки Shapely polygon = Polygon(coords) # Выполняем триангуляцию многоугольника с использованием библиотеки tripy triangles = tripy.earclip(coords) # Преобразуем вершины треугольников в формат списков кортежей triangle_ver = [list(map(tuple, triangle)) for triangle in triangles] # Вычисляем площадь каждого треугольника triangle_areas = [Polygon(triangle).area for triangle in triangle_ver] # Находим общую площадь всех треугольников total_area = sum(triangle_areas) # Определяем минимальное расстояние между точками min_distance = math.sqrt(total_area / num_points) / 2 points = [] # Равномерно распределяем точки в каждом треугольнике for i, triangle in enumerate(triangle_ver): # Вычисляем количество точек для данного треугольника пропорционально его площади num_points_in_triangle = int(num_points * (triangle_areas[i] / total_area)) # Генерируем точки внутри треугольника с учетом минимального расстояния for _ in range(num_points_in_triangle): point = generate_point_in_triangle_with_distance(triangle, points, min_distance, polygon) if polygon.contains(point): points.append(point) # Если точек меньше, чем нужно, добавляем дополнительные точки, уменьшая минимальное расстояние while len(points) < num_points: min_distance *= 0.9 for i, triangle in enumerate(triangle_ver): if len(points) >= num_points: break point = generate_point_in_triangle_with_distance(triangle, points, min_distance, polygon) if point and polygon.contains(point): points.append(point) # Возвращаем список точек, которые оказались внутри многоугольника return [(point.x, point.y) for point in points] # Функция для создания графика многоугольника def draw_polygon(coords, points=None): # Создание основного окна root = tk.Tk() root.title("Polygon from JSON coordinates") # Создание холста для рисования canvas = tk.Canvas(root, width=500, height=500) canvas.pack() # Нормализация координат для отображения на холсте x_coords = [point[0] for point in coords] y_coords = [point[1] for point in coords] min_x, max_x = min(x_coords), max(x_coords) min_y, max_y = min(y_coords), max(y_coords) scale_x = 480 / (max_x - min_x) if max_x - min_x != 0 else 1 scale_y = 480 / (max_y - min_y) if max_y - min_y != 0 else 1 normalized_coords = [ ((point[0] - min_x) * scale_x + 10, 490 - (point[1] - min_y) * scale_y + 10) for point in coords ] # Добавление первой точки в конец для замыкания многоугольника normalized_coords.append(normalized_coords[0]) # Преобразование координат в плоский список flat_coords = [coord for point in normalized_coords for coord in point] # Рисование многоугольника canvas.create_polygon(flat_coords, outline='black', fill='', width=2) # Рисование дополнительных точек if points: for point in points: normalized_point = ( (point[0] - min_x) * scale_x + 10, 490 - (point[1] - min_y) * scale_y + 10 ) canvas.create_oval( normalized_point[0], normalized_point[1], normalized_point[0], normalized_point[1], fill='red' ) # Запуск основного цикла приложения root.mainloop() # Функция для создания JavaScript файла с данными def create_js_file(points): features = [] for i, (x, y) in enumerate(points): feature = { "type": "Feature", "id": i, "geometry": { "type": "Point", "coordinates": [x, y] } } features.append(feature) js_content = f"var data = `{json.dumps({'type': 'FeatureCollection', 'features': features}, ensure_ascii=False)}`;" with open('data.js', 'w', encoding='utf-8') as js_file: js_file.write(js_content) # Получение количества точек от пользователя num_points = get_number_of_points() # Равномерное распределение точек по многоугольнику points_on_polygon = distribute_points_on_polygon_with_Seidal(coordinates, num_points) create_js_file(points_on_polygon) # Отрисовка многоугольника с равномерно распределенными точками draw_polygon(coordinates, points_on_polygon)