mirror of
https://github.com/enzet/map-machine.git
synced 2025-05-28 16:36:27 +02:00
Issue #45: add vector arithmetic.
This commit is contained in:
parent
62f10ab647
commit
edf75ff53c
3 changed files with 86 additions and 36 deletions
|
@ -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
|
||||||
|
|
|
@ -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
79
roentgen/vector.py
Normal 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"
|
Loading…
Add table
Add a link
Reference in a new issue