def __init__( self, width=768, height=512, near=0.01, far=1000, background="#111111", antialias=True, ): key_light = DirectionalLight(color="white", position=[3, 3, 3], intensity=0.66) c = PerspectiveCamera(40, width / height, near, far) c.position = [3, 3, 3] c.up = [0, 0, 1] c.add(key_light) pl = PointLight(color="white", intensity=0.1, position=[3, 3, 3]) self._scene = Scene() self._scene.background = background self._scene.add(AmbientLight()) self._scene.add(pl) renderer = Renderer( camera=c, scene=self._scene, antialias=antialias, controls=[OrbitControls(controlling=c)], height=height, width=width, ) display(renderer)
def EraseAll(self): self._shapes = {} self._displayed_pickable_objects = Group() self._current_shape_selection = None self._current_mesh_selection = None self._current_selection_material = None self._renderer.scene = Scene(children=[])
def display_scene(scene): """ :param smc: input structure structure molecule component """ obs = traverse_scene_object(scene) scene = Scene(children=list(obs.children)) box = Box3.exec_three_obj_method("setFromObject", scene) extent = (max(box.max.z - box.min.z, box.max.y - box.min.y, box.max.x - box.min.x) * 1.2) camera = OrthographicCamera(-extent, extent, extent, -extent, -2000, 2000, position=(0, 0, 2)) camera.children.extend([ AmbientLight(color="#cccccc", intensity=0.75), DirectionalLight(color="#ccaabb", position=[0, 20, 10], intensity=0.5), ]) renderer = Renderer( camera=camera, background="white", background_opacity=1, scene=scene, controls=[OrbitControls(controlling=camera)], width=500, height=500, antialias=True, ) display(renderer)
def display_StructureMoleculeComponent(smc): """ :param smc: input structure structure molecule component """ obs = traverse_scene_object(smc.initial_scene_data) obs_children = list(obs.children) obs_children.extend([ AmbientLight(color='#cccccc', intensity=0.75), DirectionalLight(color='#ccaabb', position=[0, 20, 10], intensity=0.5) ]) diag = np.linalg.norm(np.sum(smc._lattice.matrix, axis=0)) scene = Scene(children=obs_children) c = OrthographicCamera(-diag, diag, diag, -diag, -4000, 4000, position=(0, 0, 0.001)) renderer = Renderer(camera=c, background='black', background_opacity=1, scene=scene, controls=[OrbitControls(controlling=c)], width=500, height=500) display(renderer)
def display_scene(scene, size=500): """ Render a Scene object with pythreejs. :param scene: Scene object :param size: Display size :return: """ obs = _traverse_scene_object(scene) logger.debug(type(obs)) scene2render = Scene(children=list(obs.children)) logger.debug(len(scene2render.children)) # cannot use the setFromObject function because the function call is asyncronous # https://github.com/jupyter-widgets/pythreejs/issues/282 bounding_box = scene.bounding_box extent = max([p[1] - p[0] for p in zip(*bounding_box)]) * 1.2 logger.debug(f"extent : {extent}") camera = OrthographicCamera(-extent, +extent, extent, -extent, -2000, 2000, position=[0, 0, 10]) origin = scene.origin or (0, 0, 0) cam_target = tuple(-i for i in origin) controls = OrbitControls(target=cam_target, controlling=camera) camera.lookAt(cam_target) scene2render.children = scene2render.children + ( AmbientLight(color="#cccccc", intensity=0.75), DirectionalLight(color="#ccaabb", position=[0, 20, 10], intensity=0.5), camera, ) renderer = Renderer( camera=camera, background="white", background_opacity=1, scene=scene2render, controls=[controls], width=size, height=size, antialias=True, ) logger.debug("Start drawing to the notebook") display(renderer)
def pseudomaterial_render(atoms): c = cm.get_cmap("plasma") scale_axis_vertices = [[-1, -1, -1], [9, -1, -1]] scale_line_geom = Geometry(vertices=scale_axis_vertices, colors=['black'] * len(scale_axis_vertices)) scale_lines = Line( geometry=scale_line_geom, material=LineBasicMaterial(linewidth=50, vertexColors='VertexColors'), type='LinePieces', ) a = atoms.a[1] cube_vertices = [[0, 0, 0], [a, 0, 0], [a, 0, a], [a, 0, 0], [a, a, 0], [a, a, a], [a, a, 0], [0, a, 0], [0, a, a], [0, a, 0], [0, 0, 0], [0, 0, a], [a, 0, a], [a, a, a], [0, a, a], [0, 0, a]] linesgeom = Geometry(vertices=cube_vertices, colors=['black'] * len(cube_vertices)) lines = Line( geometry=linesgeom, material=LineBasicMaterial(linewidth=5, vertexColors='VertexColors'), type='LinePieces', ) balls = [] for p in atoms.itertuples(): positions = (p.x * p.a, p.y * p.a, p.z * p.a) new_ball = Mesh( geometry=SphereGeometry(radius=p.sigma, widthSegments=32, heightSegments=24), material=MeshLambertMaterial(color=rgb2hex(c(p.epsilon_norm))), position=positions) balls.append(new_ball) # [scale*2*a,scale*2*a,scale*2*a] camera = PerspectiveCamera(position=[25, a, a], up=[0, 1, 0], children=[ DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5) ]) scene = Scene(children=[ scale_lines, lines, *balls, camera, AmbientLight(color='#777') ]) renderer = Renderer( camera=camera, scene=scene, controls=[OrbitControls(controlling=camera, target=[a, a, a])]) return renderer
def create(self): self.cq_renderer = CadqueryRenderer( quality=self.quality, angular_tolerance=self.angular_tolerance, edge_accuracy=self.edge_accuracy, render_edges=self.render_edges, render_shapes=self.render_shapes, default_mesh_color=self.default_mesh_color, default_edge_color=self.default_edge_color, timeit=self.timeit, ) # Set up camera self.camera = CombinedCamera( position=(1.0, 1.0, 1.0), width=self.width, height=self.height, far=100, orthoFar=100, up=(0.0, 0.0, 1.0), ) # needs to be an extra step to take effect self.toggle_ortho(True) # Set up scene self.scene = Scene(children=[self.camera, AmbientLight(intensity=1.0)]) # Set up Controllers camera_target = (0.0, 0.0, 0.0) self.controller = OrbitControls(controlling=self.camera, target=camera_target, target0=camera_target) # Create Renderer instance self.renderer = Renderer( scene=self.scene, camera=self.camera, controls=[self.controller], antialias=True, width=self.width, height=self.height, ) return self.renderer
def display_scene(scene): """ :param smc: input structure structure molecule component """ obs = traverse_scene_object(scene) logger.debug(type(obs)) scene2render = Scene(children=list(obs.children)) logger.debug(len(scene2render.children)) # cannot use the setFromObject function because the function call is asyncronous # https://github.com/jupyter-widgets/pythreejs/issues/282 bounding_box = scene.bounding_box extent = max([p[1] - p[0] for p in zip(*bounding_box)]) * 1.2 logger.debug(f"extent : {extent}") camera = OrthographicCamera(-extent, extent, extent, -extent, -2000, 2000, position=(0, 0, 2)) scene2render.children = scene2render.children + ( AmbientLight(color="#cccccc", intensity=0.75), DirectionalLight(color="#ccaabb", position=[0, 20, 10], intensity=0.5), ) renderer = Renderer( camera=camera, background="white", background_opacity=1, scene=scene2render, controls=[OrbitControls(controlling=camera)], width=500, height=500, antialias=True, ) logger.debug("Start drawing to the notebook") display(renderer)
def show(self): """ Render the scene for the viewer. This method can be called serveral times in order to generate several visualizations which are "yoked" together. """ scene = Scene( background=self.background, children=[ self._camera, AmbientLight(color="#cccccc"), ], ) g = Group() for _, v in self._layer_lookup.items(): g.add(v) p = Picker(controlling=g, event='click') p.observe(self._interact_callback, names=["point"]) self.html = HTML("") scene.add(g) self.controls.append(p) self._renderer = Renderer( width=self._figsize[0], height=self._figsize[1], camera=self._camera, scene=scene, alpha=True, clearOpacity=0, controls=self.controls, ) self._scene = scene display(self.html, self._renderer)
def get_scene(structure): """ :param structure: """ smc = StructureMoleculeComponent(structure, bonded_sites_outside_unit_cell=False, hide_incomplete_bonds=False) obs = traverse_scene_object(smc.initial_scene_data) scene = Scene( children=[obs, AmbientLight(color='#FFFFFF', intensity=0.75)]) c = PerspectiveCamera(position=[10, 10, 10]) renderer = Renderer(camera=c, background='black', background_opacity=1, scene=scene, controls=[OrbitControls(controlling=c)], width=400, height=400) display(renderer)
def renderScene(items: List[Mesh], width: int = WIDTH, height: int = HEIGHT, camera_z: float = CAM_Z, mid_point: List[float] = [0, 0, 0]) -> Renderer: c = PerspectiveCamera(fov=90, aspect=width / height, near=1, far=1000, position=[0, 0, camera_z], up=[0, 1, 0], children=[ DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5) ]) for x in items: x.position = [x.position[i] - mid_point[i] for i in range(3)] scene = Scene(children=items + [c, AmbientLight(color='#777777')], background='#000000') renderer = Renderer(camera=c, scene=scene, width=width, height=height, controls=[OrbitControls(controlling=c)]) # scene = Scene(children=items+[c, AmbientLight(color='#777777')]) # renderer = WebGLRenderer(camera=c, # scene=scene, # width=width, height=height, # controls=[OrbitControls(controlling=c)], # alpha=True) # renderer.setClearColor('#000000', 0.5) renderer.render(scene, c) return renderer, scene, c
def DisplayMesh(self, mesh, color=default_mesh_color): """ Display a MEFISTO2 triangle mesh """ if not HAVE_SMESH: print("SMESH not installed, DisplayMesh method unavailable.") return if not isinstance(mesh, SMESH_Mesh): raise AssertionError("You mush provide an SMESH_Mesh instance") mesh_ds = mesh.GetMeshDS() # the mesh data source face_iter = mesh_ds.facesIterator() # vertices positions are stored to a liste vertices_position = [] for _ in range(mesh_ds.NbFaces()-1): face = face_iter.next() #print('Face %i, type %i' % (i, face.GetType())) #print(dir(face)) # if face.GetType == 3 : triangle mesh, then 3 nodes for j in range(3): node = face.GetNode(j) #print('Coordinates of node %i:(%f,%f,%f)'%(i, node.X(), node.Y(), node.Z())) vertices_position.append(node.X()) vertices_position.append(node.Y()) vertices_position.append(node.Z()) number_of_vertices = len(vertices_position) # then we build the vertex and faces collections as numpy ndarrays np_vertices = np.array(vertices_position, dtype='float32').reshape(int(number_of_vertices / 3), 3) # Note: np_faces is just [0, 1, 2, 3, 4, 5, ...], thus arange is used np_faces = np.arange(np_vertices.shape[0], dtype='uint32') # set geometry properties buffer_geometry_properties = {'position': BufferAttribute(np_vertices), 'index' : BufferAttribute(np_faces)} # build a BufferGeometry instance mesh_geometry = BufferGeometry(attributes=buffer_geometry_properties) mesh_geometry.exec_three_obj_method('computeVertexNormals') # then a default material mesh_material = MeshPhongMaterial(color=color, polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, shininess=0.5, wireframe=False, side='DoubleSide') edges_material = MeshPhongMaterial(color='black', polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, shininess=0.5, wireframe=True) # create a mesh unique id mesh_id = uuid.uuid4().hex # finally create the mash shape_mesh = Mesh(geometry=mesh_geometry, material=mesh_material, name=mesh_id) edges_mesh = Mesh(geometry=mesh_geometry, material=edges_material, name=mesh_id) # a special display for the mesh camera_target = [0., 0., 0.] # the point to look at camera_position = [0, 0., 100.] # the camera initial position camera = PerspectiveCamera(position=camera_position, lookAt=camera_target, up=[0, 0, 1], fov=50, children=[DirectionalLight(color='#ffffff', position=[50, 50, 50], intensity=0.9)]) scene_shp = Scene(children=[shape_mesh, edges_mesh, camera, AmbientLight(color='#101010')]) renderer = Renderer(camera=camera, background=self._background, background_opacity=self._background_opacity, scene=scene_shp, controls=[OrbitControls(controlling=camera, target=camera_target)], width=self._size[0], height=self._size[1], antialias=True) display(renderer)
def Display(self, position=None, rotation=None): # Get the overall bounding box if self._shapes: self._bb = BoundingBox([self._shapes.values()]) else: # if nothing registered yet, create a fake bb self._bb = BoundingBox([[BRepPrimAPI_MakeSphere(5.).Shape()]]) bb_max = self._bb.max orbit_radius = 1.5 * self._bb._max_dist_from_center() # Set up camera camera_target = self._bb.center camera_position = _add( self._bb.center, self._scale( [1, 1, 1] if position is None else self._scale(position))) camera_zoom = self._camera_initial_zoom self._camera = CombinedCamera(position=camera_position, width=self._size[0], height=self._size[1]) self._camera.up = (0.0, 0.0, 1.0) self._camera.mode = 'orthographic' self._camera_target = camera_target self._camera.position = camera_position if rotation is not None: self._camera.rotation = rotation # Set up lights in every of the 8 corners of the global bounding box positions = list( itertools.product(*[(-orbit_radius, orbit_radius)] * 3)) key_lights = [ DirectionalLight(color='white', position=pos, intensity=0.5) for pos in positions ] ambient_light = AmbientLight(intensity=0.1) # Set up Helpers self.axes = Axes(bb_center=self._bb.center, length=bb_max * 1.1) self.horizontal_grid = Grid(bb_center=self._bb.center, maximum=bb_max, colorCenterLine='#aaa', colorGrid='#ddd') self.vertical_grid = Grid(bb_center=self._bb.center, maximum=bb_max, colorCenterLine='#aaa', colorGrid='#ddd') # Set up scene environment = self.axes.axes + key_lights + [ ambient_light, self.horizontal_grid.grid, self.vertical_grid.grid, self._camera ] scene_shp = Scene(children=[ self._displayed_pickable_objects, self._displayed_non_pickable_objects ] + environment) # Set up Controllers self._controller = OrbitControls(controlling=self._camera, target=camera_target, target0=camera_target) # Update controller to instantiate camera position self._camera.zoom = camera_zoom self._update() # setup Picker self._picker = Picker(controlling=self._displayed_pickable_objects, event='dblclick') self._picker.observe(self.click) self._renderer = Renderer(camera=self._camera, background=self._background, background_opacity=self._background_opacity, scene=scene_shp, controls=[self._controller, self._picker], width=self._size[0], height=self._size[1], antialias=True) # set rotation and position for each grid self.horizontal_grid.set_position((0, 0, 0)) self.horizontal_grid.set_rotation((math.pi / 2.0, 0, 0, "XYZ")) self.vertical_grid.set_position((0, -bb_max, 0)) self._savestate = (self._camera.rotation, self._controller.target) # then display both 3d widgets and webui display(HBox([VBox([HBox(self._controls), self._renderer]), self.html]))
class CadqueryView(object): def __init__( self, width=600, height=400, bb_factor=1.01, quality=0.1, angular_tolerance=0.1, edge_accuracy=0.01, optimal_bb=True, render_edges=True, render_shapes=True, info=None, position=None, rotation=None, zoom=None, timeit=False, ): self.width = width self.height = height self.quality = quality self.bb_factor = bb_factor self.angular_tolerance = angular_tolerance self.edge_accuracy = edge_accuracy self.optimal_bb = optimal_bb self.render_edges = render_edges self.render_shapes = render_shapes self.info = info self.position = position self.rotation = rotation self.zoom = zoom self.timeit = timeit self.all_shapes = None self.pick_color = Color("LightGreen") self.default_mesh_color = Color((232, 176, 36)) self.default_edge_color = Color((128, 128, 128)) self.camera_distance_factor = 6 self.camera_initial_zoom = 2.5 self.features = ["mesh", "edges"] self.bb = None self.pickable_objects = None self.pick_last_mesh = None self.pick_last_mesh_color = None self.pick_mapping = {} self.camera = None self.axes = None self.grid = None self.scene = None self.controller = None self.renderer = None self.camera_position = None self.zoom = None self.savestate = None def get_transparent(self): # if one object is transparent, all are return self.pickable_objects.children[0].material.transparent def _scale(self, vec): r = self.bb.max_dist_from_center() * self.camera_distance_factor n = np.linalg.norm(vec) new_vec = [v / n * r for v in vec] return new_vec def _add(self, vec1, vec2): return list(v1 + v2 for v1, v2 in zip(vec1, vec2)) def _sub(self, vec1, vec2): return list(v1 - v2 for v1, v2 in zip(vec1, vec2)) def _norm(self, vec): n = np.linalg.norm(vec) return [v / n for v in vec] def _minus(self, vec): return [-v for v in vec] def direction(self): return self._norm(self._sub(self.camera.position, self.bb.center)) def set_plane(self, i): plane = self.clippingPlanes[i] plane.normal = self._minus(self.direction()) def _update(self): self.controller.exec_three_obj_method("update") pass def _fix_camera(self): zoom = self.camera.zoom # force the camera to zoom correctly. Seems to be a bug. self.camera.zoom = zoom + 1e-6 self.camera.zoom = zoom def _reset(self): self.camera.rotation, self.controller.target = self.savestate self.camera.position = self._add(self.bb.center, self._scale( (1, 1, 1))) self.camera.zoom = self.camera_initial_zoom self._update() def _get_group(self, group_index): try: group = self.pickable_objects for j in group_index: group = group.children[j] return group except: return None def set_axes_visibility(self, value): self.axes.set_visibility(value) def set_grid_visibility(self, value): self.grid.set_visibility(value) def set_axes_center(self, value): self.grid.set_center(value) self.axes.set_center(value) def toggle_ortho(self, value): self.camera.mode = "orthographic" if value else "perspective" def set_transparent(self, value): def toggle(group, value): for obj in group.children: if isinstance(obj, Group): toggle(obj, value) else: if isinstance(obj, Mesh): obj.material.transparent = value toggle(self.pickable_objects, value) def set_black_edges(self, value): def toggle(group, value): for obj in group.children: if isinstance(obj, Group): toggle(obj, value) else: if isinstance(obj, LineSegments2): if obj.material.linewidth == 1: obj.material.color = "#000" if value else self.default_edge_color.web_color toggle(self.pickable_objects, value) def set_visibility(self, ind, i, state): feature = self.features[i] group_index = self.pick_mapping[ind][feature] group = self._get_group(group_index) if group is not None: group.visible = state == 1 def change_visibility(self, paths): def f(states): diffs = state_diff(states.get("old"), states.get("new")) for diff in diffs: [[obj, val]] = diff.items() self.set_visibility(paths[obj], val["icon"], val["new"]) return f def set_clipping(self, tab): if tab == 0: self.renderer.clippingPlanes = [] else: self.renderer.clippingPlanes = self.clippingPlanes def _get_shape(self, shape_index): shape = self.shapes try: for j in shape_index: shape = shape["parts"][j] except: return None return shape def pick(self, value): if self.pick_last_mesh != value.owner.object: # Reset if value.owner.object is None or self.pick_last_mesh is not None: self.pick_last_mesh.material.color = self.pick_last_mesh_color self.pick_last_mesh = None self.pick_last_mesh_color = None # Change highlighted mesh if isinstance(value.owner.object, Mesh): self.pick_last_mesh = value.owner.object shape = self._get_shape(value.owner.object.ind["shape"]) bbox = BoundingBox([shape["shape"]]) self.info.bb_info( shape["name"], ( (bbox.xmin, bbox.xmax), (bbox.ymin, bbox.ymax), (bbox.zmin, bbox.zmax), bbox.center, ), ) self.pick_last_mesh_color = self.pick_last_mesh.material.color self.pick_last_mesh.material.color = self.pick_color.web_color def clip(self, index): def f(change): self.clippingPlanes[index].constant = change["new"] return f # public methods to render the view def is_ortho(self): return self.camera.mode == "orthographic" def is_transparent(self): return self.pickable_objects.children[0].material.transparent def create(self): self.cq_renderer = CadqueryRenderer( quality=self.quality, angular_tolerance=self.angular_tolerance, edge_accuracy=self.edge_accuracy, render_edges=self.render_edges, render_shapes=self.render_shapes, default_mesh_color=self.default_mesh_color, default_edge_color=self.default_edge_color, timeit=self.timeit, ) # Set up camera self.camera = CombinedCamera( position=(1.0, 1.0, 1.0), width=self.width, height=self.height, far=100, orthoFar=100, up=(0.0, 0.0, 1.0), ) # needs to be an extra step to take effect self.toggle_ortho(True) # Set up scene self.scene = Scene(children=[self.camera, AmbientLight(intensity=1.0)]) # Set up Controllers camera_target = (0.0, 0.0, 0.0) self.controller = OrbitControls(controlling=self.camera, target=camera_target, target0=camera_target) # Create Renderer instance self.renderer = Renderer( scene=self.scene, camera=self.camera, controls=[self.controller], antialias=True, width=self.width, height=self.height, ) return self.renderer def add_shapes(self, shapes, progress, position=None, rotation=None, zoom=2.5, reset=True): def all_shapes(shapes, loc=None): loc = shapes["loc"] if loc is None else loc * shapes["loc"] result = [] for shape in shapes["parts"]: if shape.get("parts") is None: compounds = [ c for c in shape["shape"] if is_compound(c) or is_solid(c) or is_shape(c) ] if compounds: if loc is None: result.append(shape["shape"]) else: reloc_shape = [ Shape(s).moved(loc).wrapped for s in compounds ] result.append(reloc_shape) else: result += all_shapes(shape, loc) return result self.shapes = shapes self.all_shapes = all_shapes(shapes) # Render Shapes render_timer = Timer(self.timeit, "| overall render time") self.pickable_objects, self.pick_mapping = self.cq_renderer.render( self.shapes, progress) render_timer.stop() progress.update() bb_timer = Timer(self.timeit, "| create bounding box") # Get bounding box self.bb = self.get_bounding_box(self.all_shapes) bb_timer.stop() progress.update() configure_timer = Timer(self.timeit, "| configure view") bb_max = self.bb.max_dist_from_center() orbit_radius = 4 * self.bb_factor * bb_max # Calculate camera postion if position is None and rotation is None: # no new defaults if reset or self.camera_position is None: # no existing position self.camera_position = self._add(self.bb.center, self._scale((1, 1, 1))) else: position = rotate(position or (1, 1, 1), *(rotation or (0, 0, 0))) self.camera_position = self._add(self.bb.center, self._scale(position)) if reset or self.zoom is None: self.zoom = zoom # Set up Helpers relative to bounding box xy_max = max(abs(self.bb.xmin), abs(self.bb.xmax), abs(self.bb.ymin), abs(self.bb.ymax)) * 1.2 self.grid = Grid( bb_center=self.bb.center, maximum=xy_max, colorCenterLine="#aaa", colorGrid="#ddd", ) self.grid.set_visibility(False) self.axes = Axes(bb_center=self.bb.center, length=self.grid.grid.size / 2) self.axes.set_visibility(False) # Set up the controller relative to bounding box self.controller.target = self.bb.center self.controller.target0 = self.bb.center # Set up lights in every of the 8 corners of the global bounding box positions = list( itertools.product(*[(-orbit_radius, orbit_radius)] * 3)) self.key_lights = [ DirectionalLight(color="white", position=position, intensity=0.12) for position in positions ] # Set up Picker self.picker = Picker(controlling=self.pickable_objects, event="dblclick") self.picker.observe(self.pick) self.renderer.controls = self.renderer.controls + [self.picker] # Set up camera self.update_camera(self.camera_position, self.zoom, orbit_radius) # Add objects to scene self._fix_camera() self.add_to_scene() # needs to be done after setup of camera self.grid.set_rotation((math.pi / 2.0, 0, 0, "XYZ")) self.grid.set_position((0, 0, 0)) self.renderer.localClippingEnabled = True self.renderer.clippingPlanes = [] # turn off when not in clipping view self.clippingPlanes = [ Plane((-1, 0, 0), 0.02 if abs(self.bb.xmax) < 1e-4 else self.bb.xmax * self.bb_factor), Plane((0, -1, 0), 0.02 if abs(self.bb.ymax) < 1e-4 else self.bb.ymax * self.bb_factor), Plane((0, 0, -1), 0.02 if abs(self.bb.zmax) < 1e-4 else self.bb.zmax * self.bb_factor), ] self.savestate = (self.camera.rotation, self.controller.target) configure_timer.stop() progress.update() return self.renderer def get_bounding_box(self, shapes): bb = BoundingBox(shapes, optimal=self.optimal_bb) if bb.is_empty(): # add origin to increase bounding box to also show origin bb = BoundingBox([[Vertex.makeVertex(0, 0, 0).wrapped]] + [shape["shape"] for shape in self.shapes]) if bb.is_empty(): # looks like only one vertex in origin is to be shown bb = BoundingBox([[Vertex.makeVertex(0.1, 0.1, 0.1).wrapped]] + [shape["shape"] for shape in self.shapes]) return bb def update_camera(self, position, zoom, orbit_radius): self.camera.position = position self.camera.zoom = zoom self.camera.far = 10 * orbit_radius self.camera.orthoFar = 10 * orbit_radius self._update() def add_to_scene(self): self.scene.add(self.key_lights) self.scene.add(self.axes.axes) self.scene.add(self.grid.grid) self.scene.add(self.pickable_objects) def clear(self): # save camera position and zoom in case we want to keep it for the object self.zoom = self.camera.zoom self.camera_position = self.camera.position self.scene.remove(self.key_lights) self.scene.remove(self.axes.axes) self.scene.remove(self.grid.grid) self.scene.remove(self.pickable_objects) @property def root_group(self): return self.pickable_objects
def visualize(self): """Start the visualization and initialize widgets""" from pythreejs import PlainGeometry, Mesh, LambertMaterial, \ PhongMaterial, DirectionalLight, \ PerspectiveCamera, Scene, AmbientLight, \ Renderer, OrbitControls, Line, \ LineBasicMaterial, BoxGeometry, make_text from matplotlib import colors from matplotlib import cm from IPython.display import display import numpy as np import ipywidgets as widgets bbox = self._compute_bounding_box() diam = bbox[1, :] - bbox[0, :] center = .5 * _np.sum(bbox, axis=0) xmin, ymin, zmin = bbox[0, :] xmax, ymax, zmax = bbox[1, :] position = (center + 2.5 * diam).tolist() # Generate coordinate system base box = PlainGeometry( vertices=_np.array([[xmin, ymin, zmin], [xmax, ymin, zmin], [xmin, ymin, zmin], [xmin, ymax, zmin], [xmin, ymin, zmin], [xmin, ymin, zmax]]), colors=['red', 'red', 'green', 'green', 'blue', 'blue']) self._coord_box = Line(geometry=box, material=LineBasicMaterial( linewidth=10, vertexColors='VertexColors'), type='LinePieces') if self.data is not None: vis_data = self.data if not self.is_real: vis_data = _np.real(self.data) if not self.is_scalar: vis_data = _np.sum(_np.abs(self.data)**2, axis=2) self._vis_data = vis_data self._cmap = cm.jet self._vmin = vis_data.min() self._vmax = vis_data.max() cnorm = colors.Normalize(vmin=self._vmin, vmax=self._vmax) facecolors = self._convert_data_to_colors(self._cmap, cnorm, vis_data) else: facecolors = self.elements.shape[0] * [ 3 * [_np.array([1., 1., 1.])] ] self._geom = PlainGeometry(vertices=self.vertices, faces=self.elements, faceColors=facecolors) self._mesh = Mesh( geometry=self._geom, material=LambertMaterial(vertexColors='VertexColors')) self._wireframe = Mesh(geometry=self._geom, material=PhongMaterial(wireframe=True, color='black')) light = DirectionalLight(color='white', position=position, intensity=0.5) camera = PerspectiveCamera(position=position, fov=20) self._scene = Scene(children=[ self._coord_box, self._mesh, self._wireframe, AmbientLight(color='white') ]) self._renderer = Renderer(camera=camera, background='white', background_opacity=1, scene=self._scene, controls=[OrbitControls(controlling=camera)]) self._axes_info = widgets.Label(value="x: red; y: green; z: blue") coord_system_toggle = widgets.Checkbox( value=self._coord_box.visible, description='Show coordinate axes', disabled=False) coord_system_toggle.observe(self.on_toggle_coord_system, names='value') if self.data is not None: # Enable/Disable wireframe wireframe_toggle = widgets.Checkbox(value=self._wireframe.visible, description='Enable wireframe', disabled=False) wireframe_toggle.observe(self.on_toggle_wireframe, names='value') # Change vmin/vmax vmin_box = widgets.FloatText(value=self._vmin, description='vmin:', disabled=False) vmin_box.observe(self.on_change_vmin, names='value') vmax_box = widgets.FloatText(value=self._vmax, description='vmax:', disabled=False) vmax_box.observe(self.on_change_vmax, names='value') vmin_info = widgets.Label( value='Lower bound: {0}'.format(self._vmin)) vmax_info = widgets.Label( value='Upper bound: {0}'.format(self._vmax)) range_info_box = widgets.VBox([vmin_info, vmax_info]) range_change = widgets.HBox([vmin_box, vmax_box]) toggles = widgets.HBox([wireframe_toggle, coord_system_toggle]) vbox = widgets.VBox( [self._axes_info, range_info_box, range_change, toggles]) display(self._renderer, vbox) else: display(self._renderer, self._axes_info, coord_system_toggle)
def Display(self): # Get the overall bounding box if self._shapes: self._bb = BoundingBox([self._shapes.values()]) else: # if nothing registered yet, create a fake bb self._bb = BoundingBox([[BRepPrimAPI_MakeSphere(5.).Shape()]]) bb_max = self._bb.max bb_diag = 2 * self._bb.diagonal # Set up camera camera_target = self._bb.center camera_position = self._scale([1, 1, 1]) self._camera = CombinedCamera(position=camera_position, width=self._size[0], height=self._size[1], far=10 * bb_diag, orthoFar=10 * bb_diag) self._camera.up = (0.0, 0.0, 1.0) self._camera.lookAt(camera_target) self._camera.mode = 'orthographic' self._camera_target = camera_target self._camera.position = camera_position # Set up lights in every of the 8 corners of the global bounding box key_lights = [ DirectionalLight(color='white', position=position, intensity=0.12) for position in list(itertools.product((-bb_diag, bb_diag), (-bb_diag, bb_diag), (-bb_diag, bb_diag))) ] ambient_light = AmbientLight(intensity=1.0) # Set up Helpers self.axes = Axes(bb_center=self._bb.center, length=bb_max * 1.1) self.grid = Grid(bb_center=self._bb.center, maximum=bb_max, colorCenterLine='#aaa', colorGrid='#ddd') # Set up scene environment = self.axes.axes + key_lights + [ambient_light, self.grid.grid, self._camera] scene_shp = Scene(children=[self._displayed_pickable_objects, self._displayed_non_pickable_objects] + environment) # Set up Controllers self._controller = OrbitControls(controlling=self._camera, target=camera_target) self._renderer = Renderer(camera=self._camera, background=self._background, background_opacity=self._background_opacity, scene=scene_shp, controls=[self._controller, self._picker], width=self._size[0], height=self._size[1], antialias=True) # needs to be done after setup of camera self.grid.set_rotation((math.pi / 2.0, 0, 0, "XYZ")) self.grid.set_position((0, 0, 0)) # Workaround: Zoom forth and back to update frame. Sometimes necessary :( self._camera.zoom = 1.01 self._update() self._camera.zoom = 1.0 self._update() # then display both 3d widgets and webui display(HBox([self._renderer, self.html]))
def build_display(self, position=None, rotation=None, camera_type="orthographic"): """ :param position: Camera Position :param rotation: Camera Rotation :param camera_type: Camera Type "orthographic" or "perspective" """ import itertools import math from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere from OCC.Display.WebGl.jupyter_renderer import Axes, Grid, _add from pythreejs import ( AmbientLight, CombinedCamera, DirectionalLight, OrbitControls, Picker, Renderer, Scene, ) # Get the overall bounding box if self._shapes: self._bb = BoundingBox([self._shapes.values()]) else: # if nothing registered yet, create a fake bb self._bb = BoundingBox([[BRepPrimAPI_MakeSphere(5.0).Shape()]]) bb_max = self._bb.max orbit_radius = 1.5 * self._bb._max_dist_from_center() # Set up camera camera_target = self._bb.center camera_position = _add( self._bb.center, self._scale( [1, 1, 1] if position is None else self._scale(position))) camera_zoom = self._camera_initial_zoom self._camera = CombinedCamera(position=camera_position, width=self._size[0], height=self._size[1]) self._camera.up = (0.0, 0.0, 1.0) self._camera.mode = camera_type self._camera_target = camera_target self._camera.position = camera_position if rotation is not None: self._camera.rotation = rotation # Set up lights in every of the 8 corners of the global bounding box positions = list( itertools.product(*[(-orbit_radius, orbit_radius)] * 3)) key_lights = [ DirectionalLight(color="white", position=pos, intensity=0.5) for pos in positions ] ambient_light = AmbientLight(intensity=0.1) # Set up Helpers self.axes = Axes(bb_center=self._bb.center, length=bb_max * 1.1) self.horizontal_grid = Grid(bb_center=self._bb.center, maximum=bb_max, colorCenterLine="#aaa", colorGrid="#ddd") self.vertical_grid = Grid(bb_center=self._bb.center, maximum=bb_max, colorCenterLine="#aaa", colorGrid="#ddd") # Set up scene temp_elems = [ ambient_light, self.horizontal_grid.grid, self.vertical_grid.grid, self._camera ] environment = self.axes.axes + key_lights + temp_elems scene_shp = Scene(children=[ self._displayed_pickable_objects, self._displayed_non_pickable_objects ] + environment) # Set up Controllers inf = 1e20 orbit_controls = OrbitControls( controlling=self._camera, target=camera_target, target0=camera_target, maxAzimuthAngle=inf, maxDistance=inf, maxZoom=inf, minAzimuthAngle=-inf, ) self._controller = orbit_controls # Update controller to instantiate camera position self._camera.zoom = camera_zoom self._update() # setup Picker self._picker = Picker(controlling=self._displayed_pickable_objects, event="dblclick") self._picker.observe(self.click) self._renderer = Renderer( camera=self._camera, background=self._background, background_opacity=self._background_opacity, scene=scene_shp, controls=[self._controller, self._picker], width=self._size[0], height=self._size[1], antialias=True, ) # set rotation and position for each grid self.horizontal_grid.set_position((0, 0, 0)) self.horizontal_grid.set_rotation((math.pi / 2.0, 0, 0, "XYZ")) self.vertical_grid.set_position((0, -bb_max, 0)) self._savestate = (self._camera.rotation, self._controller.target)
def render(self, position=None, rotation=None, zoom=2.5): self.camera_initial_zoom = zoom start_render_time = self._start_timer() # Render all shapes for i, shape in enumerate(self.shapes): s = shape["shape"] # Assume that all are edges when first element is an edge if is_edge(s[0]): self._render_shape(i, edges=s, render_edges=True, edge_color=shape["color"], edge_width=3) elif is_vertex(s[0]): self._render_shape(i, vertices=s, render_edges=False, vertex_color=shape["color"], vertex_width=6) else: # shape has only 1 object, hence first=True self._render_shape(i, shape=s[0], render_edges=True, mesh_color=shape["color"]) # Get the overall bounding box self.bb = BoundingBox([shape["shape"] for shape in self.shapes]) bb_max = self.bb.max orbit_radius = 2 * self.bb.max_dist_from_center() # Set up camera camera_target = self.bb.center camera_up = (0.0, 0.0, 1.0) if rotation != (0, 0, 0): position = rotate(position, *rotation) camera_position = self._add( self.bb.center, self._scale( [1, 1, 1] if position is None else self._scale(position))) self.camera = CombinedCamera( position=camera_position, width=self.width, height=self.height # far=10 * orbit_radius, # orthoFar=10 * orbit_radius ) self.camera.up = camera_up self.camera.mode = 'orthographic' self.camera.position = camera_position # Set up lights in every of the 8 corners of the global bounding box positions = list( itertools.product(*[(-orbit_radius, orbit_radius)] * 3)) key_lights = [ DirectionalLight(color='white', position=position, intensity=0.12) for position in positions ] ambient_light = AmbientLight(intensity=1.0) # Set up Helpers self.axes = Axes(bb_center=self.bb.center, length=bb_max * 1.1) self.grid = Grid(bb_center=self.bb.center, maximum=bb_max, colorCenterLine='#aaa', colorGrid='#ddd') # Set up scene environment = self.axes.axes + key_lights + [ ambient_light, self.grid.grid, self.camera ] self.scene = Scene(children=environment + [self.pickable_objects]) # Set up Controllers self.controller = OrbitControls(controlling=self.camera, target=camera_target, target0=camera_target) # Update controller to instantiate camera position self.camera.zoom = zoom self._update() self.picker = Picker(controlling=self.pickable_objects, event='dblclick') self.picker.observe(self.pick) # Create Renderer instance self.renderer = Renderer(scene=self.scene, camera=self.camera, controls=[self.controller, self.picker], antialias=True, width=self.width, height=self.height) self.renderer.localClippingEnabled = True self.renderer.clippingPlanes = [ Plane((1, 0, 0), self.grid.size / 2), Plane((0, 1, 0), self.grid.size / 2), Plane((0, 0, 1), self.grid.size / 2) ] # needs to be done after setup of camera self.grid.set_rotation((math.pi / 2.0, 0, 0, "XYZ")) self.grid.set_position((0, 0, 0)) self.savestate = (self.camera.rotation, self.controller.target) self._stop_timer("overall render time", start_render_time) return self.renderer
def get_objects_renderer( root_node: coin.SoSeparator, names: List[str], renderer_config: RendererConfig = RendererConfig() ) -> Tuple[Renderer, HTML]: """ Return a `Renderer` and `HTML` for rendering any coin root node of a scene graph containing LineSets or FaceSets inside Jupyter notebook. """ view_width = renderer_config.view_width view_height = renderer_config.view_height geometries = Group() part_indices = [ ] # contains the partIndex indices that relate triangle faces to shape faces render_face_set = True i = 0 for res in bfs_traversal(root_node, print_tree=False): if isinstance(res[0], coin.SoIndexedFaceSet) and render_face_set: render_face_set = False continue if isinstance(res[0], coin.SoIndexedFaceSet): render_face_set = True part_index_list = list(res[0].partIndex) part_indices.append(part_index_list) elif isinstance(res[0], coin.SoIndexedLineSet): pass else: continue geoms = create_geometry(res, show_edges=renderer_config.show_edges, show_faces=renderer_config.show_faces) for obj3d in geoms: obj3d.name = str(res[3]) + " " + str( i) #the name of the object is `object_index i` i += 1 for geom in geoms: if renderer_config.show_normals: helper = VertexNormalsHelper(geom) geometries.add(helper) if renderer_config.show_mesh and not isinstance(geom, Line): geometries.add(get_line_geometries(geom)) else: geometries.add(geom) light = PointLight(color="white", position=[40, 40, 40], intensity=1.0, castShadow=True) ambient_light = AmbientLight(intensity=0.5) camera = PerspectiveCamera(position=[0, -40, 20], fov=40, aspect=view_width / view_height) children = [camera, light, ambient_light] children.append(geometries) scene = Scene(children=children) scene.background = "#65659a" controls = [OrbitControls(controlling=camera)] html = HTML() if renderer_config.selection_mode: html, picker = generate_picker(geometries, part_indices, "mousemove") controls.append(picker) renderer = Renderer(camera=camera, scene=scene, controls=controls, width=view_width, height=view_height) return (renderer, html)
def render(self, position=None, rotation=None, zoom=None): # Render all shapes for i, shape in enumerate(self.shapes): s = shape["shape"] # Assume that all are edges when first element is an edge if is_edge(s[0]): self._render_shape(i, edges=s, render_edges=True, edge_color=shape["color"], edge_width=3) elif is_vertex(s[0]): self._render_shape(i, vertices=s, render_edges=False, vertex_color=shape["color"], vertex_width=6) else: # shape has only 1 object, hence first=True self._render_shape(i, shape=s[0], render_edges=True, mesh_color=shape["color"]) # Get the overall bounding box self.bb = BoundingBox([shape["shape"] for shape in self.shapes]) bb_max = self.bb.max bb_diag = 2 * self.bb.diagonal # Set up camera camera_target = self.bb.center camera_position = self._scale( [1, 1, 1] if position is None else position) camera_zoom = 1.0 if zoom is None else zoom self.camera = CombinedCamera(position=camera_position, width=self.width, height=self.height, far=10 * bb_diag, orthoFar=10 * bb_diag) self.camera.up = (0.0, 0.0, 1.0) self.camera.lookAt(camera_target) self.camera.mode = 'orthographic' self.camera.position = camera_position if rotation is not None: self.camera.rotation = rotation # Set up lights in every of the 8 corners of the global bounding box key_lights = [ DirectionalLight(color='white', position=position, intensity=0.12) for position in list( itertools.product((-bb_diag, bb_diag), (-bb_diag, bb_diag), (-bb_diag, bb_diag))) ] ambient_light = AmbientLight(intensity=1.0) # Set up Helpers self.axes = Axes(bb_center=self.bb.center, length=bb_max * 1.1) self.grid = Grid(bb_center=self.bb.center, maximum=bb_max, colorCenterLine='#aaa', colorGrid='#ddd') # Set up scene environment = self.axes.axes + key_lights + [ ambient_light, self.grid.grid, self.camera ] self.scene = Scene(children=environment + [self.pickable_objects]) # Set up Controllers self.controller = OrbitControls(controlling=self.camera, target=camera_target) self.picker = Picker(controlling=self.pickable_objects, event='dblclick') self.picker.observe(self.pick) # Create Renderer instance self.renderer = Renderer(scene=self.scene, camera=self.camera, controls=[self.controller, self.picker], antialias=True, width=self.width, height=self.height) self.renderer.localClippingEnabled = True self.renderer.clippingPlanes = [ Plane((1, 0, 0), self.grid.size / 2), Plane((0, 1, 0), self.grid.size / 2), Plane((0, 0, 1), self.grid.size / 2) ] # needs to be done after setup of camera self.grid.set_rotation((math.pi / 2.0, 0, 0, "XYZ")) self.grid.set_position((0, 0, 0)) self.savestate = (self.camera.rotation, self.controller.target) # Workaround: Zoom forth and back to update frame. Sometimes necessary :( self.camera.zoom = camera_zoom + 0.01 self._update() self.camera.zoom = camera_zoom self._update() return self.renderer