Esempio n. 1
0
 def test_return_endsubstring(self):
     self.assertEqual(
         substring(self.line1, 0.6, 500).wkt,
         LineString(([0.6, 0], [2, 0])).wkt)
     self.assertEqual(
         substring(self.line1, 0.6, 1.1, True).wkt,
         LineString(([1.2, 0], [2, 0])).wkt)
Esempio n. 2
0
    def test_save(self):
        self.link.save()
        extension = random()
        name = 'just a non-important value'

        geo = substring(self.link.geometry, 0, extension, normalized=True)

        self.link.name = name
        self.link.geometry = geo

        self.link.save()
        self.links.refresh()
        link2 = self.links.get(self.lid)

        self.assertEqual(link2.name, name, 'Failed to save the link name')
        self.assertAlmostEqual(link2.geometry, geo, 3,
                               'Failed to save the link geometry')

        tot_prev = self.network.count_links()
        lnk = self.links.new()
        lnk.geometry = substring(self.link.geometry, 0, 0.88, normalized=True)
        lnk.modes = 'c'
        lnk.save()

        self.assertEqual(tot_prev + 1, self.network.count_links(),
                         'Failed to save new link')
Esempio n. 3
0
 def test_return_startpoint(self):
     self.assertTrue(substring(self.line1, -500, -600).equals(Point(0, 0)))
     self.assertTrue(substring(self.line1, -500, -500).equals(Point(0, 0)))
     self.assertTrue(
         substring(self.line1, -1, -1.1, True).equals(Point(0, 0)))
     self.assertTrue(
         substring(self.line1, -1.1, -1.1, True).equals(Point(0, 0)))
Esempio n. 4
0
 def test_return_endsubstring(self):
     self.assertTrue(
         substring(self.line1, 0.6,
                   500).equals(LineString(([0.6, 0], [2, 0]))))
     self.assertTrue(
         substring(self.line1, 0.6, 1.1,
                   True).equals(LineString(([1.2, 0], [2, 0]))))
Esempio n. 5
0
 def test_return_endpoint(self):
     self.assertTrue(substring(self.line1, 500, 600).equals(Point(2, 0)))
     self.assertTrue(substring(self.line1, 500, 500).equals(Point(2, 0)))
     self.assertTrue(
         substring(self.line1, 1, 1.1, True).equals(Point(2, 0)))
     self.assertTrue(
         substring(self.line1, 1.1, 1.1, True).equals(Point(2, 0)))
Esempio n. 6
0
 def test_return_startsubstring(self):
     self.assertTrue(
         substring(self.line1, -500,
                   0.6).equals(LineString(([0, 0], [0.6, 0]))))
     self.assertTrue(
         substring(self.line1, -1.1, 0.6,
                   True).equals(LineString(([0, 0], [1.2, 0]))))
Esempio n. 7
0
 def test_return_startsubstring(self):
     self.assertEqual(
         substring(self.line1, -500, 0.6).wkt,
         LineString(([0, 0], [0.6, 0])).wkt)
     self.assertEqual(
         substring(self.line1, -1.1, 0.6, True).wkt,
         LineString(([0, 0], [1.2, 0])).wkt)
Esempio n. 8
0
 def test_return_midpoint(self):
     self.assertTrue(substring(self.line1, 0.5, 0.5).equals(Point(0.5, 0)))
     self.assertTrue(
         substring(self.line1, -0.5, -0.5).equals(Point(1.5, 0)))
     self.assertTrue(
         substring(self.line1, 0.5, 0.5, True).equals(Point(1, 0)))
     self.assertTrue(
         substring(self.line1, -0.5, -0.5, True).equals(Point(1, 0)))
Esempio n. 9
0
def lineSplit(lineInfo, cpSegment, meters):
    if LineString(cpSegment).length == 0:
        return
    remainLength = LineString(cpSegment).length
    startLen = 0
    while remainLength >= meters:
        segment = substring(LineString(cpSegment), startLen, startLen + meters)
        lineInfo.addSegment(segment)
        remainLength = remainLength - meters
        startLen = startLen + meters
    segment = substring(LineString(cpSegment), startLen, startLen + meters)
    lineInfo.addSegment(segment)
Esempio n. 10
0
    def get_half_geoms(g, a_node, b_node):
        '''
        For splitting and orienting half geoms
        '''
        # get edge data
        edge_data = g[a_node][b_node]
        # test for x coordinates
        if 'x' not in g.nodes[a_node] or 'y' not in g.nodes[a_node]:
            raise KeyError(
                f'Encountered node missing "x" or "y" coordinate attributes at node {a_node}.'
            )
        # test for y coordinates
        if 'x' not in g.nodes[b_node] or 'y' not in g.nodes[b_node]:
            raise KeyError(
                f'Encountered node missing "x" or "y" coordinate attributes at node {b_node}.'
            )
        a_x = g.nodes[a_node]['x']
        a_y = g.nodes[a_node]['y']
        b_x = g.nodes[b_node]['x']
        b_y = g.nodes[b_node]['y']
        # test for geom
        if 'geom' not in edge_data:
            raise KeyError(
                f'No edge geom found for edge {a_node}-{b_node}: '
                f'Please add an edge "geom" attribute consisting of a shapely LineString.'
            )
        # get edge geometry
        line_geom = edge_data['geom']
        if line_geom.type != 'LineString':
            raise TypeError(
                f'Expecting LineString geometry but found {line_geom.type} geometry for edge {a_node}-{b_node}.'
            )
        # check geom coordinates directionality - flip if facing backwards direction - beware 3d coords
        if not np.allclose(
            (a_x, a_y), line_geom.coords[0][:2], atol=0.001, rtol=0):
            line_geom = geometry.LineString(line_geom.coords[::-1])
        # double check that coordinates now face the forwards direction
        if not np.allclose((a_x, a_y), line_geom.coords[0][:2], atol=0.001, rtol=0) or \
                not np.allclose((b_x, b_y), line_geom.coords[-1][:2], atol=0.001, rtol=0):
            raise ValueError(
                f'Edge geometry endpoint coordinate mismatch for edge {a_node}-{b_node}'
            )
        # generate the two half geoms
        a_half_geom = ops.substring(line_geom, 0, line_geom.length / 2)
        b_half_geom = ops.substring(line_geom, line_geom.length / 2,
                                    line_geom.length)
        assert np.allclose(a_half_geom.coords[-1][:2],
                           b_half_geom.coords[0][:2],
                           atol=0.001,
                           rtol=0)

        return a_half_geom, b_half_geom
Esempio n. 11
0
 def test_return_midsubstring(self):
     self.assertEqual(
         substring(self.line1, 0.5, 0.6).wkt,
         LineString(([0.5, 0], [0.6, 0])).wkt)
     self.assertEqual(
         substring(self.line1, -0.6, -0.5).wkt,
         LineString(([1.4, 0], [1.5, 0])).wkt)
     self.assertEqual(
         substring(self.line1, 0.5, 0.6, True).wkt,
         LineString(([1, 0], [1.2, 0])).wkt)
     self.assertEqual(
         substring(self.line1, -0.6, -0.5, True).wkt,
         LineString(([0.8, 0], [1, 0])).wkt)
Esempio n. 12
0
 def test_return_substring_with_vertices(self):
     self.assertTrue(
         substring(self.line2, 1,
                   7).equals(LineString(([3, 1], [3, 6], [4, 6]))))
     self.assertTrue(
         substring(self.line2, 0.2, 0.9,
                   True).equals(LineString(([3, 1.5], [3, 6], [3.75, 6]))))
     self.assertTrue(
         substring(self.line2, 0, 0.9,
                   True).equals(LineString(([3, 0], [3, 6], [3.75, 6]))))
     self.assertTrue(
         substring(self.line2, 0.2, 1,
                   True).equals(LineString(([3, 1.5], [3, 6], [4.5, 6]))))
Esempio n. 13
0
 def test_return_midsubstring(self):
     self.assertTrue(
         substring(self.line1, 0.5,
                   0.6).equals(LineString(([0.5, 0], [0.6, 0]))))
     self.assertTrue(
         substring(self.line1, 0.6,
                   0.5).equals(LineString(([0.6, 0], [0.5, 0]))))
     self.assertTrue(
         substring(self.line1, -0.5,
                   -0.6).equals(LineString(([1.5, 0], [1.4, 0]))))
     self.assertTrue(
         substring(self.line1, -0.6,
                   -0.5).equals(LineString(([1.4, 0], [1.5, 0]))))
     self.assertTrue(
         substring(self.line1, 0.5, 0.6,
                   True).equals(LineString(([1, 0], [1.2, 0]))))
     self.assertTrue(
         substring(self.line1, 0.6, 0.5,
                   True).equals(LineString(([1.2, 0], [1, 0]))))
     self.assertTrue(
         substring(self.line1, -0.5, -0.6,
                   True).equals(LineString(([1, 0], [0.8, 0]))))
     self.assertTrue(
         substring(self.line1, -0.6, -0.5,
                   True).equals(LineString(([0.8, 0], [1, 0]))))
Esempio n. 14
0
 def test_return_midsubstring(self):
     self.assertTrue(substring(self.line1, 0.5, 0.6).equals(LineString(([0.5, 0], [0.6, 0]))))
     self.assertTrue(substring(self.line1, 0.6, 0.5).equals(LineString(([0.6, 0], [0.5, 0]))))
     self.assertTrue(substring(self.line1, -0.5, -0.6).equals(LineString(([1.5, 0], [1.4, 0]))))
     self.assertTrue(substring(self.line1, -0.6, -0.5).equals(LineString(([1.4, 0], [1.5, 0]))))
     self.assertTrue(substring(self.line1, 0.5, 0.6, True).equals(LineString(([1, 0], [1.2, 0]))))
     self.assertTrue(substring(self.line1, 0.6, 0.5, True).equals(LineString(([1.2, 0], [1, 0]))))
     self.assertTrue(substring(self.line1, -0.5, -0.6, True).equals(LineString(([1, 0], [0.8, 0]))))
     self.assertTrue(substring(self.line1, -0.6, -0.5, True).equals(LineString(([0.8, 0], [1, 0]))))
Esempio n. 15
0
def split_linestring(
        geometry: Union[LineString, MultiLineString, Iterable],
        max_length: float,
        pool: Pool = None) -> Union[List[LineString], List[List[LineString]]]:
    """
    Splits a LineString into smaller parts with equal length not exceeding max_length. NOTE: the length must be provided
    in an appropriate unit as of the one used in LineString coordinate system. If the input geometry is a
    MultiLineString each LineString geometry is divided. If the input geometry is neither a LineString nor a
    MultiLineString the same geometry is returned within the list.

    :param geometry: The LineString object needs splitting

    :param max_length: The maximum length that each split will have. NOTE: The actual length would not exceed this
                       value.

    :param pool: a process pool to be used for parallelism. The pool is only used if the geometry is of type iterable.

    :return: a list of LineString Object if the input is LineString or MultiLineString; or a list of list of LineString,
             if the input geometry is an iterable of LineString and MultiString.

    """
    output = None
    if isinstance(geometry, LineString):
        length = geometry.length
        n_parts = int(np.ceil(length / max_length))
        fractions = np.linspace(0, 1, n_parts + 1)
        output = [
            ops.substring(geometry,
                          start_fraction,
                          end_fraction,
                          normalized=True) for start_fraction, end_fraction in
            zip(fractions[:-1], fractions[1:])
        ]
    elif isinstance(geometry, MultiLineString):
        output = []
        for linestring in geometry.geoms:
            output.extend(split_linestring(linestring, max_length))
    elif isinstance(
            geometry, Iterable
    ):  # make sure this is listed after LineString & MultiLineString
        if pool is not None:  # PARALLEL
            # print('PARALLEL')
            chunked_geometry = to_chunk(geometry, pool=pool)
            pool_output = [
                pool.apply_async(split_linestring, (chunk, max_length))
                for chunk in chunked_geometry
            ]

            output = []
            for e in pool_output:
                output.extend(e.get())
        else:  # SERIAL
            # print('SERIAL')
            output = [split_linestring(e, max_length) for e in geometry]

    else:
        output = [geometry]

    return output
Esempio n. 16
0
 def getTerminusWidth(self):
     """Compute box width at points where terminus intersects box, and return average width in km."""
     if self.referencebox.geom_type == 'MultiLineString':
         box = ops.linemerge(ops.MultiLineString(self.referencebox))
     else:
         box = ops.LineString(self.referencebox)
     # Split box into two halves
     half1 = ops.substring(box, 0, 0.5, normalized=True)
     half2 = ops.substring(box, 0.5, 1, normalized=True)
     # Get terminus intersections with box halves
     tx1 = self.terminus.intersection(half1)
     tx2 = self.terminus.intersection(half2)
     # Get distance from intersection point to other half
     tx1_dist = tx1.distance(half2)
     tx2_dist = tx2.distance(half1)
     # Get average distance across box, i.e. average terminus width
     average_width = (tx1_dist + tx2_dist) / 2 / 10**3
     return average_width
Esempio n. 17
0
    def test_return_midpoint(self):
        self.assertTrue(substring(self.line1, 0.5, 0.5).equals(Point(0.5, 0)))
        self.assertTrue(substring(self.line1, -0.5, -0.5).equals(Point(1.5, 0)))
        self.assertTrue(substring(self.line1, 0.5, 0.5, True).equals(Point(1, 0)))
        self.assertTrue(substring(self.line1, -0.5, -0.5, True).equals(Point(1, 0)))

        # Coming from opposite ends
        self.assertTrue(substring(self.line1, 1.5, -0.5).equals(Point(1.5, 0)))
        self.assertTrue(substring(self.line1, -0.5, 1.5).equals(Point(1.5, 0)))
        self.assertTrue(substring(self.line1, -0.7, 0.3, True).equals(Point(0.6, 0)))
        self.assertTrue(substring(self.line1, 0.3, -0.7, True).equals(Point(0.6, 0)))
Esempio n. 18
0
    def calculate_center_lane(self, resolution: float):
        """ Calculate center lane of the road by applying lane offsets
         and store them in the respective center lanes. """
        ref_line = self.plan_view.midline
        if not self.lanes.lane_offsets:
            center_lane = ref_line
        else:
            sample_distances = np.linspace(
                0.0, ref_line.length,
                int(ref_line.length / resolution) + 1)
            offsets = []

            for offset_idx, offset in enumerate(self.lanes.lane_offsets):
                if offset_idx == len(self.lanes.lane_offsets) - 1:
                    section_distances = sample_distances[
                        offset.start_offset <= sample_distances]
                else:
                    next_offset = self.lanes.lane_offsets[offset_idx + 1]
                    indices = ((offset.start_offset <= sample_distances) &
                               (sample_distances < next_offset.start_offset)
                               ).nonzero()[0]
                    section_distances = sample_distances[indices]
                coefficients = list(reversed(offset.polynomial_coefficients))
                section_offset = np.polyval(
                    coefficients, section_distances - offset.start_offset)
                offsets.append(section_offset)

            offsets = np.hstack(offsets)
            points = []
            for i, d in enumerate(sample_distances):
                point = ref_line.interpolate(d)
                theta = normalise_angle(self.plan_view.calc(d)[1] + np.pi / 2)
                normal = np.array([np.cos(theta), np.sin(theta)])
                points.append(tuple(point + offsets[i] * normal))

            center_lane = LineString(ramer_douglas(points, dist=0.01))
            if not center_lane.is_simple:
                coords_list = []
                for non_intersecting_ls in unary_union(center_lane):
                    if non_intersecting_ls.length > 0.5:
                        coords_list.extend(non_intersecting_ls.coords)
                center_lane = LineString(coords_list)

        # Assign midlines for each center lane for every lane section
        for ls in self.lanes.lane_sections:
            lane = ls.center_lanes[0]
            lane._ref_line = substring(center_lane,
                                       ls.start_distance / ref_line.length,
                                       (ls.start_distance + ls.length) /
                                       ref_line.length,
                                       normalized=True)
Esempio n. 19
0
    def cut_polygon_to_resolution(self, poly, resolution):
        """cuts the straight lines into equally sized line segments no larger than the prescribed resolution"""
        segments = []
        poly_coords = list(poly.exterior.coords)
        for i in range(len(poly_coords) - 1):
            line = LineString((poly_coords[i], poly_coords[i + 1]))
            # we here determine the actual resolution of the polygons
            divs = line.length / (np.ceil(line.length / resolution))

            for j in np.arange(0, line.length, divs):
                segment = substring(line, j, j + divs)
                segments.extend(list(segment.coords)[1:2])
        final_polygon = Polygon(segments[:])
        return final_polygon
Esempio n. 20
0
def cut_vector(vector_path, cut_distances):
    """Cut vector at defined distances."""

    sub_vectors = []  # Holds sub-vectors

    # Read the full vector
    vector = read_vector(vector_path)

    # Cut vector at every distance point in cut_distances
    for i, dist in enumerate(cut_distances):
        # First segment
        if i == 0:
            sub_v = op.substring(vector, 0, dist, normalized=True)
        # Later segments
        else:
            sub_v = op.substring(vector,
                                 cut_distances[i - 1],
                                 dist,
                                 normalized=True)

        # Add cut segment to list
        sub_vectors.append(sub_v)
    return sub_vectors
Esempio n. 21
0
 def test_return_endsubstring_reversed(self):
     # not normalized
     self.assertEqual(substring(self.line1, 500, -1).wkt, LineString(([2, 0], [1, 0])).wkt)
     self.assertEqual(substring(self.line3, 4, 2.5).wkt, LineString(([0, 4], [0, 3], [0, 2.5])).wkt)
     self.assertEqual(substring(self.line3, 500, -1.5).wkt, LineString(([0, 4], [0, 3], [0, 2.5])).wkt)
     # normalized
     self.assertEqual(substring(self.line1, 1.1, -0.5, True).wkt, LineString(([2, 0], [1.0, 0])).wkt)
     self.assertEqual(substring(self.line3, 1, 0.5, True).wkt, LineString(([0, 4], [0, 3], [0, 2.0])).wkt)
     self.assertEqual(substring(self.line3, 1.1, -0.5, True).wkt, LineString(([0, 4], [0, 3], [0, 2.0])).wkt)
Esempio n. 22
0
 def test_return_startsubstring_reversed(self):
     # not normalized
     self.assertEqual(substring(self.line1, -1, -500).wkt, LineString(([1, 0], [0, 0])).wkt)
     self.assertEqual(substring(self.line3, 3.5, 0).wkt, LineString(([0, 3.5], [0, 3], [0, 2], [0, 1], [0, 0])).wkt)
     self.assertEqual(substring(self.line3, -1.5, -500).wkt, LineString(([0, 2.5], [0, 2], [0, 1], [0, 0])).wkt)
     # normalized
     self.assertEqual(substring(self.line1, -0.5, -1.1, True).wkt, LineString(([1.0, 0], [0, 0])).wkt)
     self.assertEqual(substring(self.line3, 0.5, 0, True).wkt, LineString(([0, 2.0], [0, 1], [0, 0])).wkt)
     self.assertEqual(substring(self.line3, -0.5, -1.1, True).wkt, LineString(([0, 2.0], [0, 1], [0, 0])).wkt)
Esempio n. 23
0
def make_messy_graph(G):
    # test that redundant (sraight) intersections are removed
    G_messy = G.copy(G)

    # complexify the graph - write changes to new graph to avoid in-place iteration errors
    for i, (s, e, k, d) in enumerate(G.edges(data=True, keys=True)):
        # flip each third geom
        if i % 3 == 0:
            flipped_coords = np.fliplr(d['geom'].coords.xy)
            G_messy[s][e][k]['geom'] = geometry.LineString(
                [[x, y] for x, y in zip(flipped_coords[0], flipped_coords[1])])
        # split each second geom
        if i % 2 == 0:
            line_geom = G[s][e][k]['geom']
            # check geom coordinates directionality - flip if facing backwards direction
            if not (G.nodes[s]['x'], G.nodes[s]['y']) == line_geom.coords[0][:2]:
                flipped_coords = np.fliplr(line_geom.coords.xy)
                line_geom = geometry.LineString([[x, y] for x, y in zip(flipped_coords[0], flipped_coords[1])])
            # remove old edge
            G_messy.remove_edge(s, e)
            # new midpoint 'x' and 'y' coordinates
            s_geom = ops.substring(line_geom, 0, 0.5, normalized=True)
            e_geom = ops.substring(line_geom, 0.5, 1, normalized=True)
            # looking for the non-matching coordinates
            mid_x, mid_y = s_geom.coords[-1][:2]
            # add new edges
            G_messy.add_edge(s, f'{s}-{e}', geom=s_geom)
            G_messy.add_edge(e, f'{s}-{e}', geom=e_geom)
            G_messy.nodes[f'{s}-{e}']['x'] = mid_x
            G_messy.nodes[f'{s}-{e}']['y'] = mid_y

    # test recursive weld by manually adding a chained series of orphan nodes
    geom = G[10][43][0]['geom']
    geom_a = ops.substring(geom, 0, 0.25, normalized=True)
    G_messy.add_edge(10, 't_1', geom=geom_a)
    a_x, a_y = geom_a.coords[-1][:2]
    G_messy.nodes['t_1']['x'] = a_x
    G_messy.nodes['t_1']['y'] = a_y
    geom_b = ops.substring(geom, 0.25, 0.5, normalized=True)
    G_messy.add_edge('t_1', 't_2', geom=geom_b)
    b_x, b_y = geom_b.coords[-1][:2]
    G_messy.nodes['t_2']['x'] = b_x
    G_messy.nodes['t_2']['y'] = b_y
    geom_c = ops.substring(geom, 0.5, 0.75, normalized=True)
    G_messy.add_edge('t_2', 't_3', geom=geom_c)
    c_x, c_y = geom_c.coords[-1][:2]
    G_messy.nodes['t_3']['x'] = c_x
    G_messy.nodes['t_3']['y'] = c_y
    geom_d = ops.substring(geom, 0.75, 1.0, normalized=True)
    G_messy.add_edge('t_3', 43, geom=geom_d)
    # remove original geom
    G_messy.remove_edge(10, 43)

    return G_messy
Esempio n. 24
0
    def get_as_shape(self, cap_style=CAP_STYLE.flat):
        """
        Get marking as a shapely Polygon or MultiPolygon

        :param cap_style: cap style to use when performing buffer
        :return: shapely Polygon or MultiPolygon
        """
        if self.dashes[1] == 0:  # if solid line
            buffer = self.alignment.buffer(self.linewidth / 2, cap_style=cap_style)
        else:  # if dashed line
            buffer = MultiPolygon()
            dash_length, gap = self.dashes
            for s in np.arange(0, self.alignment.length, dash_length + gap):
                assert hasattr(ops, "substring"), "Shapely>=1.7.0 is required for OBJ export of dashed lines."
                dash_segment = ops.substring(self.alignment, s, min(s + dash_length, self.alignment.length))
                buffer = buffer.union(dash_segment.buffer(self.linewidth / 2, cap_style=cap_style))
        return buffer
Esempio n. 25
0
    def shape(self) -> LineString:
        "Returns the shape of the route. The route is has to be continuous."
        if self.start.line.line_id == self.end.line.line_id:
            return substring(self.start.line.geometry,
                             self.start.relative_offset,
                             self.end.relative_offset,
                             normalized=True)

        result = []
        first = self.start.split()[1]
        last = self.end.split()[0]
        if first is not None:
            result.append(first)
        result += [line.geometry for line in self.path_inbetween]
        if last is not None:
            result.append(last)

        return join_lines(result)
def project(line: Line, coord: Coordinates) -> PointOnLine:
    """Computes the nearest point to `coord` on the line

    Returns: The point on `line` where this nearest point resides"""
    fraction = line.geometry.project(Point(coord.lon, coord.lat),
                                     normalized=True)

    to_projection_point = substring(line.geometry,
                                    0.0,
                                    fraction,
                                    normalized=True)

    meters_to_projection_point = line_string_length(to_projection_point)
    geometry_length = line_string_length(line.geometry)

    length_fraction = meters_to_projection_point / geometry_length

    return PointOnLine(line, length_fraction)
Esempio n. 27
0
 def test_return_startpoint(self):
     self.assertTrue(substring(self.line1, -500, -600).equals(Point(0, 0)))
     self.assertTrue(substring(self.line1, -500, -500).equals(Point(0, 0)))
     self.assertTrue(substring(self.line1, -1, -1.1, True).equals(Point(0, 0)))
     self.assertTrue(substring(self.line1, -1.1, -1.1, True).equals(Point(0, 0)))               
Esempio n. 28
0
 def test_return_endpoint(self):
     self.assertTrue(substring(self.line1, 500, 600).equals(Point(2, 0)))
     self.assertTrue(substring(self.line1, 500, 500).equals(Point(2, 0)))
     self.assertTrue(substring(self.line1, 1, 1.1, True).equals(Point(2, 0)))   
     self.assertTrue(substring(self.line1, 1.1, 1.1, True).equals(Point(2, 0)))
Esempio n. 29
0
 def test_return_endsubstring(self):
     self.assertTrue(substring(self.line1, 0.6, 500).equals(LineString(([0.6, 0], [2, 0]))))
     self.assertTrue(substring(self.line1, 0.6, 1.1, True).equals(LineString(([1.2, 0], [2, 0]))))
Esempio n. 30
0
def confinement(huc: int,
                flowlines_orig: Path,
                confining_polygon_orig: Path,
                output_folder: Path,
                buffer_field: str,
                confinement_type: str,
                reach_codes: List[str],
                min_buffer: float = 0.0,
                bankfull_expansion_factor: float = 1.0,
                debug: bool = False,
                meta=None):
    """Generate confinement attribute for a stream network

    Args:
        huc (integer): Huc identifier
        flowlines (path): input flowlines layer
        confining_polygon (path): valley bottom or other boundary defining confining margins
        output_folder (path): location to store confinement project and output geopackage
        buffer_field (string): name of float field with buffer values in meters (i.e. 'BFWidth')
        confinement_type (string): name of type of confinement generated
        reach_codes (List[int]): NHD reach codes for features to include in outputs
        min_buffer (float): minimum bankfull value to use in buffers e.g. raster cell resolution
        bankfull_expansion_factor (float): factor to expand bankfull on each side of bank
        debug (bool): run tool in debug mode (save intermediate outputs). Default = False
        meta (Dict[str,str]): dictionary of riverscapes metadata key: value pairs
    """

    log = Logger("Confinement")
    log.info(f'Confinement v.{cfg.version}')  # .format(cfg.version))

    try:
        int(huc)
    except ValueError:
        raise Exception(
            'Invalid HUC identifier "{}". Must be an integer'.format(huc))

    if not (len(huc) == 4 or len(huc) == 8):
        raise Exception('Invalid HUC identifier. Must be four digit integer')

    # Make the projectXML
    project, _realization, proj_nodes, report_path = create_project(
        huc, output_folder, {'ConfinementType': confinement_type})

    # Incorporate project metadata to the riverscapes project
    if meta is not None:
        project.add_metadata(meta)

    # Copy input shapes to a geopackage
    flowlines_path = os.path.join(
        output_folder, LayerTypes['INPUTS'].rel_path,
        LayerTypes['INPUTS'].sub_layers['FLOWLINES'].rel_path)
    confining_path = os.path.join(
        output_folder, LayerTypes['INPUTS'].rel_path,
        LayerTypes['INPUTS'].sub_layers['CONFINING_POLYGON'].rel_path)

    copy_feature_class(flowlines_orig, flowlines_path, epsg=cfg.OUTPUT_EPSG)
    copy_feature_class(confining_polygon_orig,
                       confining_path,
                       epsg=cfg.OUTPUT_EPSG)

    _nd, _inputs_gpkg_path, inputs_gpkg_lyrs = project.add_project_geopackage(
        proj_nodes['Inputs'], LayerTypes['INPUTS'])

    output_gpkg = os.path.join(output_folder,
                               LayerTypes['CONFINEMENT'].rel_path)
    intermediates_gpkg = os.path.join(output_folder,
                                      LayerTypes['INTERMEDIATES'].rel_path)

    # Creates an empty geopackage and replaces the old one
    GeopackageLayer(output_gpkg, delete_dataset=True)
    GeopackageLayer(intermediates_gpkg, delete_dataset=True)

    # Add the flowlines file with some metadata
    project.add_metadata({'BufferField': buffer_field},
                         inputs_gpkg_lyrs['FLOWLINES'][0])

    # Add the confinement polygon
    project.add_project_geopackage(proj_nodes['Intermediates'],
                                   LayerTypes['INTERMEDIATES'])
    _nd, _inputs_gpkg_path, out_gpkg_lyrs = project.add_project_geopackage(
        proj_nodes['Outputs'], LayerTypes['CONFINEMENT'])

    # Additional Metadata
    project.add_metadata(
        {
            'Min Buffer': str(min_buffer),
            "Expansion Factor": str(bankfull_expansion_factor)
        }, out_gpkg_lyrs['CONFINEMENT_BUFFERS'][0])

    # Generate confining margins
    log.info(f"Preparing output geopackage: {output_gpkg}")
    log.info(f"Generating Confinement from buffer field: {buffer_field}")

    # Load input datasets and set the global srs and a meter conversion factor
    with GeopackageLayer(flowlines_path) as flw_lyr:
        srs = flw_lyr.spatial_ref
        meter_conversion = flw_lyr.rough_convert_metres_to_vector_units(1)

    geom_confining_polygon = get_geometry_unary_union(confining_path,
                                                      cfg.OUTPUT_EPSG)

    # Calculate Spatial Constants
    # Get a very rough conversion factor for 1m to whatever units the shapefile uses
    offset = 0.1 * meter_conversion
    selection_buffer = 0.1 * meter_conversion

    # Standard Outputs
    field_lookup = {
        'side': ogr.FieldDefn("Side", ogr.OFTString),
        'flowlineID': ogr.FieldDefn(
            "NHDPlusID", ogr.OFTString
        ),  # ArcGIS cannot read Int64 and will show up as 0, however data is stored correctly in GPKG
        'confinement_type': ogr.FieldDefn("Confinement_Type", ogr.OFTString),
        'confinement_ratio': ogr.FieldDefn("Confinement_Ratio", ogr.OFTReal),
        'constriction_ratio': ogr.FieldDefn("Constriction_Ratio", ogr.OFTReal),
        'length': ogr.FieldDefn("ApproxLeng", ogr.OFTReal),
        'confined_length': ogr.FieldDefn("ConfinLeng", ogr.OFTReal),
        'constricted_length': ogr.FieldDefn("ConstrLeng", ogr.OFTReal),
        'bankfull_width': ogr.FieldDefn("Bankfull_Width", ogr.OFTReal),
        'buffer_width': ogr.FieldDefn("Buffer_Width", ogr.OFTReal),
        # Couple of Debug fields too
        'process': ogr.FieldDefn("ErrorProcess", ogr.OFTString),
        'message': ogr.FieldDefn("ErrorMessage", ogr.OFTString)
    }

    field_lookup['side'].SetWidth(5)
    field_lookup['confinement_type'].SetWidth(5)

    # Here we open all the necessary output layers and write the fields to them. There's no harm in quickly
    # Opening these layers to instantiate them

    # Standard Outputs
    with GeopackageLayer(output_gpkg,
                         layer_name=LayerTypes['CONFINEMENT'].
                         sub_layers["CONFINEMENT_MARGINS"].rel_path,
                         write=True) as margins_lyr:
        margins_lyr.create(ogr.wkbLineString, spatial_ref=srs)
        margins_lyr.ogr_layer.CreateField(field_lookup['side'])
        margins_lyr.ogr_layer.CreateField(field_lookup['flowlineID'])
        margins_lyr.ogr_layer.CreateField(field_lookup['length'])

    with GeopackageLayer(output_gpkg,
                         layer_name=LayerTypes['CONFINEMENT'].
                         sub_layers["CONFINEMENT_RAW"].rel_path,
                         write=True) as raw_lyr:
        raw_lyr.create(ogr.wkbLineString, spatial_ref=srs)
        raw_lyr.ogr_layer.CreateField(field_lookup['flowlineID'])
        raw_lyr.ogr_layer.CreateField(field_lookup['confinement_type'])
        raw_lyr.ogr_layer.CreateField(field_lookup['length'])

    with GeopackageLayer(output_gpkg,
                         layer_name=LayerTypes['CONFINEMENT'].
                         sub_layers["CONFINEMENT_RATIO"].rel_path,
                         write=True) as ratio_lyr:
        ratio_lyr.create(ogr.wkbLineString, spatial_ref=srs)
        ratio_lyr.ogr_layer.CreateField(field_lookup['flowlineID'])
        ratio_lyr.ogr_layer.CreateField(field_lookup['confinement_ratio'])
        ratio_lyr.ogr_layer.CreateField(field_lookup['constriction_ratio'])
        ratio_lyr.ogr_layer.CreateField(field_lookup['length'])
        ratio_lyr.ogr_layer.CreateField(field_lookup['confined_length'])
        ratio_lyr.ogr_layer.CreateField(field_lookup['constricted_length'])

    with GeopackageLayer(intermediates_gpkg,
                         layer_name=LayerTypes['INTERMEDIATES'].
                         sub_layers["CONFINEMENT_BUFFER_SPLIT"].rel_path,
                         write=True) as lyr:
        lyr.create(ogr.wkbPolygon, spatial_ref=srs)
        lyr.ogr_layer.CreateField(field_lookup['side'])
        lyr.ogr_layer.CreateField(field_lookup['flowlineID'])
        lyr.ogr_layer.CreateField(field_lookup['bankfull_width'])
        lyr.ogr_layer.CreateField(field_lookup['buffer_width'])

    with GeopackageLayer(output_gpkg,
                         layer_name=LayerTypes['CONFINEMENT'].
                         sub_layers["CONFINEMENT_BUFFERS"].rel_path,
                         write=True) as lyr:
        lyr.create(ogr.wkbPolygon, spatial_ref=srs)
        lyr.ogr_layer.CreateField(field_lookup['flowlineID'])
        lyr.ogr_layer.CreateField(field_lookup['bankfull_width'])
        lyr.ogr_layer.CreateField(field_lookup['buffer_width'])

    with GeopackageLayer(intermediates_gpkg,
                         layer_name=LayerTypes['INTERMEDIATES'].
                         sub_layers["SPLIT_POINTS"].rel_path,
                         write=True) as lyr:
        lyr.create(ogr.wkbPoint, spatial_ref=srs)
        lyr.ogr_layer.CreateField(field_lookup['side'])
        lyr.ogr_layer.CreateField(field_lookup['flowlineID'])

    with GeopackageLayer(intermediates_gpkg,
                         layer_name=LayerTypes['INTERMEDIATES'].
                         sub_layers["FLOWLINE_SEGMENTS"].rel_path,
                         write=True) as lyr:
        lyr.create(ogr.wkbLineString, spatial_ref=srs)
        lyr.ogr_layer.CreateField(field_lookup['side'])
        lyr.ogr_layer.CreateField(field_lookup['flowlineID'])

    with GeopackageLayer(intermediates_gpkg,
                         layer_name=LayerTypes['INTERMEDIATES'].
                         sub_layers["ERROR_POLYLINES"].rel_path,
                         write=True) as lyr:
        lyr.create(ogr.wkbLineString, spatial_ref=srs)
        lyr.ogr_layer.CreateField(field_lookup['process'])
        lyr.ogr_layer.CreateField(field_lookup['message'])

    with GeopackageLayer(intermediates_gpkg,
                         layer_name=LayerTypes['INTERMEDIATES'].
                         sub_layers["ERROR_POLYGONS"].rel_path,
                         write=True) as lyr:
        lyr.create(ogr.wkbPolygon, spatial_ref=srs)
        lyr.ogr_layer.CreateField(field_lookup['process'])
        lyr.ogr_layer.CreateField(field_lookup['message'])

    # Generate confinement per Flowline
    with GeopackageLayer(flowlines_path) as flw_lyr, \
            GeopackageLayer(output_gpkg, layer_name=LayerTypes['CONFINEMENT'].sub_layers["CONFINEMENT_MARGINS"].rel_path, write=True) as margins_lyr, \
            GeopackageLayer(output_gpkg, layer_name=LayerTypes['CONFINEMENT'].sub_layers["CONFINEMENT_RAW"].rel_path, write=True) as raw_lyr, \
            GeopackageLayer(output_gpkg, layer_name=LayerTypes['CONFINEMENT'].sub_layers["CONFINEMENT_RATIO"].rel_path, write=True) as ratio_lyr, \
            GeopackageLayer(intermediates_gpkg, layer_name=LayerTypes['INTERMEDIATES'].sub_layers["SPLIT_POINTS"].rel_path, write=True) as dbg_splitpts_lyr, \
            GeopackageLayer(intermediates_gpkg, layer_name=LayerTypes['INTERMEDIATES'].sub_layers["FLOWLINE_SEGMENTS"].rel_path, write=True) as dbg_flwseg_lyr, \
            GeopackageLayer(intermediates_gpkg, layer_name=LayerTypes['INTERMEDIATES'].sub_layers["CONFINEMENT_BUFFER_SPLIT"].rel_path, write=True) as conf_buff_split_lyr, \
            GeopackageLayer(output_gpkg, layer_name=LayerTypes['CONFINEMENT'].sub_layers["CONFINEMENT_BUFFERS"].rel_path, write=True) as buff_lyr, \
            GeopackageLayer(intermediates_gpkg, layer_name=LayerTypes['INTERMEDIATES'].sub_layers["ERROR_POLYLINES"].rel_path, write=True) as dbg_err_lines_lyr, \
            GeopackageLayer(intermediates_gpkg, layer_name=LayerTypes['INTERMEDIATES'].sub_layers["ERROR_POLYGONS"].rel_path, write=True) as dbg_err_polygons_lyr:

        err_count = 0

        for flowline, _counter, progbar in flw_lyr.iterate_features(
                "Generating confinement for flowlines",
                attribute_filter="FCode IN ({0})".format(','.join(
                    [key for key in reach_codes])),
                write_layers=[
                    margins_lyr, raw_lyr, ratio_lyr, dbg_splitpts_lyr,
                    dbg_flwseg_lyr, buff_lyr, conf_buff_split_lyr,
                    dbg_err_lines_lyr, dbg_err_polygons_lyr
                ]):
            # Load Flowline
            flowlineID = int(flowline.GetFieldAsInteger64("NHDPlusID"))

            bankfull_width = flowline.GetField(buffer_field)
            buffer_value = max(bankfull_width, min_buffer)

            geom_flowline = GeopackageLayer.ogr2shapely(flowline)
            if not geom_flowline.is_valid or geom_flowline.is_empty or geom_flowline.length == 0:
                progbar.erase()
                log.warning("Invalid flowline with id: {}".format(flowlineID))
                continue

            # Generate buffer on each side of the flowline
            geom_buffer = geom_flowline.buffer(
                ((buffer_value * meter_conversion) / 2) *
                bankfull_expansion_factor,
                cap_style=2)

            # inital cleanup if geom is multipolygon
            if geom_buffer.geom_type == "MultiPolygon":
                log.warning(f"Cleaning multipolygon for id{flowlineID}")
                polys = [g for g in geom_buffer if g.intersects(geom_flowline)]
                if len(polys) == 1:
                    geom_buffer = polys[0]

            if not geom_buffer.is_valid or geom_buffer.is_empty or geom_buffer.area == 0 or geom_buffer.geom_type not in [
                    "Polygon"
            ]:
                progbar.erase()
                log.warning("Invalid flowline (after buffering) id: {}".format(
                    flowlineID))
                dbg_err_lines_lyr.create_feature(
                    geom_flowline, {
                        "ErrorProcess": "Generate Buffer",
                        "ErrorMessage": "Invalid Buffer"
                    })
                err_count += 1
                continue

            buff_lyr.create_feature(
                geom_buffer, {
                    "NHDPlusID": flowlineID,
                    "Buffer_Width": buffer_value,
                    "Bankfull_Width": bankfull_width
                })

            # Split the Buffer by the flowline
            geom_buffer_splits = split(
                geom_buffer, geom_flowline
            )  # snap(geom, geom_buffer)) <--shapely does not snap vertex to edge. need to make new function for this to ensure more buffers have 2 split polygons
            # Process only if 2 buffers exist
            if len(geom_buffer_splits) != 2:

                # Lets try to split this again by slightly extending the line
                geom_newline = scale(geom_flowline, 1.1, 1.1, origin='center')
                geom_buffer_splits = split(geom_buffer, geom_newline)

                if len(geom_buffer_splits) != 2:
                    # triage the polygon if still cannot split it
                    error_message = f"WARNING: Flowline FID {flowline.GetFID()} | Incorrect number of split buffer polygons: {len(geom_buffer_splits)}"
                    progbar.erase()
                    log.warning(error_message)
                    dbg_err_lines_lyr.create_feature(
                        geom_flowline, {
                            "ErrorProcess": "Buffer Split",
                            "ErrorMessage": error_message
                        })
                    err_count += 1
                    if len(geom_buffer_splits) > 1:
                        for geom in geom_buffer_splits:
                            dbg_err_polygons_lyr.create_feature(
                                geom, {
                                    "ErrorProcess": "Buffer Split",
                                    "ErrorMessage": error_message
                                })
                    else:
                        dbg_err_polygons_lyr.create_feature(
                            geom_buffer_splits, {
                                "ErrorProcess": "Buffer Split",
                                "ErrorMessage": error_message
                            })
                    continue

            # Generate point to test side of flowline
            geom_offset = geom_flowline.parallel_offset(offset, "left")
            if not geom_offset.is_valid or geom_offset.is_empty or geom_offset.length == 0:
                progbar.erase()
                log.warning("Invalid flowline (after offset) id: {}".format(
                    flowlineID))
                err_count += 1
                dbg_err_lines_lyr.create_feature(
                    geom_flowline, {
                        "ErrorProcess":
                        "Offset Error",
                        "ErrorMessage":
                        "Invalid flowline (after offset) id: {}".format(
                            flowlineID)
                    })
                continue

            geom_side_point = geom_offset.interpolate(0.5, True)

            # Store output segements
            lgeoms_right_confined_flowline_segments = []
            lgeoms_left_confined_flowline_segments = []

            for geom_side in geom_buffer_splits:

                # Identify side of flowline
                side = "LEFT" if geom_side.contains(
                    geom_side_point) else "RIGHT"

                # Save the polygon
                conf_buff_split_lyr.create_feature(
                    geom_side, {
                        "Side": side,
                        "NHDPlusID": flowlineID,
                        "Buffer_Width": buffer_value,
                        "Bankfull_Width": bankfull_width
                    })

                # Generate Confining margins
                geom_confined_margins = geom_confining_polygon.boundary.intersection(
                    geom_side)  # make sure intersection splits lines
                if geom_confined_margins.is_empty:
                    continue

                # Multilinestring to individual linestrings
                lines = [
                    line for line in geom_confined_margins
                ] if geom_confined_margins.geom_type == 'MultiLineString' else [
                    geom_confined_margins
                ]
                for line in lines:
                    margins_lyr.create_feature(
                        line, {
                            "Side": side,
                            "NHDPlusID": flowlineID,
                            "ApproxLeng": line.length / meter_conversion
                        })

                    # Split flowline by Near Geometry
                    pt_start = nearest_points(Point(line.coords[0]),
                                              geom_flowline)[1]
                    pt_end = nearest_points(Point(line.coords[-1]),
                                            geom_flowline)[1]

                    for point in [pt_start, pt_end]:
                        dbg_splitpts_lyr.create_feature(
                            point, {
                                "Side": side,
                                "NHDPlusID": flowlineID
                            })

                    distance_sorted = sorted([
                        geom_flowline.project(pt_start),
                        geom_flowline.project(pt_end)
                    ])
                    segment = substring(geom_flowline, distance_sorted[0],
                                        distance_sorted[1])

                    # Store the segment by flowline side
                    if segment.is_valid and segment.geom_type in [
                            "LineString", "MultiLineString"
                    ]:
                        if side == "LEFT":
                            lgeoms_left_confined_flowline_segments.append(
                                segment)
                        else:
                            lgeoms_right_confined_flowline_segments.append(
                                segment)

                        dbg_flwseg_lyr.create_feature(segment, {
                            "Side": side,
                            "NHDPlusID": flowlineID
                        })

            # Raw Confinement Output
            # Prepare flowline splits
            splitpoints = [
                Point(x, y)
                for line in lgeoms_left_confined_flowline_segments +
                lgeoms_right_confined_flowline_segments for x, y in line.coords
            ]
            cut_distances = sorted(
                list(
                    set([
                        geom_flowline.project(point) for point in splitpoints
                    ])))
            lgeoms_flowlines_split = []
            current_line = geom_flowline
            cumulative_distance = 0.0
            while len(cut_distances) > 0:
                distance = cut_distances.pop(0) - cumulative_distance
                if not distance == 0.0:
                    outline = cut(current_line, distance)
                    if len(outline) == 1:
                        current_line = outline[0]
                    else:
                        current_line = outline[1]
                        lgeoms_flowlines_split.append(outline[0])
                    cumulative_distance = cumulative_distance + distance
            lgeoms_flowlines_split.append(current_line)

            # Confined Segments
            lgeoms_confined_left_split = select_geoms_by_intersection(
                lgeoms_flowlines_split,
                lgeoms_left_confined_flowline_segments,
                buffer=selection_buffer)
            lgeoms_confined_right_split = select_geoms_by_intersection(
                lgeoms_flowlines_split,
                lgeoms_right_confined_flowline_segments,
                buffer=selection_buffer)

            lgeoms_confined_left = select_geoms_by_intersection(
                lgeoms_confined_left_split,
                lgeoms_confined_right_split,
                buffer=selection_buffer,
                inverse=True)
            lgeoms_confined_right = select_geoms_by_intersection(
                lgeoms_confined_right_split,
                lgeoms_confined_left_split,
                buffer=selection_buffer,
                inverse=True)

            geom_confined = unary_union(lgeoms_confined_left_split +
                                        lgeoms_confined_right_split)

            # Constricted Segments
            lgeoms_constricted_l = select_geoms_by_intersection(
                lgeoms_confined_left_split,
                lgeoms_confined_right_split,
                buffer=selection_buffer)
            lgeoms_constrcited_r = select_geoms_by_intersection(
                lgeoms_confined_right_split,
                lgeoms_confined_left_split,
                buffer=selection_buffer)
            lgeoms_constricted = []
            for geom in lgeoms_constricted_l + lgeoms_constrcited_r:
                if not any(g.equals(geom) for g in lgeoms_constricted):
                    lgeoms_constricted.append(geom)
            geom_constricted = MultiLineString(lgeoms_constricted)

            # Unconfined Segments
            lgeoms_unconfined = select_geoms_by_intersection(
                lgeoms_flowlines_split,
                lgeoms_confined_left_split + lgeoms_confined_right_split,
                buffer=selection_buffer,
                inverse=True)

            # Save Raw Confinement
            for con_type, geoms in zip(["Left", "Right", "Both", "None"], [
                    lgeoms_confined_left, lgeoms_confined_right,
                    lgeoms_constricted, lgeoms_unconfined
            ]):
                for g in geoms:
                    if g.geom_type == "LineString":
                        raw_lyr.create_feature(
                            g, {
                                "NHDPlusID": flowlineID,
                                "Confinement_Type": con_type,
                                "ApproxLeng": g.length / meter_conversion
                            })
                    elif geoms.geom_type in ["Point", "MultiPoint"]:
                        progbar.erase()
                        log.warning(
                            f"Flowline FID: {flowline.GetFID()} | Point geometry identified generating outputs for Raw Confinement."
                        )
                    else:
                        progbar.erase()
                        log.warning(
                            f"Flowline FID: {flowline.GetFID()} | Unknown geometry identified generating outputs for Raw Confinement."
                        )

            # Calculated Confinement per Flowline
            confinement_ratio = geom_confined.length / geom_flowline.length if geom_confined else 0.0
            constricted_ratio = geom_constricted.length / geom_flowline.length if geom_constricted else 0.0

            # Save Confinement Ratio
            attributes = {
                "NHDPlusID":
                flowlineID,
                "Confinement_Ratio":
                confinement_ratio,
                "Constriction_Ratio":
                constricted_ratio,
                "ApproxLeng":
                geom_flowline.length / meter_conversion,
                "ConfinLeng":
                geom_confined.length /
                meter_conversion if geom_confined else 0.0,
                "ConstrLeng":
                geom_constricted.length /
                meter_conversion if geom_constricted else 0.0
            }

            ratio_lyr.create_feature(geom_flowline, attributes)

    # Write a report

    report = ConfinementReport(output_gpkg, report_path, project)
    report.write()

    progbar.finish()
    log.info(f"Count of Flowline segments with errors: {err_count}")
    log.info('Confinement Finished')
    return
Esempio n. 31
0
 def test_return_startsubstring(self):
     self.assertTrue(substring(self.line1, -500, 0.6).equals(LineString(([0, 0], [0.6, 0]))))
     self.assertTrue(substring(self.line1, -1.1, 0.6, True).equals(LineString(([0, 0], [1.2, 0]))))
Esempio n. 32
0
    def to_tpar_boundary(self,
                         dest_path,
                         boundary,
                         interval,
                         x_var='lon',
                         y_var='lat',
                         hs_var='sig_wav_ht',
                         per_var='pk_wav_per',
                         dir_var='pk_wav_dir',
                         dir_spread=20.):
        ''' This function writes parametric boundary forcing to a set of 
            TPAR files at a given distance based on gridded wave output. It returns the string to be included in the Swan INPUT file.

            At present simple nearest neighbour point lookup is used.
            
            Args:
            TBD
        '''
        from shapely.ops import substring

        bound_string = "BOUNDSPEC SEGM XY "
        point_string = "&\n {xp:0.8f} {yp:0.8f} "
        file_string = "&\n {len:0.8f} '{fname}' 1 "

        for xp, yp in boundary.exterior.coords:
            bound_string += point_string.format(xp=xp, yp=yp)

        bound_string += "&\n VAR FILE "

        n_pts = int((boundary.length) / interval)
        splits = np.linspace(0, 1., n_pts)
        boundary_points = []
        j = 0
        for i in range(len(splits) - 1):
            segment = substring(boundary.exterior,
                                splits[i],
                                splits[i + 1],
                                normalized=True)
            xp = segment.coords[1][0]
            yp = segment.coords[1][1]
            logger.debug(f'Extracting point: {xp},{yp}')
            ds_point = self._obj.sel(indexers={
                x_var: xp,
                y_var: yp
            },
                                     method='nearest',
                                     tolerance=interval)
            if len(ds_point.time) == len(self._obj.time):
                if not np.any(np.isnan(ds_point[hs_var])):
                    with open(f'{dest_path}/{j}.TPAR', 'wt') as f:
                        f.write('TPAR\n')
                        for t in range(len(ds_point.time)):
                            ds_row = ds_point.isel(time=t)
                            lf = '{tt} {hs:0.2f} {per:0.2f} {dirn:0.1f} {spr:0.2f}\n'
                            f.write(
                                lf.format(tt=str(ds_row['time'].dt.strftime(
                                    '%Y%m%d.%H%M%S').values),
                                          hs=float(ds_row[hs_var]),
                                          per=float(ds_row[per_var]),
                                          dirn=float(ds_row[dir_var]),
                                          spr=dir_spread))
                    bound_string += file_string.format(len=splits[i + 1] *
                                                       boundary.length,
                                                       fname=f'{j}.TPAR')
                    j += 1

        return bound_string
Esempio n. 33
0
 def test_return_substring_issue682(self):
     assert list(substring(self.line2, 0.1, 0).coords) == [(3.0, 0.1),
                                                           (3.0, 0.0)]
for i in range(len(boundaries)):
    if (boundaries[i] != []):
        neighbors = []
        precinct_polygon = boundaries[i][0]
        precinct = LineString(list(precinct_polygon.exterior.coords))
        size_precinct = precinct_polygon.boundary.length
        for j in possibleNeighbors[i]:
            other_polygon = boundaries[j][0]
            other = LineString(list(other_polygon.exterior.coords))
            smaller = precinct if (
                size_precinct < other_polygon.boundary.length) else other
            bigger = precinct if (
                size_precinct >= other_polygon.boundary.length) else other
            distance = 0
            while (distance < smaller.boundary.length):
                sub_boarder = substring(smaller, distance,
                                        distance + coincident)
                maximum_dist = max([
                    Point(point).distance(bigger)
                    for point in sub_boarder.coords
                ])
                if (maximum_dist <= coincident):
                    neighbors.append(utah_precincts[j]['properties']['cname'])
                    break
                else:
                    distance += (coincident / 4)
        utah_precincts[i]['properties']['neighbors'] = neighbors

with open("C:/Users/Denis/Software Engineering/Data/Utah/Precincts/Utah.json",
          "w") as utah:
    json.dump(utah_data, utah, indent=2)
Esempio n. 35
0
 def test_return_midpoint(self):
     self.assertTrue(substring(self.line1, 0.5, 0.5).equals(Point(0.5, 0)))        
     self.assertTrue(substring(self.line1, -0.5, -0.5).equals(Point(1.5, 0)))
     self.assertTrue(substring(self.line1, 0.5, 0.5, True).equals(Point(1, 0)))        
     self.assertTrue(substring(self.line1, -0.5, -0.5, True).equals(Point(1, 0)))       
Esempio n. 36
0
 def test_return_substring_issue848(self):
     line = shape(json.loads(data_issue_848))
     cut_line = substring(line, 0.7, 0.8, normalized=True)
     assert len(cut_line.coords) == 53
Esempio n. 37
0
 def test_return_substring_with_vertices(self):
     self.assertTrue(substring(self.line2, 1, 7).equals(LineString(([3, 1], [3, 6], [4, 6]))))
     self.assertTrue(substring(self.line2, 0.2, 0.9, True).equals(LineString(([3, 1.5], [3, 6], [3.75, 6]))))