Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
Will return one ray per pixel, as set in camera.resolution.
Parameters
--------------
camera : trimesh.scene.Camera
Returns
--------------
vectors : (n, 3) float
Ray direction vectors in camera frame with z == -1
"""
# get the on-plane coordinates
xy, pixels = ray_pixel_coords(camera)
# convert vectors to 3D unit vectors
vectors = util.unitize(
np.column_stack((xy, -np.ones_like(xy[:, :1]))))
return vectors, pixels
if final and (angle > tol.seg_angle_min).sum() < 3:
log.debug('final: angle %s', str(angle))
return None
# check segment length as a fraction of drawing scale
scaled = segment / scale
if (scaled > tol.seg_frac).any():
if verbose:
log.debug('circle fit error: segment %s', str(scaled))
return None
# check to make sure the line segments on the ends are actually
# tangent with the candidate circle fit
mid_pt = points[[0, -2]] + (vectors[[0, -1]] * .5)
radial = util.unitize(mid_pt - C)
ends = util.unitize(vectors[[0, -1]])
tangent = np.abs(np.arccos(util.diagonal_dot(radial, ends)))
tangent = np.abs(tangent - np.pi / 2).max()
if tangent > tol.tangent:
if verbose:
log.debug('circle fit error: tangent %f',
np.degrees(tangent))
return None
result = {'center': C,
'radius': R}
return result
# it's a lot easier to treat 2D as 3D with a zero Z value
points, is_2D = util.stack_3D(points, return_2D=True)
# find the two edge vectors of the triangle
edge_direction = np.diff(points, axis=0)
edge_midpoints = (edge_direction * 0.5) + points[:2]
# three points define a plane, so find signed normal
plane_normal = np.cross(*edge_direction[::-1])
plane_normal /= np.linalg.norm(plane_normal)
# unit vector along edges
vector_edge = util.unitize(edge_direction)
# perpendicular cector to each segment
vector_perp = util.unitize(np.cross(vector_edge, plane_normal))
# run the line-line intersection to find the point
intersects, center = line_line(origins=edge_midpoints,
directions=vector_perp,
plane_normal=plane_normal)
if not intersects:
raise ValueError('segments do not intersect:\n{}'.format(
str(points)))
# radius is euclidean distance
radius = ((points[0] - center) ** 2).sum() ** .5
# vectors from points on arc to center point
vector = util.unitize(points - center)
# if it's a closed segment modulus to start vertex
if is_closed:
tid %= len(lines)
# the vector connecting the two ends of the arc
vector = lines[tid[:, 0]] - lines[tid[:, 1]]
# the length of the connector segment
length = (np.linalg.norm(vector, axis=1))
# perpendicular vectors by crossing vector with Z
perp = np.cross(
np.column_stack((vector, np.zeros(len(vector)))),
np.ones((len(vector), 3)) * [0, 0, 1])
# strip the zero Z
perp = util.unitize(perp[:, :2])
# midpoint of each line
midpoint = lines[tid].mean(axis=1)
# calculate the signed radius of each arc segment
radius = (length / 2.0) / np.sin(angle / 2.0)
# offset magnitude to point on arc
offset = radius - np.cos(angle / 2) * radius
# convert each arc to three points:
# start, any point on arc, end
three = np.column_stack((
lines[tid[:, 0]],
midpoint + perp * offset.reshape((-1, 1)),
lines[tid[:, 1]])).reshape((-1, 3, 2))
# Compute 3D locations of those vertices
verts_3d = np.c_[verts_2d, np.zeros(n)]
verts_3d = tf.transform_points(verts_3d, tf_mat)
base_verts_3d = np.c_[base_verts_2d,
np.zeros(len(base_verts_2d))]
base_verts_3d = tf.transform_points(base_verts_3d,
tf_mat)
# keep matching sequence of vertices and 0- indexed faces
vertices = [base_verts_3d]
faces = [faces_2d]
# Compute plane normals for each turn --
# each turn induces a plane halfway between the two vectors
v1s = util.unitize(path[1:-1] - path[:-2])
v2s = util.unitize(path[1:-1] - path[2:])
norms = np.cross(np.cross(v1s, v2s), v1s + v2s)
norms[(norms == 0.0).all(1)] = v1s[(norms == 0.0).all(1)]
norms = util.unitize(norms)
final_v1 = util.unitize(path[-1] - path[-2])
norms = np.vstack((norms, final_v1))
v1s = np.vstack((v1s, final_v1))
# Create all side walls by projecting the 3d vertices into each plane
# in succession
for i in range(len(norms)):
verts_3d_prev = verts_3d
# Rotate if needed
if angles is not None:
tf_mat = tf.rotation_matrix(angles[i],
norms[i],
# doing this with a sparse matrix
summed = np.zeros((vertex_count, 3))
for face, normal in zip(faces, face_normals):
summed[face] += normal
return summed
try:
summed = summed_sparse()
except BaseException:
log.warning(
'unable to use sparse matrix, falling back!',
exc_info=True)
summed = summed_loop()
# invalid normals will be returned as zero
vertex_normals = util.unitize(summed)
return vertex_normals
base_verts_3d = np.c_[base_verts_2d,
np.zeros(len(base_verts_2d))]
base_verts_3d = tf.transform_points(base_verts_3d,
tf_mat)
# keep matching sequence of vertices and 0- indexed faces
vertices = [base_verts_3d]
faces = [faces_2d]
# Compute plane normals for each turn --
# each turn induces a plane halfway between the two vectors
v1s = util.unitize(path[1:-1] - path[:-2])
v2s = util.unitize(path[1:-1] - path[2:])
norms = np.cross(np.cross(v1s, v2s), v1s + v2s)
norms[(norms == 0.0).all(1)] = v1s[(norms == 0.0).all(1)]
norms = util.unitize(norms)
final_v1 = util.unitize(path[-1] - path[-2])
norms = np.vstack((norms, final_v1))
v1s = np.vstack((v1s, final_v1))
# Create all side walls by projecting the 3d vertices into each plane
# in succession
for i in range(len(norms)):
verts_3d_prev = verts_3d
# Rotate if needed
if angles is not None:
tf_mat = tf.rotation_matrix(angles[i],
norms[i],
path[i])
verts_3d_prev = tf.transform_points(verts_3d_prev,
tf_mat)
# R = ------------------
# 2 * sin(theta / 2)
nonzero = mesh.face_adjacency_angles > np.radians(.01)
denominator = np.abs(
2.0 * np.sin(mesh.face_adjacency_angles[nonzero] / 1.0))
# consider the distance between the non- shared vertices of the
# face adjacency pair as the key distance
point_pairs = mesh.vertices[mesh.face_adjacency_unshared]
vectors = np.diff(point_pairs,
axis=1).reshape((-1, 3))
# the vertex indices of the shared edge for the adjacency pairx
edges = mesh.face_adjacency_edges
# unit vector along shared the edge
edges_vec = util.unitize(np.diff(mesh.vertices[edges],
axis=1).reshape((-1, 3)))
# the vector of the perpendicular projection to the shared edge
perp = np.subtract(
vectors, (util.diagonal_dot(
vectors, edges_vec).reshape(
(-1, 1)) * edges_vec))
# the length of the perpendicular projection
span = util.row_norm(perp)
# complete the values for non- infinite radii
radii = np.ones(len(mesh.face_adjacency)) * np.inf
radii[nonzero] = span[nonzero] / denominator
return radii, span
matrix)[0]
# preserve face normals if we have them stored
new_face_normals = None
if has_rotation and 'face_normals' in self._cache:
# transform face normals by rotation component
new_face_normals = util.unitize(
transformations.transform_points(
self.face_normals,
matrix=matrix,
translate=False))
# preserve vertex normals if we have them stored
new_vertex_normals = None
if has_rotation and 'vertex_normals' in self._cache:
new_vertex_normals = util.unitize(
transformations.transform_points(
self.vertex_normals,
matrix=matrix,
translate=False))
# if transformation flips winding of triangles
if has_rotation and transformations.flips_winding(matrix):
log.debug('transform flips winding')
# fliplr will make array non C contiguous
# which will cause hashes to be more
# expensive than necessary so wrap
self.faces = np.ascontiguousarray(
np.fliplr(self.faces))
# assign the new values
self.vertices = new_vertices