RavRasp/RavResp.py

168 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)