def boxline(object_id, axis, direction, delim, suffix, start, end, line_width, move, color, parent): line_width = line_width / SCL_CLICK end = Position(x=(end.x - start.x) / SCL_CLICK, y=(end.y - start.y) / SCL_CLICK, z=(end.z - start.z) / SCL_CLICK) if start.y == end.y and start.z == end.z: scale = Scale(x=abs(start.x - end.x), y=line_width, z=line_width) elif start.x == end.x and start.z == end.z: scale = Scale(x=line_width, y=abs(start.y - end.y), z=line_width) elif start.x == end.x and start.y == end.y: scale = Scale(x=line_width, y=line_width, z=abs(start.z - end.z)) name = f"{object_id}{delim}{axis}{direction}_{suffix}" position = Position(statistics.median([start.x, end.x]), statistics.median([start.y, end.y]), statistics.median([start.z, end.z])) if name not in CONTROLS[object_id]: CONTROLS[object_id][name] = Box( object_id=name, # TODO: restore ttl=arblib.TTL_TEMP, parent=parent, scale=scale, position=position, material=Material(color=color, transparent=True, opacity=0.4, shader="flat"), ) scene.add_object(CONTROLS[object_id][name]) elif move: scene.update_object(CONTROLS[object_id][name], position=position, scale=scale)
def init_origin(scene: Scene): """Origin object, construction cone, so user knows ARB is running.""" # TODO: migrate to shared-scene setting size = [0.2, 0.4, 0.2] scene.add_object(Cone( # 370mm x 370mm # 750mm object_id="arb-origin", material=Material( color=Color(255, 114, 33), transparent=True, opacity=0.5, shader="flat"), position=Position(0, size[1] / 2, 0), scale=Scale(size[0] / 2, size[1], size[2] / 2))) scene.add_object(Cone( object_id="arb-origin-hole", **{"material-extras": {"transparentOccluder": True}}, position=Position(0, size[1] - (size[1] / 2 / 15), 0), scale=Scale(size[0] / 15, size[1] / 10, size[2] / 15))) scene.add_object(Box( object_id="arb-origin-base", material=Material( color=Color(0, 0, 0), transparent=True, opacity=0.5, shader="flat"), position=Position(0, size[1] / 20, 0), scale=Scale(size[0], size[1] / 10, size[2])))
def dir_clickers(object_id, axis, direction, delim, position, color, cones, callback, move, parent): position = Position(x=position.x / SCL_CLICK, y=position.y / SCL_CLICK, z=position.z / SCL_CLICK) loc = Position(x=position.x / SCL_CLICK, y=position.y / SCL_CLICK, z=position.z / SCL_CLICK) npos = 0.1 / SCL_CLICK if direction == "p": npos = -0.1 / SCL_CLICK if axis == "x": loc = Position(x=position.x + npos, y=position.y, z=position.z) elif axis == "y": loc = Position(x=position.x, y=position.y + npos, z=position.z) elif axis == "z": loc = Position(x=position.x, y=position.y, z=position.z + npos) name_pos = f"{object_id}{delim}{axis}p_{direction}" name_neg = f"{object_id}{delim}{axis}n_{direction}" if name_pos not in CONTROLS[object_id]: CONTROLS[object_id][name_pos] = Cone( # click object positive object_id=name_pos, clickable=True, position=position, rotation=cones[axis + direction][0], scale=Scale(0.05 / SCL_CLICK, 0.09 / SCL_CLICK, 0.05 / SCL_CLICK), material=Material(color=color, transparent=True, opacity=arblib.OPC_CLINE), # TODO: restore ttl=arblib.TTL_TEMP, parent=parent, evt_handler=callback) scene.add_object(CONTROLS[object_id][name_pos]) elif move: scene.update_object(CONTROLS[object_id][name_pos], position=position) if name_neg not in CONTROLS[object_id]: CONTROLS[object_id][name_neg] = Cone( # click object negative object_id=name_neg, clickable=True, position=loc, rotation=cones[axis + direction][1], scale=Scale(0.05 / SCL_CLICK, 0.09 / SCL_CLICK, 0.05 / SCL_CLICK), material=Material(color=color, transparent=True, opacity=arblib.OPC_CLINE), # TODO: restore ttl=arblib.TTL_TEMP, parent=parent, evt_handler=callback) scene.add_object(CONTROLS[object_id][name_neg]) elif move: scene.update_object(CONTROLS[object_id][name_neg], position=loc)
def update(self, data): self.src_width = data["image"]["width"] self.src_height = data["image"]["height"] # update rotation new_quat = data["pose"]["quaternions"] new_euler = Rotation(*new_quat).euler filtered_euler = self.rot_filter.add( (new_euler.x, new_euler.y, new_euler.z)) # filter filtered_euler[0] *= -1.2 # flip direction and scale up a bit filtered_euler[0] += 5 # rotate up a bit filtered_euler[1] *= 0.7 # scale down # head faces backward at first, rotate head 180 to correct filtered_euler[1] += 180 self.rot = Rotation(*filtered_euler) # update translation new_trans = data["pose"]["translation"] new_trans[0] = 0.0 new_trans[1] = -0.07 new_trans[2] = -0.045 self.trans = self.trans_filter.add(new_trans) # filter self.trans = Position(*new_trans) self.bbox = np.array(data["bbox"]).reshape((2, -1)) new_lmks = np.array(data["landmarks"]) # [x1, y1, x2, y2...] self.lmks_raw = self.lmks_filter.add(new_lmks) # filter self.landmarks = self.lmks_raw.reshape((-1, 2)) # [[x1,y1],[x2,y2]...] self.center = np.mean(self.landmarks, axis=0) # "center of mass" of face self.landmarks = self.normalize_to_COM(self.landmarks, self.center)
def do_scale_select(camname, objid, scale=None): color = arblib.CLR_SCALE delim = f"_{Mode.SCALE.value}_" callback = scaleline_callback obj = scene.get_persisted_obj(objid) position = Position() if "position" in obj.data: position = obj.data.position if not scale: scale = Scale() if "scale" in obj.data: scale = obj.data.scale xl, yl, zl = get_clicklines_len(obj) # scale entire object + or - on all axis root = make_clickroot(objid, position, delim, move=True) make_clickline("x", xl, objid, position, delim, color, callback, move=True, parent=root) # TODO: restore make_followspot(objid, position, delim, color) sca = Scale(round(scale.x, 3), round(scale.y, 3), round(scale.z, 3)) USERS[camname].set_textright( f"{USERS[camname].target_style} s({sca.x},{sca.y},{sca.z})")
def set_clipboard(self, callback=None, object_type=None, scale=Scale(0.05, 0.05, 0.05), position=Position(0, 0, -CLIP_RADIUS/SCL_HUD), color=Color(255, 255, 255), url=None): if object_type: self.clipboard = Object( # show item to be created object_id=f"{self.camname}_clipboard", object_type=object_type, position=position, parent=self.hud.object_id, scale=Scale(scale.x/SCL_HUD, scale.y/SCL_HUD, scale.z/SCL_HUD), material=Material(color=color, transparent=True, opacity=0.4), url=url, clickable=True, evt_handler=callback) self.scene.add_object(self.clipboard) self.cliptarget = Circle( # add helper target object to find true origin object_id=f"{self.camname}_cliptarget", position=position, parent=self.hud.object_id, scale=Scale(0.005/SCL_HUD, 0.005/SCL_HUD, 0.005/SCL_HUD), material=Material(color=Color(255, 255, 255), transparent=True, opacity=0.4), clickable=True, evt_handler=callback) self.scene.add_object(self.cliptarget)
def do_rotate_select(camname, objid, rotation=None): color = arblib.CLR_ROTATE delim = f"_{Mode.ROTATE.value}_" callback = rotateline_callback obj = scene.get_persisted_obj(objid) position = Position() if "position" in obj.data: position = obj.data.position if not rotation: rotation = Rotation() if "rotation" in obj.data: rotation = obj.data.rotation xl, yl, zl = get_clicklines_len(obj) # rotate object + or - on 3 axis, plus show original axis as after # effect root = make_clickroot(objid, position, delim) ghost = make_clickroot(objid, position, delim, rotation=rotation, move=True) make_clickline("x", xl, objid, position, delim, color, callback, ghost=ghost, parent=root) make_clickline("y", yl, objid, position, delim, color, callback, ghost=ghost, parent=root) make_clickline("z", zl, objid, position, delim, color, callback, ghost=ghost, parent=root) # TODO: restore make_followspot(objid, position, delim, color) try: rote = arblib.rotation_quat2euler( (rotation.x, rotation.y, rotation.z, rotation.w)) except ValueError as error: print(f"Rotation error: {error}") return euler = (round(rote[0], 1), round(rote[1], 1), round(rote[2], 1)) USERS[camname].set_textright( f"{USERS[camname].target_style}d r({euler[0]},{euler[1]},{euler[2]})")
def do_nudge_select(camname, objid, position=None): color = arblib.CLR_NUDGE delim = f"_{Mode.NUDGE.value}_" callback = nudgeline_callback obj = scene.get_persisted_obj(objid) if not position: position = Position() if "position" in obj.data: position = obj.data.position xl, yl, zl = get_clicklines_len(obj) # nudge object + or - on 3 axis root = make_clickroot(objid, position, delim, move=True) make_clickline("x", xl, objid, position, delim, color, callback, move=True, parent=root) make_clickline("y", yl, objid, position, delim, color, callback, move=True, parent=root) make_clickline("z", zl, objid, position, delim, color, callback, move=True, parent=root) # TODO: restore make_followspot(objid, position, delim, color, move=True) pos = Position(round(position.x, 3), round(position.y, 3), round(position.z, 3)) USERS[camname].set_textright( f"{USERS[camname].target_style} p({pos.x},{pos.y},{pos.z})")
def make_hudtext(self, label, position, text): text = Text( object_id=f"{label}_{self.camname}", parent=self.hud.object_id, text=text, position=Position(position.x / SCL_HUD, position.y / SCL_HUD, position.z / SCL_HUD), color=CLR_HUDTEXT, scale=Scale(0.1 / SCL_HUD, 0.1 / SCL_HUD, 0.1 / SCL_HUD), ) self.scene.add_object(text) return text
def show_redpill_obj(camname, object_id): # any scene changes must not persist obj = scene.get_persisted_obj(object_id) # enable mouse enter/leave pos/rot/scale position = Position() if "position" in obj.data: position = obj.data.position rotation = Rotation() if "rotation" in obj.data: rotation = obj.data.rotation scale = Scale() if "scale" in obj.data: scale = obj.data.scale USERS[camname].set_textstatus(" ".join([ f"{object_id}", f"p({position.x},{position.y},{position.z})", f"r({rotation.x},{rotation.y},{rotation.z},{rotation.w})", f"s({scale.x},{scale.y},{scale.z})" ]))
def regline(object_id, axis, direction, delim, suffix, start, end, line_width, move, color, parent): line_width = line_width / SCL_CLICK end = Position(x=(end.x - start.x) / SCL_CLICK, y=(end.y - start.y) / SCL_CLICK, z=(end.z - start.z) / SCL_CLICK) name = f"{object_id}{delim}{axis}{direction}_{suffix}" if name not in CONTROLS[object_id]: CONTROLS[object_id][name] = Line( object_id=name, color=color, # TODO: restore ttl=arblib.TTL_TEMP, parent=parent, start=start, end=end) scene.add_object(CONTROLS[object_id][name]) elif move: scene.update_object(CONTROLS[object_id][name], start=start, end=end)
def make_followspot(object_id, position, delim, color, parent, move=False): name = f"{object_id}{delim}spot" if name not in CONTROLS[object_id]: CONTROLS[object_id][name] = Circle( # follow spot on ground object_id=name, scale=Scale(0.1, 0.1, 0.1), # TODO: restore ttl=arblib.TTL_TEMP, position=Position(position.x, arblib.FLOOR_Y, position.z), rotation=Rotation(-0.7, 0, 0, 0.7), parent=parent, material=Material(color=color, transparent=True, opacity=0.4, shader="flat"), ) scene.add_object(CONTROLS[object_id][name]) elif move: scene.update_object(CONTROLS[object_id][name], position=position)
def stretchline_callback(_scene, event, msg): obj, direction, move = handle_clickline_event(event, Mode.STRETCH) if not obj or not direction or not move or "scale" not in obj.data or "position" not in obj.data: return scaled = sca = obj.data.scale moved = loc = obj.data.position inc = meters_increment(USERS[event.data.source].target_style) if direction == "xp": scaled = Scale(x=incr_pos(sca.x, inc), y=sca.y, z=sca.z) moved = Position(x=recenter(scaled.x, sca.x, loc.x, move), y=loc.y, z=loc.z) elif direction == "xn": scaled = Scale(x=incr_neg(sca.x, inc), y=sca.y, z=sca.z) moved = Position(x=recenter(scaled.x, sca.x, loc.x, move), y=loc.y, z=loc.z) elif direction == "yp": scaled = Scale(x=sca.x, y=incr_pos(sca.y, inc), z=sca.z) moved = Position(x=loc.x, y=recenter(scaled.y, sca.y, loc.y, move), z=loc.z) elif direction == "yn": scaled = Scale(x=sca.x, y=incr_neg(sca.y, inc), z=sca.z) moved = Position(x=loc.x, y=recenter(scaled.y, sca.y, loc.y, move), z=loc.z) elif direction == "zp": scaled = Scale(x=sca.x, y=sca.y, z=incr_pos(sca.z, inc)) moved = Position(x=loc.x, y=loc.y, z=recenter(scaled.z, sca.z, loc.z, move)) elif direction == "zn": scaled = Scale(x=sca.x, y=sca.y, z=incr_neg(sca.z, inc)) moved = Position(x=loc.x, y=loc.y, z=recenter(scaled.z, sca.z, loc.z, move)) if scaled.x <= 0 or scaled.y <= 0 or scaled.z <= 0: return arblib.stretch_obj(scene, obj.object_id, scale=scaled, position=moved) print(f"{str(obj.data.scale)} to {str(scaled)}") do_stretch_select(event.data.source, obj.object_id, scale=scaled)
def nudgeline_callback(_scene, event, msg): obj, direction, move = handle_clickline_event(event, Mode.NUDGE) if not obj or not direction or "position" not in obj.data: return nudged = loc = obj.data.position inc = meters_increment(USERS[event.data.source].target_style) if direction == "xp": nudged = Position(x=incr_pos(loc.x, inc), y=loc.y, z=loc.z) elif direction == "xn": nudged = Position(x=incr_neg(loc.x, inc), y=loc.y, z=loc.z) elif direction == "yp": nudged = Position(x=loc.x, y=incr_pos(loc.y, inc), z=loc.z) elif direction == "yn": nudged = Position(x=loc.x, y=incr_neg(loc.y, inc), z=loc.z) elif direction == "zp": nudged = Position(x=loc.x, y=loc.y, z=incr_pos(loc.z, inc)) elif direction == "zn": nudged = Position(x=loc.x, y=loc.y, z=incr_neg(loc.z, inc)) arblib.move_obj(scene, obj.object_id, nudged) print(f"{str(obj.data.position)} to {str(nudged)}") # always redraw nudgelines do_nudge_select(event.data.source, obj.object_id, position=nudged)
def __init__(self, scene: Scene, camname, panel_callback): self.scene = scene self.camname = camname self.mode = Mode.NONE self.clipboard = self.cliptarget = None self.target_id = self.target_control_id = None self.position = self.rotation = None self.position_last = self.rotation_last = None self.gesturing = False self.target_style = self.typetext = "" self.locky = LOCK_YOFF self.lockx = LOCK_XOFF self.wloc_start = self.wloc_end = None self.wrot_start = self.wrot_end = None self.lamp = None init_origin(self.scene) # set HUD to each user self.hud = Box( object_id=f"hud_{camname}", parent=camname, material=Material(transparent=True, opacity=0), position=Position(0, 0, 0), scale=Scale(SCL_HUD, SCL_HUD, SCL_HUD), rotation=Rotation(0, 0, 0, 1), ) self.scene.add_object(self.hud) self.hudtext_left = self.make_hudtext( "hudTextLeft", Position(-0.15, 0.15, -0.5), str(self.mode)) self.hudtext_right = self.make_hudtext( "hudTextRight", Position(0.1, 0.15, -0.5), "") self.hudtext_status = self.make_hudtext( "hudTextStatus", Position(0.02, -0.15, -0.5), "") # workaround x=0 bad? # AR Control Panel self.follow_lock = False self.follow = Box( object_id=f"follow_{camname}", parent=camname, material=Material(transparent=True, opacity=0), position=Position(0, 0, -PANEL_RADIUS * 0.1), scale=Scale(0.1, 0.01, 0.1), rotation=Rotation(0.7, 0, 0, 0.7), ) self.scene.add_object(self.follow) self.redpill = False self.slider = False self.panel = {} # button dictionary self.dbuttons = {} buttons = [ # top row [Mode.ROTATE, -2, 1, True, ButtonType.ACTION], [Mode.NUDGE, -1, 1, True, ButtonType.ACTION], [Mode.SCALE, 0, 1, True, ButtonType.ACTION], [Mode.STRETCH, 1, 1, True, ButtonType.ACTION], [Mode.MODEL, 2, 1, True, ButtonType.ACTION], [Mode.CREATE, 3, 1, True, ButtonType.ACTION], # center row [Mode.REDPILL, -2, 0, True, ButtonType.TOGGLE], [Mode.MOVE, -1, 0, True, ButtonType.ACTION], [Mode.LOCK, 0, 0, True, ButtonType.TOGGLE], [Mode.DELETE, 1, 0, True, ButtonType.ACTION], [Mode.PARENT, 2, 0, True, ButtonType.ACTION], # bottom row [Mode.WALL, -2, -1, True, ButtonType.ACTION], [Mode.OCCLUDE, -1, -1, True, ButtonType.ACTION], [Mode.RENAME, 0, -1, True, ButtonType.ACTION], [Mode.COLOR, 1, -1, True, ButtonType.ACTION], [Mode.LAMP, 2, -1, True, ButtonType.TOGGLE], [Mode.SLIDER, 3, -1, False, ButtonType.TOGGLE], # TODO: adjust scale ] for but in buttons: pbutton = Button( scene, camname, but[0], but[1], but[2], enable=but[3], btype=but[4], parent=self.follow.object_id, callback=panel_callback) self.panel[pbutton.button.object_id] = pbutton
def make_clickline(axis, linelen, objid, start, delim, color, callback, ghost=None, parent=None, move=False): if objid not in CONTROLS.keys(): CONTROLS[objid] = {} endx = endy = endz = 0 direction = "p" if linelen < 0: direction = "n" if axis == "x": endx = linelen elif axis == "y": endy = linelen elif axis == "z": endz = linelen start = Position(0, 0, 0) end = Position(x=start.x + endx, y=start.y + endy, z=start.z + endz) boxline( # reference line object_id=objid, axis=axis, direction=direction, delim=delim, suffix="line", color=color, start=start, end=end, line_width=0.005, move=move, parent=parent) if ghost: boxline( # ghostline aligns to parent rotation object_id=objid, axis=axis, direction=direction, delim=delim, suffix="ghost", color=(255, 255, 255), start=start, end=end, line_width=0.005, move=move, parent=ghost) if ghost: cones = arblib.ROTATE_CONES else: cones = arblib.DIRECT_CONES dir_clickers( # click objects object_id=objid, axis=axis, direction=direction, delim=delim, position=end, color=color, cones=cones, callback=callback, move=move, parent=parent)
def make_wall(camname): # Wall theory: capture two poses and use them to place a wall object. # Also assumes first corner easier to capture accurate rotation than last. # Click 1: Capture the position and rotation. # Click 2: Capture the position only. sloc = USERS[camname].wloc_start eloc = USERS[camname].wloc_end srot = USERS[camname].wrot_start erot = USERS[camname].wrot_end print(f"S POS {str(sloc)}") print(f"E POS {str(eloc)}") # center point (blue) locx = statistics.median([sloc.x, eloc.x]) locy = statistics.median([sloc.y, eloc.y]) locz = statistics.median([sloc.z, eloc.z]) pos = Position(locx, locy, locz) scene.add_object(arblib.temp_loc_marker(pos, Color(0, 0, 255))) print(f"wall position {str(pos)}") # rotation print(f"S ROT {str(srot)}") print(f"E ROT {str(erot)}") rotx = arblib.probable_quat(srot.x) roty = arblib.probable_quat(srot.y) rotz = arblib.probable_quat(srot.z) rotw = arblib.probable_quat(srot.w) rot = Rotation(rotx, roty, rotz, rotw) gaze = (rotx, roty, rotz, rotw) scene.add_object(arblib.temp_rot_marker(pos, rot)) print(f"wall rotation {str(rot)}") # which axis to use for wall? use camera gaze # TODO: rotation still off if gaze in arblib.GAZES[0]: height = abs(sloc.y - eloc.y) width = abs(sloc.x - eloc.x) elif gaze in arblib.GAZES[1]: height = abs(sloc.y - eloc.y) width = abs(sloc.z - eloc.z) elif gaze in arblib.GAZES[2]: height = abs(sloc.z - eloc.z) width = abs(sloc.x - eloc.x) else: # TODO: (placeholder) add direction and hypotenuse height = abs(sloc.y - eloc.y) width = abs(sloc.x - eloc.x) print(f"Non-axis parallel rotation: {str(rot)}") # scale scax = width scay = height scaz = arblib.WALL_WIDTH sca = Scale(scax, scay, scaz) print(f"wall scale {str(sca)}") # make wall randstr = str(random.randrange(0, 1000000)) new_wall = Box( persist=True, clickable=True, object_id=f"wall_{randstr}", position=pos, rotation=rot, scale=sca, material=Material(color=Color(200, 200, 200), transparent=True, opacity=0.5), ) scene.add_object(new_wall) USERS[camname].target_id = new_wall.object_id print(f"Created {new_wall.object_id} r{str(rot)} s{str(sca)}")
def do_stretch_select(camname, objid, scale=None): color = arblib.CLR_STRETCH delim = f"_{Mode.STRETCH.value}_" callback = stretchline_callback obj = scene.get_persisted_obj(objid) position = Position() if "position" in obj.data: position = obj.data.position if not scale: object_type = "box" if "object_type" in obj.data: object_type = obj.data.object_type rotation = Rotation() if "rotation" in obj.data: rotation = obj.data.rotation scale = Scale() if "scale" in obj.data: scale = obj.data.scale # TODO: scale too unpredictable, modify if object_type == GLTF.object_type: return # TODO: scale too unpredictable, modify if rotation.quaternion.__dict__ != Rotation(x=0, y=0, z=0, w=1).quaternion.__dict__: return xl, yl, zl = get_clicklines_len(obj) # scale and reposition on one of 6 sides root = make_clickroot(objid, position, delim, move=True) make_clickline("x", xl, objid, position, delim, color, callback, move=True, parent=root) make_clickline("x", -xl, objid, position, delim, color, callback, move=True, parent=root) make_clickline("y", yl, objid, position, delim, color, callback, move=True, parent=root) make_clickline("y", -yl, objid, position, delim, color, callback, move=True, parent=root) make_clickline("z", zl, objid, position, delim, color, callback, move=True, parent=root) make_clickline("z", -zl, objid, position, delim, color, callback, move=True, parent=root) # TODO: restore make_followspot(objid, position, delim, color) sca = Scale(round(scale.x, 3), round(scale.y, 3), round(scale.z, 3)) USERS[camname].set_textright( f"{USERS[camname].target_style} s({sca.x},{sca.y},{sca.z})")
def __init__(self, scene: Scene, camname, mode, x=0, y=0, label="", parent=None, drop=None, color=CLR_BUTTON, enable=True, callback=None, btype=ButtonType.ACTION): self.scene = scene if label == "": label = mode.value if parent is None: parent = camname scale = Scale(0.1, 0.1, 0.01) else: scale = Scale(1, 1, 1) self.type = btype self.enabled = enable if enable: self.colorbut = color else: self.colorbut = CLR_BUTTON_DISABLED self.colortxt = CLR_BUTTON_TEXT if len(label) > 8: # easier to read self.label = f"{label[:6]}..." else: self.label = label self.mode = mode self.dropdown = drop self.active = False if drop is None: obj_name = f"{camname}_button_{mode.value}" else: obj_name = f"{camname}_button_{mode.value}_{drop}" shape = Box.object_type if btype == ButtonType.TOGGLE: shape = Cylinder.object_type scale = Scale(scale.x / 2, scale.y, scale.z / 2) self.button = Object( # box is main button object_id=obj_name, object_type=shape, parent=parent, material=Material( color=self.colorbut, transparent=True, opacity=OPC_BUTTON, shader="flat"), position=Position(x * 1.1, PANEL_RADIUS, y * -1.1), scale=scale, clickable=True, evt_handler=callback, ) scene.add_object(self.button) scale = Scale(1, 1, 1) if btype == ButtonType.TOGGLE: scale = Scale(scale.x * 2, scale.y * 2, scale.z) self.text = Text( # text child of button object_id=f"{self.button.object_id}_text", parent=self.button.object_id, text=self.label, # position inside to prevent ray events position=Position(0, -0.1, 0), rotation=Rotation(-0.7, 0, 0, 0.7), scale=scale, color=self.colortxt, ) scene.add_object(self.text)
def scene_callback(_scene, event, msg): # This is the MQTT message callback function for the scene object_id = action = msg_type = object_type = None if "object_id" in msg: object_id = msg["object_id"] if "action" in msg: action = msg["action"] if "type" in msg: msg_type = msg["type"] if "data" in msg and "object_type" in msg["data"]: object_type = msg["data"]["object_type"] # print(f'{object_type} {action} {msg_type} {object_id}') if object_type == "camera": # camera updates define users present camname = object_id if camname not in USERS: USERS[camname] = arblib.User(scene, camname, panel_callback) # save camera's attitude in the world USERS[camname].position = Position(msg["data"]["position"]["x"], msg["data"]["position"]["y"], msg["data"]["position"]["z"]) USERS[camname].rotation = Rotation(msg["data"]["rotation"]["x"], msg["data"]["rotation"]["y"], msg["data"]["rotation"]["z"], msg["data"]["rotation"]["w"]) rx = msg["data"]["rotation"]["x"] ry = msg["data"]["rotation"]["y"] # floating controller if not USERS[camname].follow_lock: ty = -(ry + USERS[camname].locky) / 0.7 * math.pi / 2 tx = -(rx + USERS[camname].lockx) / 0.7 * math.pi / 2 px = arblib.PANEL_RADIUS * -math.cos(ty) py = arblib.PANEL_RADIUS * math.sin(tx) pz = arblib.PANEL_RADIUS * math.sin(ty) scene.update_object(USERS[camname].follow, position=Position(px, py, pz)) # else: # TODO: panel lock position drop is inaccurate # users[camname].lockx = rx + arblib.LOCK_XOFF # users[camname].locky = -(ry * math.pi) - arblib.LOCK_YOFF # mouse event elif action == "clientEvent": object_id = msg["object_id"] # camera updates define users present camname = msg["data"]["source"] if camname not in USERS: USERS[camname] = arblib.User(scene, camname, panel_callback) # show objects with events if msg_type == EVT_MOUSEENTER: if USERS[camname].redpill: show_redpill_obj(camname, object_id) else: USERS[camname].set_textstatus(object_id) elif msg_type == EVT_MOUSELEAVE: USERS[camname].set_textstatus("") # handle click elif msg_type == EVT_MOUSEDOWN: # clicked on persisted object to modify update_controls(USERS[camname].target_id) USERS[camname].target_id = object_id # always update if USERS[camname].mode == Mode.DELETE: arblib.delete_obj(scene, object_id) elif USERS[camname].mode == Mode.MOVE: do_move_select(camname, object_id) elif USERS[camname].mode == Mode.NUDGE: do_nudge_select(camname, object_id) elif USERS[camname].mode == Mode.SCALE: do_scale_select(camname, object_id) elif USERS[camname].mode == Mode.STRETCH: do_stretch_select(camname, object_id) elif USERS[camname].mode == Mode.ROTATE: do_rotate_select(camname, object_id) elif USERS[camname].mode == Mode.COLOR: arblib.color_obj(scene, object_id, Color(USERS[camname].target_style)) elif USERS[camname].mode == Mode.OCCLUDE: arblib.occlude_obj(scene, object_id, USERS[camname].target_style) elif USERS[camname].mode == Mode.RENAME or USERS[ camname].mode == Mode.PARENT: if len(USERS[camname].typetext) > 0: # edits already made new_id = USERS[camname].typetext USERS[camname].typetext = "" if USERS[camname].mode == Mode.PARENT: arblib.parent_obj(scene, object_id, new_id) else: do_rename(camname, object_id, new_id) else: # no edits yet, load previous name to change USERS[camname].typetext = object_id USERS[camname].set_textright(USERS[camname].typetext)
def show_redpill_scene(enabled): # any scene changes must not persist # show gridlines name = "grid_redpill" path = [] glen = arblib.GRIDLEN y = arblib.FLOOR_Y for z in range(-glen, glen + 1): if (z % 2) == 0: path.append(Position(-glen, y, z)) path.append(Position(glen, y, z)) else: path.append(Position(glen, y, z)) path.append(Position(-glen, y, z)) for x in range(-glen, glen + 1): if (x % 2) == 0: path.append(Position(x, y, glen)) path.append(Position(x, y, -glen)) else: path.append(Position(x, y, -glen)) path.append(Position(x, y, glen)) if enabled: scene.add_object( ThickLine(object_id=name, path=path, color=arblib.CLR_GRID)) else: arblib.delete_obj(scene, name) objs = scene.get_persisted_objs() for object_id in objs: obj = objs[object_id] # show occluded objects if "material-extras" in obj.data and "transparentOccluder" in obj.data[ "material-extras"]: name = "redpill_" + obj.object_id if enabled: object_type = "box" if "object_type" in obj.data: object_type = obj.data.object_type position = Position() if "position" in obj.data: position = obj.data.position rotation = Rotation() if "rotation" in obj.data: rotation = obj.data.rotation scale = Scale() if "scale" in obj.data: scale = obj.data.scale url = None if "url" in obj.data: url = obj.data.url color = Color() if "material" in obj.data and "color" in obj.data.material: color = obj.data.material.color scene.add_object( Object( object_id=name, object_type=object_type, position=position, rotation=rotation, scale=scale, clickable=True, url=url, material=Material(color=color, transparent=True, opacity=0.5), )) print("Wrapping occlusion " + name) else: arblib.delete_obj(scene, name)