<s> """<STR_LIT>""" <EOL> import functools <EOL> import py2d . Math <EOL> class Vision : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , obstructors , debug = False ) : <EOL> """<STR_LIT>""" <EOL> self . set_obstructors ( obstructors ) <EOL> self . debug = debug <EOL> self . debug_points = [ ] <EOL> self . debug_linesegs = [ ] <EOL> def set_obstructors ( self , obstructors ) : <EOL> """<STR_LIT>""" <EOL> def flatten_list ( l ) : <EOL> return functools . reduce ( lambda x , y : x + y , l ) <EOL> self . obs_points = flatten_list ( obstructors ) <EOL> self . obs_segs = flatten_list ( [ list ( zip ( strip , strip [ <NUM_LIT:1> : ] ) ) for strip in obstructors ] ) <EOL> self . cached_vision = None <EOL> self . cached_position = None <EOL> self . cached_radius = None <EOL> def get_vision ( self , eye , radius , boundary ) : <EOL> """<STR_LIT>""" <EOL> if self . cached_vision == None or ( self . cached_position - eye ) . get_length_squared ( ) > <NUM_LIT:1> : <EOL> self . calculate ( eye , radius , boundary ) <EOL> return self . cached_vision <EOL> def calculate ( self , eye , radius , boundary ) : <EOL> """<STR_LIT>""" <EOL> self . cached_radius = radius <EOL> self . cached_position = eye <EOL> self . debug_points = [ ] <EOL> self . debug_linesegs = [ ] <EOL> radius_squared = radius * radius <EOL> closest_points = lambda points , reference : sorted ( points , key = lambda p : ( p - reference ) . get_length_squared ( ) ) <EOL> def sub_segment ( small , big ) : <EOL> return py2d . Math . distance_point_lineseg_squared ( small [ <NUM_LIT:0> ] , big [ <NUM_LIT:0> ] , big [ <NUM_LIT:1> ] ) < <NUM_LIT> and py2d . Math . distance_point_lineseg_squared ( small [ <NUM_LIT:1> ] , big [ <NUM_LIT:0> ] , big [ <NUM_LIT:1> ] ) < <NUM_LIT> <EOL> def segment_in_obs ( seg ) : <EOL> for line_segment in self . obs_segs : <EOL> if sub_segment ( seg , line_segment ) : <EOL> return True <EOL> return False <EOL> def check_visibility ( p ) : <EOL> bpoints = set ( boundary . points ) <EOL> if p not in bpoints : <EOL> if ( eye - p ) . get_length_squared ( ) > radius_squared : return False <EOL> if not boundary . contains_point ( p ) : return False <EOL> for line_segment in obs_segs : <EOL> if py2d . Math . check_intersect_lineseg_lineseg ( eye , p , line_segment [ <NUM_LIT:0> ] , line_segment [ <NUM_LIT:1> ] ) : <EOL> if line_segment [ <NUM_LIT:0> ] != p and line_segment [ <NUM_LIT:1> ] != p : <EOL> return False <EOL> return True <EOL> def lineseg_in_radius ( seg ) : <EOL> return py2d . Math . distance_point_lineseg_squared ( eye , seg [ <NUM_LIT:0> ] , seg [ <NUM_LIT:1> ] ) <= radius_squared <EOL> obs_segs = filter ( lineseg_in_radius , self . obs_segs ) <EOL> visible_points = list ( filter ( check_visibility , set ( self . obs_points + boundary . points ) ) ) <EOL> boundary_intersection_points = py2d . Math . intersect_linesegs_linesegs ( obs_segs , list ( zip ( boundary . points , boundary . points [ <NUM_LIT:1> : ] ) ) + [ ( boundary . points [ - <NUM_LIT:1> ] , boundary . points [ <NUM_LIT:0> ] ) ] ) <EOL> if self . debug : self . debug_points . extend ( [ ( p , <NUM_LIT> ) for p in visible_points ] ) <EOL> if self . debug : self . debug_points . extend ( [ ( p , <NUM_LIT> ) for p in boundary_intersection_points ] ) <EOL> for line_segment in obs_segs : <EOL> i = <NUM_LIT:0> <EOL> while i < len ( boundary_intersection_points ) : <EOL> p = boundary_intersection_points [ i ] <EOL> if py2d . Math . distance_point_lineseg_squared ( p , line_segment [ <NUM_LIT:0> ] , line_segment [ <NUM_LIT:1> ] ) > <NUM_LIT> and py2d . Math . check_intersect_lineseg_lineseg ( eye , p , line_segment [ <NUM_LIT:0> ] , line_segment [ <NUM_LIT:1> ] ) : <EOL> boundary_intersection_points . remove ( p ) <EOL> else : <EOL> i += <NUM_LIT:1> <EOL> visible_points += boundary_intersection_points <EOL> poly = py2d . Math . Polygon ( ) <EOL> poly . add_points ( visible_points ) <EOL> poly . sort_around ( eye ) <EOL> i = <NUM_LIT:0> <EOL> while i < len ( poly . points ) : <EOL> p = poly . points [ i - <NUM_LIT:1> ] <EOL> c = poly . points [ i ] <EOL> n = poly . points [ ( i + <NUM_LIT:1> ) % len ( poly . points ) ] <EOL> intersections = set ( py2d . Math . intersect_linesegs_ray ( obs_segs , eye , c ) + py2d . Math . intersect_poly_ray ( boundary . points , eye , c ) ) <EOL> intersections = [ ip for ip in intersections if ip != c and boundary . contains_point ( ip ) ] <EOL> if self . debug : self . debug_points . extend ( [ ( pt , <NUM_LIT> ) for pt in intersections ] ) <EOL> if intersections : <EOL> intersection = min ( intersections , key = lambda p : ( p - eye ) . length_squared ) <EOL> sio_pc = segment_in_obs ( ( p , c ) ) <EOL> sio_cn = segment_in_obs ( ( c , n ) ) <EOL> if not sio_pc : <EOL> poly . points . insert ( i , intersection ) <EOL> i += <NUM_LIT:1> <EOL> if segment_in_obs ( ( poly . points [ i - <NUM_LIT:3> ] , poly . points [ i - <NUM_LIT:1> ] ) ) : <EOL> poly . points . remove ( poly . points [ i - <NUM_LIT:2> ] ) <EOL> i -= <NUM_LIT:1> <EOL> elif sio_pc and not sio_cn : <EOL> poly . points . insert ( i + <NUM_LIT:1> , intersection ) <EOL> i += <NUM_LIT:1> <EOL> i += <NUM_LIT:1> <EOL> if segment_in_obs ( ( poly . points [ - <NUM_LIT:1> ] , poly . points [ <NUM_LIT:1> ] ) ) : <EOL> poly . points [ <NUM_LIT:0> ] , poly . points [ <NUM_LIT:1> ] = poly . points [ <NUM_LIT:1> ] , poly . points [ <NUM_LIT:0> ] <EOL> self . cached_vision = poly <EOL> return poly </s>
