import torch
import math
from imodal.Utilities import rot2d, linear_transform
[docs]def generate_unit_square(points_per_side, dtype=None):
""" Generates an unit square on the plane.
Parameters
----------
points_per_side : int
Number of points that will be generated for each side of the square.
dtype : torch.dtype, default=None
Type of the output points. If None, dtype is set to `torch.get_default_dtype()`.
Returns
-------
torch.Tensor
Points of the output square.
"""
points = torch.zeros(4*points_per_side, 2, dtype=dtype)
points[0:points_per_side, 0] = torch.linspace(0., 1., points_per_side + 1, dtype=dtype)[1:]
points[points_per_side:2*points_per_side, 1] = torch.linspace(0., 1., points_per_side + 1, dtype=dtype)[1:]
points[points_per_side-1:2*points_per_side, 0] = 1.
points[2*points_per_side:3*points_per_side, 0] = torch.linspace(1., 0., points_per_side + 1, dtype=dtype)[1:]
points[2*points_per_side:3*points_per_side, 1] = 1.
points[3*points_per_side:4*points_per_side, 1] = torch.linspace(1., 0., points_per_side + 1, dtype=dtype)[1:]
return points - torch.tensor([0.5, 0.5])
[docs]def generate_unit_circle(angular_resolution, dtype=None):
""" Generates an unit circle on the plane.
The generated circle is not closed, i.e. first and last point are not the same.
Parameters
----------
angular_resolution : int
Angular resolution of the circle.
dtype : torch.dtype, default=None
Type of the output points. If None, dtype is set to `torch.get_default_dtype()`.
Returns
-------
torch.Tensor
Points of the output circle
"""
return torch.stack(
[torch.cos(torch.linspace(0, 2.*math.pi, angular_resolution + 1, dtype=dtype)[:-1]),
torch.sin(torch.linspace(0, 2.*math.pi, angular_resolution + 1, dtype=dtype)[:-1])], axis=1)
[docs]def generate_rectangle(aabb, points_density, dtype=None):
""" Generates a rectangle on the plane.
Parameters
----------
aabb : Utilities.AABB
Boundaries of the resulting rectangle.
points_density : float
Linear point density of the resulting rectangle.
dtype : torch.dtype, default=None
Type of the output points. If None, dtype is set to `torch.get_default_dtype()`.
Returns
-------
torch.Tensor
Points of the output rectangle.
"""
if aabb.dim != 2:
raise NotImplementedError()
points_x = math.ceil(aabb.shape[0]*points_density)
points_y = math.ceil(aabb.shape[1]*points_density)
points = torch.zeros(2*(points_x+points_y), 2, dtype=dtype)
# Bottom side
points[0:points_x, 0] = torch.linspace(aabb.xmin, aabb.xmax, points_x + 1, dtype=dtype)[1:]
points[0:points_x, 1] = aabb.ymin*torch.ones(points_x)
# Right side
points[points_x:points_x+points_y, 0] = aabb.xmax*torch.ones(points_y)
points[points_x:points_x+points_y, 1] = torch.linspace(aabb.ymin, aabb.ymax, points_y + 1, dtype=dtype)[1:]
# Top side
points[points_x+points_y:2*points_x+points_y, 0] = torch.linspace(aabb.xmax, aabb.xmin, points_x + 1, dtype=dtype)[1:]
points[points_x+points_y:2*points_x+points_y, 1] = aabb.ymax*torch.ones(points_x)
# Left side
points[2*points_x+points_y:, 0] = aabb.xmin*torch.ones(points_y)
points[2*points_x+points_y:, 1] = torch.linspace(aabb.ymax, aabb.ymin, points_y + 1, dtype=dtype)[1:]
return points
[docs]def generate_mesh_grid(aabb, resolution, dtype=None):
""" Generates a grid on the plane.
Parameters
----------
aabb : Utilities.AABB
Boundaries of the resulting grid.
resolution : Iterable
Side resolution of the resulting grid.
dtype : torch.dtype, default=None
Type of the output points. If None, dtype is set to `torch.get_default_dtype()`.
Returns
-------
tuple
2-tuple of tensor representing the grid.
"""
return torch.meshgrid([torch.linspace(kmin, kmax, count, dtype=dtype) for kmin, kmax, count in zip(aabb.kmin, aabb.kmax, resolution)])
[docs]def generate_disc_density(density, outer_radius=1., inner_radius=0.):
""" Generate points on a disc with constant surfacic density.
Parameters
----------
density : float
Point density of the resulting disc.
outer_radius : float, default=1.
Radius of the outer boundary.
inner_radius : float, default=0.
Radius of the inner boundary.
dtype : torch.dtype, default=None
Type of the output points. If None, dtype is set to `torch.get_default_dtype()`.
Returns
-------
torch.Tensor
Tensor of points representing the disc on the plane.
"""
assert outer_radius > inner_radius
radials = torch.linspace(inner_radius, outer_radius, math.ceil((outer_radius-inner_radius)*density)).tolist()
angular_resolutions = [2.*math.pi*r*density for r in radials]
return torch.cat([torch.stack([
r*torch.cos(torch.linspace(0., 2.*math.pi, math.ceil(angular_resolution))),
r*torch.sin(torch.linspace(0., 2.*math.pi, math.ceil(angular_resolution)))], dim=1)
for angular_resolution, r in zip(angular_resolutions, radials)])
[docs]def generate_boudin(left_width, right_width, height, thickness, arc_resolution, cap_resolution, fill_resolution):
t = torch.linspace(0., math.pi, arc_resolution)
half_circle = torch.stack([torch.cos(t), torch.sin(t)], dim=1)
t = torch.linspace(math.pi, 0., arc_resolution)
reversed_half_circle = torch.stack([torch.cos(t), torch.sin(t)], dim=1)
left_arc = linear_transform(half_circle, rot2d(math.pi/2.))*torch.tensor([left_width, height])
right_arc = linear_transform(reversed_half_circle, rot2d(math.pi/2.))*torch.tensor([right_width, height-thickness*2.]) + torch.tensor([thickness, 0.])
top_cap = linear_transform(half_circle, rot2d(-math.pi/2.))*torch.tensor([thickness, thickness]) + torch.tensor([thickness, height-thickness])
bottom_cap = linear_transform(half_circle, rot2d(-math.pi/2.))*torch.tensor([thickness, thickness]) + torch.tensor([thickness, -height+thickness])
top_fill = torch.stack([torch.linspace(thickness, 0., fill_resolution), height*torch.ones(fill_resolution)], dim=1)[1:-1]
bottom_fill = torch.stack([torch.linspace(0., thickness, fill_resolution), -height*torch.ones(fill_resolution)], dim=1)[1:-1]
boudin = torch.cat([left_arc, bottom_fill, bottom_cap, right_arc, top_cap, top_fill])
return boudin