示例#1
0
  def test_normal_jacobian_random(self):
    """Test the Jacobian of the triangle normal function."""
    tensor_size = np.random.randint(3)
    tensor_shape = np.random.randint(1, 10, size=(tensor_size)).tolist()
    v0_init, v1_init, v2_init = [
        np.random.random(size=tensor_shape + [3]) for _ in range(3)
    ]
    v0_tensor, v1_tensor, v2_tensor = [
        tf.convert_to_tensor(value=v) for v in [v0_init, v1_init, v2_init]
    ]

    with self.subTest(name="v0"):
      self.assert_jacobian_is_correct_fn(
          lambda x: triangle.normal(x, v1_tensor, v2_tensor), [v0_init],
          atol=1e-4,
          delta=1e-9)

    with self.subTest(name="v1"):
      self.assert_jacobian_is_correct_fn(
          lambda x: triangle.normal(v0_tensor, x, v2_tensor), [v1_init],
          atol=1e-4,
          delta=1e-9)

    with self.subTest(name="v2"):
      self.assert_jacobian_is_correct_fn(
          lambda x: triangle.normal(v0_tensor, v1_tensor, x), [v2_init],
          atol=1e-4,
          delta=1e-9)
示例#2
0
def triangle_area(vertex0, vertex1, vertex2, name=None):
  """Computes triangle areas.

  Note:
    Computed triangle area = 0.5 * | e1 x e2 | where e1 and e2 are edges
      of triangle.

    In the following, A1 to An are optional batch dimensions, which must be
    broadcast compatible.

    In the following, A1 to An are optional batch dimensions.

  Args:
    vertex0: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      represents the first vertex of a triangle.
    vertex1: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      represents the second vertex of a triangle.
    vertex2: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      represents the third vertex of a triangle.
    name: A name for this op. Defaults to "triangle_area".

  Returns:
    A tensor of shape `[A1, ..., An, 1]`, where the last dimension represents
      the triangle areas.
  """
  with tf.compat.v1.name_scope(name, "triangle_area"):
    vertex0 = tf.convert_to_tensor(value=vertex0)
    vertex1 = tf.convert_to_tensor(value=vertex1)
    vertex2 = tf.convert_to_tensor(value=vertex2)

    triangle_normals = triangle.normal(
        vertex0, vertex1, vertex2, normalize=False)
    areas = 0.5 * tf.linalg.norm(tensor=triangle_normals, axis=-1)
    return areas
示例#3
0
  def test_normal_random(self, clockwise):
    """Tests the triangle normal computation in each axis."""
    tensor_size = np.random.randint(3)
    tensor_shape = np.random.randint(1, 10, size=(tensor_size)).tolist()
    zeros = np.zeros(shape=tensor_shape + [1])

    for i in range(3):
      v0 = np.random.random(size=tensor_shape + [3])
      v1 = np.random.random(size=tensor_shape + [3])
      v2 = np.random.random(size=tensor_shape + [3])
      v0[..., i] = 0.
      v1[..., i] = 0.
      v2[..., i] = 0.
      n = np.zeros_like(v0)
      n[..., i] = 1.
      normal = triangle.normal(v0, v1, v2, clockwise)

      with self.subTest(name="n"):
        self.assertAllClose(tf.abs(normal), n)

      with self.subTest(name="v1-v0"):
        self.assertAllClose(vector.dot(normal, (v1 - v0)), zeros)

      with self.subTest(name="v2-v0"):
        self.assertAllClose(vector.dot(normal, (v2 - v0)), zeros)
示例#4
0
  def test_normal_jacobian_preset(self, *vertices):
    """Test the Jacobian of the triangle normal function."""
    v0_init, v1_init, v2_init = [np.array(v) for v in vertices]
    v0_tensor, v1_tensor, v2_tensor = [
        tf.convert_to_tensor(value=v) for v in [v0_init, v1_init, v2_init]
    ]

    with self.subTest(name="v0"):
      self.assert_jacobian_is_correct_fn(
          lambda x: triangle.normal(x, v1_tensor, v2_tensor), [v0_init])

    with self.subTest(name="v1"):
      self.assert_jacobian_is_correct_fn(
          lambda x: triangle.normal(v0_tensor, x, v2_tensor), [v1_init])

    with self.subTest(name="v2"):
      self.assert_jacobian_is_correct_fn(
          lambda x: triangle.normal(v0_tensor, v1_tensor, x), [v2_init])
示例#5
0
def face_normals(faces,
                 clockwise=True,
                 normalize=True,
                 name="normals_face_normals"):
    """Computes face normals for meshes.

  This function supports planar convex polygon faces. Note that for
  non-triangular faces, this function uses the first 3 vertices of each
  face to calculate the face normal.

  Note:
    In the following, A1 to An are optional batch dimensions.

  Args:
    faces: A tensor of shape `[A1, ..., An, M, 3]`, which stores vertices
      positions of each face, where M is the number of vertices of each face.
      The rank of this tensor should be at least 2.
    clockwise: Winding order to determine front-facing faces. The order of
      vertices should be either clockwise or counterclockwise.
    normalize: A `bool` defining whether output normals are normalized.
    name: A name for this op. Defaults to "normals_face_normals".

  Returns:
    A tensor of shape `[A1, ..., An, 3]` containing the face normals.

  Raises:
    ValueError: If the shape of `vertices`, `faces` is not supported.
  """
    with tf.name_scope(name):
        faces = tf.convert_to_tensor(value=faces)

        shape.check_static(tensor=faces,
                           tensor_name="faces",
                           has_rank_greater_than=1,
                           has_dim_equals=(-1, 3),
                           has_dim_greater_than=(-2, 2))

        vertices = tf.unstack(faces, axis=-2)
        vertices = vertices[:3]
        return triangle.normal(*vertices,
                               clockwise=clockwise,
                               normalize=normalize)
示例#6
0
 def test_normal_assert(self, v0, v1, v2):
   """Tests the triangle normal assertion."""
   with self.assertRaises(tf.errors.InvalidArgumentError):
     self.evaluate(triangle.normal(v0, v1, v2))