//  [python]
def _discard_obstructing_wedges_and_corners(self, candidate_wedges, targets,
                                                sources):
        r"""
        Discard wedges for which at least one of the source or target are
        "inside" the wedge

        Inputs
        ------
        candidate_wedges : [num_candidate_wedges], int
            Candidate wedges.
            Entries correspond to wedges indices.

        targets : [num_targets, 3], tf.float
            Coordinates of the targets.

        sources : [num_sources, 3], tf.float
            Coordinates of the sources.

        Output
        -------
        wedges_indices : [num_targets, num_sources, max_num_paths], tf.int
            Indices of the wedges that interacted with the diffracted paths
        """

        epsilon = tf.cast(SolverBase.EPSILON, self._rdtype)

        # [num_candidate_wedges, 3]
        origins = tf.gather(self._wedges_origin, candidate_wedges)

        # Expand to broadcast with sources/targets and 0/n faces
        # [1, num_candidate_wedges, 1, 3]
        origins = tf.expand_dims(origins, axis=0)
        origins = tf.expand_dims(origins, axis=2)

        # Normals
        # [num_candidate_wedges, 2, 3]
        # [:,0,:] : 0-face
        # [:,1,:] : n-face
        normals = tf.gather(self._wedges_normals, candidate_wedges)
        # Expand to broadcast with the sources or targets
        # [1, num_candidate_wedges, 2, 3]
        normals = tf.expand_dims(normals, axis=0)

        # Expand to broadcast with candidate and 0/n faces wedges
        # [num_sources, 1, 1, 3]
        sources = expand_to_rank(sources, 4, 1)
        # [num_targets, 1, 1, 3]
        targets = expand_to_rank(targets, 4, 1)
        # Sources/Targets vectors
        # [num_sources, num_candidate_wedges, 1, 3]
        u_t = sources - origins
        # [num_targets, num_candidate_wedges, 1, 3]
        u_r = targets - origins

        # [num_sources, num_candidate_wedges, 2]
        sources_valid_half_space = dot(u_t, normals)
        sources_valid_half_space = tf.greater(sources_valid_half_space,
                    tf.fill(tf.shape(sources_valid_half_space), epsilon))
        # [num_sources, num_candidate_wedges]
        sources_valid_half_space = tf.reduce_any(sources_valid_half_space,
                                                 axis=2)
        # Expand to broadcast with targets
        # [1, num_sources, num_candidate_wedges]
        sources_valid_half_space = tf.expand_dims(sources_valid_half_space,
                                                  axis=0)

        # [num_targets, num_candidate_wedges, 2]
        targets_valid_half_space = dot(u_r, normals)
        targets_valid_half_space = tf.greater(targets_valid_half_space,
                            tf.fill(tf.shape(targets_valid_half_space),epsilon))
        # [num_targets, num_candidate_wedges]
        targets_valid_half_space = tf.reduce_any(targets_valid_half_space,
                                                 axis=2)
        # Expand to broadcast with sources
        # [num_targets, 1, num_candidate_wedges]
        targets_valid_half_space = tf.expand_dims(targets_valid_half_space,
                                                  axis=1)

        # [num_targets, num_sources, max_num_paths = num_candidate_wedges]
        mask = tf.logical_and(sources_valid_half_space,
                              targets_valid_half_space)

        # Discard paths with no valid link
        # [max_num_paths]
        valid_paths = tf.where(tf.reduce_any(mask, axis=(0,1)))[:,0]
        # [num_targets, num_sources, max_num_paths]
        mask = tf.gather(mask, valid_paths, axis=2)
        # [max_num_paths]
        wedges_indices = tf.gather(candidate_wedges, valid_paths, axis=0)
        # Set invalid wedges to -1
        # [num_targets, num_sources, max_num_paths]
        wedges_indices = tf.where(mask, wedges_indices, -1)

        return wedges_indices