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)

