Skip to content

mnns.line_functions

Functions for random lines.

Functions:

Name Description
add_points_to_line

Given a list of points and a line, add the projected points to the line.

create_line

Generate random lines with random orientations with midpoints ranging from

find_intersects

Given a list of LineStrings, finds all the lines that intersect and where.

find_line_intersects

Given a list of LineStrings, find all the lines that intersect

add_points_to_line

add_points_to_line(
    line: LineString,
    points: list[Point],
    return_ordering=False,
)

Given a list of points and a line, add the projected points to the line.

See general form at: https://stackoverflow.com/questions/34754777/shapely-split-linestrings-at-intersections-with-other-linestrings

Source code in mnns/line_functions.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
def add_points_to_line(
    line: LineString, points: list[Point], return_ordering=False
):
    """
    Given a list of points and a line, add the projected points to the line.

    See general form at:
    https://stackoverflow.com/questions/34754777/shapely-split-linestrings-at-intersections-with-other-linestrings

    """
    # First coords of line (start + end)
    coords = [line.coords[0], line.coords[-1]]

    # Add the coords from the points
    coords += [(p.x, p.y) for p in points]

    # Calculate the distance along the line for each point
    dists = [line.project(Point(p)) for p in coords]

    # Sort the coords based on the distances
    coords, ordering = map(
        list,
        zip(
            *[
                (point, ind)
                for _, point, ind in sorted(
                    zip(dists, coords, range(len(coords)))
                )
            ]
        ),
    )

    ordering.remove(0)
    ordering.remove(1)
    ordering = [ordering[i] - 2 for i in range(len(ordering))]

    # Overwrite old line
    line = LineString(coords)

    if return_ordering:
        return line, ordering
    else:
        return line

create_line

create_line(
    length: float = 1,
    xmin: float = 0,
    xmax: float = 1,
    ymin: float = 0,
    ymax: float = 1,
    rng: Generator | None = None,
    angle_dist: str = "uniform",
    angle_kwargs: dict | None = None,
) -> LineString

Generate random lines with random orientations with midpoints ranging from area from xmin to xmax and from ymin to ymax.

Parameters:

Name Type Description Default
length float

Length of line

1
xmin float

Minimum x coordinate midpoint.

0
xmax float

Minimum x coordinate midpoint.

1
ymin float

Minimum y coordinate midpoint.

0
ymax float

Minimum y coordinate midpoint.

1
rng Generator

Generator object usually created from default_rng from numpy.random. A seeded generator can be passed for consistent random numbers. If None, uses the default NumPy random functions.

None

Returns:

Name Type Description
out LineString

LineString of the generated line.

Source code in mnns/line_functions.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def create_line(
    length: float = 1,
    xmin: float = 0,
    xmax: float = 1,
    ymin: float = 0,
    ymax: float = 1,
    rng: np.random.Generator | None = None,
    angle_dist: str = "uniform",
    angle_kwargs: dict | None = None,
) -> LineString:
    """
    Generate random lines with random orientations with midpoints ranging from
    area from ``xmin`` to ``xmax`` and from ``ymin`` to ``ymax``.

    Parameters
    ----------
    length : float
        Length of line

    xmin : float
        Minimum x coordinate midpoint.

    xmax : float
        Minimum x coordinate midpoint.

    ymin : float
        Minimum y coordinate midpoint.

    ymax : float
        Minimum y coordinate midpoint.

    rng : Generator
        Generator object usually created from ``default_rng`` from
        ``numpy.random``. A seeded generator can be passed for consistent
        random numbers. If None, uses the default NumPy random functions.

    Returns
    -------
    out : LineString
        LineString of the generated line.

    """
    # Set default arguments
    if rng is None:
        rng = np.random.default_rng()

    if angle_kwargs is None:
        angle_kwargs = dict()

    if angle_dist == "uniform" and not angle_kwargs:
        angle_kwargs = {"low": 0, "high": np.pi}

    # Get angle distribution
    try:
        dist = getattr(rng, angle_dist)
    except AttributeError as e:
        raise ValueError(
            "Distribution not found in 'numpy.random.Generator'"
        ) from e

    # Randomly generate midpoints
    xmid = rng.uniform(xmin, xmax)
    ymid = rng.uniform(ymin, ymax)

    # Randomly generate angle
    angle = dist(**angle_kwargs)

    # Create the line string object
    xhalf = length / 2 * np.cos(angle)
    yhalf = length / 2 * np.sin(angle)

    xstart, xend = xmid - xhalf, xmid + xhalf
    ystart, yend = ymid - yhalf, ymid + yhalf

    out = LineString([(xstart, ystart), (xend, yend)])
    return out

find_intersects

find_intersects(
    lines: list,
) -> dict[tuple[int, int], Point]

Given a list of LineStrings, finds all the lines that intersect and where.

Parameters:

Name Type Description Default
lines list of LineStrings

List of the LineStrings to find the intersections of.

required

Returns:

Name Type Description
out dict

Dictionary where the key is a tuple of the pair of intersecting lines and the value is the intersection locations.

Source code in mnns/line_functions.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def find_intersects(lines: list) -> dict[tuple[int, int], Point]:
    """
    Given a list of LineStrings, finds all the lines that intersect and where.

    Parameters
    ----------
    lines : list of LineStrings
        List of the LineStrings to find the intersections of.

    Returns
    -------
    out : dict
        Dictionary where the key is a tuple of the pair of intersecting lines
        and the value is the intersection locations.

    """
    out = {}

    for i, j in zip(*np.triu_indices(n=len(lines), k=1)):
        # Check for intersection first before calculating it
        if lines[i].intersects(lines[j]):
            out.update({(i, j): lines[i].intersection(lines[j])})

    return out

find_line_intersects

find_line_intersects(
    ind: int, lines: list[LineString]
) -> dict[tuple[int, int], Point]

Given a list of LineStrings, find all the lines that intersect with a specified line in the list given by the index ind.

Source code in mnns/line_functions.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def find_line_intersects(
    ind: int, lines: list[LineString]
) -> dict[tuple[int, int], Point]:
    """
    Given a list of LineStrings, find all the lines that intersect
    with a specified line in the list given by the index ``ind``.

    """
    out = {}

    for j in range(len(lines)):
        # Skip intersection with the line itself
        if ind == j:
            continue

        # Checking if these's an intersection first is faster
        if lines[ind].intersects(lines[j]):
            if ind < j:
                out.update({(ind, j): lines[ind].intersection(lines[j])})
            else:
                out.update({(j, ind): lines[ind].intersection(lines[j])})

    return out