示例#1
0
def viewer(paths: list) -> None:
    from blastsight.view.viewer import Viewer
    v = Viewer()

    # Auto-load files when called from CLI
    v.load_multiple(paths, v.load_mesh)

    v.show()
示例#2
0
#!/usr/bin/env python

import numpy as np
import pathlib

from blastsight.view.viewer import Viewer
"""
In this demo, we'll manually slice a mesh, and detect the vertices
of that slice, so we can draw a line there.
"""

v = Viewer()
"""
First, we'll load a mesh file.
Then, we'll slice the mesh by a plane.
We need the plane's normal and any point that belongs to that plane.
"""
path = f'{pathlib.Path(__file__).parent.parent}/test_files/caseron.off'
mesh = v.load_mesh(path, color=[0.0, 0.0, 1.0], alpha=0.3)

origin = mesh.centroid
normal = np.array([0.2, 1.0, 0.8])

slices = v.slice_meshes(origin, normal)
"""
Then, we'll show the detected vertices.
We'll draw them as a line, so the slice is more evident.
"""

for mesh_slice in slices:
    vertices = mesh_slice.get('vertices')
示例#3
0
In this demo, we'll show how you can animate a cross-section so you can simulate that you're scanning a mine.

A Cross-Section is equivalent as slicing a mesh, but without returning the vertices of each slice.
This means that we can easily generate a cross-section of all the rendered meshes in real time.

Internally, it's a visual effect, which means we have to manually activate the cross-section mode
with 'v.set_cross_section(True). This activates the cross-section with default values for the plane.

You can change the plane description with v.cross_section(origin, normal), where 'origin' is a point
on the plane, and 'normal' is the normal of the plane.

To deactivate the cross-section, just use 'v.set_cross_section(False)'.

"""

v = Viewer()
mesh_path = f'{pathlib.Path(__file__).parent.parent}/test_files/caseron.off'
block_path = f'{pathlib.Path(__file__).parent.parent}/test_files/rainbow.csv'

mesh = v.load_mesh(mesh_path, color=[1.0, 0.8, 0.0])
blocks = v.load_blocks(block_path)
low, high = v.bounding_box()


def scan(origin):
    v.cross_section(origin, np.array([1.0, 0.0, 0.0]))


def scan_left(*args, **kwargs):
    v.signal_animation_finished.disconnect()
示例#4
0
def demo_text():
    viewer = Viewer()
    viewer.setWindowTitle('BlastSight (Text demo)')

    # Load a mesh
    path = f'{pathlib.Path(__file__).parent.parent}/test_files/caseron.off'
    mesh = viewer.load_mesh(path, color=[1.0, 1.0, 0.0], alpha=0.1)

    # Setup the grid using the bounding box of the figure
    min_bound, max_bound = mesh.bounding_box

    viewer.grid.origin = min_bound
    viewer.grid.size = max_bound - min_bound
    viewer.grid.color = [1.0, 0.8, 0.0]
    viewer.grid.mark_separation = 10
    viewer.grid.is_visible = True

    # Showcase orientations
    viewer.text(text='Facing: Elevation',
                position=mesh.center,
                rotation=[0.0, 0.0, 0.0],
                scale=10)
    viewer.text(text='Facing: North',
                position=mesh.center,
                rotation=[0.0, 90.0, 90.0],
                scale=10)
    viewer.text(text='Facing: East',
                position=mesh.center,
                rotation=[90.0, 0.0, 0.0],
                scale=10)

    viewer.show()
示例#5
0
#!/usr/bin/env python

import pathlib

from blastsight.view.viewer import Viewer
"""
In this demo, we'll show how you can easily take screenshots of the viewer.
"""

v = Viewer()
path = f'{pathlib.Path(__file__).parent.parent}/test_files/caseron.off'

v.load_mesh(path)
v.fit_to_screen()
v.resize(800, 800)
"""
You can take a screenshot without even seeing the viewer,
but if you need to see it anyway, uncomment those "optional" lines.
"""

for i in range(3):
    v.show(detached=True, timer=1)  # Optional
    v.take_screenshot(f'screenshot_{i}.png')
    v.rotation_angle += [0.0, 120.0, 0.0]
    v.close()  # Optional, needed if v.show(detached=True) is used

print('Ready!')
示例#6
0
#!/usr/bin/env python

import pathlib

from blastsight.view.viewer import Viewer
"""
In this demo, a mesh and a block set will be dynamically sliced by yourself,
by clicking in two parts of the screen.
"""

viewer = Viewer()
title = viewer.windowTitle()
viewer.setWindowTitle(f'{title} - Click two points in the screen.')

mesh_path = f'{pathlib.Path(__file__).parent.parent}/test_files/caseron.off'
block_path = f'{pathlib.Path(__file__).parent.parent}/test_files/rainbow.csv'

mesh = viewer.load_mesh(mesh_path, color=[0.0, 0.8, 0.6], alpha=0.2)
blocks = viewer.load_blocks(block_path, alpha=0.1)

original_size = blocks.block_size


def slice_elements(description: dict) -> None:
    """
    The method slice_elements reacts to viewer.signal_slice_description,
    and receives a description of the slice, so you can do whatever you
    want with that information.

    :param description: Description of the cross-section
    :return: None
示例#7
0
#!/usr/bin/env python

import pathlib

from blastsight.view.viewer import Viewer
"""
In this demo, we'll show how you can measure mesh distances from the viewer.
"""

v = Viewer()
title = v.windowTitle()

v.setWindowTitle(f'{title} - Click two points of a mesh.')

path = f'{pathlib.Path(__file__).parent.parent}/test_files/caseron.off'
mesh = v.load_mesh(path, color=[0.0, 0.3, 1.0])

phantom_tube = v.tubes(vertices=[mesh.center, mesh.center],
                       color=[1.0, 0.8, 0.0],
                       visible=False)


def update_info(d: dict):
    print(f'Distance dictionary: {d}')
    distance = d.get('distance')
    v.setWindowTitle(f'{title} - Distance: {distance}')

    points = [d.get('point_a'), d.get('point_b')]
    if distance is None:
        phantom_tube.is_visible = False
    else:
示例#8
0
#!/usr/bin/env python

import pathlib

from blastsight.view.viewer import Viewer
"""
In this demo, we'll show how you can create a basic animation.

An animation is interpreted as changing the state of the viewer one frame at the time.
That means we'll define a function that makes a change in one single frame.
The function must receive a single argument, of the same type of the 'start' and 'end' values.
"""

v = Viewer()
path = f'{pathlib.Path(__file__).parent.parent}/test_files/caseron.off'
mesh = v.load_mesh(path, highlight=True)


def autorotate(angle):
    v.set_rotation_angle([0.0, -angle, 0.0])


"""
The animate() method receives a 'start' value, an 'end' value, a 'method' (the function that changes
one frame in the viewer), and two optional kwargs: 'milliseconds' (how much time should the
animation last) and 'steps' (smoothness of the animation depends on this).
"""

# Start animation
v.animate(0, 360, autorotate, milliseconds=3000, steps=100)
示例#9
0
#!/usr/bin/env python

import pathlib

from blastsight.view.viewer import Viewer

"""
In this demo, we'll show how you can use the signals of the viewer.
"""

v = Viewer()

title = v.windowTitle()
v.setWindowTitle(f'{title} - Double click in a mesh.')

path = f'{pathlib.Path(__file__).parent.parent}/test_files/caseron.off'
v.load_mesh(path)


def update_info(x: list):
    update_title = []
    for d in v.get_all_drawables():
        d.is_highlighted = False

    for attr in x:
        _id = attr.get('id')
        name = attr.get('name')

        v.get_drawable(_id).is_highlighted = True
        update_title.append(name)
示例#10
0
def demo():
    viewer = Viewer()
    viewer.setWindowTitle('BlastSight (Demo)')

    """
    You can load a mesh with viewer.mesh().
    The minimum arguments needed are: x, y, z, indices.

    The color will be random unless you specify it with an RGB array.
    """
    viewer.mesh(x=[1, 3, 2],
                y=[0, 0, 1],
                z=[-3, -3, -3],
                color=[0.0, 0.0, 1.0],
                indices=[[0, 1, 2]],
                alpha=0.7,
                name='Normal Mesh')

    """
    Alternatively, you can use the arguments: vertices, indices
    You can load it directly as a wireframe, if you want.
    """
    viewer.mesh(vertices=[[1, 0, -3], [3, 0, -3], [2, -1, -3]],
                color=[1.0, 0.5, 0.0],
                indices=[[0, 1, 2]],
                alpha=1.0,
                wireframe=True,
                name='Wireframed Mesh')

    """
    A highlighted mesh renders as both a normal mesh and a wireframed mesh.
    """
    viewer.mesh(x=[-3, -1, -2, -2],
                y=[0, 0, 1, -1],
                z=[-3, -3, -3, -3],
                color=[1.0, 0.5, 0.5],
                indices=[[0, 1, 2], [0, 3, 1]],
                alpha=1.0,
                highlight=True,
                name='Highlighted Mesh')

    """
    You can load a set of blocks with viewer.blocks().
    Each value is mapped with the respective vertex.
    The arguments vmin, vmax and colormap are optional.

    The colormap is two colors separated with a`-`.
    For example, `red-blue`, `cyan-magenta`, etc.

    Alternatively, you can pass an HTML color, like
    "#FF0000-#00FF00", as long as it's separated
    by the `-` character.
    """
    viewer.blocks(x=[-4, 4, 0],
                  y=[0, 0, 5],
                  z=[0, 0, 0],
                  block_size=[1.0, 1.0, 1.0],
                  values=[0.5, 1.0, 1.5],
                  vmin=0.5,
                  vmax=1.5,
                  alpha=1.0,
                  colormap='red-blue',
                  name='Blocks')

    """
    You can load a set of points with viewer.points().
    Points and blocks receive the same arguments,
    except block_size (a point has point_size).
    That means you can also pass values, instead of colors.

    If you're manually setting the colors, the `colormap`
    argument will be ignored.
    """
    viewer.points(vertices=[[-3, 2, 0], [0, 2, 1], [3, 2, 0]],
                  point_size=1.0,
                  color=[[1.0, 1.0, 0.0],
                         [0.0, 1.0, 1.0],
                         [1.0, 0.0, 1.0]],
                  alpha=1.0,
                  marker='square',
                  name='Points rendered as squares')

    """
    You can also set multiple sizes for the points.
    If you pass an array instead of a float in the point_size argument,
    each point from vertices (or x, y, z) will have that particular size.
    """
    viewer.points(vertices=[[-2, 3, 1], [0, 3, 0], [2, 3, 1]],
                  point_size=[0.3, 0.6, 0.9],
                  color=[[1.0, 0.0, 0.0],
                         [0.0, 1.0, 0.0],
                         [0.0, 0.0, 1.0]],
                  alpha=1.0,
                  marker='circle',
                  name='Points rendered as circles')

    """
    As you might have noticed in the `marker` argument, 
    you can have more than one point marker.

    Currently the markers are:
    - square: Squares that always face the camera.
    - circle: Circles that always face the camera.
    - sphere: Circles with a 3D effect.
    """
    viewer.points(vertices=[[-3, 5, 0], [3, 5, 0]],
                  point_size=2.0,
                  color=[[0.8, 0.5, 0.2],
                         [0.5, 0.2, 0.8]],
                  alpha=1.0,
                  marker='sphere',
                  name='Points rendered as spheres')

    """
    You can load a set of lines with viewer.lines().
    You need at least two vertices.

    If you need to join the first and the last vertex
    to form a loop, pass `loop=True` as argument.
    """
    viewer.lines(x=[-1.0, 1.0, -1.0, 1.0],
                 y=[1.0, 1.0, -1.0, -1.0],
                 z=[-2.0, -2.0, -2.0, -2.0],
                 color=[0.2, 0.8, 0.8],
                 alpha=1.0,
                 loop=True,
                 name='Looped lines')

    """
    You can also create a thicker line with the thickness argument.
    """
    viewer.lines(x=[-1.0, 1.0, -1.0, 1.0],
                 y=[0.5, 0.5, -0.5, -0.5],
                 z=[-2.5, -2.5, -2.5, -2.5],
                 color=[0.8, 0.8, 0.2],
                 alpha=0.7,
                 thickness=10,
                 loop=False,
                 name='Un-looped thick lines')

    """
    A tube is similar to a line, except that you
    can set the tube's radius and resolution
    (quality of the tube).
    At the moment, only tubes can have multiple colors,
    where len(colors) == len(vertices) - 1
    """
    viewer.tubes(x=[1.0, -1.0, 1.0, -1.0],
                 y=[2.0, 2.0, -2.0, -2.0],
                 z=[-1.5, -1.5, -1.5, -1.5],
                 color=[[1.0, 0.5, 0.0],
                        [0.5, 1.0, 0.0],
                        [0.5, 0.0, 1.0]],
                 radius=0.2,
                 resolution=150,
                 alpha=1.0,
                 loop=False,
                 name='Tubes')

    """
    A clever calculation with the bounding boxes of all the
    visible elements allows you to set the camera far enough
    that you can see every element on the screen without
    even showing the window.

    This method sets the world rotation at the center of the
    bounding box of all the visible elements.

    You might want to set the viewer's size before calling this
    method. (E.g.: viewer.resize(800, 600))
    """
    viewer.fit_to_screen()

    """
    Every drawable can be accessed with the viewer.get_all_drawables() method.
    """
    for drawable in viewer.get_all_drawables():
        print(f'ID: {drawable.id}\t Type: {type(drawable)}\t Name: {drawable.name}')

    """
    Finally, you can show the viewer with all the elements.
    You don't really need to call viewer.fit_to_screen(),
    since it's automatically called.

    If you want to disable it, use viewer.show(autofit=False).
    """
    viewer.show()