Esempio n. 1
0
 def set_view_orientation(self, dir_x, dir_y, dir_z,
                          up_x, up_y, up_z):
     # Normalize the look direction
     dir_len = math.sqrt(dir_x*dir_x + dir_y*dir_y + dir_z*dir_z)
     one_over_dir_len = 1.0 / float(dir_len)
     dir_x *= one_over_dir_len
     dir_y *= one_over_dir_len
     dir_z *= one_over_dir_len
     
     # We need up to be perpendicular to the look direction, so we subtract
     # off the projection of the look direction onto the up vector
     look_dot_up = dir_x * up_x + dir_y * up_y + dir_z * up_z
     up_x -= look_dot_up * dir_x
     up_y -= look_dot_up * dir_y
     up_z -= look_dot_up * dir_z
     
     # Normalize the up vector
     up_len = math.sqrt(up_x*up_x + up_y*up_y + up_z*up_z)
     one_over_up_len = 1.0 / float(up_len)
     up_x *= one_over_up_len
     up_y *= one_over_up_len
     up_z *= one_over_up_len
     
     self.render_state.set_look_dir(GeocentricCoordinates(dir_x, dir_y, dir_z))
     self.render_state.set_up_dir(GeocentricCoordinates(up_x, up_y, up_z))
     
     self.must_update_view = True
     
     self.overlay_manager.set_view_orientation(GeocentricCoordinates(dir_x, dir_y, dir_z), 
                                               GeocentricCoordinates(up_x, up_y, up_z))
Esempio n. 2
0
    def update_objects(self, labels, update_type):
        if self.update_type.Reset in update_type:
            self.labels = [None] * len(labels)
            for i in range(0, len(labels)):
                self.labels[i] = self.label(labels[i])
            self.queue_for_reload(False)
        elif self.update_type.UpdatePositions in update_type:
            if len(labels) != len(self.labels):
                return

            # Since we don't store the positions in any GPU memory, and do the
            # transformations manually, we can just update the positions stored
            # on the label objects.
            for i in range(0, len(self.labels)):
                pos = labels[i].gc_coords
                self.labels[i].x = pos.x
                self.labels[i].y = pos.y
                self.labels[i].z = pos.z

        self.sky_region_map.clear()
        for l in self.labels:
            if self.COMPUTE_REGIONS:
                region = self.sky_region_map.get_object_region(
                    GeocentricCoordinates(l.x, l.y, l.z))
            else:
                region = self.sky_region_map.CATCHALL_REGION_ID
            self.sky_region_map.get_region_data(region).append(l)
Esempio n. 3
0
class RenderState(object):
    '''
    Contains all the state necessary for the SkyRenderer
    to render properly.
    '''
    camera_pos = GeocentricCoordinates(0, 0, 0)
    look_dir = GeocentricCoordinates(1, 0, 0)
    up_dir = GeocentricCoordinates(0, 1, 0)
    radius_of_view = 45.0  # in degrees
    up_angle = 0.0
    cos_up_angle = 1.0
    sin_up_angle = 0.0
    screen_width = 480  # originally 100
    screen_height = 800  # originally 100
    transform_to_device = create_identity()
    transform_to_screen = create_identity()
    night_vision_mode = False
    active_sky_region_set = None

    def set_camera_pos(self, pos):
        self.camera_pos = pos.copy()

    def set_look_dir(self, new_dir):
        self.look_dir = new_dir.copy()

    def set_up_dir(self, new_dir):
        self.up_dir = new_dir.copy()

    def set_up_angle(self, angle):
        self.up_angle = angle
        self.cos_up_angle = math.cos(angle)
        self.sin_up_angle = math.sin(angle)

    def set_screen_size(self, width, height):
        self.screen_width = width
        self.screen_height = height

    def set_tranformation_matrices(self, to_device, to_screen):
        self.transform_to_device = to_device
        self.transform_to_screen = to_screen

    def __init__(self):
        '''
Esempio n. 4
0
def getXYZ(ra_dec):
    '''
    Convert ra and dec to x,y,z where the point is place on the unit sphere.
    '''
    ra_radians = degrees_to_radians(ra_dec.ra)
    dec_radians = degrees_to_radians(ra_dec.dec)
    x = math.cos(ra_radians) * math.cos(dec_radians)
    y = math.sin(ra_radians) * math.cos(dec_radians)
    z = math.sin(dec_radians)
    return GeocentricCoordinates(x, y, z)
Esempio n. 5
0
 def __init__(self, model):
     '''
     constructor
     '''
     AbstractAstronomicalSource.__init__(self)
     self.zenith = GeocentricCoordinates(0, 0, 0)
     self.nadir = GeocentricCoordinates(0, 0, 0)
     self.north = GeocentricCoordinates(0, 0, 0)
     self.south = GeocentricCoordinates(0, 0, 0)
     self.east = GeocentricCoordinates(0, 0, 0)
     self.west = GeocentricCoordinates(0, 0, 0)
 
     self.line_sources = []
     self.text_sources = []
 
     self.lastUpdateTimeMs = 0
     
     self.model = model
     
     vertices = [self.north, self.east, self.south, self.west, self.north]
     self.line_sources.append(LineSource(vertices, self.LINE_COLOR, 1.5))
     
     self.text_sources.append(TextSource("ZENITH", self.LABEL_COLOR, self.zenith))
     self.text_sources.append(TextSource("NADIR", self.LABEL_COLOR, self.nadir))
     self.text_sources.append(TextSource("NORTH", self.LABEL_COLOR, self.north))
     self.text_sources.append(TextSource("SOUTH", self.LABEL_COLOR, self.south))
     self.text_sources.append(TextSource("EAST", self.LABEL_COLOR, self.east))
     self.text_sources.append(TextSource("WEST", self.LABEL_COLOR, self.west))
Esempio n. 6
0
    def __init__(self, planet, model):
        '''
        Constructor
        '''
        AbstractAstronomicalSource.__init__(self)

        self.point_sources = []
        self.image_sources = []
        self.label_sources = []
        self.planet = planet
        self.model = model
        self.name = planet.name_resource_id
        self.current_coords = GeocentricCoordinates(0, 0, 0)
        self.sun_coords = None
        self.image_id = -1

        self.last_update_time_Ms = 0
Esempio n. 7
0
class SkyRegionMap(object):
    '''
    This is a utility class which divides the sky into a fixed set of regions
    and maps each of the regions into a generic data object which contains the
    data for rendering that region of the sky.  For a given frame, this class
    will determine which regions are on-screen and which are totally
    off-screen, and will return only the on-screen ones (so we can avoid paying
    the cost of rendering the ones that aren't on-screen).  There should
    typically be one of these objects per type of object being rendered: for
    example, points and labels will each have their own SkyRegionMap.
    
    Each region consists of a center (a point on the unit sphere) and an angle,
    and should contain every object on the unit sphere within the specified
    angle from the region's center.
    
    This also allows for a special "catchall" region which is always rendered
    and may contain objects from anywhere on the unit sphere.  This is useful
    because, for small layers, it is cheaper to just render the
    whole layer than to break it up into smaller pieces.
    
    The center of all regions is fixed for computational reasons.  This allows
    us to find the distance between each region and the current look direction
    once per frame and share that between all SkyRegionMaps.  For most types
    of objects, they can also use regions with the same radius, which means
    that they are the same exact part of the unit sphere.  For these we can
    compute the regions which are on screen ("active regions") once per frame,
    and share that between all SkyRegionMaps.  These are called "standard
    regions", as opposed to "non-standard regions", where the region's angle
    may be greater than that of the standard region.  Non-standard regions
    are necessary for some types of objects, such as lines, which may not be
    fully contained within any standard region.  For lines, we can find the
    region center which is closest to fully containing the line, and simply
    increase the angle until it does fully contain it.
    '''
    class ObjectRegionData(object):
        '''
        Data representing an individual object's position in a region.
        We care about the region itself for obvious reasons, but we care about
        the dot product with the center because it is a measure of how
        close it is to the center of a region.
        '''
        def __init__(self):
            '''
            constructor
            '''
            self.region = SkyRegionMap().CATCHALL_REGION_ID
            self.region_center_dot_product = -1

    class RegionDataFactory(object):
        '''
        Factory class where the construct method is set during
        instantiation to produce RegionData objects
        '''
        def construct(self):
            raise Exception("This method must be overwritten")

        def __init__(self, construct_method):
            '''
            constructor
            '''
            self.construct = construct_method

    CATCHALL_REGION_ID = -1
    REGION_COVERAGE_ANGLE_IN_RADIANS = 0.396023592
    REGION_CENTERS32 = [ \
        GeocentricCoordinates(-0.850649066269, 0.525733930059, -0.000001851469),
        GeocentricCoordinates(-0.934170971625, 0.000004098751, -0.356825719588),
        GeocentricCoordinates(0.577349931933, 0.577346773818, 0.577354100533),
        GeocentricCoordinates(0.577350600623, -0.577350601554, -0.577349603176),
        GeocentricCoordinates(-0.577354427427, -0.577349954285, 0.577346424572),
        GeocentricCoordinates(-0.577346098609, 0.577353779227, -0.577350928448),
        GeocentricCoordinates(-0.577349943109, -0.577346729115, -0.577354134060),
        GeocentricCoordinates(-0.577350598760, 0.577350586653, 0.577349620871),
        GeocentricCoordinates(0.577354458161, 0.577349932864, -0.577346415259),
        GeocentricCoordinates(0.577346091159, -0.577353793196, 0.577350921929),
        GeocentricCoordinates(-0.850652559660, -0.525728277862, -0.000004770234),
        GeocentricCoordinates(-0.934173742309, 0.000002107583, 0.356818466447),
        GeocentricCoordinates(0.525734450668, 0.000000594184, -0.850648744032),
        GeocentricCoordinates(0.000002468936, -0.356819496490, -0.934173349291),
        GeocentricCoordinates(0.525727798231, -0.000004087575, 0.850652855821),
        GeocentricCoordinates(-0.000002444722, 0.356819517910, 0.934173340909),
        GeocentricCoordinates(-0.525727787986, 0.000004113652, -0.850652862340),
        GeocentricCoordinates(0.000004847534, 0.356824675575, -0.934171371162),
        GeocentricCoordinates(-0.000004885718, -0.850652267225, 0.525728750974),
        GeocentricCoordinates(-0.356825215742, -0.934171164408, -0.000003995374),
        GeocentricCoordinates(0.000000767410, 0.850649364293, 0.525733447634),
        GeocentricCoordinates(0.356825180352, 0.934171177447, 0.000003952533),
        GeocentricCoordinates(-0.000000790693, -0.850649344735, -0.525733478367),
        GeocentricCoordinates(0.356818960048, -0.934173554182, -0.000001195818),
        GeocentricCoordinates(0.850652555004, 0.525728284381, 0.000004773028),
        GeocentricCoordinates(0.934170960449, -0.000004090369, 0.356825748459),
        GeocentricCoordinates(-0.525734410621, -0.000000609085, 0.850648769177),
        GeocentricCoordinates(-0.000004815869, -0.356824668124, 0.934171373956),
        GeocentricCoordinates(0.000004877336, 0.850652255118, -0.525728769600),
        GeocentricCoordinates(-0.356819001026, 0.934173538350, 0.000001183711),
        GeocentricCoordinates(0.850649050437, -0.525733955204, 0.000001879409),
        GeocentricCoordinates(0.934173759073, -0.000002136454, -0.356818422675)]

    def get_active_regions(self, look_dir, fovy_in_degrees, aspect):
        '''
        Computes the data necessary to determine which regions on the screen
        are active.  This should be produced once per frame and passed to
        the getDataForActiveRegions method of all SkyRegionMap objects to
        get the active regions for each map.
        
        lookDir The direction the user is currently facing.
        fovyInDegrees The field of view (in degrees).
        aspect The aspect ratio of the screen.
        Returns a data object containing data for quickly determining the
        active regions.
        '''
        half_fovy = degrees_to_radians(fovy_in_degrees) / 2.0
        screen_angle = math.asin(
            math.sin(half_fovy) * math.sqrt(1 + aspect * aspect))
        angle_threshold = screen_angle + self.REGION_COVERAGE_ANGLE_IN_RADIANS
        dot_product_threshold = math.cos(angle_threshold)
        region_center_dot_products = [0] * len(self.REGION_CENTERS32)
        active_standard_regions = []

        i = 0
        for i in range(len(self.REGION_CENTERS32)):
            d_product = dot_product(look_dir, self.REGION_CENTERS32[i])
            region_center_dot_products[i] = d_product

            if d_product > dot_product_threshold:
                active_standard_regions.append(i)

        return ActiveRegionData(region_center_dot_products, \
                                screen_angle, active_standard_regions)

    def get_object_region(self, gc_coords):
        '''
        returns to region that contains the coordinate
        '''
        return self.get_object_region_data(gc_coords).region

    def get_object_region_data(self, gc_coords):
        '''
        returns the region a point belongs in, as well as the dot product of the
        region center and the position.  The latter is a measure of how close it
        is to the center of the region (1 being a perfect match).
        '''
        data = self.ObjectRegionData()

        i = 0
        for i in range(len(self.REGION_CENTERS32)):
            d_product = dot_product(self.REGION_CENTERS32[i], gc_coords)

            if d_product > data.region_center_dot_product:
                data.region_center_dot_product = d_product
                data.region = i

        return data

    def clear(self):
        self.region_data.clear()
        self.region_coverage_angles = None

    def set_region_data(self, r_id, data):
        '''
        sets generic RenderingRegionData as specified by ObjectManager
        which instantiated this class
        '''
        self.region_data[r_id] = data

    def get_region_coverage_angle(self, r_id):
        if self.region_coverage_angles == None:
            return self.REGION_COVERAGE_ANGLE_IN_RADIANS
        else:
            return self.region_coverage_angles[r_id]

    def set_region_coverage_angle(self, r_id, angle_in_radians):
        '''
        Sets the coverage angle for a sky region.  Needed for non-point objects.
        '''
        if self.region_coverage_angles == None:
            self.region_coverage_angles = [self.REGION_COVERAGE_ANGLE_IN_RADIANS] * \
                len(self.REGION_CENTERS32)
        self.region_coverage_angles[r_id] = angle_in_radians

    def get_region_data(self, r_id):
        '''
        Lookup the region data corresponding to a region ID.  If none exists,
        and a region data constructor has been set (see setRegionDataConstructor),
        that will be used to create a new region - otherwise, this will return
        None.  This can be useful while building or updating a region, but to get
        the region data when rendering a frame, use getDataForActiveRegions().
        '''
        data = None

        if r_id in self.region_data.keys():
            data = self.region_data[r_id]
        elif self.region_data_factory != None:
            data = self.region_data_factory.construct()
            self.set_region_data(r_id, data)

        return data

    def get_data_for_active_regions(self, active_region_data):
        '''
        returns the rendering data for the active regions.  When using a
        SkyRegionMap for rendering, this is the function will return the
        data for the regions you need to render.
        '''
        data = []

        if self.CATCHALL_REGION_ID in self.region_data.keys():
            data.append(self.region_data[self.CATCHALL_REGION_ID])

        if self.region_coverage_angles == None:
            for region in active_region_data.active_standard_regions:
                if region in self.region_data.keys():
                    data.append(self.region_data[region])
            return data
        else:
            for i in range(len(self.REGION_CENTERS32)):
                if active_region_data.region_is_active(i, self.region_coverage_angles[i])\
                    and i in self.region_data.keys():
                    data.append(self.region_data[i])
            return data

    def __init__(self):
        '''
        Constructor
        '''
        self.region_coverage_angles = None
        self.region_data = {}
        self.region_data_factory = None
Esempio n. 8
0
    def __init__(self, layer_id, texture_manager):
        '''
        Constructor
        '''
        RendererObjectManager.__init__(self, layer_id, texture_manager)

        self.vertex_buffer = VertexBuffer(0, True)
        self.color_buffer = ColorBuffer(0, True)
        self.index_buffer = IndexBuffer(0, True)
        self.sun_pos = GeocentricCoordinates(0, 1, 0)

        num_vertices = self.NUM_VERTEX_BANDS * self.NUM_STEPS_IN_BAND
        num_indices = (self.NUM_VERTEX_BANDS - 1) * self.NUM_STEPS_IN_BAND * 6
        self.vertex_buffer.reset(num_vertices)
        self.color_buffer.reset(num_vertices)
        self.index_buffer.reset(num_indices)

        sin_angles = [0.0] * self.NUM_STEPS_IN_BAND
        cos_angles = [0.0] * self.NUM_STEPS_IN_BAND

        angle_in_band = 0
        d_angle = 2 * math.pi / float(self.NUM_STEPS_IN_BAND - 1)
        for i in range(0, self.NUM_STEPS_IN_BAND):
            sin_angles[i] = math.sin(angle_in_band)
            cos_angles[i] = math.cos(angle_in_band)
            angle_in_band += d_angle

        band_step = 2.0 / float((self.NUM_VERTEX_BANDS - 1) + self.EPSILON)

        vb = self.vertex_buffer
        cb = self.color_buffer
        band_pos = 1
        for band in range(0, self.NUM_VERTEX_BANDS):
            a, r, g, b = 0, 0, 0, 0

            if band_pos > 0:
                intensity = long(band_pos * 20 + 50) & 0xFFFFFFFF
                a = 0xFF
                r = (intensity << 16) & 0x00FF0000
                g = (intensity << 16) & 0x0000FF00
                b = (intensity << 16) & 0x000000FF
            else:
                intensity = long(band_pos * 40 + 40) & 0xFFFFFFFF
                color = (intensity << 16) | (intensity << 8) | (intensity)
                a = 0xFF
                r = color & 0x00FF0000
                g = color & 0x0000FF00
                b = color & 0x000000FF

            band_pos -= band_step

            sin_phi = math.sqrt(1 -
                                band_pos * band_pos) if band_pos > -1 else 0
            for i in range(0, self.NUM_STEPS_IN_BAND):
                vb.add_point(
                    Vector3(cos_angles[i] * sin_phi, band_pos,
                            sin_angles[i] * sin_phi))
                cb.add_color(a, r, g, b)

        ib = self.index_buffer

        # Set the indices for the first band.
        top_band_start = 0
        bottom_band_start = self.NUM_STEPS_IN_BAND
        for triangle_band in range(0, self.NUM_VERTEX_BANDS - 1):
            for offset_from_start in range(0, self.NUM_STEPS_IN_BAND - 1):
                # Draw one quad as two triangles.
                top_left = (top_band_start + offset_from_start)
                top_right = (top_left + 1)

                bottom_left = (bottom_band_start + offset_from_start)
                bottom_right = (bottom_left + 1)

                # First triangle
                ib.add_index(top_left)
                ib.add_index(bottom_right)
                ib.add_index(bottom_left)

                # Second triangle
                ib.add_index(top_right)
                ib.add_index(bottom_right)
                ib.add_index(top_left)

            # Last quad: connect the end with the beginning.

            # Top left, bottom right, bottom left
            ib.add_index((top_band_start + self.NUM_STEPS_IN_BAND - 1))
            ib.add_index(bottom_band_start)
            ib.add_index((bottom_band_start + self.NUM_STEPS_IN_BAND - 1))

            # Top right, bottom right, top left
            ib.add_index(top_band_start)
            ib.add_index(bottom_band_start)
            ib.add_index((top_band_start + self.NUM_STEPS_IN_BAND - 1))

            top_band_start += self.NUM_STEPS_IN_BAND
            bottom_band_start += self.NUM_STEPS_IN_BAND