What a slog

This commit is contained in:
XANTRONIX 2025-03-23 01:06:16 -04:00
parent 01ff03e7b4
commit a4cf0cddc5

View file

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