Skip to content

Commit

Permalink
Spliting Utils in 3
Browse files Browse the repository at this point in the history
  • Loading branch information
axel7083 committed Dec 23, 2020
1 parent 971685d commit f042807
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 276 deletions.
18 changes: 9 additions & 9 deletions src/scripts/CanvasPolygon.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from math import radians, cos, sin
from src.scripts import utils
from src.scripts import utils, CanvasUtils


class CanvasPolygon:
Expand Down Expand Up @@ -58,28 +58,28 @@ def movement(self, event):
end_x = self.canvas.canvasx(event.x) # Translate mouse x screen coordinate to canvas coordinate
end_y = self.canvas.canvasy(event.y) # Translate mouse y screen coordinate to canvas coordinate

deltax = end_x - self.init_x # Find the difference
deltay = end_y - self.init_y # Find the difference
delta_x = end_x - self.init_x # Find the difference
delta_y = end_y - self.init_y # Find the difference

self.new_position(deltax, deltay)
self.new_position(delta_x, delta_y)

self.init_x = end_x # Update previous current with new location
self.init_y = end_y

self.canvas.move(self.id_, deltax, deltay) # Move object
self.canvas.move(self.id_, delta_x, delta_y) # Move object

def stop_movement(self, event):
""" Updates move attribute and sticks the moving polygon to nearby polygon """

nearby = utils.is_nearby(self.id_, self.canvas, self.magnet_slider)
if nearby:
self.delete()
CanvasPolygon(utils.replace(utils.tuple_to_list(self.coords), utils.tuple_to_list(nearby)),
CanvasPolygon(CanvasUtils.replace(utils.tuple_to_list(self.coords), utils.tuple_to_list(nearby)),
self.color, self.tag, self.canvas, self.magnet_slider)

self.move = False

def new_position(self, deltax, deltay):
def new_position(self, delta_x, delta_y):
""" Updates the coords of a polygon given the coordinates of the translation """

coord = utils.tuple_to_list(self.coords) # Retrieve object points coordinates
Expand All @@ -90,9 +90,9 @@ def new_position(self, deltax, deltay):

# check if index of coordinates in range of i and len(old_coord) in old_coord is pair (x coord)
if (coord.index(coordinates, i, len(coord)) % 2) == 0:
coords.append(coordinates + deltax)
coords.append(coordinates + delta_x)
else: # index's impair => y-coord
coords.append(coordinates + deltay)
coords.append(coordinates + delta_y)
i += 1

self.set_coords(tuple(coords))
Expand Down
92 changes: 92 additions & 0 deletions src/scripts/CanvasUtils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import math
import numpy
from src.scripts import PolygonUtils


# Constants
MAX_MED_TRIANGLE = 2
MAX_SM_TRIANGLE = 4
MAX_SQUARE = 3
MAX_BIG_TRIANGLE = 2
MAX_PARALLELOGRAM = 4
CANVAS_SIDE = 700


def enable_validate_button(btn_validate, enable):
""" Disables validate button to let AI work """

if enable:
btn_validate['state'] = "normal"
else:
btn_validate['state'] = "disabled"


def reset_canvas(drawing_place, labels):
""" Resets canvas and labels when user clicks on Reset Button """

figures = drawing_place.find_all()
for fig in figures:
drawing_place.delete(fig)

for label in labels:
label["text"] = "0"


def update_count_label(label, action, drawing_place=None, labels=None):
""" Updates the count of a label """

str_count = label["text"]
count = int(str_count)

if action == "+":
label["text"] = str(count + 1)
elif action == "-":
label["text"] = str(count - 1)
elif action == "reset":
reset_canvas(drawing_place, labels)


def replace(original, change):
""" Calculates new polygon points after a matching point has been found in isNearby() """

if original and change:
diff = [change[0][0] - change[1][0], change[0][1] - change[1][1]]
new = []
placed = 0
for i, p in enumerate(original):
if p == change[0][0]:
if original[i + 1]: # prevents a list index out of range error from happening
if original[i + 1] == change[0][1]:
new.append(change[1][0])
new.append(change[1][1])
placed = i + 2
else:
new.append(p - diff[0]) if i % 2 == 0 else new.append(p - diff[1])
else:
new.append(p - diff[0]) if i % 2 == 0 else new.append(p - diff[1])

new.pop(placed)
return new


def get_settings_by_type(_type, x_pos, y_pos):
unit = 100
side = round(math.sqrt(2) * 100)

if _type == "bt":
return MAX_BIG_TRIANGLE, numpy.array(
PolygonUtils.get_triangle_points(x_pos, y_pos, 0, unit * 2)).flatten().tolist()
elif _type == "p":
return MAX_PARALLELOGRAM, numpy.array(
PolygonUtils.get_parallelogram_points(x_pos, y_pos, 0, side / 2)).flatten().tolist()
elif _type == "mt":
return MAX_MED_TRIANGLE, numpy.array(PolygonUtils.get_triangle_points(x_pos, y_pos, 0, side)).flatten().tolist()
elif _type == "s":
return MAX_SQUARE, numpy.array(PolygonUtils.get_square_points(x_pos, y_pos, 0, unit)).flatten().tolist()
elif _type == "st":
return MAX_SM_TRIANGLE, numpy.array(PolygonUtils.get_triangle_points(x_pos, y_pos, 0, unit)).flatten().tolist()


def label_value(label):
""" Converts label text to int """
return int(label["text"])
137 changes: 137 additions & 0 deletions src/scripts/PolygonUtils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import math
from shapely.geometry import Polygon
from shapely.ops import cascaded_union
from random import uniform
import matplotlib.pyplot as plt
import numpy
import json


def center_index(shape, index):
""" Center a polygon to one of its position """

if index == 0:
return shape

x_coords, y_coords = shape.exterior.xy
move = [x_coords[0] - x_coords[index], y_coords[0] - y_coords[index]]
coordinates = []

for i in range(len(x_coords)):
coordinates.append([x_coords[i] + move[0], y_coords[i] + move[1]])

return Polygon(coordinates)


def rotate_by(x_pivot, y_pivot, x_pos, y_pos, angle):
""" Rotate a point (x,y) around (cx, cy) """

angle = (math.pi * angle) / 4
return [math.cos(angle) * (x_pos - x_pivot) - math.sin(angle) * (y_pos - y_pivot) + x_pivot,
math.sin(angle) * (x_pos - x_pivot) + math.cos(angle) * (y_pos - y_pivot) + y_pivot]


def get_triangle_points(x_pos, y_pos, rotation, size):
""" From one origin point get 3 coordinates of triangles """

return [[x_pos, y_pos], rotate_by(x_pos, y_pos, x_pos + size, y_pos, rotation), rotate_by(x_pos, y_pos, x_pos, y_pos + size, rotation)]


def get_square_points(x_pos, y_pos, rotation, size):
""" From one origin point get the 4 coordinates of the square """

rotation %= 2
return [[x_pos, y_pos],
rotate_by(x_pos, y_pos, x_pos + size, y_pos, rotation),
rotate_by(x_pos, y_pos, x_pos + size, y_pos + size, rotation),
rotate_by(x_pos, y_pos, x_pos, y_pos + size, rotation)]


def get_parallelogram_points(x_pos, y_pos, rotation, size):
""" From one origin point the 4 coordinates of the parallelogram """

if rotation <= 3:
return [[x_pos, y_pos],
rotate_by(x_pos, y_pos, x_pos + size, y_pos + size, rotation),
rotate_by(x_pos, y_pos, x_pos + size, y_pos + 3 * size, rotation),
rotate_by(x_pos, y_pos, x_pos, y_pos + 2 * size, rotation)]
# flip parallelogram
else:
return [[x_pos, y_pos],
rotate_by(x_pos, y_pos, x_pos - size, y_pos + size, rotation),
rotate_by(x_pos, y_pos, x_pos - size, y_pos + 3 * size, rotation),
rotate_by(x_pos, y_pos, x_pos, y_pos + 2 * size, rotation)]


def fit_function(types, state, ref):
""" Function which evaluate how good the shapes overlap the reference """

polygons = Polygon()
for i, shape in enumerate(state):
polygons = cascaded_union([
polygons,
get_shape_polygon_by_index(types, i, shape[0], shape[1], shape[2], shape[3])
])

return ref.difference(polygons)


def get_shape_polygon_by_index(shapes, index, x_pos, y_pos, rotation, point_index, offset=0.005):
"""" Get polygon depending on the """
unit = 1
side = math.sqrt(unit * 2)

if shapes[index] == "bt":
return center_index(
Polygon(get_triangle_points(x_pos, y_pos, rotation, unit * 2 - offset)),
point_index
)
elif shapes[index] == "p":
return center_index(
Polygon(get_parallelogram_points(x_pos, y_pos, rotation, side / 2 - offset)),
point_index
)
elif shapes[index] == "mt":
return center_index(
Polygon(get_triangle_points(x_pos, y_pos, rotation, side - offset)),
point_index
)
elif shapes[index] == "s":
return center_index(
Polygon(get_square_points(x_pos, y_pos, rotation, unit - offset)),
point_index
)
elif shapes[index] == "st":
return center_index(
Polygon(get_triangle_points(x_pos, y_pos, rotation, unit - offset)),
point_index
)


def get_corner_count_by_index(shapes, index):
""" Get the number of corner per index """
if shapes[index] == "bt":
return 3
elif shapes[index] == "p":
return 3
elif shapes[index] == "mt":
return 3
elif shapes[index] == "s":
return 4
elif shapes[index] == "st":
return 3


def get_rot_by_index(shapes, index):
""" Number of rotation available per shape """
if shapes[index] == "s":
return 2
elif shapes[index] == "p":
return 4
else:
return 8


def merge(polygons):
""" Merge a list of polygons into one """
return cascaded_union(polygons)
8 changes: 4 additions & 4 deletions src/scripts/TangramSolver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import copy
from src.scripts import utils
from src.scripts import utils, PolygonUtils
from shapely.geometry import Polygon, LineString


Expand Down Expand Up @@ -36,13 +36,13 @@ def corner_explore(self, ref, shape_index, state):
x = sub_ref.exterior.xy[0][i]
y = sub_ref.exterior.xy[1][i]

for r in range(utils.get_rot_by_index(self.shapes, shape_index)):
for r in range(PolygonUtils.get_rot_by_index(self.shapes, shape_index)):

for point_index in range(utils.get_corner_count_by_index(self.shapes, shape_index)):
for point_index in range(PolygonUtils.get_corner_count_by_index(self.shapes, shape_index)):

new_state = copy.deepcopy(state)
new_state.append([x, y, r, point_index])
poly = utils.get_shape_polygon_by_index(self.shapes, shape_index, x, y, r, point_index)
poly = PolygonUtils.get_shape_polygon_by_index(self.shapes, shape_index, x, y, r, point_index)

# new_ref = fit_function(state, ref)
diff = ref.difference(poly)
Expand Down
Loading

0 comments on commit f042807

Please sign in to comment.