diff --git a/roentgen/flinger.py b/roentgen/flinger.py index 39b5b90..740cc75 100644 --- a/roentgen/flinger.py +++ b/roentgen/flinger.py @@ -13,36 +13,6 @@ __email__ = "me@enzet.ru" EQUATOR_LENGTH: float = 40_075_017 # (in meters) -def angle(vector: np.array): - """ - For the given vector compute an angle between it and (1, 0) vector. The - result is in [0, 2π]. - """ - if vector[0] < 0: - return np.arctan(vector[1] / vector[0]) + np.pi - if vector[1] < 0: - return np.arctan(vector[1] / vector[0]) + 2 * np.pi - else: - return np.arctan(vector[1] / vector[0]) - - -def turn_by_angle(vector: np.array, angle: float): - """ - Turn vector by an angle. - """ - return np.array(( - vector[0] * np.cos(angle) - vector[1] * np.sin(angle), - vector[0] * np.sin(angle) + vector[1] * np.cos(angle), - )) - - -def norm(vector: np.array) -> np.array: - """ - Compute vector with the same direction and length 1. - """ - return vector / np.linalg.norm(vector) - - def pseudo_mercator(coordinates: np.array) -> np.array: """ Use spherical pseudo-Mercator projection to convert geo coordinates into diff --git a/roentgen/road.py b/roentgen/road.py index 55effcd..1573a58 100644 --- a/roentgen/road.py +++ b/roentgen/road.py @@ -2,14 +2,15 @@ Road shape drawing. """ from dataclasses import dataclass -from typing import List, Any, Dict +from typing import List import numpy as np import svgwrite from shapely.geometry import LineString, Point from roentgen.constructor import Road -from roentgen.flinger import Flinger, angle, turn_by_angle, norm +from roentgen.flinger import Flinger +from roentgen.vector import angle, turn_by_angle, norm from roentgen.osm_reader import OSMNode @@ -135,16 +136,16 @@ class RoadPart: drawing.add(line) if self.right_connection is not None: - circle = drawing.circle(self.right_connection, 2) + circle = drawing.circle(self.right_connection, 1.2) drawing.add(circle) if self.left_connection is not None: - circle = drawing.circle(self.left_connection, 2) + circle = drawing.circle(self.left_connection, 1.2) drawing.add(circle) if self.right_projection is not None: - circle = drawing.circle(self.right_projection, 2, fill="#FF0000") + circle = drawing.circle(self.right_projection, 1.2, fill="#FF0000") drawing.add(circle) if self.left_projection is not None: - circle = drawing.circle(self.left_projection, 2, fill="#0000FF") + circle = drawing.circle(self.left_projection, 1.2, fill="#0000FF") drawing.add(circle) self.draw_entrance(drawing, True) diff --git a/roentgen/vector.py b/roentgen/vector.py new file mode 100644 index 0000000..fd48815 --- /dev/null +++ b/roentgen/vector.py @@ -0,0 +1,79 @@ +""" +Vector utility. +""" +import numpy as np + + +def angle(vector: np.array): + """ + For the given vector compute an angle between it and (1, 0) vector. The + result is in [0, 2π]. + """ + if vector[0] < 0: + return np.arctan(vector[1] / vector[0]) + np.pi + if vector[1] < 0: + return np.arctan(vector[1] / vector[0]) + 2 * np.pi + else: + return np.arctan(vector[1] / vector[0]) + + +def turn_by_angle(vector: np.array, angle: float): + """ + Turn vector by an angle. + """ + return np.array(( + vector[0] * np.cos(angle) - vector[1] * np.sin(angle), + vector[0] * np.sin(angle) + vector[1] * np.cos(angle), + )) + + +def norm(vector: np.array) -> np.array: + """ + Compute vector with the same direction and length 1. + """ + return vector / np.linalg.norm(vector) + + +class Line: + """ + Infinity line: Ax + By + C = 0. + """ + + def __init__(self, start: np.array, end: np.array): + # if start.near(end): + # util.error("cannot create line by one point") + self.a: float = start[1] - end[1] + self.b: float = end[0] - start[0] + self.c: float = start.x * end.y - end.x * start.y + + def parallel_shift(self, shift: np.array): + """ + Shift current vector according with shift. + + :param shift: shift vector + """ + self.c -= self.a * shift.x + self.b * shift.y + + def is_parallel(self, other: "Line") -> bool: + """ + If lines are parallel or equal. + """ + return np.allclose(other.a * self.b - self.a * other.b, 0) + + def get_intersection_point(self, other: "Line") -> np.array: + """ + Get point of intersection current line with other. + """ + if other.a * self.b - self.a * other.b == 0: + return np.array((0, 0)) + + x: float = -(self.b * other.c - other.b * self.c) / ( + other.a * self.b - self.a * other.b + ) + y: float = -(self.a * other.c - other.a * self.c) / ( + other.b * self.a - self.b * other.a + ) + return np.array((x, y)) + + def __repr__(self) -> str: + return f"{self.a} * x + {self.b} * y + {self.c} == 0"