import numpy as np # =============================== relationships to build the graph =============================== def rotate_vec2d(vec, degrees): """ rotate a vector anti-clockwise :param vec: :param degrees: :return: """ theta = np.radians(degrees) c, s = np.cos(theta), np.sin(theta) R = np.array(((c, -s), (s, c))) return R@vec # ---------- Remote Directional Relations -------------------------------------------------------- def is_front(obj1, obj2, direction_vec)->bool: diff = obj2.pos - obj1.pos return diff@direction_vec > 0.1 def is_back(obj1, obj2, direction_vec)->bool: diff = obj2.pos - obj1.pos return diff@direction_vec < -0.1 def is_left(obj1, obj2, direction_vec)->bool: left_vec = rotate_vec2d(direction_vec, -90) diff = obj2.pos - obj1.pos return diff@left_vec > 0.1 def is_right(obj1, obj2, direction_vec)->bool: left_vec = rotate_vec2d(direction_vec, 90) diff = obj2.pos - obj1.pos return diff@left_vec > 0.1 # ---------- Alignment and Adjacency Relations --------------------------------------------------- def is_close(obj1, obj2, direction_vec=None)->bool: # indicate whether two objects are adjacent to each other, # which, unlike local directional relations, carry no directional information distance = np.abs(obj1.pos - obj2.pos) return np.sum(distance)==20 def is_aligned(obj1, obj2, direction_vec=None)->bool: # indicate if two entities are on the same horizontal or vertical line diff = obj2.pos - obj1.pos return np.any(diff==0) # ---------- Local Directional Relations --------------------------------------------------------- def is_top_adj(obj1, obj2, direction_vec=None)->bool: return obj1.x==obj2.x and obj1.y==obj2.y+20 def is_left_adj(obj1, obj2, direction_vec=None)->bool: return obj1.y==obj2.y and obj1.x==obj2.x-20 def is_top_left_adj(obj1, obj2, direction_vec=None)->bool: return obj1.y==obj2.y+20 and obj1.x==obj2.x-20 def is_top_right_adj(obj1, obj2, direction_vec=None)->bool: return obj1.y==obj2.y+20 and obj1.x==obj2.x+20 def is_down_adj(obj1, obj2, direction_vec=None)->bool: return is_top_adj(obj2, obj1) def is_right_adj(obj1, obj2, direction_vec=None)->bool: return is_left_adj(obj2, obj1) def is_down_right_adj(obj1, obj2, direction_vec=None)->bool: return is_top_left_adj(obj2, obj1) def is_down_left_adj(obj1, obj2, direction_vec=None)->bool: return is_top_right_adj(obj2, obj1) # ---------- More Remote Directional Relations (not used) ---------------------------------------- def top_left(obj1, obj2, direction_vec)->bool: return (obj1.x-obj2.x) <= (obj1.y-obj2.y) def top_right(obj1, obj2, direction_vec)->bool: return -(obj1.x-obj2.x) <= (obj1.y-obj2.y) def down_left(obj1, obj2, direction_vec)->bool: return top_right(obj2, obj1, direction_vec) def down_right(obj1, obj2, direction_vec)->bool: return top_left(obj2, obj1, direction_vec) def fan_top(obj1, obj2, direction_vec)->bool: top_left = (obj1.x-obj2.x) <= (obj1.y-obj2.y) top_right = -(obj1.x-obj2.x) <= (obj1.y-obj2.y) return top_left and top_right def fan_down(obj1, obj2, direction_vec)->bool: return fan_top(obj2, obj1, direction_vec) def fan_right(obj1, obj2, direction_vec)->bool: down_left = (obj1.x-obj2.x) >= (obj1.y-obj2.y) top_right = -(obj1.x-obj2.x) <= (obj1.y-obj2.y) return down_left and top_right def fan_left(obj1, obj2, direction_vec)->bool: return fan_right(obj2, obj1, direction_vec) # ---------- Ad-hoc Relations -------------------------------------------------------------------- def needs(obj1, obj2, direction_vec=None)->bool: return np.argmax(obj1.type) == 0 and np.argmax(obj2.type) == 3 def opens(obj1, obj2, direction_vec=None)->bool: return np.argmax(obj1.type) == 3 and np.argmax(obj2.type) == 8 def collects(obj1, obj2, direction_vec=None)->bool: return np.argmax(obj1.type) == 0 and np.argmax(obj2.type) == 6