utils
func round_xy
Call Type: normal
View Source
def round_xy(x: float, y: float, decimals: int = 3) -> Tuple[float, float]:
k = 10 ** decimals
return (round(x * k) / k, round(y * k) / k)
func line_polygon_intersection_points
Call Type: normal
View Source
def line_polygon_intersection_points(line: LineString, polygon: Polygon) -> List[Tuple[float, float]]:
inter = line.intersection(polygon.boundary)
pts: List[Tuple[float, float]] = []
def add_pt(p: Point):
pts.append((p.x, p.y))
if inter.is_empty:
return []
if isinstance(inter, Point):
add_pt(inter)
else:
for geom in getattr(inter, "geoms", [inter]):
if isinstance(geom, Point):
add_pt(geom)
elif isinstance(geom, LineString):
c = list(geom.coords)
add_pt(Point(c[0]))
add_pt(Point(c[-1]))
# Dedup (rounded) & sort along line parameter
seen = set()
out: List[Tuple[float, float]] = []
for x, y in pts:
rx, ry = round_xy(x, y, 6)
if (rx, ry) not in seen:
seen.add((rx, ry))
out.append((x, y))
p0 = line.coords[0]
p1 = line.coords[-1]
dx = p1[0] - p0[0]
dy = p1[1] - p0[1]
denom = dx * dx + dy * dy or 1.0
def tparam(pt: Tuple[float, float]) -> float:
x, y = pt
return ((x - p0[0]) * dx + (y - p0[1]) * dy) / denom
out.sort(key=tparam)
return out
func rotated_infinite_transects
Call Type: normal
View Source
def rotated_infinite_transects(polygon: Polygon, spacing: float, angle_deg: float) -> List[LineString]:
minx, miny, maxx, maxy = polygon.envelope.bounds
width = maxx - minx
height = maxy - miny
max_len = max(width, height) + 100.0
cx, cy = (minx + maxx) / 2.0, (miny + maxy) / 2.0
lines: List[LineString] = []
x = minx - max_len
end_x = maxx + max_len
verticals: List[LineString] = []
while x <= end_x:
verticals.append(LineString([(x, miny - max_len), (x, maxy + max_len)]))
x += spacing
return [rotate(v, angle_deg, origin=(cx, cy), use_radians=False) for v in verticals]
func parse_kml_file
Call Type: normal
Parse KML Placemarks with <coordinates> entries "lon,lat[,alt]".
Returns {placemark_name: GeoPoints([(lon,lat), ...])}
View Source
def parse_kml_file(kmlstr: str) -> Dict[str, GeoPoints]:
"""
Parse KML Placemarks with `<coordinates>` entries `"lon,lat[,alt]"`.
Returns `{placemark_name: GeoPoints([(lon,lat), ...])}`
"""
doc = minidom.parseString(kmlstr)
placemarks = doc.getElementsByTagName("Placemark")
result: Dict[str, GeoPoints] = {}
for pm in placemarks:
name_nodes = pm.getElementsByTagName("name")
coords_nodes = pm.getElementsByTagName("coordinates")
if not name_nodes or not coords_nodes:
continue
name = name_nodes[0].firstChild.nodeValue.strip()
coords_text = coords_nodes[0].firstChild.nodeValue.strip()
gp = parse_kml_coordinates_to_geopoints(coords_text)
result[name] = gp
return result
func parse_kml_coordinates_to_geopoints
Call Type: normal
View Source
def parse_kml_coordinates_to_geopoints(kml_coordinates: str) -> GeoPoints:
pts: List[Tuple[float, float]] = []
for token in kml_coordinates.strip().split():
parts = token.split(",")
if len(parts) >= 2:
lon = float(parts[0])
lat = float(parts[1])
pts.append((lon, lat))
return GeoPoints(pts)