kwcoco.demo.boids
¶
Module Contents¶
Classes¶
Efficient numpy based backend for generating boid positions. |
Functions¶
|
vec = np.random.rand(10, 2) |
|
Like np.ravel_multi_index but returns positions in an upper triangular |
Ignore: |
|
|
Finds the closet point from p on line segment (e1, e2) |
Fast and responsive BOID rendering. This is an easter egg. |
|
- class kwcoco.demo.boids.Boids(num, dims=2, rng=None, **kwargs)[source]¶
Bases:
ubelt.NiceRepr
Efficient numpy based backend for generating boid positions.
BOID = bird-oid object
References
https://www.youtube.com/watch?v=mhjuuHl6qHM https://medium.com/better-programming/boids-simulating-birds-flock-behavior-in-python-9fff99375118 https://en.wikipedia.org/wiki/Boids
Example
>>> from kwcoco.demo.boids import * # NOQA >>> num_frames = 10 >>> num_objects = 3 >>> rng = None >>> self = Boids(num=num_objects, rng=rng).initialize() >>> paths = self.paths(num_frames) >>> # >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> plt = kwplot.autoplt() >>> from mpl_toolkits.mplot3d import Axes3D # NOQA >>> ax = plt.gca(projection='3d') >>> ax.cla() >>> # >>> for path in paths: >>> time = np.arange(len(path)) >>> ax.plot(time, path.T[0] * 1, path.T[1] * 1, ',-') >>> ax.set_xlim(0, num_frames) >>> ax.set_ylim(-.01, 1.01) >>> ax.set_zlim(-.01, 1.01) >>> ax.set_xlabel('time') >>> ax.set_ylabel('u-pos') >>> ax.set_zlabel('v-pos') >>> kwplot.show_if_requested()
import xdev _ = xdev.profile_now(self.compute_forces)() _ = xdev.profile_now(self.update_neighbors)()
- Ignore:
self = Boids(num=5, rng=0).initialize() self.pos
fig = kwplot.figure(fnum=10, do_clf=True) ax = fig.gca()
verts = np.array([[0, 0], [1, 0], [0.5, 2]]) com = verts.mean(axis=0) verts = (verts - com) * 0.02
import kwimage poly = kwimage.Polygon(exterior=verts)
- def rotate(poly, theta):
sin_ = np.sin(theta) cos_ = np.cos(theta) rot_ = np.array(((cos_, -sin_),
return poly.warp(rot_)
- for _ in xdev.InteractiveIter(list(range(10000))):
self.step() ax.cla() import math for rx in range(len(self.pos)):
x, y = self.pos[rx] dx, dy = (self.vel[rx] / np.linalg.norm(self.vel[rx], axis=0))
theta = (np.arctan2(dy, dx) - math.tau / 4) boid_poly = rotate(poly, theta).translate(self.pos[rx]) color = ‘red’ if rx == 0 else ‘blue’ boid_poly.draw(ax=ax, color=color)
tip = boid_poly.data[‘exterior’].data[2] tx, ty = tip
s = 100.0 vel = self.vel[rx] acc = self.acc[rx] com = self.acc[rx]
spsteer = self.sep_steering[rx] cmsteer = self.com_steering[rx] alsteer = self.align_steering[rx] avsteer = self.avoid_steering[rx]
# plt.arrow(tip[0], tip[1], s * vel[0], s * vel[1], color=’green’) plt.arrow(tip[0], tip[1], s * acc[1], s * acc[1], color=’purple’)
plt.arrow(tip[0], tip[1], s * spsteer[0], s * spsteer[1], color=’dodgerblue’) plt.arrow(tip[0], tip[1], s * cmsteer[0], s * cmsteer[1], color=’orange’) plt.arrow(tip[0], tip[1], s * alsteer[0], s * alsteer[1], color=’pink’) plt.arrow(tip[0], tip[1], s * avsteer[0], s * avsteer[1], color=’black’)
ax.set_xlim(0, 1) ax.set_ylim(0, 1) xdev.InteractiveIter.draw()
rx = 0
- kwcoco.demo.boids.clamp_mag(vec, mag, axis=None)[source]¶
vec = np.random.rand(10, 2) mag = 1.0 axis = 1 new_vec = clamp_mag(vec, mag, axis) np.linalg.norm(new_vec, axis=axis)
- kwcoco.demo.boids.triu_condense_multi_index(multi_index, dims, symetric=False)[source]¶
Like np.ravel_multi_index but returns positions in an upper triangular condensed square matrix
Examples
- multi_index (Tuple[ArrayLike]):
indexes for each dimension into the square matrix
- dims (Tuple[int]):
shape of each dimension in the square matrix (should all be the same)
- symetric (bool):
if True, converts lower triangular indices to their upper triangular location. This may cause a copy to occur.
References
https://stackoverflow.com/a/36867493/887074 https://numpy.org/doc/stable/reference/generated/numpy.ravel_multi_index.html#numpy.ravel_multi_index
Examples
>>> dims = (3, 3) >>> symetric = True >>> multi_index = (np.array([0, 0, 1]), np.array([1, 2, 2])) >>> condensed_idxs = triu_condense_multi_index(multi_index, dims, symetric=symetric) >>> assert condensed_idxs.tolist() == [0, 1, 2]
>>> n = 7 >>> symetric = True >>> multi_index = np.triu_indices(n=n, k=1) >>> condensed_idxs = triu_condense_multi_index(multi_index, [n] * 2, symetric=symetric) >>> assert condensed_idxs.tolist() == list(range(n * (n - 1) // 2)) >>> from scipy.spatial.distance import pdist, squareform >>> square_mat = np.zeros((n, n)) >>> conden_mat = squareform(square_mat) >>> conden_mat[condensed_idxs] = np.arange(len(condensed_idxs)) + 1 >>> square_mat = squareform(conden_mat) >>> print('square_mat =\n{}'.format(ub.repr2(square_mat, nl=1)))
>>> n = 7 >>> symetric = True >>> multi_index = np.tril_indices(n=n, k=-1) >>> condensed_idxs = triu_condense_multi_index(multi_index, [n] * 2, symetric=symetric) >>> assert sorted(condensed_idxs.tolist()) == list(range(n * (n - 1) // 2)) >>> from scipy.spatial.distance import pdist, squareform >>> square_mat = np.zeros((n, n)) >>> conden_mat = squareform(square_mat, checks=False) >>> conden_mat[condensed_idxs] = np.arange(len(condensed_idxs)) + 1 >>> square_mat = squareform(conden_mat) >>> print('square_mat =\n{}'.format(ub.repr2(square_mat, nl=1)))
- Ignore:
>>> import xdev >>> n = 30 >>> symetric = True >>> multi_index = np.triu_indices(n=n, k=1) >>> condensed_idxs = xdev.profile_now(triu_condense_multi_index)(multi_index, [n] * 2)
- Ignore:
# Numba helps here when ub.allsame is gone from numba import jit triu_condense_multi_index2 = jit(nopython=True)(triu_condense_multi_index) triu_condense_multi_index2 = jit()(triu_condense_multi_index) triu_condense_multi_index2(multi_index, [n] * 2) %timeit triu_condense_multi_index(multi_index, [n] * 2) %timeit triu_condense_multi_index2(multi_index, [n] * 2)
- kwcoco.demo.boids._spatial_index_scratch()[source]¶
- Ignore:
!pip install git+git://github.com/carsonfarmer/fastpair.git
from fastpair import FastPair fp = FastPair() fp.build(list(map(tuple, self.pos.tolist()))) #
!pip install pyqtree from pyqtree import Index spindex = Index(bbox=(0, 0, 1., 1.))
# this example assumes you have a list of items with bbox attribute for item in items:
spindex.insert(item, item.bbox)
!pip install grispy import grispy
index = grispy.GriSPy(data=self.pos) index.bubble_neighbors(self.pos, distance_upper_bound=0.1)
- kwcoco.demo.boids.closest_point_on_line_segment(pts, e1, e2)[source]¶
Finds the closet point from p on line segment (e1, e2)
- Parameters
pts (ndarray) – xy points [Nx2]
e1 (ndarray) – the first xy endpoint of the segment
e2 (ndarray) – the second xy endpoint of the segment
- Returns
pt_on_seg - the closest xy point on (e1, e2) from ptp
- Return type
ndarray
References
http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
Example
>>> # ENABLE_DOCTEST >>> from kwcoco.demo.boids import * # NOQA >>> verts = np.array([[ 21.83012702, 13.16987298], >>> [ 16.83012702, 21.83012702], >>> [ 8.16987298, 16.83012702], >>> [ 13.16987298, 8.16987298], >>> [ 21.83012702, 13.16987298]]) >>> rng = np.random.RandomState(0) >>> pts = rng.rand(64, 2) * 20 + 5 >>> e1, e2 = verts[0:2] >>> closest_point_on_line_segment(pts, e1, e2)
- Ignore:
from numba import jit closest_point_on_line_segment2 = jit(closest_point_on_line_segment) closest_point_on_line_segment2(pts, e1, e2) %timeit closest_point_on_line_segment(pts, e1, e2) %timeit closest_point_on_line_segment2(pts, e1, e2)