Issue #45: add vector arithmetic.

This commit is contained in:
Sergey Vartanov 2021-06-01 03:32:29 +03:00
parent 62f10ab647
commit edf75ff53c
3 changed files with 86 additions and 36 deletions

View file

@ -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

View file

@ -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)

79
roentgen/vector.py Normal file
View file

@ -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"