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) 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: def pseudo_mercator(coordinates: np.array) -> np.array:
""" """
Use spherical pseudo-Mercator projection to convert geo coordinates into Use spherical pseudo-Mercator projection to convert geo coordinates into

View file

@ -2,14 +2,15 @@
Road shape drawing. Road shape drawing.
""" """
from dataclasses import dataclass from dataclasses import dataclass
from typing import List, Any, Dict from typing import List
import numpy as np import numpy as np
import svgwrite import svgwrite
from shapely.geometry import LineString, Point from shapely.geometry import LineString, Point
from roentgen.constructor import Road 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 from roentgen.osm_reader import OSMNode
@ -135,16 +136,16 @@ class RoadPart:
drawing.add(line) drawing.add(line)
if self.right_connection is not None: 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) drawing.add(circle)
if self.left_connection is not None: 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) drawing.add(circle)
if self.right_projection is not None: 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) drawing.add(circle)
if self.left_projection is not None: 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) drawing.add(circle)
self.draw_entrance(drawing, True) 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"