Загрузить файлы в «/»

This commit is contained in:
Роман Марков 2024-06-30 16:15:00 +00:00
parent 117c81b557
commit 47554eadad
5 changed files with 41245 additions and 0 deletions

167
RavResp.py Normal file
View File

@ -0,0 +1,167 @@
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)

40934
regions.json Normal file

File diff suppressed because it is too large Load Diff

144
tripy.py Normal file
View File

@ -0,0 +1,144 @@
import math
import sys
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
EPSILON = math.sqrt(sys.float_info.epsilon)
def earclip(polygon):
"""
Simple earclipping algorithm for a given polygon p.
polygon is expected to be an array of 2-tuples of the cartesian points of the polygon
For a polygon with n points it will return n-2 triangles.
The triangles are returned as an array of 3-tuples where each item in the tuple is a 2-tuple of the cartesian point.
e.g
>>> polygon = [(0,1), (-1, 0), (0, -1), (1, 0)]
>>> triangles = tripy.earclip(polygon)
>>> triangles
[((1, 0), (0, 1), (-1, 0)), ((1, 0), (-1, 0), (0, -1))]
Implementation Reference:
- https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
"""
ear_vertex = []
triangles = []
polygon = [Point(*point) for point in polygon]
if _is_clockwise(polygon):
polygon.reverse()
point_count = len(polygon)
for i in range(point_count):
prev_index = i - 1
prev_point = polygon[prev_index]
point = polygon[i]
next_index = (i + 1) % point_count
next_point = polygon[next_index]
if _is_ear(prev_point, point, next_point, polygon):
ear_vertex.append(point)
while ear_vertex and point_count >= 3:
ear = ear_vertex.pop(0)
i = polygon.index(ear)
prev_index = i - 1
prev_point = polygon[prev_index]
next_index = (i + 1) % point_count
next_point = polygon[next_index]
polygon.remove(ear)
point_count -= 1
triangles.append(((prev_point.x, prev_point.y), (ear.x, ear.y), (next_point.x, next_point.y)))
if point_count > 3:
prev_prev_point = polygon[prev_index - 1]
next_next_index = (i + 1) % point_count
next_next_point = polygon[next_next_index]
groups = [
(prev_prev_point, prev_point, next_point, polygon),
(prev_point, next_point, next_next_point, polygon),
]
for group in groups:
p = group[1]
if _is_ear(*group):
if p not in ear_vertex:
ear_vertex.append(p)
elif p in ear_vertex:
ear_vertex.remove(p)
return triangles
def _is_clockwise(polygon):
s = 0
polygon_count = len(polygon)
for i in range(polygon_count):
point = polygon[i]
point2 = polygon[(i + 1) % polygon_count]
s += (point2.x - point.x) * (point2.y + point.y)
return s > 0
def _is_convex(prev, point, next):
return _triangle_sum(prev.x, prev.y, point.x, point.y, next.x, next.y) < 0
def _is_ear(p1, p2, p3, polygon):
ear = _contains_no_points(p1, p2, p3, polygon) and \
_is_convex(p1, p2, p3) and \
_triangle_area(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y) > 0
return ear
def _contains_no_points(p1, p2, p3, polygon):
for pn in polygon:
if pn in (p1, p2, p3):
continue
elif _is_point_inside(pn, p1, p2, p3):
return False
return True
def _is_point_inside(p, a, b, c):
area = _triangle_area(a.x, a.y, b.x, b.y, c.x, c.y)
area1 = _triangle_area(p.x, p.y, b.x, b.y, c.x, c.y)
area2 = _triangle_area(p.x, p.y, a.x, a.y, c.x, c.y)
area3 = _triangle_area(p.x, p.y, a.x, a.y, b.x, b.y)
areadiff = abs(area - sum([area1, area2, area3])) < EPSILON
return areadiff
def _triangle_area(x1, y1, x2, y2, x3, y3):
return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0)
def _triangle_sum(x1, y1, x2, y2, x3, y3):
return x1 * (y3 - y2) + x2 * (y1 - y3) + x3 * (y2 - y1)
def calculate_total_area(triangles):
result = []
for triangle in triangles:
sides = []
for i in range(3):
next_index = (i + 1) % 3
pt = triangle[i]
pt2 = triangle[next_index]
# Distance between two points
side = math.sqrt(math.pow(pt2[0] - pt[0], 2) + math.pow(pt2[1] - pt[1], 2))
sides.append(side)
# Heron's numerically stable forumla for area of a triangle:
# https://en.wikipedia.org/wiki/Heron%27s_formula
# However, for line-like triangles of zero area this formula can produce an infinitesimally negative value
# as an input to sqrt() due to the cumulative arithmetic errors inherent to floating point calculations:
# https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf
# For this purpose, abs() is used as a reasonable guard against this condition.
c, b, a = sorted(sides)
area = .25 * math.sqrt(abs((a + (b + c)) * (c - (a - b)) * (c + (a - b)) * (a + (b - c))))
result.append((area, a, b, c))
triangle_area = sum(tri[0] for tri in result)
return triangle_area

BIN
Пример1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
Пример2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB