示例#1
0
    def ray_tracer(self, bundle, reps, min_energy, tree=True):
        """
        Creates a ray bundle or uses a reflected ray bundle, and intersects it
        with all objects, uses intersect_ray(). Based on the intersections,
        generates an outgoing ray in accordance with way the incoming ray
        reflects or refracts off any surfaces.
        
        Arguments:
        bundle - the initial incoming bundle
        reps - stop iteration after this many ray bundles were generated (i.e. 
            after the original rays intersected some surface this many times).
        min_energy - the minimum energy the rays have to have continue tracking
            them; rays with a lower energy are discarded. A float.
        tree - if True, register each bundle in self.tree, otherwise only
            register the last bundle.
        
        Returns: 
        A tuple containing an array of vertices and an array of the the direcitons
        of the last outgoing raybundle (note that the vertices of the new bundle are the 
        intersection points of the previous incoming bundle)
        
        NB: the order of the rays within the arrays may change, but they are tracked
        by the ray tree
        """
        self.tree = RayTree()
        bund = bundle
        if tree is True:
            self.tree.append(bund)

        # A list of surfaces and their matching objects:
        surfaces = self._asm.get_surfaces()
        objects = self._asm.get_objects()
        num_surfs = len(surfaces)

        surfs_per_obj = [len(obj.get_surfaces()) for obj in objects]
        surfs_until_obj = N.hstack((N.r_[0], N.add.accumulate(surfs_per_obj)))
        surf_ownership = N.repeat(N.arange(len(objects)), surfs_per_obj)
        ray_ownership = -1 * N.ones(bund.get_num_rays())
        surfs_relevancy = N.ones((num_surfs, bund.get_num_rays()),
                                 dtype=N.bool)

        for i in xrange(reps):
            front_surf, owned_rays = self.intersect_ray(bund, surfaces, objects, \
                surf_ownership, ray_ownership, surfs_relevancy)
            outg = []
            record = []
            out_ray_own = []
            new_surfs_relevancy = []
            weak_ray_pos = []

            for surf_idx in xrange(num_surfs):
                inters = front_surf[surf_idx, owned_rays[surf_idx]]
                if not any(inters):
                    surfaces[surf_idx].done()
                    continue
                surfaces[surf_idx].select_rays(N.nonzero(inters)[0])
                new_outg = surfaces[surf_idx].get_outgoing()
                new_record = new_outg

                # Fix parent indexing to refer to the full original bundle:
                parents = N.nonzero(
                    owned_rays[surf_idx])[0][new_outg.get_parents()]
                new_outg.set_parents(parents)

                # Delete rays with negligible energies
                delete = new_outg.get_energy() <= min_energy
                weak_ray_pos.append(delete)
                if delete.any():
                    new_outg = new_outg.delete_rays(N.nonzero(delete)[0])
                surfaces[surf_idx].done()

                # Aggregate outgoing bundles from all the objects
                outg.append(new_outg)
                record.append(new_record)

                # Add new ray-ownership information to the total list:
                obj_idx = surf_ownership[surf_idx]
                surf_rel_idx = surf_idx - surfs_until_obj[obj_idx]
                object_owns_outg = objects[obj_idx].own_rays(
                    new_outg, surf_rel_idx)
                out_ray_own.append(N.where(object_owns_outg, obj_idx, -1))

                # Add new surface-relevancy information, saying which surfaces
                # of the full list of surfaces must be checked next. This is
                # somewhat memory-intensize and requires optimization.
                surf_relev = N.ones((num_surfs, new_outg.get_num_rays()),
                                    dtype=N.bool)
                surf_relev[surf_ownership == obj_idx] = \
                    objects[obj_idx].surfaces_for_next_iteration(new_outg, surf_rel_idx)
                new_surfs_relevancy.append(surf_relev)

            bund = concatenate_rays(outg)
            if tree:
                # stores parent branch for purposes of ray tracking
                record = concatenate_rays(record)

                if record.get_num_rays() != 0:
                    weak_ray_pos = N.hstack(weak_ray_pos)
                    record = bund + record.inherit(N.nonzero(weak_ray_pos)[0])
                    self.tree.append(record)

            if bund.get_num_rays() == 0:
                # All rays escaping
                break

            ray_ownership = N.hstack(out_ray_own)
            surfs_relevancy = N.hstack(new_surfs_relevancy)

        if not tree:
            # Save only the last bundle. Don't bother moving weak rays to end.
            record = concatenate_rays(record)
            self.tree.append(record)

        return bund.get_vertices(), bund.get_directions()