Coverage for pygeodesy/clipy.py : 96%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*-
an arbitrary (convex) region.
Box clip functions L{clipCS4} I{Cohen-Sutherland} and L{clipLB6} I{Liang-Barsky}, region clip functions L{clipFHP4} I{Foster-Hormann-Popa}, L{clipGH4} I{Greiner-Hormann} and L{clipSH} and L{clipSH3} I{Sutherland-Hodgeman}. . ''' # make sure int/int division yields float quotient, see .basics
# from pygeodesy.basics import len2 # from .fmath _height_, _i_, _invalid_, _j_, _lat_, _lon_, \ _near_, _not_, _points_, _start_, _too_ # from pygeodesy.props import Property_RO # from .fsums
# from math import fabs # from .fmath
'''(INTERNAL) Get the clip box edges.
@see: Class C{_Box} in .ellipsoidalBaseDI.py. ''' raise ValueError(_invalid_) except (AttributeError, TypeError, ValueError) as x: raise ClipError(name, 2, (lowerleft, upperight), cause=x)
'''(INTERNAL) Clip region or box. ''' LatLon_(yt, xr), LatLon_(yb, xr))
'''(INTERNAL) Check for near-equal points. '''
'''(INTERNAL) Check for not near-equal points. ''' fabs(p1.lon - p2.lon) > eps
'''(INTERNAL) Get the points to clip as a list. ''' # only remove the final, closing point n -= 1 pts = pts[:n] raise PointsError(points=n, txt=_too_(_few_)) else:
'''(INTERNAL) Cohen-Sutherland line clipping. ''' # single-bit clip codes
self._xr, self._yt = _box4(lowerleft, upperight, name)
# def clip4(self, p, c): # clip point p for code c # if c & _CS._YB: # return self.lon4(p, self._yb) # elif c & _CS._YT: # return self.lon4(p, self._yt) # elif c & _CS._XL: # return self.lat4(p, self._xl) # elif c & _CS._XR: # return self.lat4(p, self._xr) # # should never get here # raise _AssertionError(self._DOT_(self.clip4.__name__))
else:
return _CS._YT, self.lon4, self._yt, p else: # inside
return _CS._XL, self.lat4, self._xl, p else: # inside
def nop4(self, b, p): # PYCHOK no cover if p: # should never get here raise _AssertionError(self._DOT_(self.nop4.__name__)) return _CS._IN, self.nop4, b, p
'''4-Tuple C{(start, end, i, j)} for each edge of a I{clipped} path with the C{start} and C{end} points (C{LatLon}) of the portion of the edge inside or on the clip box and the indices C{i} and C{j} (C{int}) of the edge start and end points in the original path. '''
'''Clip a path against a rectangular clip box using the U{Cohen-Sutherland <https://WikiPedia.org/wiki/Cohen-Sutherland_algorithm>} algorithm.
@arg points: The points (C{LatLon}[]). @arg lowerleft: Bottom-left corner of the clip box (C{LatLon}). @arg upperight: Top-right corner of the clip box (C{LatLon}). @kwarg closed: Optionally, close the path (C{bool}). @kwarg inull: Optionally, retain null edges if inside (C{bool}).
@return: Yield a L{ClipCS4Tuple}C{(start, end, i, j)} for each edge of the I{clipped} path.
@raise ClipError: The B{C{lowerleft}} and B{C{upperight}} corners specify an invalid clip box.
@raise PointsError: Insufficient number of B{C{points}}. '''
pass else: # inside else: # PYCHOK no cover raise _AssertionError(_DOT_(cs.name, 'for_else'))
elif inull and not c2: yield T4(p2, p2, i, j)
'''4-Tuple C{(lat, lon, height, clipid)} for each point of the L{clipFHP4} result with the C{lat}-, C{lon}gitude, C{height} and C{clipid} of the polygon or clip.
@note: The C{height} is a L{HeightX} instance if this point is an intersection, otherwise a L{Height} or C{int(0)}. '''
'''Is this an intersection? ''' return isinstance(self.height, HeightX)
'''Is this an original (polygon) point? ''' return not self.isintersection
'''Clip one or more polygons against a clip region or box using U{Forster-Hormann-Popa <https://www.ScienceDirect.com/science/article/pii/S259014861930007X>}'s C++ implementation transcoded to pure Python.
@arg points: The polygon points and clips (C{LatLon}[]). @arg corners: Three or more points defining the clip regions (C{LatLon}[]) or two points to specify a single, rectangular clip box. @kwarg closed: If C{True}, close each result clip (C{bool}). @kwarg inull: If C{True}, retain null edges in result clips (C{bool}). @kwarg raiser: If C{True}, throw L{ClipError} exceptions (C{bool}). @kwarg esp: Tolerance for eliminating null edges (C{degrees}, same units as the B{C{points}} and B{C{corners}} coordinates).
@return: Yield a L{ClipFHP4Tuple}C{(lat, lon, height, clipid)} for each clipped point. The result may consist of several clips, each a (closed) polygon with a unique C{clipid}.
@raise ClipError: Insufficient B{C{points}} or B{C{corners}} or an open clip.
@see: U{Forster, Hormann and Popa<https://www.ScienceDirect.com/science/ article/pii/S259014861930007X>}, class L{BooleanFHP} and function L{clipGH4}. ''' name=clipFHP4.__name__, eps=eps) inull=inull, raiser=P._raiser, eps=eps)
'''4-Tuple C{(lat, lon, height, clipid)} for each point of the L{clipGH4} result with the C{lat}-, C{lon}gitude, C{height} and C{clipid} of the polygon or clip.
@note: The C{height} is a L{HeightX} instance if this is an intersection, otherwise a L{Height} or C{int(0)}. '''
'''Clip one or more polygons against a clip region or box using the U{Greiner-Hormann <http://www.Inf.USI.CH/hormann/papers/Greiner.1998.ECO.pdf>} algorithm, U{Correia <https://GitHub.com/helderco/univ-polyclip>}'s implementation modified and extended.
@arg points: The polygon points and clips (C{LatLon}[]). @arg corners: Three or more points defining the clip regions (C{LatLon}[]) or two points to specify a single, rectangular clip box. @kwarg closed: If C{True}, close each result clip (C{bool}). @kwarg inull: If C{True}, retain null edges in result clips (C{bool}). @kwarg raiser: If C{True}, throw L{ClipError} exceptions (C{bool}). @kwarg xtend: If C{True}, extend edges of I{degenerate cases}, an attempt to handle the latter (C{bool}). @kwarg esp: Tolerance for eliminating null edges (C{degrees}, same units as the B{C{points}} and B{C{corners}} coordinates).
@return: Yield a L{ClipGH4Tuple}C{(lat, lon, height, clipid)} for each clipped point. The result may consist of several clips, each a (closed) polygon with a unique C{clipid}.
@raise ClipError: Insufficient B{C{points}} or B{C{corners}}, an open clip, a I{degenerate case} or I{unhandled} intersection.
@note: To handle I{degenerate cases} like C{point-edge} and C{point-point} intersections, use function L{clipFHP4}.
@see: U{Greiner-Hormann<https://WikiPedia.org/wiki/Greiner–Hormann_clipping_algorithm>}, U{Ionel Daniel Stroe<https://Davis.WPI.edu/~matt/courses/clipping/>}, I{Correia}'s U{univ-polyclip<https://GitHub.com/helderco/univ-polyclip>}, class L{BooleanGH} and function L{clipFHP4}. ''' name=clipGH4.__name__, kind=_points_) raiser=S._raiser, xtend=S._xtend, eps=eps)
# Liang-Barsky trim t[0] or t[1] return False # too far below elif q < 0: # vertical or horizontal return False # ... outside
'''6-Tuple C{(start, end, i, fi, fj, j)} for each edge of the I{clipped} path with the C{start} and C{end} points (C{LatLon}) of the portion of the edge inside or on the clip box, indices C{i} and C{j} (both C{int}) of the original path edge start and end points and I{fractional} indices C{fi} and C{fj} (both L{FIx}) of the C{start} and C{end} points along the edge of the original path.
@see: Class L{FIx} and function L{pygeodesy.fractional}. '''
'''Clip a path against a rectangular clip box using the U{Liang-Barsky <https://www.CSE.UNT.edu/~renka/4230/LineClipping.pdf>} algorithm.
@arg points: The points (C{LatLon}[]). @arg lowerleft: Bottom-left corner of the clip box (C{LatLon}). @arg upperight: Top-right corner of the clip box (C{LatLon}). @kwarg closed: Optionally, close the path (C{bool}). @kwarg inull: Optionally, retain null edges if inside (C{bool}).
@return: Yield a L{ClipLB6Tuple}C{(start, end, i, fi, fj, j)} for each edge of the I{clipped} path.
@raise ClipError: The B{C{lowerleft}} and B{C{upperight}} corners specify an invalid clip box.
@raise PointsError: Insufficient number of B{C{points}}.
@see: U{Liang-Barsky Line Clipping<https://www.CS.Helsinki.FI/group/goa/ viewing/leikkaus/intro.html>}, U{Liang-Barsky line clipping algorithm <https://www.Skytopia.com/project/articles/compsci/clipping.html>} and U{Liang-Barsky algorithm<https://WikiPedia.org/wiki/Liang-Barsky_algorithm>}. ''' xr, yt = _box4(lowerleft, upperight, clipLB6.__name__)
# non-null edge pts[i]...pts[j] _LB( dx, xr - x1, t) and \ _LB(-dy, -yb + y1, t) and \ _LB( dy, yt - y1, t): # clip edge pts[i]...pts[j] # at fractions t[0] to t[1] x1 + f * dx) else:
x1 + t * dx) else:
fi = FIx(fi, fin=fin) yield T6(p1, p1, i, fi, fi, j) # else: # outside # pass FIx(j, fin=fin), j)
'''(INTERNAL) Sutherland-Hodgman polyon clipping. '''
raise ValueError(_not_(_convex_)) raise ValueError(NN(_near_, 'zero area')) except (PointsError, TypeError, ValueError) as x: raise ClipError(name, n, cs, cause=x)
# clip points, closed always # _ap(p1) _in(p1, p2, e)) # ... outside # elif d1 > 0: # both outside # pass
# replace points, in-place else: raise ClipError(self.name, ne, self._cs, txt=_too_(_few_))
# assert len(pts) == np
# and set self._x1, ._y1, ._dx, ._dy and # ._xy for each non-null clip edge
else: # original point
# corner c1 and clip edge c1 to c2, indicating where # point p is located: to the right, to the left or # on top of the (extended) clip edge from c1 to c2 float(p.lon - self._x1) * self._dy # clockwise corners, +1 means point p is to the right # of, -1 means on the left of, 0 means on edge c1 to c2
# of polygon edge p1 to p2 and the current clip edge, # where p1 and p2 are known to NOT be located on the # same side of or on the current, non-null clip edge # <https://StackOverflow.com/questions/563198/ # how-do-you-detect-where-two-line-segments-intersect> if fabs(d) < EPS: # PYCHOK no cover raise _AssertionError(self._DOT_(self.intersect.__name__))
'''(INTERNAL) List of _SH clipped points. '''
'''(INTERNAL) LatLon_ for _SH intersections. ''' # __slots__ are no longer space savers, see # the comments at the class .points.LatLon_ # __slots__ = _lat_, _lon_, 'classof', 'edge', _name_
'''3-Tuple C{(start, end, original)} for each edge of a I{clipped} polygon, the C{start} and C{end} points (C{LatLon}) of the portion of the edge inside or on the clip region and C{original} indicates whether the edge is part of the original polygon or part of the clip region (C{bool}). '''
'''Clip a polygon against a clip region or box using the U{Sutherland-Hodgman <https://WikiPedia.org/wiki/Sutherland-Hodgman_algorithm>} algorithm.
@arg points: The polygon points (C{LatLon}[]). @arg corners: Three or more points defining a convex clip region (C{LatLon}[]) or two points to specify a rectangular clip box. @kwarg closed: Close the clipped points (C{bool}). @kwarg inull: Optionally, include null edges (C{bool}).
@return: Yield the clipped points (C{LatLon}[]).
@raise ClipError: The B{C{corners}} specify a polar, zero-area, non-convex or otherwise invalid clip box or region.
@raise PointsError: Insufficient number of B{C{points}}. '''
'''Clip a polygon against a clip region or box using the U{Sutherland-Hodgman <https://WikiPedia.org/wiki/Sutherland-Hodgman_algorithm>} algorithm.
@arg points: The polygon points (C{LatLon}[]). @arg corners: Three or more points defining a convex clip region (C{LatLon}[]) or two points to specify a rectangular clip box. @kwarg closed: Close the clipped points (C{bool}). @kwarg inull: Optionally, include null edges (C{bool}).
@return: Yield a L{ClipSH3Tuple}C{(start, end, original)} for each edge of the I{clipped} polygon.
@raise ClipError: The B{C{corners}} specify a polar, zero-area, non-convex or otherwise invalid clip box or region.
@raise PointsError: Insufficient number of B{C{points}} or B{C{corners}}. '''
# **) MIT License # # Copyright (C) 2018-2023 -- mrJean1 at Gmail -- All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. |