Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
 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)
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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]))
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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]))
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
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)
Ejemplo n.º 20
0
    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