What a slog
This commit is contained in:
parent
01ff03e7b4
commit
a4cf0cddc5
1 changed files with 126 additions and 4 deletions
130
lib/xmet/geo.py
130
lib/xmet/geo.py
|
@ -2,9 +2,22 @@ import re
|
|||
import math
|
||||
import shapely
|
||||
|
||||
from typing import Self
|
||||
from typing import Self, Union
|
||||
|
||||
def each_intermediate_point(p1: shapely.Point,
|
||||
p2: shapely.Point,
|
||||
intersection: Union[shapely.LineString, shapely.MultiLineString]):
|
||||
typeof = type(intersection)
|
||||
|
||||
if typeof is shapely.LineString:
|
||||
pass
|
||||
elif typeof is shapely.MultiLineString:
|
||||
pass
|
||||
|
||||
class PointSequence(list):
|
||||
linestring: shapely.LineString
|
||||
polygon: shapely.Polygon
|
||||
|
||||
@staticmethod
|
||||
def from_file(path: str) -> Self:
|
||||
ret = PointSequence()
|
||||
|
@ -25,7 +38,8 @@ class PointSequence(list):
|
|||
def __init__(self, points: list=None):
|
||||
super().__init__()
|
||||
|
||||
self.poly = None
|
||||
self.linestring = None
|
||||
self.polygon = None
|
||||
|
||||
if points is not None:
|
||||
for point in points:
|
||||
|
@ -43,10 +57,11 @@ class PointSequence(list):
|
|||
return self[-1] == self[0]
|
||||
|
||||
def close(self):
|
||||
if self[-1] != self[0]:
|
||||
if not self.is_closed():
|
||||
self.append(self[0])
|
||||
|
||||
self.poly = shapely.Polygon(self)
|
||||
self.linestring = shapely.LineString(self)
|
||||
self.polygon = shapely.Polygon(self)
|
||||
|
||||
def nearest_index(self, point: shapely.Point) -> int:
|
||||
indices = list()
|
||||
|
@ -58,6 +73,113 @@ class PointSequence(list):
|
|||
|
||||
return indices[0][0]
|
||||
|
||||
class PolygonBuilder():
|
||||
point_first: shapely.Point
|
||||
point_last: shapely.Point
|
||||
|
||||
def __init__(self, sequence: PointSequence, bounds: PointSequence):
|
||||
self.sequence = sequence
|
||||
self.bounds = bounds
|
||||
self.point_first = None
|
||||
self.point_last = None
|
||||
self.total = 0
|
||||
|
||||
def yield_point(self, point: shapely.Point):
|
||||
"""
|
||||
Yield the single point to the caller, while maintaining state of
|
||||
whether this point is the first or last point seen by the polygon
|
||||
builder.
|
||||
"""
|
||||
if self.point_first is None:
|
||||
self.point_first = point
|
||||
|
||||
self.point_last = point
|
||||
|
||||
yield point
|
||||
|
||||
self.total += 1
|
||||
|
||||
def each_intermediate_point(self, p1: shapely.Point, p2: shapely.Point):
|
||||
count = len(self.bounds)
|
||||
|
||||
i1 = self.bounds.nearest_index(p1) + count
|
||||
i2 = self.bounds.nearest_index(p2) + count
|
||||
|
||||
if i1 > i2:
|
||||
return
|
||||
|
||||
for i in range(i1, i2+1):
|
||||
yield from self.yield_point(self.bounds[i % count])
|
||||
|
||||
def each_point_within(self):
|
||||
last = None
|
||||
|
||||
for point in self.sequence:
|
||||
if last is None:
|
||||
last = point
|
||||
continue
|
||||
|
||||
last_within = self.bounds.polygon.contains(last)
|
||||
point_within = self.bounds.polygon.contains(point)
|
||||
|
||||
#
|
||||
# If the first point in the current line exists within the other
|
||||
# geometry, then yield it.
|
||||
#
|
||||
if last_within:
|
||||
yield from self.yield_point(last)
|
||||
|
||||
#
|
||||
# Check for intersections with the line in the other geometry.
|
||||
#
|
||||
inter = self.bounds.linestring.intersection(shapely.LineString([last, point]))
|
||||
|
||||
if inter.geom_type == 'Point':
|
||||
#
|
||||
# If the intersection is a single point, then yield that
|
||||
# point.
|
||||
#
|
||||
yield from self.yield_point(inter)
|
||||
elif inter.geom_type == 'MultiPoint':
|
||||
#
|
||||
# If the intersection is multiple points, then yield those
|
||||
# points, as well as all between on the other geometry, if and
|
||||
# only if the intersection does not constitute the first and
|
||||
# last point.
|
||||
#
|
||||
last_geom = None
|
||||
|
||||
for geom in inter.geoms:
|
||||
if last_geom is None:
|
||||
last_geom = geom
|
||||
continue
|
||||
|
||||
yield from self.yield_point(last_geom)
|
||||
yield from self.each_intermediate_point(last_geom, geom)
|
||||
yield from self.yield_point(geom)
|
||||
|
||||
last_geom = geom
|
||||
|
||||
#
|
||||
# If the second point in the current line exists within the other
|
||||
# geometry, then yield that.
|
||||
#
|
||||
if point_within:
|
||||
yield from self.yield_point(point)
|
||||
|
||||
#
|
||||
# If only two points have been yielded, then yield the intermediate
|
||||
# between the end and the start (reversed).
|
||||
#
|
||||
if self.total == 2:
|
||||
yield from self.each_intermediate_point(self.point_last,
|
||||
self.point_first)
|
||||
|
||||
last = point
|
||||
|
||||
def process(self) -> shapely.Polygon:
|
||||
pass
|
||||
|
||||
def heading(p1: shapely.Point, p2: shapely.Point) -> float:
|
||||
dx = p2.x - p1.x
|
||||
dy = p2.y - p1.y
|
||||
|
|
Loading…
Add table
Reference in a new issue