예제 #1
0
def gravity_map(bodies, box, step):
    left, top, right, bottom = box
    width, height = right - left, bottom - top
    image = Image.new('L', (width, height))
    draw = ImageDraw.Draw(image)
    for y in range(top, bottom + 1, step):
        for x in range(left, right + 1, step):
            tx = 0
            ty = 0
            cx = x + step / 2
            cy = y + step / 2
            body = physics.Body(cx, cy, 0, True)
            for other in bodies:
                dist2 = (body.x - other.x) ** 2 + (body.y - other.y) ** 2
                if dist2 == 0:
                    continue # TODO: max out
                magnitude = physics.G * other.mass / dist2
                dx, dy = util.unit_vector(body, other)
                dx, dy = dx * magnitude, dy * magnitude
                tx, ty = tx + dx, ty + dy
            length = (tx * tx + ty * ty) ** 0.5
            value = int(math.log10(length / physics.G) * 128)
            value = min(255, value)
            value = max(0, value)
            draw.rectangle((x, y, x + step, y + step), fill=value)
    image = image.transpose(Image.FLIP_TOP_BOTTOM)
    return pyglet.image.ImageData(width, height, 'L', image.tostring(), width * -1)
예제 #2
0
 def closestWall(self, pos, direction):
     # Find closest wall to an edge in the rectangle
     dists = torch.tensor([self.width, self.height]).reshape(2, 1) / 2 - pos.abs()
     min_dist, ax = dists.min(dim=0)
     signs = pos[ax, torch.arange(pos.shape[1])] > 0
     angle = (3 - 2 * signs.float()) * pi / 2 - (1 - ax.float()) * pi / 2
     return min_dist, angle_between(direction, unit_vector(angle))
예제 #3
0
    def closestWall(self, position, direction):
        # closest wall on a circle lies on a line through the origin
        theta = torch.atan2(position[1], position[0]).float()
        wall = self.radius * unit_vector(theta)

        min_dist = torch.norm(wall.abs() - position.abs(), p=2, dim=0)

        angle = angle_between(position, direction)
        return min_dist, angle
예제 #4
0
def rot(axis, theta):
    """
    :param axis: any 1*3 numpy array or ["x", "y", "z"]
    :param theta: rotation degree
    :return: 4*4 with rotation matrix calculated
    """
    axis = unit_vector(axis)
    mat = np.identity(4)
    mat[:3, :3] = rotation_matrix(axis, theta)
    return mat
예제 #5
0
def rotation_matrix(axis, theta):
    k = unit_vector(axis)
    theta = np.deg2rad(theta)  # convert degree to radians
    cos_theta = np.cos(theta)
    sin_theta = np.sin(theta)
    v_theta = 1 - cos_theta

    return np.array([[
        k[0] * k[0] * v_theta + cos_theta,
        k[0] * k[1] * v_theta - k[2] * sin_theta,
        k[0] * k[2] * v_theta + k[1] * sin_theta
    ],
                     [
                         k[0] * k[1] * v_theta + k[2] * sin_theta,
                         k[1] * k[1] * v_theta + cos_theta,
                         k[1] * k[2] * v_theta - k[0] * sin_theta
                     ],
                     [
                         k[0] * k[2] * v_theta - k[1] * sin_theta,
                         k[1] * k[2] * v_theta + k[0] * sin_theta,
                         k[2] * k[2] * v_theta + cos_theta
                     ]])
예제 #6
0
def update(bodies):
    results = {}
    for body in bodies:
        if body.fixed:
            continue
        tx, ty = 0, 0
        for other in bodies:
            if other == body:
                continue
            dist2 = (body.x - other.x) ** 2 + (body.y - other.y) ** 2
            magnitude = G * other.mass / dist2
            dx, dy = util.unit_vector(body, other)
            dx, dy = dx * magnitude, dy * magnitude
            tx, ty = tx + dx, ty + dy
        # TODO: sound based on G forces
        #tt = abs(tx) + abs(ty)
        #print int(tt / G)
        results[body] = (tx, ty)
    for body, (dx, dy) in results.iteritems():
        body.force(dx, dy)
        body.move()
        
예제 #7
0
def trans(axis, length):
    axis = unit_vector(axis)
    mat = np.identity(4)
    mat[:3, 3] = np.transpose(axis * length)
    return mat
예제 #8
0
    def trajectories(self, N=100, dt=0.02):
        perimeter = self.params['perimeter']
        T = self.params["T"]
        n = int(T / dt)
        mu, sigma, b = [
            self.params[i]
            for i in ["mean_rotation", "std_dev_rotation", "std_dev_forward"]
        ]

        rotation_velocities = torch.tensor(
            np.random.normal(mu, sigma, size=(n, N))).float()
        forward_velocities = torch.tensor(np.random.rayleigh(
            b, size=(n, N))).float()

        positions = ntorch.zeros((n, 2, N), names=("t", "ax", "sample"))
        vs = torch.zeros((n, N))
        angles = rotation_velocities
        directions = torch.zeros((n, 2, N))

        vs[0] = self.params["v0"]
        theta = torch.rand(N) * 2 * np.pi
        directions[0] = unit_vector(theta)
        positions[{
            "t": 0
        }] = ntorch.tensor(self.scene.random(N), names=("sample", "ax"))

        for i in range(1, n):
            dist, phi = self.scene.closestWall(positions[{
                "t": i - 1
            }].values, directions[i - 1])
            wall = (dist < perimeter) & (phi.abs() < np.pi / 2)
            angle_correction = torch.where(
                wall,
                phi.sign() * (np.pi / 2 - phi.abs()), torch.zeros_like(phi))
            angles[i] += angle_correction

            vs[i] = torch.where(
                wall,
                (1 - self.params["velocity_reduction"]) * (vs[i - 1]),
                forward_velocities[i],
            )
            positions[{
                "t": i
            }] = (positions[{
                "t": i - 1
            }] + directions[i - 1] * vs[i] * dt)

            mat = rotation_matrix(angles[i] * dt)
            directions[i] = torch.einsum("ijk,jk->ik", mat, directions[i - 1])

        idx = np.round(np.linspace(
            0, n - 2, self.params["trajectory_length"])).astype(int)
        # idx = np.array(sorted(np.random.choice(np.arange(n), size=self.params["trajectory_length"], replace=False)))

        dphis = ntorch.tensor(angles[idx] * dt, names=("t", "sample"))
        velocities = ntorch.tensor(vs[idx], names=("t", "sample"))
        vel = ntorch.stack((velocities, dphis.cos(), dphis.sin()), "input")

        xs = ntorch.tensor(positions.values[idx], names=("t", "ax", "sample"))
        # xs0 = positions[{'t': 0}]
        xs0 = ntorch.tensor(self.scene.random(n=N), names=("sample", "ax"))

        hd = torch.atan2(directions[:, 1], directions[:, 0])
        hd0 = ntorch.tensor(hd[0][None], names=("hd", "sample"))
        hd = ntorch.tensor(hd[idx + 1][None], names=("hd", "t", "sample"))

        xs = xs.transpose('sample', 't', 'ax')
        hd = hd.transpose('sample', 't', 'hd')
        vel = vel.transpose('sample', 't', 'input')
        xs0 = xs0.transpose('sample', 'ax')
        hd0 = hd0.transpose('sample', 'hd')

        return xs, hd, vel, xs0, hd0
예제 #9
0
 def random(self, n=1, perimeter=0):
     t = 2 * pi * torch.rand(n).float()
     u = torch.rand((n, 2)).sum(dim=1)
     r = torch.where(u > 1, 2 - u, u)
     return (r * unit_vector(t)).transpose(0, 1) * (self.radius - perimeter)
예제 #10
0
 def plot(self):
     ts = torch.linspace(0, 2 * pi, 1000)
     data = unit_vector(ts).numpy() * self.radius
     plt.plot(*data)