Example #1
0
def coastline(resolution="110m", radius=1.0, geocentric=True):
    fname = shp.natural_earth(resolution=resolution,
                              category="physical",
                              name="coastline")
    reader = shp.Reader(fname)

    dtype = np.float32
    blocks = pv.MultiBlock()

    for i, record in enumerate(reader.records()):
        for geometry in record.geometry:
            xy = np.array(geometry.coords[:], dtype=dtype)

            if geocentric:
                xr = np.radians(xy[:, 0]).reshape(-1, 1)
                yr = np.radians(90 - xy[:, 1]).reshape(-1, 1)

                x = radius * np.sin(yr) * np.cos(xr)
                y = radius * np.sin(yr) * np.sin(xr)
                z = radius * np.cos(yr)
            else:
                # otherwise, geodetic
                x = xy[:, 0].reshape(-1, 1)
                y = xy[:, 1].reshape(-1, 1)
                z = np.zeros_like(x)

            xyz = np.hstack((x, y, z))
            poly = pv.lines_from_points(xyz, close=False)
            blocks.append(poly)

    return blocks
Example #2
0
def test_multi_block_save_lines(tmpdir):
    radius = 1
    xr = np.random.random(10)
    yr = np.random.random(10)
    x = radius * np.sin(yr) * np.cos(xr)
    y = radius * np.sin(yr) * np.sin(xr)
    z = radius * np.cos(yr)
    xyz = np.stack((x, y, z), axis=1)

    poly = pyvista.lines_from_points(xyz, close=False)
    blocks = pyvista.MultiBlock()
    for _ in range(2):
        blocks.append(poly)

    path = tmpdir.mkdir("tmpdir")
    line_filename = str(path.join('lines.vtk'))
    block_filename = str(path.join('blocks.vtmb'))
    poly.save(line_filename)
    blocks.save(block_filename)

    poly_load = pyvista.read(line_filename)
    assert np.allclose(poly_load.points, poly.points)

    blocks_load = pyvista.read(block_filename)
    assert np.allclose(blocks_load[0].points, blocks[0].points)
Example #3
0
def get_coastlines(resolution="110m"):
    """
    Modified version of 
    https://github.com/bjlittle/poc-ngvat/blob/master/poc-3/utils.py
    """
    fname = shp.natural_earth(resolution=resolution,
                              category="physical",
                              name="coastline")
    reader = shp.Reader(fname)

    dtype = np.float32
    blocks = pv.MultiBlock()

    for i, record in enumerate(reader.records()):
        for geometry in record.geometry:
            xy = np.array(geometry.coords[:], dtype=dtype)
            x = xy[:, 0].reshape(-1, 1)
            y = xy[:, 1].reshape(-1, 1)
            z = np.zeros_like(x)

            xyz = np.hstack((x, y, z))
            poly = pv.lines_from_points(xyz, close=False)
            blocks.append(poly)

    return blocks
Example #4
0
def test_lines_from_points():
    points = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0]])
    poly = pyvista.lines_from_points(points)
    assert poly.n_cells == 2
    assert poly.n_points == 3
    cells = poly.lines
    assert np.allclose(cells[:3], [2, 0, 1])
    assert np.allclose(cells[3:], [2, 1, 2])
Example #5
0
    def boundary(
        self, surface: Optional[pv.PolyData] = None, radius: Optional[float] = None
    ) -> pv.PolyData:
        """
        The region of the bounding-box that intersects on the surface of the mesh
        that will be enclosed.

        Parameters
        ----------
        surface : PolyData, optional
            The :class:`pyvista.PolyData` mesh that will be enclosed by the
            bounding-box boundary.
        radius : float, default=1.0
            The radius of the mesh that will be enclosed by the bounding-box
            boundary. Note that, the ``radius`` is only used when the ``surface``
            is not provided.

        Returns
        -------
        PolyData
            The boundary of the bounding-box.

        Notes
        -----
        .. versionadded:: 0.1.0

        """
        self._generate_bbox_mesh(surface=surface, radius=radius)

        # TODO: address "fudge-factor" z-level
        radius = self._surface_radius + self._surface_radius / 1e4

        edge_idxs = self._bbox_face_edge_idxs()
        edge_lons = self._bbox_lons[edge_idxs]
        edge_lats = self._bbox_lats[edge_idxs]
        edge_xyz = to_xyz(edge_lons, edge_lats, radius=radius)
        edge = pv.lines_from_points(edge_xyz, close=True)

        return edge
 def add_vector_line_in_orbit(self, center_point, vector_point):
     self.vtk_widget.subplot(0, 0)
     self.vector_line_from_sc = pv.lines_from_points(np.array([center_point, center_point + 1e7 * vector_point]))
     self.vtk_widget.add_mesh(self.vector_line_from_sc, color='w')
     return
Example #7
0
# address = 'Holzgerlingen DE'
# graph = ox.graph_from_address(address, dist=500, network_type='drive')
# pickle.dump(graph, open('/tmp/tmp.p', 'wb'))

# Alternatively, use the pickeled graph included in our examples.
from pyvista import examples
graph = examples.download_osmnx_graph()

###############################################################################
# Next, convert the edges into pyvista lines using
# :func:`pyvista.lines_from_points`.

nodes, edges = ox.graph_to_gdfs(graph)
lines = []

# convert each edge into a line
for idx, row in edges.iterrows():
    x_pts = row['geometry'].xy[0]
    y_pts = row['geometry'].xy[1]
    z_pts = np.zeros(len(x_pts))
    pts = np.column_stack((x_pts, y_pts, z_pts))
    line = pv.lines_from_points(pts)
    lines.append(line)

###############################################################################
# Finally, merge the lines and plot

combined_lines = lines[0].merge(lines[1:])
combined_lines.plot(line_width=3, cpos='xy')
Example #8
0
def sampleDataBlockProfile(dataBlock,
                           line_walldists,
                           pointid=None,
                           cutterobj=None,
                           normal=None) -> Profile:
    """Sample data block over a wall-normal profile

    Given a dataBlock containing a 'grid' and 'wall' block, this will return a
    PolyData object that samples 'grid' at the wall distances specified in
    line_walldists. This assumes that the 'wall' block has a field named
    'Normals' containing the wall-normal vectors.

    The location of the profile is defined by either the index of a point in
    the 'wall' block or by specifying a vtk implicit function (such as
    vtk.vtkPlane) that intersects the 'wall' object. The latter uses the
    vtk.vtkCutter filter to determine the intersection.

    Parameters
    ----------
    dataBlock : pv.MultiBlock
        MultiBlock containing the 'grid' and 'wall' objects
    line_walldists : numpy.ndarray
        The locations normal to the wall that should be sampled and returned.
        Locations are expected to be in order.
    pointid : int, optional
        Index of the point in 'wall' where the profile should be taken.
        (default: None)
    cutterobj : vtk.vtkPlane, optional
        VTK object that defines the profile location via intersection with the
        'wall'
    normal : numpy.ndarray, optional
        If given, use this vector as the wall normal.

    Returns
    -------
    vtkpytools.Profile
    """

    wall = dataBlock['wall']

    if 'Normals' not in wall.array_names:
        raise RuntimeError(
            'The wall object must have a "Normals" field present.')
    if not (isinstance(pointid, int) ^ bool(cutterobj)):  #xnor
        raise RuntimeError('Must provide either pointid or cutterobj.')

    if isinstance(pointid, int):
        wallnormal = wall['Normals'][pointid, :] if normal is None else normal
        wallnormal = np.tile(wallnormal, (len(line_walldists), 1))

        sample_points = line_walldists[:, None] * wallnormal
        sample_points += wall.points[pointid]

        sample_line = pv.lines_from_points(sample_points)
        sample_line = sample_line.sample(dataBlock['grid'])
        sample_line['WallDistance'] = line_walldists

    else:
        cutterout = vCutter(wall, cutterobj)
        if cutterout.points.shape[0] != 1:
            raise RuntimeError(
                'vCutter resulted in {:d} points instead of 1.'.format(
                    cutterout.points.shape[0]))

        wallnormal = cutterout['Normals'] if normal is None else normal

        sample_points = line_walldists[:, None] * wallnormal
        sample_points += cutterout.points

        sample_line = pv.lines_from_points(sample_points)
        sample_line = sample_line.sample(dataBlock['grid'])
        sample_line['WallDistance'] = line_walldists

        sample_line = Profile(sample_line)
        sample_line.setWallDataFromPolyDataPoint(cutterout)

    return sample_line
Example #9
0
def line(
    lons: npt.ArrayLike,
    lats: npt.ArrayLike,
    surface: Optional[pv.PolyData] = None,
    radius: Optional[float] = None,
    npts: Optional[int] = GEODESIC_NPTS,
    ellps: Optional[str] = ELLIPSE,
    close: Optional[bool] = False,
) -> pv.PolyData:
    """
    Create a geodesic line consisting of one or more connected geodesic
    line segments.

    Parameters
    ----------
    lons : ArrayLike
        The longitudes (degrees) of the geodesic line segments, in the half-closed
        interval [-180, 180). Note that, longitudes will be wrapped to this
        interval.
    lats : ArrayLike
        The latitudes (degrees) of the geodesic line segments, in the closed
        interval [-90, 90].
    surface : PolyData, optional
        The surface that the geodesic line will be rendered over.
    radius : float, default=1.0
        The radius of the surface that the geodesic line will be rendered over.
        Note that, the ``radius`` is only used when the ``surface`` is not
        provided.
    npts : float, default=GEODESIC_NPTS
        The number of equally spaced geodesic points in a line segment, excluding
        the segment end-point, but including the segment start-point i.e., ``npts``
        must be at least 2.
    ellps : str, default=ELLIPSE
        The ellipsoid for geodesic calculations. See :func:`pyproj.get_ellps_map`.
    close : bool, default=False
        Whether to close the geodesic line segments into a loop i.e., the last
        point is connected to the first point.

    Returns
    -------
    PolyData
        The geodesic line.

    Notes
    -----
    .. versionadded:: 0.1.0

    """
    if surface is not None:
        radius = calculate_radius(surface)

    radius = 1.0 if radius is None else abs(radius)

    # TODO: address "fudge-factor" z-level
    radius += radius / 1e4

    if not isinstance(lons, Iterable):
        lons = [lons]
    if not isinstance(lats, Iterable):
        lats = [lats]

    lons = np.asanyarray(lons)
    lats = np.asanyarray(lats)
    n_lons, n_lats = lons.size, lats.size

    if n_lons != n_lats:
        emsg = (
            f"Require the same number of longitudes ({n_lons}) and "
            f"latitudes ({n_lats})."
        )
        raise ValueError(emsg)

    if n_lons < 2:
        emsg = (
            "Require a line geometry containing at least 2 longitude/latitude "
            f"values, got '{n_lons}'."
        )
        raise ValueError(emsg)

    # ensure the specified line geometry is open
    if np.isclose(lons[0], lons[-1]) and np.isclose(lats[0], lats[-1]):
        lons, lats = lons[-1], lats[-1]

    line_lons, line_lats = [], []
    geod = pyproj.Geod(ellps=ellps)

    for idx in range(n_lons - 1):
        glons, glats = npoints_by_idx(
            lons,
            lats,
            idx,
            idx + 1,
            npts=npts,
            include_start=True,
            include_end=False,
            geod=geod,
        )
        line_lons.extend(glons)
        line_lats.extend(glats)

    # finally, include the end-point
    line_lons.append(lons[-1])
    line_lats.append(lats[-1])

    xyz = to_xyz(line_lons, line_lats, radius=radius)
    lines = pv.lines_from_points(xyz, close=close)

    return lines