コード例 #1
0
ファイル: asserts_test.py プロジェクト: yangbooom/graphics
    def test_assert_nonzero_norm_passthrough(self):
        """Checks that the assert is a passthrough when the flag is False."""
        vector_input = _pick_random_vector()

        vector_output = asserts.assert_nonzero_norm(vector_input)

        self.assertIs(vector_input, vector_output)
コード例 #2
0
def normal(v0: type_alias.TensorLike,
           v1: type_alias.TensorLike,
           v2: type_alias.TensorLike,
           clockwise: bool = False,
           normalize: bool = True,
           name: str = "triangle_normal") -> tf.Tensor:
    """Computes face normals (triangles).

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

  Args:
    v0: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      represents the first vertex of a triangle.
    v1: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      represents the second vertex of a triangle.
    v2: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      represents the third vertex of a triangle.
    clockwise: Winding order to determine front-facing triangles.
    normalize: A `bool` indicating whether output normals should be normalized
      by the function.
    name: A name for this op. Defaults to "triangle_normal".

  Returns:
    A tensor of shape `[A1, ..., An, 3]`, where the last dimension represents
      a normalized vector.

  Raises:
    ValueError: If the shape of `v0`, `v1`, or `v2` is not supported.
  """
    with tf.name_scope(name):
        v0 = tf.convert_to_tensor(value=v0)
        v1 = tf.convert_to_tensor(value=v1)
        v2 = tf.convert_to_tensor(value=v2)

        shape.check_static(tensor=v0, tensor_name="v0", has_dim_equals=(-1, 3))
        shape.check_static(tensor=v1, tensor_name="v1", has_dim_equals=(-1, 3))
        shape.check_static(tensor=v2, tensor_name="v2", has_dim_equals=(-1, 3))
        shape.compare_batch_dimensions(tensors=(v0, v1, v2),
                                       last_axes=-2,
                                       broadcast_compatible=True)

        normal_vector = vector.cross(v1 - v0, v2 - v0, axis=-1)
        normal_vector = asserts.assert_nonzero_norm(normal_vector)
        if not clockwise:
            normal_vector *= -1.0
        if normalize:
            return tf.nn.l2_normalize(normal_vector, axis=-1)
        return normal_vector
コード例 #3
0
ファイル: asserts_test.py プロジェクト: yangbooom/graphics
    def test_assert_nonzero_norm_exception_raised(self, value, dtype):
        """Checks that assert_nonzero_norm fails for values below eps."""
        vector = tf.constant((value, ), dtype=dtype)

        with self.assertRaises(tf.errors.InvalidArgumentError):
            self.evaluate(asserts.assert_nonzero_norm(vector))
コード例 #4
0
def interpolate(points,
                weights,
                indices,
                normalize=True,
                allow_negative_weights=False,
                name=None):
    """Weighted interpolation for M-D point sets.

  Given an M-D point set, this function can be used to generate a new point set
  that is formed by interpolating a subset of points in the set.

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

  Args:
    points: A tensor with shape `[B1, ..., Bk, M] and rank R > 1, where M is the
      dimensionality of the points.
    weights: A tensor with shape `[A1, ..., An, P]`, where P is the number of
      points to interpolate for each output point.
    indices: A tensor of dtype tf.int32 and shape `[A1, ..., An, P, R-1]`, which
      contains the point indices to be used for each output point. The R-1
      dimensional axis gives the slice index of a single point in `points`. The
      first n+1 dimensions of weights and indices must match, or be broadcast
      compatible.
    normalize: A `bool` describing whether or not to normalize the weights on
      the last axis.
    allow_negative_weights: A `bool` describing whether or not negative weights
      are allowed.
    name: A name for this op. Defaults to "weighted_interpolate".

  Returns:
    A tensor of shape `[A1, ..., An, M]` storing the interpolated M-D
    points. The first n dimensions will be the same as weights and indices.
  """
    with tf.compat.v1.name_scope(name, "weighted_interpolate",
                                 [points, weights, indices]):
        points = tf.convert_to_tensor(value=points)
        weights = tf.convert_to_tensor(value=weights)
        indices = tf.convert_to_tensor(value=indices)

        shape.check_static(tensor=points,
                           tensor_name="points",
                           has_rank_greater_than=1)
        shape.check_static(tensor=indices,
                           tensor_name="indices",
                           has_rank_greater_than=1,
                           has_dim_equals=(-1, points.shape.ndims - 1))
        shape.compare_dimensions(tensors=(weights, indices),
                                 axes=(-1, -2),
                                 tensor_names=("weights", "indices"))
        shape.compare_batch_dimensions(tensors=(weights, indices),
                                       last_axes=(-2, -3),
                                       tensor_names=("weights", "indices"),
                                       broadcast_compatible=True)
        if not allow_negative_weights:
            weights = asserts.assert_all_above(weights, 0.0, open_bound=False)

        if normalize:
            sums = tf.reduce_sum(input_tensor=weights, axis=-1, keepdims=True)
            sums = asserts.assert_nonzero_norm(sums)
            weights = safe_ops.safe_signed_div(weights, sums)
        point_lists = tf.gather_nd(points, indices)
        return vector.dot(point_lists,
                          tf.expand_dims(weights, axis=-1),
                          axis=-2,
                          keepdims=False)