Example #1
0
def virtualHelixMesh(pos1,
                     pos2,
                     radius: float = 1.0,
                     color: str = 'red') -> Mesh:
    pos1 = np.array(pos1, dtype=float)
    pos2 = np.array(pos2, dtype=float)
    delta = pos2 - pos1
    dist = np.linalg.norm(delta)
    c_geometry = CylinderBufferGeometry(radiusTop=radius,
                                        radiusBottom=radius,
                                        height=dist,
                                        radiusSegments=16)
    # print(c_geometry.height)
    v2 = normalize(delta)

    # NOTE default direction in Three.js is the Y direction for geometry
    v1 = np.array((0, 1, 0))

    # Calculate angle between Vectors
    angle = math.atan2(np.dot(np.cross(v1, v2), v1), np.dot(v1, v2))

    normal_vec = normalize(np.cross(v1, v2)).tolist()

    mid_point = (pos2 + pos1) / 2
    xAxis = [mid_point[0], 0, 0]
    yAxis = [0, mid_point[1], 0]
    zAxis = [0, 0, mid_point[2]]

    mesh = Mesh(geometry=c_geometry, material=MeshLambertMaterial(color=color))

    rotm = rotationMatrix(v2)
    mesh.setRotationFromMatrix(threeMatrix(rotm))
    mesh.position = mid_point.tolist()
    return mesh, mid_point
Example #2
0
 def __init__(self, color='pink', transparent=False):
     Mesh.__init__(self,
                   geometry=PlaneGeometry(),
                   material=MeshBasicMaterial(color=color))
     self.material.side = 'DoubleSide'
     if transparent:
         self.material.transparent = transparent
         self.material.opacity = 0.5
Example #3
0
 def __init__(self, p1, p2, p3, color='yellow'):
     geometry = BufferGeometry(
         attributes={
             'position':
             BufferAttribute(np.vstack((
                 p1, p2, p3)).reshape(3, 3).astype(np.float32),
                             normalized=False)
         })
     material = MeshBasicMaterial(color=color)
     material.side = 'DoubleSide'
     Mesh.__init__(self, geometry=geometry, material=material)
Example #4
0
def create_face_geom(
        coord_vals: SoCoordValsListType,
        face_indices: SoIndicesListType,
        face_color: SoVectorType,
        transparency: float,
        translation: SoVectorType = None,
        quaternion: SoQuaternionType = None
) -> ThreeJSSceneGraphObjectListType:
    """
    Returns a pythreejs `Mesh` object that consists of the faces given by
    face_indices and the coord_vals.
    
    Additionally the attributes `Mesh.default_material` and `Mesh.geometry.default_color`
    will be set before returning the Mesh. Those attributes contain references to the
    default colors and materials that are set in this function to restore later changes.
    """
    vertices = np.asarray(coord_vals, dtype='float32')
    faces = np.asarray(face_indices, dtype='uint16')

    normals = compute_normals(faces, vertices)

    faces = faces.ravel()
    vertexcolors = np.asarray([face_color] * len(coord_vals), dtype='float32')

    face_geometry = BufferGeometry(
        attributes=dict(position=BufferAttribute(vertices, normalized=False),
                        index=BufferAttribute(faces, normalized=False),
                        normal=BufferAttribute(normals, normalized=False),
                        color=BufferAttribute(vertexcolors, normalized=False)))
    # this is used for returning to original state after highlighting
    face_geometry.default_color = vertexcolors

    # BUG: This is a bug in pythreejs and currently does not work
    #faceGeometry.exec_three_obj_method('computeFaceNormals')
    #faceGeometry.exec_three_obj_method('computeVertexNormals')
    col = so_col_to_hex(face_color)
    material = MeshPhongMaterial(color=col,
                                 transparency=transparency,
                                 depthTest=True,
                                 depthWrite=True,
                                 metalness=0)
    object_mesh = Mesh(
        geometry=face_geometry,
        material=material,
        position=[0, 0, 0]  # Center the cube
    )
    object_mesh.default_material = material

    if quaternion:
        object_mesh.quaternion = quaternion
    if translation:
        object_mesh.position = translation
    return [object_mesh]
Example #5
0
def convert_object_to_pythreejs(object):
    """
    Cases for the conversion
    :return:
    """
    obs = []
    if object['type'] == 'spheres':
        for ipos in object['positions']:
            obj3d = Mesh(geometry=SphereBufferGeometry(radius=object['radius'],
                                                       widthSegments=32,
                                                       heightSegments=16),
                         material=MeshLambertMaterial(color=object["color"]),
                         position=ipos)
            obs.append(obj3d)
    elif object['type'] == 'cylinders':
        for ipos in object['positionPairs']:
            obj3d = _get_cylinder_from_vec(ipos[0],
                                           ipos[1],
                                           color=object['color'])
            obs.append(obj3d)
    elif object['type'] == 'lines':
        for ipos, jpos in zip(object['positions'][::2],
                              object['positions'][1::2]):
            obj3d = _get_line_from_vec(ipos, jpos)
            obs.append(obj3d)
    return obs
def convert_object_to_pythreejs(object):
    """
    Cases for the conversion
    :return:
    """
    obs = []
    if object["type"] == "spheres":
        for ipos in object["positions"]:
            obj3d = Mesh(
                geometry=SphereBufferGeometry(radius=object["radius"],
                                              widthSegments=32,
                                              heightSegments=16),
                material=MeshLambertMaterial(color=object["color"]),
                position=ipos,
            )
            obs.append(obj3d)
    elif object["type"] == "cylinders":
        for ipos in object["positionPairs"]:
            obj3d = _get_cylinder_from_vec(ipos[0],
                                           ipos[1],
                                           color=object["color"])
            obs.append(obj3d)
    elif object["type"] == "lines":
        for ipos, jpos in zip(object["positions"][::2],
                              object["positions"][1::2]):
            obj3d = _get_line_from_vec(ipos, jpos)
            obs.append(obj3d)
    else:
        warnings.warn(
            f"Primitive type {object['type']} has not been implemented for this renderer."
        )
    return obs
Example #7
0
def faces_to_mesh(name, vertices, faces, colors, opacity=None):
    """

    :param name:
    :param vertices:
    :param faces:
    :param colors:
    :param opacity:
    :return:
    """
    geometry = BufferGeometry(attributes=dict(
        position=BufferAttribute(vertices, normalized=False),
        index=BufferAttribute(faces, normalized=False),
        color=BufferAttribute(colors),
    ))

    mat_atts = dict(vertexColors="VertexColors", side="DoubleSide")
    if opacity is not None:
        mat_atts["opacity"] = opacity
        mat_atts["transparent"] = True

    material = MeshBasicMaterial(**mat_atts)
    mesh = Mesh(
        name=name,
        geometry=geometry,
        material=material,
    )
    return mesh
Example #8
0
def animate_mesh(mesh, norm_displ_verts, displ_time, displ_magn):
    from pythreejs import (
        AnimationAction,
        AnimationClip,
        AnimationMixer,
        NumberKeyframeTrack,
    )

    mesh.morphAttributes = {
        "position": [
            BufferAttribute(norm_displ_verts),
        ]
    }

    morphed_mesh = Mesh(
        mesh,
        MeshPhongMaterial(color="#ff3333", shininess=150, morphTargets=True))

    pill_track = NumberKeyframeTrack(name=".morphTargetInfluences[0]",
                                     times=displ_time,
                                     values=displ_magn)
    pill_clip = AnimationClip(tracks=[pill_track])
    pill_action = AnimationAction(AnimationMixer(morphed_mesh), pill_clip,
                                  morphed_mesh)

    return pill_action
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
Example #10
0
    def __init__(
        self,
        image: Union[str, np.ndarray],
        center_pos: Coord3 = (0, 0, 0),
        rotation: Coord3 = (0, 0, 0),
        width: float = 10,
        height: float = 10,
        *args,
        **kwargs
        ):
        """
        Plot an image as a plane.

        Arguments:
            image (Union[str, np.ndarray]): The image to plot. This can be a
                URL, a blob, or a numpy array. If it is a numpy array, it must
                be either 2D (greyscale), 3D (RGB), or 4D (RGBA).
            center_pos: Center pos
            rotation: Rotation of the img
                plane, in radians
            width (float: 10): The width of the final rendered plane
            height (float: 10): The height of the final rendered plane

        """
        super().__init__(*args, **kwargs)
        if isinstance(image, str):
            tex = ImageTexture(imageUri=image)
        elif isinstance(image, (list, np.ndarray)):
            if len(image.shape) == 2:
                # handle 2D (grayscale).
                # broadcast to rgba channels:
                image = np.array([image, image, image, np.ones(image.shape)]).T
            elif image.shape[-1] == 3:
                # handle RGB:
                image = np.dstack([image, np.ones(image.shape)])

            tex = DataTexture(data=image.astype(np.float32), type="FloatType")
        else:
            raise ValueError(f"Expected string or array, but got {type(image)}")
        plane = PlaneGeometry(width=width, height=height)
        mat = MeshBasicMaterial(map=tex)
        mesh = Mesh(geometry=plane, material=mat, position=center_pos)
        mesh.rotation = rotation if len(rotation) == 4 else [*rotation, "XYZ"]
        self.center = center_pos
        self.size = (width,height)
        self._objects.append(mesh)
Example #11
0
def _get_cylinder_from_vec(v0, v1, radius=0.15, color="#FFFFFF"):
    v0 = np.array(v0)
    v1 = np.array(v1)
    vec = v1 - v0
    mid_point = (v0 + v1) / 2.
    rot_vec = np.cross([0, 1, 0], vec)
    rot_vec_len = np.linalg.norm(rot_vec)
    rot_vec = rot_vec / rot_vec_len
    rot_arg = np.arccos(np.dot([0, 1, 0], vec) / np.linalg.norm(vec))
    new_bond = Mesh(geometry=CylinderBufferGeometry(radiusTop=radius,
                                                    radiusBottom=radius,
                                                    height=np.linalg.norm(v1 -
                                                                          v0),
                                                    radialSegments=12,
                                                    heightSegments=10),
                    material=MeshLambertMaterial(color=color),
                    position=tuple(mid_point))
    rot = R.from_rotvec(rot_arg * rot_vec)
    new_bond.quaternion = tuple(rot.as_quat())
    return new_bond
Example #12
0
def virtualHelixMesh(   pos1,
                        pos2,
                        radius: float = 1.0,
                        color: str = 'red') -> Mesh:
    pos1 = np.array(pos1, dtype=float)
    pos2 = np.array(pos2, dtype=float)
    delta = pos2 - pos1
    dist = np.linalg.norm(delta)
    c_geometry = CylinderBufferGeometry(  radiusTop=radius,
                                            radiusBottom=radius,
                                            height=dist,
                                            radiusSegments=16
                                    )
    # print(c_geometry.height)
    v2 = normalize(delta)

    # NOTE default direction in Three.js is the Y direction for geometry
    v1 = np.array((0, 1, 0))

    # Calculate angle between Vectors
    angle = math.atan2(
                np.dot(np.cross(v1, v2), v1),
                        np.dot(v1, v2)
            )

    normal_vec = normalize(np.cross(v1, v2)).tolist()

    mid_point = (pos2 + pos1) / 2
    xAxis = [mid_point[0], 0, 0]
    yAxis = [0, mid_point[1], 0]
    zAxis = [0, 0, mid_point[2]]

    mesh = Mesh(geometry=c_geometry,
                material=MeshLambertMaterial(color=color))

    rotm = rotationMatrix(v2)
    mesh.setRotationFromMatrix(threeMatrix(rotm))
    mesh.position = mid_point.tolist()
    return mesh, mid_point
def _get_cylinder_from_vec(v0, v1, d_args=None):
    """Draw the cylinder given the two endpoints.
    
    Args:
        v0 (list): one endpoint of line
        v1 (list): other endpoint of line
        d_args (dict): properties of the line (line_width and color)
    
    Returns:
        Mesh: Pythreejs object that displays the cylinders
    """
    obj_args = update_object_args(d_args, "Cylinders", ['radius', 'color'])
    v0 = np.array(v0)
    v1 = np.array(v1)
    vec = v1 - v0
    mid_point = (v0 + v1) / 2.0
    rot_vec = np.cross([0, 1, 0], vec)
    rot_vec_len = np.linalg.norm(rot_vec)
    rot_vec = rot_vec / rot_vec_len
    rot_arg = np.arccos(np.dot([0, 1, 0], vec) / np.linalg.norm(vec))
    new_bond = Mesh(
        geometry=CylinderBufferGeometry(
            radiusTop=obj_args['radius'],
            radiusBottom=obj_args['radius'],
            height=np.linalg.norm(v1 - v0),
            radialSegments=12,
            heightSegments=10,
        ),
        material=MeshLambertMaterial(color=obj_args['color']),
        position=tuple(mid_point),
    )
    rot = R.from_rotvec(rot_arg * rot_vec)
    quat = tuple(rot.as_quat())
    if any(isnan(itr_q) for itr_q in quat):
        new_bond.quaternion = (0, 0, 0, 0)
    else:
        new_bond.quaternion = quat

    return new_bond
Example #14
0
 def _load_mesh(self, dae, scale):
     materials = self._load_material(dae)
     for geometry in dae.geometries:
         for primitive in geometry.primitives:
             vertices = primitive.vertex[primitive.vertex_index] * scale
             normals = primitive.normal[primitive.normal_index]
             buffer_geometry = BufferGeometry(
                 attributes={
                     'position': BufferAttribute(array=vertices),
                     'normal': BufferAttribute(array=normals)
                 })
             material = materials[primitive.material]
             mesh = Mesh(geometry=buffer_geometry, material=material)
             self.add(mesh)
Example #15
0
    def occ_shape_to_threejs(self, shp: TopoDS_Shape, shape_color, edge_color,
                             transparency, opacity):
        # first, compute the tesselation
        from .renderer_occ import occ_shape_to_faces
        from .threejs_utils import create_material

        np_vertices, np_faces, np_normals, edges = occ_shape_to_faces(
            shp, self.quality, self.render_edges, self.parallel)

        # set geometry properties
        buffer_geometry_properties = {
            "position": BufferAttribute(np_vertices),
            "index": BufferAttribute(np_faces),
        }
        if self.compute_normals_mode == NORMAL.SERVER_SIDE:
            if np_normals.shape != np_vertices.shape:
                raise AssertionError("Wrong number of normals/shapes")
            buffer_geometry_properties["normal"] = BufferAttribute(np_normals)

        # build a BufferGeometry instance
        shape_geometry = BufferGeometry(attributes=buffer_geometry_properties)

        # if the client has to render normals, add the related js instructions
        if self.compute_normals_mode == NORMAL.CLIENT_SIDE:
            shape_geometry.exec_three_obj_method("computeVertexNormals")

        # then a default material
        shp_material = create_material(shape_color,
                                       transparent=transparency,
                                       opacity=opacity)

        # and to the dict of shapes, to have a mapping between meshes and shapes
        mesh_id = "%s" % uuid.uuid4().hex

        self.mesh_id = mesh_id
        # finally create the mesh
        shape_mesh = Mesh(geometry=shape_geometry,
                          material=shp_material,
                          name=mesh_id)

        # edge rendering, if set to True
        if self.render_edges:
            edge_list = flatten(list(map(explode, edges)))
            lines = LineSegmentsGeometry(positions=edge_list)
            mat = LineMaterial(linewidth=1, color=edge_color)
            edge_lines = LineSegments2(lines, mat, name=mesh_id)
        else:
            edge_lines = None

        return shape_mesh, edge_lines
def _get_spheres(ctk_scene, d_args=None):

    if ctk_scene.phiEnd and ctk_scene.phiStart:
        phi_length = ctk_scene.phiEnd - ctk_scene.phiStart
    else:
        phi_length = np.pi * 2

    return [
        Mesh(
            geometry=SphereBufferGeometry(
                radius=ctk_scene.radius,
                phiStart=ctk_scene.phiStart or 0,
                phiLength=phi_length,
                widthSegments=32,
                heightSegments=32,
            ),
            material=MeshLambertMaterial(color=ctk_scene.color),
            position=tuple(ipos),
        ) for ipos in ctk_scene.positions
    ]
def _get_surface_from_positions(positions, d_args, draw_edges=False):
    # get defaults
    obj_args = update_object_args(d_args, "Surfaces", ["color", "opacity"])
    num_triangle = len(positions) / 3.0
    assert num_triangle.is_integer()
    # make decision on transparency
    if obj_args["opacity"] > 0.99:
        transparent = False
    else:
        transparent = True

    num_triangle = int(num_triangle)
    index_list = [[itr * 3, itr * 3 + 1, itr * 3 + 2]
                  for itr in range(num_triangle)]
    # Vertex ositions as a list of lists
    surf_vertices = BufferAttribute(array=positions, normalized=False)
    # Indices
    surf_indices = BufferAttribute(array=np.array(index_list,
                                                  dtype=np.uint16).ravel(),
                                   normalized=False)
    geometry = BufferGeometry(attributes={
        "position": surf_vertices,
        "index": surf_indices
    })
    new_surface = Mesh(
        geometry=geometry,
        material=MeshLambertMaterial(
            color=obj_args["color"],
            side="DoubleSide",
            transparent=transparent,
            opacity=obj_args["opacity"],
        ),
    )
    if draw_edges == True:
        edges = EdgesGeometry(geometry)
        edges_lines = LineSegments(edges,
                                   LineBasicMaterial(color=obj_args["color"]))
        return new_surface, edges_lines
    else:
        return new_surface, None
Example #18
0
 def __init__(self, color='red', radius=0.025):
     Mesh.__init__(self,
                   geometry=SphereGeometry(radius=radius),
                   material=MeshLambertMaterial(color=color))
Example #19
0
    def AddShapeToScene(
        self,
        shp,
        shape_color=None,  # the default
        render_edges=False,
        edge_color=None,
        vertex_color=None,
        quality=1.0,
        transparency=False,
        opacity=1.0,
    ):
        # first, compute the tesselation
        tess = ShapeTesselator(shp)
        tess.Compute(compute_edges=render_edges,
                     mesh_quality=quality,
                     parallel=True)
        # get vertices and normals
        vertices_position = tess.GetVerticesPositionAsTuple()

        number_of_triangles = tess.ObjGetTriangleCount()
        number_of_vertices = len(vertices_position)

        # number of vertices should be a multiple of 3
        if number_of_vertices % 3 != 0:
            raise AssertionError("Wrong number of vertices")
        if number_of_triangles * 9 != number_of_vertices:
            raise AssertionError("Wrong number of triangles")

        # 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),
        }
        if self._compute_normals_mode == NORMAL.SERVER_SIDE:
            # get the normal list, converts to a numpy ndarray. This should not raise
            # any issue, since normals have been computed by the server, and are available
            # as a list of floats
            np_normals = np.array(tess.GetNormalsAsTuple(),
                                  dtype="float32").reshape(-1, 3)
            # quick check
            if np_normals.shape != np_vertices.shape:
                raise AssertionError("Wrong number of normals/shapes")
            buffer_geometry_properties["normal"] = BufferAttribute(np_normals)

        # build a BufferGeometry instance
        shape_geometry = BufferGeometry(attributes=buffer_geometry_properties)

        # if the client has to render normals, add the related js instructions
        if self._compute_normals_mode == NORMAL.CLIENT_SIDE:
            shape_geometry.exec_three_obj_method("computeVertexNormals")

        # then a default material
        shp_material = self._material(shape_color,
                                      transparent=transparency,
                                      opacity=opacity)

        # and to the dict of shapes, to have a mapping between meshes and shapes
        mesh_id = "%s" % uuid.uuid4().hex
        self._shapes[mesh_id] = shp

        # finally create the mesh
        shape_mesh = Mesh(geometry=shape_geometry,
                          material=shp_material,
                          name=mesh_id)

        # edge rendering, if set to True
        if render_edges:
            edges = list(
                map(
                    lambda i_edge: [
                        tess.GetEdgeVertex(i_edge, i_vert)
                        for i_vert in range(tess.ObjEdgeGetVertexCount(i_edge))
                    ],
                    range(tess.ObjGetEdgeCount()),
                ))
            edge_list = _flatten(list(map(_explode, edges)))
            lines = LineSegmentsGeometry(positions=edge_list)
            mat = LineMaterial(linewidth=1, color=edge_color)
            edge_lines = LineSegments2(lines, mat, name=mesh_id)
            self._displayed_non_pickable_objects.add(edge_lines)

        return shape_mesh
Example #20
0
"""
Link up the StructureMoleculeComponent objects to pythreejs
Also includes some helper functions for draw addition objects using pythreejs
"""

from pythreejs import MeshLambertMaterial, Mesh, SphereBufferGeometry, CylinderBufferGeometry, Object3D, LineSegments2, LineSegmentsGeometry, LineMaterial, Scene, AmbientLight, Renderer, OrbitControls, OrthographicCamera, DirectionalLight
from crystal_toolkit.components.structure import StructureMoleculeComponent
from IPython.display import display
from scipy.spatial.transform import Rotation as R
import numpy as np
ball = Mesh(geometry=SphereBufferGeometry(radius=1,
                                          widthSegments=32,
                                          heightSegments=16),
            material=MeshLambertMaterial(color='red'),
            position=[0, 1, 0])


def traverse_scene_object(scene_data, parent=None):
    """
    Recursivesly populate a scene object with tree of children
    :param scene_data:
    :param parent:
    :return:
    """
    for sub_object in scene_data["contents"]:
        if "type" in sub_object.keys():
            parent.add(convert_object_to_pythreejs(sub_object))
        else:
            new_parent = Object3D(name=sub_object["name"])
            if parent is None:
                parent = new_parent
Example #21
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)
Example #22
0
    def _render_shape(self,
                      shape_index,
                      shape=None,
                      edges=None,
                      vertices=None,
                      mesh_color=None,
                      edge_color=None,
                      vertex_color=None,
                      render_edges=False,
                      edge_width=1,
                      vertex_width=5,
                      deflection=0.05,
                      transparent=False,
                      opacity=1.0):

        edge_list = None
        edge_lines = None
        points = None
        shape_mesh = None

        if shape is not None:
            if mesh_color is None:
                mesh_color = self.default_mesh_color
            if edge_color is None:
                edge_color = self.default_edge_color
            if vertex_color is None:
                vertex_color = self.default_edge_color  # same as edge_color

            # BEGIN copy
            # The next lines are copied with light modifications from
            # https://github.com/tpaviot/pythonocc-core/blob/master/src/Display/WebGl/jupyter_renderer.py

            # first, compute the tesselation
            tess = Tesselator(shape)
            tess.Compute(uv_coords=False,
                         compute_edges=render_edges,
                         mesh_quality=self.quality,
                         parallel=True)

            # get vertices and normals
            vertices_position = tess.GetVerticesPositionAsTuple()

            number_of_triangles = tess.ObjGetTriangleCount()
            number_of_vertices = len(vertices_position)

            # number of vertices should be a multiple of 3
            if number_of_vertices % 3 != 0:
                raise AssertionError("Wrong number of vertices")
            if number_of_triangles * 9 != number_of_vertices:
                raise AssertionError("Wrong number of triangles")

            # 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')

            # compute normals
            np_normals = np.array(tess.GetNormalsAsTuple(),
                                  dtype='float32').reshape(-1, 3)
            if np_normals.shape != np_vertices.shape:
                raise AssertionError("Wrong number of normals/shapes")

            # build a BufferGeometry instance
            shape_geometry = BufferGeometry(
                attributes={
                    'position': BufferAttribute(np_vertices),
                    'index': BufferAttribute(np_faces),
                    'normal': BufferAttribute(np_normals)
                })

            shp_material = self._material(mesh_color,
                                          transparent=True,
                                          opacity=opacity)

            shape_mesh = Mesh(geometry=shape_geometry,
                              material=shp_material,
                              name="mesh_%d" % shape_index)

            if render_edges:
                edge_list = list(
                    map(
                        lambda i_edge: [
                            tess.GetEdgeVertex(i_edge, i_vert)
                            for i_vert in range(
                                tess.ObjEdgeGetVertexCount(i_edge))
                        ], range(tess.ObjGetEdgeCount())))

            # END copy

        if vertices is not None:
            vertices_list = []
            for vertex in vertices:
                p = BRep_Tool.Pnt(vertex)
                vertices_list.append((p.X(), p.Y(), p.Z()))
            vertices_list = np.array(vertices_list, dtype=np.float32)

            attributes = {
                "position": BufferAttribute(vertices_list, normalized=False)
            }

            mat = PointsMaterial(color=vertex_color,
                                 sizeAttenuation=False,
                                 size=vertex_width)
            geom = BufferGeometry(attributes=attributes)
            points = Points(geometry=geom, material=mat)

        if edges is not None:
            edge_list = [discretize_edge(edge, deflection) for edge in edges]

        if edge_list is not None:
            edge_list = _flatten(list(map(_explode, edge_list)))
            lines = LineSegmentsGeometry(positions=edge_list)
            mat = LineMaterial(linewidth=edge_width, color=edge_color)
            edge_lines = LineSegments2(lines,
                                       mat,
                                       name="edges_%d" % shape_index)

        if shape_mesh is not None or edge_lines is not None or points is not None:
            index_mapping = {"mesh": None, "edges": None, "shape": shape_index}
            if shape_mesh is not None:
                ind = len(self.pickable_objects.children)
                self.pickable_objects.add(shape_mesh)
                index_mapping["mesh"] = ind
            if edge_lines is not None:
                ind = len(self.pickable_objects.children)
                self.pickable_objects.add(edge_lines)
                index_mapping["edges"] = ind
            if points is not None:
                ind = len(self.pickable_objects.children)
                self.pickable_objects.add(points)
                index_mapping["mesh"] = ind
            self.pick_mapping.append(index_mapping)
Example #23
0
    def __init__(self,
        mesh: trimesh.Trimesh = None,
        obj: str = None,
        normalize: bool =False,
        color: Union[str,ColorRGB] ="#00bbee",
        alpha: float=1.,
        transform: Union[Callable, None] = None,
        *args,
        **kwargs
        ):
        """
        Add a mesh to the scene.

        Arguments:
            mesh: Mesh object, with attributes verticies, faces
            obj: object filename
            normalize : Normalize the coordinates of the vertices
                to be between -1 and 1
            color: Color for the mesh
            alpha: transparency of the mesh
            transform: a function to transform the vertices

        """
        if mesh is not None and obj is not None:
            raise ValueError('Received both mesh and obj')
        if isinstance(mesh, str):
            # perhaps this is a filename?
            try:
                mesh = trimesh.load(args[0])
            except Exception as e:
                raise ValueError(
                    "Did not understand arguments to method Figure#mesh"
                ) from e
        if isinstance(obj, np.ndarray):
            obj_data = obj
        elif isinstance(obj, list):
            obj_data = np.asarray(obj)
            # Do something with this obj_data?
        elif isinstance(obj, str):
            if "\n" in obj:
                # this is the file contents.
                raise NotImplementedError()
            else:
                try:
                    # open the mesh file
                    mesh = trimesh.load(obj)

                except Exception as e:
                    raise ValueError("Could not read file as OBJ") from e
        assert hasattr(mesh, "vertices") and hasattr(mesh, "faces"), "Invalid mesh object"
        if mesh is None:
            raise ValueError("Could not understand how to parse mesh.")

        if transform is None:
            transform = lambda x: x

        verts = transform(mesh.vertices)
        faces = mesh.faces

        if normalize:
            # Normalize the vertex indices to be between -1,1
            # Shifting these does change the coordinate system,
            # so visualizing multiple meshes won't work
            verts[:, 0] = _normalize_shift(verts[:, 0])
            verts[:, 1] = _normalize_shift(verts[:, 1])
            verts[:, 2] = _normalize_shift(verts[:, 2])

        geo = BufferGeometry(
            attributes={
                "position": BufferAttribute(
                    array=verts.astype("float32"),
                    normalized=False,
                    # dtype=np.float64
                ),
                "index": BufferAttribute(
                    array=faces.astype("uint64").ravel(),
                    normalized=False,
                    # dtype=np.float64,
                ),
            }
        )
        self._coords = verts
        transparent = alpha != 1.
        mat = MeshLambertMaterial(color=color, opacity=alpha, transparent=transparent)
        mesh = Mesh(geometry=geo, material=mat)
        geo.exec_three_obj_method("computeVertexNormals")
        super().__init__(*args, **kwargs)
        self._objects.append(mesh)
Example #24
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)
Example #25
0
    def _render_shape(
        self,
        shape_index,
        shape=None,
        edges=None,
        vertices=None,
        mesh_color=None,
        edge_color=None,
        vertex_color=None,
        render_edges=False,
        edge_width=1,
        vertex_width=5,
        transparent=False,
        opacity=1.0,
    ):

        edge_list = None
        edge_lines = None
        points = None
        shape_mesh = None

        start_render_time = self._start_timer()
        if shape is not None:
            if mesh_color is None:
                mesh_color = self.default_mesh_color
            if edge_color is None:
                edge_color = self.default_edge_color
            if vertex_color is None:
                vertex_color = self.default_edge_color  # same as edge_color

            # Compute the tesselation
            start_tesselation_time = self._start_timer()

            np_vertices, np_triangles, np_normals = tessellate(
                shape, self.quality, self.angular_tolerance
            )

            if np_normals.shape != np_vertices.shape:
                raise AssertionError("Wrong number of normals/shapes")

            self._stop_timer("tesselation time", start_tesselation_time)

            # build a BufferGeometry instance
            shape_geometry = BufferGeometry(
                attributes={
                    "position": BufferAttribute(np_vertices),
                    "index": BufferAttribute(np_triangles.ravel()),
                    "normal": BufferAttribute(np_normals),
                }
            )

            shp_material = self._material(mesh_color, transparent=True, opacity=opacity)

            shape_mesh = Mesh(
                geometry=shape_geometry, material=shp_material, name="mesh_%d" % shape_index
            )

            if render_edges:
                edges = get_edges(shape)

        if vertices is not None:
            vertices_list = []
            for vertex in vertices:
                vertices_list.append(get_point(vertex))
            vertices_list = np.array(vertices_list, dtype=np.float32)

            attributes = {"position": BufferAttribute(vertices_list, normalized=False)}

            mat = PointsMaterial(color=vertex_color, sizeAttenuation=False, size=vertex_width)
            geom = BufferGeometry(attributes=attributes)
            points = Points(geometry=geom, material=mat)

        if edges is not None:
            start_discretize_time = self._start_timer()
            edge_list = [discretize_edge(edge, self.edge_accuracy) for edge in edges]
            self._stop_timer("discretize time", start_discretize_time)

        if edge_list is not None:
            edge_list = flatten(list(map(explode, edge_list)))
            lines = LineSegmentsGeometry(positions=edge_list)
            mat = LineMaterial(linewidth=edge_width, color=edge_color)
            edge_lines = LineSegments2(lines, mat, name="edges_%d" % shape_index)

        if shape_mesh is not None or edge_lines is not None or points is not None:
            index_mapping = {"mesh": None, "edges": None, "shape": shape_index}
            if shape_mesh is not None:
                ind = len(self.pickable_objects.children)
                self.pickable_objects.add(shape_mesh)
                index_mapping["mesh"] = ind
            if edge_lines is not None:
                ind = len(self.pickable_objects.children)
                self.pickable_objects.add(edge_lines)
                index_mapping["edges"] = ind
            if points is not None:
                ind = len(self.pickable_objects.children)
                self.pickable_objects.add(points)
                index_mapping["mesh"] = ind
            self.pick_mapping.append(index_mapping)
        self._stop_timer("shape render time", start_render_time)
Example #26
0
    def AddShapeToScene(self,
                        shp,  # the TopoDS_Shape to be displayed
                        shape_color=default_shape_color,  # the default
                        render_edges=False,
                        edge_color=default_edge_color,
                        compute_uv_coords=False,
                        quality=1.0,
                        transparency=False,
                        opacity=1.):
        # first, compute the tesselation
        tess = Tesselator(shp)
        tess.Compute(uv_coords=compute_uv_coords,
                     compute_edges=render_edges,
                     mesh_quality=quality,
                     parallel=self._parallel)
        # get vertices and normals
        vertices_position = tess.GetVerticesPositionAsTuple()

        number_of_triangles = tess.ObjGetTriangleCount()
        number_of_vertices = len(vertices_position)

        # number of vertices should be a multiple of 3
        if number_of_vertices % 3 != 0:
            raise AssertionError("Wrong number of vertices")
        if number_of_triangles * 9 != number_of_vertices:
            raise AssertionError("Wrong number of triangles")

        # 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)}
        if self._compute_normals_mode == NORMAL.SERVER_SIDE:
            # get the normal list, converts to a numpy ndarray. This should not raise
            # any issue, since normals have been computed by the server, and are available
            # as a list of floats
            np_normals = np.array(tess.GetNormalsAsTuple(), dtype='float32').reshape(-1, 3)
            # quick check
            if np_normals.shape != np_vertices.shape:
                raise AssertionError("Wrong number of normals/shapes")
            buffer_geometry_properties['normal'] = BufferAttribute(np_normals)

        # build a BufferGeometry instance
        shape_geometry = BufferGeometry(attributes=buffer_geometry_properties)

        # if the client has to render normals, add the related js instructions
        if self._compute_normals_mode == NORMAL.CLIENT_SIDE:
            shape_geometry.exec_three_obj_method('computeVertexNormals')

        # then a default material
        shp_material = self._material(shape_color, transparent=transparency, opacity=opacity)
        # create a mesh unique id
        mesh_id = uuid.uuid4().hex

        # finally create the mash
        shape_mesh = Mesh(geometry=shape_geometry,
                          material=shp_material,
                          name=mesh_id)


        # and to the dict of shapes, to have a mapping between meshes and shapes
        self._shapes[mesh_id] = shp

        # edge rendering, if set to True
        edge_lines = None
        if render_edges:
            edges = list(map(lambda i_edge: [tess.GetEdgeVertex(i_edge, i_vert) for i_vert in range(tess.ObjEdgeGetVertexCount(i_edge))], range(tess.ObjGetEdgeCount())))
            edges = list(filter(lambda edge: len(edge) == 2, edges))
            np_edge_vertices = np.array(edges, dtype=np.float32).reshape(-1, 3)
            np_edge_indices = np.arange(np_edge_vertices.shape[0], dtype=np.uint32)
            edge_geometry = BufferGeometry(attributes={
                'position': BufferAttribute(np_edge_vertices),
                'index'   : BufferAttribute(np_edge_indices)
            })
            edge_material = LineBasicMaterial(color=edge_color, linewidth=1)
            edge_lines = LineSegments(geometry=edge_geometry, material=edge_material)

        # Add geometries to pickable or non pickable objects
        self._displayed_pickable_objects.add(shape_mesh)
        if render_edges:
            self._displayed_non_pickable_objects.add(edge_lines)