aboutsummaryrefslogtreecommitdiff
path: root/diplomacy/utils/equilateral_triangle.py
diff options
context:
space:
mode:
authornotoraptor <stevenbocco@gmail.com>2019-08-14 12:22:22 -0400
committerPhilip Paquette <pcpaquette@gmail.com>2019-08-14 12:40:01 -0400
commit5c3bd9b3802e2001a7e77baf2911386135a03839 (patch)
treee641744650b05cddc85bc60c2d7e2d6fe2d88b47 /diplomacy/utils/equilateral_triangle.py
parent5acb4ff23be4757a49b234f93928f13c436b60c6 (diff)
[Web] Integrated new maps on the web interface
- Fixed bug with incorrect dislodged unit on pure map - [python] Make sure dummy powers are registered only for standard maps. - Hardcoded supply centers into SVG files. - Removed supply centers CSS classes. - Update positions for units and dislodged units on all maps. - Converted SVGs to React. - Removed "sym" classes and hardcode related styles into symbol definitions. - Reordered map list (standard at top, then other ones in alphabetical order) - Displayed + button for all maps and disable it for maps without variants. - Minified generated code when converting SVG files to React. - [web] Added ability to hide/display map abbreviations.
Diffstat (limited to 'diplomacy/utils/equilateral_triangle.py')
-rw-r--r--diplomacy/utils/equilateral_triangle.py173
1 files changed, 173 insertions, 0 deletions
diff --git a/diplomacy/utils/equilateral_triangle.py b/diplomacy/utils/equilateral_triangle.py
new file mode 100644
index 0000000..d31fe79
--- /dev/null
+++ b/diplomacy/utils/equilateral_triangle.py
@@ -0,0 +1,173 @@
+# ==============================================================================
+# Copyright (C) 2019 - Philip Paquette, Steven Bocco
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see <https://www.gnu.org/licenses/>.
+# ==============================================================================
+# pylint: disable=anomalous-backslash-in-string
+""" Helper class to compute intersection of a line (OM) with a side of an equilateral triangle,
+ with O the barycenter of the equilateral triangle and M a point outside the triangle.
+ A
+ / | M
+ / O |
+ C /______| B
+
+ A = top, B = right, C = left
+ O = center of triangle
+ M = point outside of triangle
+"""
+class EquilateralTriangle:
+ """ Helper class that represent an equilateral triangle.
+ Used to compute intersection of a line with a side of convoy symbol, which is an equilateral triangle.
+ """
+ __slots__ = ('x_a', 'y_a', 'x_b', 'y_b', 'x_c', 'y_c', 'x_o', 'y_o', 'height',
+ 'line_ab_a', 'line_ab_b', 'line_ac_a', 'line_ac_b')
+
+ def __init__(self, x_top, y_top, x_right, y_right, x_left, y_left):
+ """ Constructor """
+ assert y_left == y_right > y_top
+ assert x_left < x_top < x_right
+ self.x_a = x_top
+ self.y_a = y_top
+ self.x_b = x_right
+ self.y_b = y_right
+ self.x_c = x_left
+ self.y_c = y_left
+ self.height = self.y_b - self.y_a
+ self.x_o = self.x_a
+ self.y_o = self.y_a + 2 * self.height / 3
+ self.line_ab_a = (self.y_b - self.y_a) / (self.x_b - self.x_a)
+ self.line_ab_b = self.y_b - self.x_b * self.line_ab_a
+ self.line_ac_a = (self.y_c - self.y_a) / (self.x_c - self.x_a)
+ self.line_ac_b = self.y_c - self.x_c * self.line_ac_a
+
+ def __line_om(self, x_m, y_m):
+ """ Returns the slope and the intersect of the line between O and M
+ :return: a, b - respectively the slope and the intercept of the line OM
+ """
+ # pylint:disable=invalid-name
+ a = (y_m - self.y_o) / (x_m - self.x_o)
+ b = y_m - a * x_m
+ return a, b
+
+ def _intersection_with_ab(self, x_m, y_m):
+ """ Return coordinates of intersection of line (OM) with line (AB).
+ :param x_m: x coordinate of M
+ :param y_m: y coordinate of M
+ :return: coordinates (x, y) of intersection, or (None, None) if either
+ (OM) and (AB) don't intersect, or intersection point is not in segment AB.
+ """
+ # pylint:disable=invalid-name
+ a, b = self.line_ab_a, self.line_ab_b
+ if x_m == self.x_o:
+ # (OM) is a vertical line
+ x = x_m
+ else:
+ u, v = self.__line_om(x_m, y_m)
+ if a == u:
+ # (OM) and (AB) are parallel. No intersection.
+ return None, None
+ x = (v - b) / (a - u)
+ y = a * x + b
+ if self.x_a <= x <= self.x_b and self.y_a <= y <= self.y_b:
+ return x, y
+ return None, None
+
+ def _intersection_with_ac(self, x_m, y_m):
+ """ Return coordinates of intersection of line (OM) with line (AC).
+ :param x_m: x coordinate of M
+ :param y_m: y coordinate of M
+ :return: coordinates (x, y) of intersection, or (None, None) if either
+ (OM) and (AC) don't intersect, or intersection point is not in segment AC.
+ """
+ # pylint:disable=invalid-name
+ a, b = self.line_ac_a, self.line_ac_b
+ if x_m == self.x_o:
+ x = x_m
+ else:
+ u, v = self.__line_om(x_m, y_m)
+ if a == u:
+ return None, None
+ x = (v - b) / (a - u)
+ y = a * x + b
+ if self.x_c <= x <= self.x_a and self.y_a <= y <= self.y_c:
+ return x, y
+ return None, None
+
+ def _intersection_with_bc(self, x_m, y_m):
+ """ Return coordinates of intersection of line (OM) with line (BC).
+ NB: (BC) is an horizontal line.
+ :param x_m: x coordinate of M
+ :param y_m: y coordinate of M
+ :return: coordinates (x, y) of intersection, or (None, None) if either
+ (OM) and (BC) don't intersect, or intersection point is not in segment BC.
+ """
+ # pylint:disable=invalid-name
+ y = self.y_c
+ if x_m == self.x_o:
+ x = x_m
+ else:
+ a, b = self.__line_om(x_m, y_m)
+ if a == 0:
+ return None, None
+ x = (y - b) / a
+ if self.x_c <= x <= self.x_a:
+ return x, y
+ return None, None
+
+ def intersection(self, x_m, y_m):
+ """ Return coordinates of the intersection of (OM) with equilateral triangle,
+ with M the point with coordinates (x_m, y_m). Only the intersection with
+ the side of triangle near M is considered.
+ :param x_m: x coordinate of M
+ :param y_m: y coordinate of M
+ :return: a couple (x, y) of floating values.
+ """
+ # pylint:disable=invalid-name
+ if self.x_o == x_m and self.y_o == y_m:
+ return x_m, y_m
+
+ if self.x_o == x_m:
+ if y_m < self.y_o:
+ return x_m, self.y_a
+ # Otherwise, vertical line intersects BC
+ return x_m, self.y_c
+
+ if self.y_o == y_m:
+ if x_m < self.x_o:
+ # horizontal line intersects AC
+ a, b = self.line_ac_a, self.line_ac_b
+ else:
+ # horizontal line intersects AB
+ a, b = self.line_ab_a, self.line_ab_b
+ x = (y_m - b) / a
+ return x, y_m
+
+ # Otherwise, get nearest point in intersections with AB, AC, BC
+ p1_x, p1_y = self._intersection_with_ab(x_m, y_m)
+ p2_x, p2_y = self._intersection_with_ac(x_m, y_m)
+ p3_x, p3_y = self._intersection_with_bc(x_m, y_m)
+ distances = []
+ if p1_x is not None:
+ distance_1 = ((p1_x - x_m) ** 2 + (p1_y - y_m) ** 2) ** 0.5
+ distances.append((distance_1, p1_x, p1_y))
+ if p2_x is not None:
+ distance_2 = ((p2_x - x_m) ** 2 + (p2_y - y_m) ** 2) ** 0.5
+ distances.append((distance_2, p2_x, p2_y))
+ if p3_x is not None:
+ distance_3 = ((p3_x - x_m) ** 2 + (p3_y - y_m) ** 2) ** 0.5
+ distances.append((distance_3, p3_x, p3_y))
+
+ assert distances
+ distances.sort()
+ return distances[0][1:]