# -*- coding: utf-8 -*- import bpy import bgl import blf import sys import os import datetime import math from . sun_calc import degToRad, format_hms from . properties import Display, Sun # --------------------------------------------------------------------------- class MapObject: class Origin: x = 0 y = 0 def __init__(self, t, w, h): self.type = t self.width = w self.height = h self.heightFactor = .50 self.opacity = 1.0 self.focused = False self.view3d_area = None self.colorStyle = 'N' self.origin = self.Origin() def set_dimensions(self, width): self.width = width self.height = int(width * self.heightFactor) def check_focus(self, context, event): self.focused = self.is_focused(context, event) return self.focused def is_focused(self, context, event): if context.area != self.view3d_area: return False x = event.mouse_region_x y = event.mouse_region_y for reg in self.view3d_area.regions: if reg.type == 'WINDOW': if x < 0 or x > reg.width: return False else: break if x < self.origin.x or x > (self.origin.x + self.width) or \ y < self.origin.y or y > (self.origin.y + self.height) or \ y < 0 or y > reg.height: return False return True def near_border(self, context, event): if context.area != self.view3d_area: return False x = event.mouse_region_x y = event.mouse_region_y for reg in self.view3d_area.regions: if reg.type == 'WINDOW': if x < 20 or x > (reg.width - 20) or \ y < 20 or y > (reg.height - 20): return True else: break return False # --------------------------------------------------------------------------- class MapClass: class mouse: pass class grab: class spot: pass class offset: pass class zoom: pass class image: pass def __init__(self): self.handler1 = None self.handler2 = None self.view3d_area = None self.draw_region = None self.glImage = None self.mapLocation = 'VIEWPORT' self.init_zoom_preference = True self.reset(self.mapLocation) def init(self, location): self.object = [MapObject('MAP', 0, 0), MapObject('TEXT', 100, 160)] self.object[0].set_dimensions(200) self.object[1].origin.x = 10 self.object[1].origin.y = 80 self.mapLocation = location def zoom_preferences(self, invert_zoom_wheel, invert_mouse_zoom): self.init_zoom_preference = False if invert_zoom_wheel: self.zoom.wheel_up = 'OUT' self.zoom.wheel_down = 'IN' else: self.zoom.wheel_up = 'IN' self.zoom.wheel_down = 'OUT' if invert_mouse_zoom: self.zoom.mouse_up = 'IN' self.zoom.mouse_down = 'OUT' else: self.zoom.mouse_up = 'OUT' self.zoom.mouse_down = 'IN' def reset(self, location): self.init(location) self.action = None self.isActive = False self.start = False self.stop = False self.lockCrosshair = True self.showInfo = False self.latitude = 0.0 self.longitude = 0.0 self.ctrlPress = False self.altPress = False self.lineWidth = 1.0 self.textureless = False self.mouse.x = 0 self.mouse.y = 0 self.grab.spot.x = 0 self.grab.spot.y = 0 self.grab.offset.x = 0 self.grab.offset.y = 0 self.zoom.width = 0 self.zoom.x = 0 self.zoom.y = 0 self.image.name = None self.image.bindcode = 0 self.image.loaded = False self.image.free_it = False def clear_callbacks(self): if self.mapLocation == 'PANEL': pl = bpy.types.SpaceProperties else: pl = bpy.types.SpaceView3D if self.handler2 is not None: pl.draw_handler_remove(self.handler2, 'WINDOW') self.handler2 = None if self.handler1 is not None: pl.draw_handler_remove(self.handler1, 'WINDOW') self.handler1 = None def set_view3d_area(self, area): for obj in self.object: obj.view3d_area = area def activate(self, context): if context.area.type == 'PROPERTIES': self.reset(self.mapLocation) def fw(self, context): if self.mapLocation == 'PANEL': self.draw_region = context.region areas = bpy.context.screen.areas for area in areas: if area.type == 'VIEW_3D': self.view3d_area = context.area if self.mapLocation == 'PANEL': return True for reg in area.regions: if reg.type == 'WINDOW': self.draw_region = reg Display.refresh() return True return False if not fw(self, context): self.draw_region = context.region self.set_view3d_area(self.view3d_area) self.start = True if self.mapLocation == 'PANEL': self.handler1 = bpy.types.SpaceProperties.draw_handler_add( Map_load_callback, (self, context), 'WINDOW', 'POST_PIXEL') else: self.handler1 = bpy.types.SpaceView3D.draw_handler_add( Map_load_callback, (self, context), 'WINDOW', 'POST_PIXEL') self.isActive = True return True else: return False def activateBGLcallback(self, context): if self.mapLocation == 'PANEL': self.handler2 = bpy.types.SpaceProperties.draw_handler_add( Draw_map_callback, (self, context), 'WINDOW', 'POST_PIXEL') else: self.handler2 = bpy.types.SpaceView3D.draw_handler_add( Draw_map_callback, (self, context), 'WINDOW', 'POST_PIXEL') self.view3d_area = context.area self.set_view3d_area(self.view3d_area) bpy.ops.sunpos.map('INVOKE_DEFAULT') def deactivate(self): self.clear_callbacks() self.stop = False self.action = None self.image.loaded = False if self.glImage is not None: try: if self.glImage.bindcode == self.image.bindcode: self.glImage.gl_free() bpy.data.images.remove(self.glImage) except: pass self.image.free_it = False self.glImage = None self.image.bindcode = 0 self.isActive = False if Sun.SP: Sun.SP.ShowMap = False def load_blender_image(self, file_name): if file_name == "None": self.textureless = True self.object[0].heightFactor = .5 return True else: self.textureless = False # S.L. fix to use any relative path dir_path = os.path.dirname(os.path.realpath(__file__)) self.image.name = dir_path + os.path.sep + file_name if os.path.exists(self.image.name): try: self.glImage = bpy.data.images.load(self.image.name) if self.glImage is not None: self.image.loaded = True self.glImage.user_clear() self.object[0].heightFactor = \ self.glImage.size[1] / self.glImage.size[0] return True else: return False except: pass return False def load_gl_image(self): for i in range(1, 6): # Make up to 6 tries to load image self.glImage.gl_load(bgl.GL_NEAREST, bgl.GL_NEAREST) if self.glImage.bindcode != 0: self.image.bindcode = self.glImage.bindcode return True return False def show_text_in_viewport(self, text): def text_line(fx, fy, reduce, c, str): bgl.glColor4f(c[0], c[1], c[2], c[3]) blf.position(0, fx, fy, 0) blf.draw(0, str) if reduce: fy -= 20 return fy if text.colorStyle == 'N': tColor = (0.8, 0.8, 0.8, 1.0) vColor = (1.0, 1.0, 1.0, 1.0) else: tColor = (0.0, 0.0, 0.0, 1.0) vColor = (0.23, 0.09, 0.18, 1.0) blf.size(0, 14, 72) fx = text.origin.x fy = text.origin.y + 140 fy = text_line(fx + 10, fy, True, tColor, str(Sun.SP.Month) + " / " + str(Sun.SP.Day) + " / " + str(Sun.SP.Year)) fy = text_line(fx, fy, False, tColor, " Day: ") fy = text_line(fx + 40, fy, True, vColor, str(Sun.SP.Day_of_year)) fy = text_line(fx, fy, False, tColor, "Time: ") fy = text_line(fx + 40, fy, True, vColor, format_hms(Sun.SP.Time)) if Sun.ShowRiseSet: fy -= 10 fy = text_line(fx, fy, True, tColor, "Solar Noon:") fy = text_line(fx + 14, fy, True, vColor, format_hms(Sun.SolarNoon.time)) fy -= 10 fy = text_line(fx, fy, False, tColor, "Rise: ") if Sun.RiseSetOK: fy = text_line(fx + 40, fy, True, vColor, format_hms(Sun.Sunrise.time)) else: fy = text_line(fx + 40, fy, True, vColor, "--------") fy = text_line(fx, fy, False, tColor, " Set: ") if Sun.RiseSetOK: fy = text_line(fx + 40, fy, True, vColor, format_hms(Sun.Sunset.time)) else: fy = text_line(fx + 40, fy, True, vColor, "--------") def locked_crosshair_event(self, action, event): self.mouse.x = event.mouse_region_x self.mouse.y = event.mouse_region_y self.grab.offset.x = event.mouse_region_x self.grab.offset.y = event.mouse_region_y self.lockCrosshair = True Display.refresh() return Map_function[action](event) # ----------------------------------------------------------------------- def event_controller(self, context, event): if not Sun.SP.ShowMap or event.type == 'TIMER': return {'PASS_THROUGH'} mapInFocus = self.object[0].check_focus(context, event) if event.type == 'MOUSEMOVE': if self.action == None: if mapInFocus: if self.object[0].near_border(context, event): return {'PASS_THROUGH'} else: return {'RUNNING_MODAL'} else: return {'PASS_THROUGH'} if self.action in ('PAN', 'ZOOM', 'TIME', 'DAY', 'G'): return self.locked_crosshair_event(self.action, event) if event.type in ('LEFT_CTRL', 'LEFT_ALT', 'RIGHT_CTRL', 'RIGHT_ALT'): Key_function[event.type](event) return {'RUNNING_MODAL'} self.object[1].check_focus(context, event) if event.type in ('MIDDLEMOUSE', 'LEFTMOUSE', 'G'): val = Key_function[event.type](context, event) if val: return val elif event.type in ('RIGHTMOUSE', 'ESC', 'T', 'D', 'X', 'Y', 'R', 'S', 'E', 'A', 'O', 'C', 'H', 'F1'): Display.refresh() return Key_function[event.type](event) if self.action in ('PAN', 'ZOOM', 'TIME', 'DAY', 'G', 'O'): return self.locked_crosshair_event(self.action, event) if not mapInFocus: return {'PASS_THROUGH'} if self.action in ('X', 'Y'): return Map_function[self.action](event) else: self.mouse.x = event.mouse_region_x self.mouse.y = event.mouse_region_y if event.type == 'WHEELUPMOUSE': wheel_zoom(self.zoom.wheel_up) elif event.type == 'WHEELDOWNMOUSE': wheel_zoom(self.zoom.wheel_down) elif self.action == 'CROSS': self.lockCrosshair = False Display.refresh() return {'RUNNING_MODAL'} # --------------------------------------------------------------------------- Map = MapClass() # --------------------------------------------------------------------------- def key_Ctrl(event): if event.value == 'PRESS': Map.ctrlPress = True elif event.value == 'RELEASE': Map.ctrlPress = False def key_Alt(event): if event.value == 'PRESS': Map.altPress = True elif event.value == 'RELEASE': Map.altPress = False def key_Esc(event): if Map.object[1].focused and Map.showInfo: if event.value == 'RELEASE': Map.action = None Map.showInfo = False return {'RUNNING_MODAL'} if Map.object[0].focused: if Map.action is None: Map.stop = True return {'FINISHED'} if Map.action is not None: if event.value == 'RELEASE': Map.action = None return {'RUNNING_MODAL'} return {'PASS_THROUGH'} def key_LeftMouse(context, event): if event.value == 'PRESS': if Map.action is not None: Map.action = None Display.refresh() return {'RUNNING_MODAL'} elif Map.object[0].focused: if Map.object[0].near_border(context, event): Map.action = 'BORDER' Map.lockCrosshair = True return {'PASS_THROUGH'} Map.action = 'CROSS' Map.lockCrosshair = False Display.refresh() else: return {'PASS_THROUGH'} elif event.value == 'RELEASE': Map.lockCrosshair = True Map.action = None Display.refresh() return {'PASS_THROUGH'} return False def key_MiddleMouse(context, event): if event.value == 'PRESS': if Map.object[1].focused and Map.showInfo: Map.action = 'G' if Map.action != 'G' else None Map.grab.spot.y = event.mouse_region_y Map.grab.spot.x = event.mouse_region_x elif Map.object[0].focused: if Map.ctrlPress: map = Map.object[0] Map.action = 'ZOOM' Map.zoom.width = map.width Map.zoom.x = map.origin.x Map.zoom.y = map.origin.y else: Map.action = 'PAN' Map.grab.spot.x = event.mouse_region_x Map.grab.spot.y = event.mouse_region_y else: return {'PASS_THROUGH'} elif event.value == 'RELEASE': Map.action = None Map.object[0].focused = False Map.object[1].focused = False Display.refresh() return {'RUNNING_MODAL'} # --------------------------------------------------------------------------- def key_A(event): if event.value == 'PRESS': if Map.object[0].focused: Sun.SP.ObjectGroup = 'ANALEMMA' else: return {'PASS_THROUGH'} return {'RUNNING_MODAL'} def key_C(event): if event.value == 'PRESS': if Map.object[0].focused or Map.object[1].focused: if Map.object[1].colorStyle == 'N': Map.object[1].colorStyle = 'R' else: Map.object[1].colorStyle = 'N' else: return {'PASS_THROUGH'} return {'RUNNING_MODAL'} def key_E(event): if event.value == 'PRESS': if Map.object[0].focused: Sun.SP.ObjectGroup = 'ECLIPTIC' else: return {'PASS_THROUGH'} return {'RUNNING_MODAL'} def key_G(context, event): if event.value == 'PRESS': if Map.object[1].focused and Map.showInfo: Map.action = 'G' if Map.action != 'G' else None Map.grab.spot.y = event.mouse_region_y Map.grab.spot.x = event.mouse_region_x Display.refresh() elif Map.object[0].focused: Map.action = 'PAN' if Map.action != 'PAN' else None Map.grab.spot.x = event.mouse_region_x Map.grab.spot.y = event.mouse_region_y return False else: return {'PASS_THROUGH'} return {'RUNNING_MODAL'} def key_H(event): if event.value == 'PRESS': if Map.object[0].focused: Map.action = None bpy.ops.object.help_operator('INVOKE_DEFAULT') return {'RUNNING_MODAL'} def key_R(event): if event.value == 'PRESS': if Map.object[0].focused: Map.lineWidth += 1.0 if Map.lineWidth == 4.0: Map.lineWidth = 0.0 else: Map.action = None return {'PASS_THROUGH'} return {'RUNNING_MODAL'} def key_S(event): if event.value == 'PRESS': if Map.object[0].focused: Map.showInfo = True if not Map.showInfo else False Sun.PP.ShowRiseSet = True Sun.ShowRiseSet = True else: return {'PASS_THROUGH'} return {'RUNNING_MODAL'} def key_TDOXY(event): if event.value == 'PRESS': if Map.object[0].focused: Map.grab.spot.x = event.mouse_region_x Map.grab.spot.y = event.mouse_region_y if event.type == 'T': if Map.action == 'TIME': Map.action = None Map.showInfo = False else: Map.action = 'TIME' Map.showInfo = True elif event.type == 'D': if Map.action == 'DAY': Map.action = None Map.showInfo = False else: Map.action = 'DAY' Map.showInfo = True else: Map.action = event.type else: Map.action = None return {'PASS_THROUGH'} return {'RUNNING_MODAL'} # --------------------------------------------------------------------------- def map_Pan(event): return {'RUNNING_MODAL'} def map_Zoom(event): mouse_zoom() return {'RUNNING_MODAL'} def map_Time(event): if event.type == 'WHEELUPMOUSE': time_change_wheel(Map.zoom.wheel_up) elif event.type == 'WHEELDOWNMOUSE': time_change_wheel(Map.zoom.wheel_down) else: time_change() return {'RUNNING_MODAL'} def map_Day(event): if event.type == 'WHEELUPMOUSE': day_change_wheel(Map.zoom.wheel_up) elif event.type == 'WHEELDOWNMOUSE': day_change_wheel(Map.zoom.wheel_down) else: day_change() return {'RUNNING_MODAL'} def map_G(event): if Map.grab.offset.x < Map.grab.spot.x: off = Map.grab.spot.x - Map.grab.offset.x Map.object[1].origin.x -= off else: off = Map.grab.offset.x - Map.grab.spot.x Map.object[1].origin.x += off if Map.grab.offset.y < Map.grab.spot.y: off = Map.grab.spot.y - Map.grab.offset.y Map.object[1].origin.y -= off else: off = Map.grab.offset.y - Map.grab.spot.y Map.object[1].origin.y += off Map.grab.spot.x = Map.mouse.x Map.grab.spot.y = Map.mouse.y return {'RUNNING_MODAL'} def map_O(event): if event.type == 'WHEELUPMOUSE': opacity_change_wheel(Map.zoom.wheel_up) elif event.type == 'WHEELDOWNMOUSE': opacity_change_wheel(Map.zoom.wheel_down) else: opacity_change() Display.refresh() return {'RUNNING_MODAL'} def map_X(event): if event.type == 'WHEELUPMOUSE': X_change_wheel(Map.zoom.wheel_up) elif event.type == 'WHEELDOWNMOUSE': X_change_wheel(Map.zoom.wheel_down) else: Map.mouse.y = Map.grab.spot.y Map.mouse.x = event.mouse_region_x Map.lockCrosshair = False Display.refresh() return {'RUNNING_MODAL'} def map_Y(event): if event.type == 'WHEELUPMOUSE': Y_change_wheel(Map.zoom.wheel_up) elif event.type == 'WHEELDOWNMOUSE': Y_change_wheel(Map.zoom.wheel_down) else: Map.mouse.x = Map.grab.spot.x Map.mouse.y = event.mouse_region_y Map.lockCrosshair = False Display.refresh() return {'RUNNING_MODAL'} ############################################################################ Key_function = dict([('LEFT_CTRL', key_Ctrl), ('LEFT_ALT', key_Alt), ('RIGHT_CTRL', key_Ctrl), ('RIGHT_ALT', key_Alt), ('MIDDLEMOUSE', key_MiddleMouse), ('LEFTMOUSE', key_LeftMouse), ('RIGHTMOUSE', key_Esc), ('ESC', key_Esc), ('A', key_A), ('E', key_E), ('G', key_G), ('C', key_C), ('H', key_H), ('F1', key_H), ('R', key_R), ('S', key_S), ('T', key_TDOXY), ('D', key_TDOXY), ('O', key_TDOXY), ('X', key_TDOXY), ('Y', key_TDOXY)]) # --------------------------------------------------------------------------- Map_function = dict([('PAN', map_Pan), ('ZOOM', map_Zoom), ('TIME', map_Time), ('DAY', map_Day), ('G', map_G), ('O', map_O), ('X', map_X), ('Y', map_Y)]) ############################################################################ def wheel_zoom(action): mf = 0.2 if Map.ctrlPress else 0.0 af = 0.07 if Map.altPress else 0.0 if action == 'IN': scale = 1.10 + mf - af else: scale = .90 - mf + af if Map.object[0].width * scale < 50: return else: Map.object[0].set_dimensions(int(int(Map.object[0].width * scale))) x = Map.mouse.x - Map.object[0].origin.x y = Map.mouse.y - Map.object[0].origin.y Map.object[0].origin.x += x - int(x * scale) Map.object[0].origin.y += y - int(y * scale) Map.lockCrosshair = True Display.refresh() def mouse_zoom(): if Map.mouse.y > Map.grab.spot.y: s = Map.mouse.y - Map.grab.spot.y action = Map.zoom.mouse_up elif Map.mouse.y < Map.grab.spot.y: s = Map.grab.spot.y - Map.mouse.y action = Map.zoom.mouse_down else: s = 0 action = Map.zoom.mouse_down if action == 'IN': scale = 1 + s * .01 else: scale = 1 - s * .006 w = int(Map.zoom.width * scale) if w < 50: return Map.object[0].set_dimensions(w) x = Map.grab.spot.x - Map.zoom.x y = Map.grab.spot.y - Map.zoom.y Map.object[0].origin.x = x - int(x * scale) + Map.zoom.x Map.object[0].origin.y = y - int(y * scale) + Map.zoom.y # --------------------------------------------------------------------------- def check_time_boundary(): if Sun.SP.Time > 24.0: Sun.SP.Time += -24.0 elif Sun.SP.Time < 0.0: Sun.SP.Time += 24.0 Display.refresh() def time_change_wheel(action): if action == 'IN': val = 1.0 if not Map.altPress else 0.0166 else: val = -1.0 if not Map.altPress else -0.0166 mf = 1.5 if Map.ctrlPress else 1.0 Sun.SP.Time += mf * val check_time_boundary() def time_change(): if Map.mouse.x == Map.grab.spot.x: return mf = 50 if Map.ctrlPress else 1000 if Map.altPress: sx = 0.0001 if Map.mouse.x > Map.grab.spot.x else -0.0001 else: sx = (Map.mouse.x - Map.grab.spot.x) / mf Sun.SP.Time += sx Map.grab.spot.x = Map.mouse.x check_time_boundary() # --------------------------------------------------------------------------- def day_change_wheel(action): wf = wheel_factor(action) day_change_bounds(wf) def day_change(): if Map.mouse.x == Map.grab.spot.x: return cf = 1 if Map.ctrlPress else 3 if Map.altPress: mf = 1 if Map.mouse.x > Map.grab.spot.x else -1 else: mf = (Map.mouse.x - Map.grab.spot.x) / cf day_change_bounds(mf) Map.grab.spot.x = Map.mouse.x def day_change_bounds(wf): if Sun.SP.Day_of_year + wf > 366: Sun.SP.Day_of_year = 1 Sun.SP.Year += 1 elif Sun.SP.Day_of_year + wf < 1: Sun.SP.Day_of_year = 366 Sun.SP.Year -= 1 else: Sun.SP.Day_of_year += wf dt = (datetime.date(Sun.SP.Year, 1, 1) + datetime.timedelta(Sun.SP.Day_of_year - 1)) Sun.SP.Day = dt.day Sun.SP.Month = dt.month Display.refresh() # --------------------------------------------------------------------------- def opacity_change_wheel(action): if action == 'IN': val = 0.05 if not Map.altPress else 0.01 else: val = -0.05 if not Map.altPress else -0.01 mf = 1.5 if Map.ctrlPress else 1.0 obj = Map.object[0] obj.opacity += mf * val opacity_change_bounds(obj) def opacity_change(): if Map.mouse.x > Map.grab.spot.x: s = Map.mouse.x - Map.grab.spot.x action = '+' elif Map.mouse.x < Map.grab.spot.x: s = Map.grab.spot.x - Map.mouse.x action = '-' else: action = '-' s = 0 s /= 10 obj = Map.object[0] if action == '+': scale = obj.opacity + s * .002 else: scale = obj.opacity - s * .002 obj.opacity = scale opacity_change_bounds(obj) def opacity_change_bounds(obj): if obj.opacity > 1.0: obj.opacity = 1.0 Map.grab.spot.x = Map.mouse.x elif obj.opacity < 0.0: obj.opacity = 0.0 Map.grab.spot.x = Map.mouse.x # --------------------------------------------------------------------------- def X_change_wheel(action): wf = wheel_factor(action) if Sun.SP.Longitude + wf > 180.0: Sun.SP.Longitude = -180.0 elif Sun.SP.Longitude + wf < -180.0: Sun.SP.Longitude = 180.0 else: Sun.SP.Longitude += wf def Y_change_wheel(action): wf = wheel_factor(action) if Sun.SP.Latitude + wf > 90.0: Sun.SP.Latitude = -90.0 elif Sun.SP.Latitude + wf < -90.0: Sun.SP.Latitude = 90.0 else: Sun.SP.Latitude += wf def wheel_factor(action): if action == 'IN': val = 5.0 if not Map.altPress else 1.0 else: val = -5.0 if not Map.altPress else -1.0 wf = 3 * val if Map.ctrlPress else 1.0 * val return wf ############################################################################ def Map_load_callback(self, context): if Sun.SP.ShowMap and not Map.image.loaded: Map.glImage = None if not Map.load_blender_image(Sun.MapName): print("Could not load image file: ", Map.image.name) Sun.SP.ShowMap = False if Map.start: def set_region_data(): Map.activateBGLcallback(context) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) Map.object[0].set_dimensions(0) Map.toolProps = None Map.toolPropsWidth = 0 for reg in Map.view3d_area.regions: if reg.type == 'TOOL_PROPS': Map.toolProps = reg Map.toolProps_width = reg.width elif reg.type == 'WINDOW': Map.region = reg Map.saved_region_width = reg.width Map.object[0].set_dimensions(int(reg.width * .8)) Map.object[0].origin.x = \ int((Map.region.width - Map.object[0].width) / 2) Map.object[0].origin.y = 2 return Map.start = False if Map.image.loaded: if not Map.load_gl_image(): print("Could not load image file: ", Map.image.name) elif Map.glImage.bindcode != 0: Map.image.free_it = True set_region_data() return print("Could not get texture in gl_load()") Map.glImage = None Map.image.bindcode = 0 Sun.SP.ShowMap = False elif Map.textureless: set_region_data() return else: Sun.SP.ShowMap = False return if Map.stop: Map.deactivate() return return ############################################################################ def Draw_map_callback(self, context): if context.area != Map.view3d_area: return elif context.area.type == 'PROPERTIES' and \ context.space_data.context != 'WORLD': return # Check if window area has changed for sticky zoom theMap = Map.object[0] if Map.region.width < Map.saved_region_width: diff = Map.saved_region_width - Map.region.width if theMap.origin.x + theMap.width > Map.saved_region_width: if theMap.origin.x > 0: theMap.origin.x -= diff else: theMap.width -= diff else: if Map.toolProps is not None: if Map.toolProps.width > Map.toolProps_width: theMap.origin.x -= diff Map.toolProps_width = Map.toolProps.width if theMap.origin.x < 0: theMap.origin.x += diff else: diff = Map.region.width - Map.saved_region_width if theMap.width > Map.saved_region_width: theMap.width += diff else: if Map.toolProps is not None: if Map.toolProps.width < Map.toolProps_width: theMap.origin.x += diff Map.toolProps_width = Map.toolProps.width theMap.set_dimensions(theMap.width) Map.saved_region_width = Map.region.width # Latitude and longitude are set to an equidistant # cylindrical projection with lat/long 0/0 exactly # in the middle of the image. zLong = theMap.width / 2 longFac = zLong / 180 zLat = theMap.height / 2 latFac = zLat / 90 crossChange = True if not Map.action == 'PAN': x = Map.mouse.x y = Map.mouse.y if x < theMap.origin.x or x > theMap.origin.x + theMap.width: crossChange = False x = 0 else: testBoundary = theMap.origin.x + theMap.width if testBoundary < Map.region.width: rightBoundary = testBoundary else: rightBoundary = Map.region.width if x > rightBoundary: crossChange = False x = rightBoundary cX = x - zLong - theMap.origin.x if longFac: newLongitude = cX / longFac else: newLongitude = 0.0 if y < theMap.origin.y or y < 0: crossChange = False y = 0 elif y > theMap.origin.y + theMap.height: crossChange = False y = theMap.origin.y + theMap.height cY = y - zLat - theMap.origin.y if latFac: newLatitude = cY / latFac else: newLatitude = 0.0 if newLatitude == Map.latitude and newLongitude == Map.longitude: crossChange = False else: Map.latitude = newLatitude Map.longitude = newLongitude else: if Map.grab.offset.x < Map.grab.spot.x: off = Map.grab.spot.x - Map.grab.offset.x theMap.origin.x -= off else: off = Map.grab.offset.x - Map.grab.spot.x theMap.origin.x += off if Map.grab.offset.y < Map.grab.spot.y: off = Map.grab.spot.y - Map.grab.offset.y theMap.origin.y -= off else: off = Map.grab.offset.y - Map.grab.spot.y theMap.origin.y += off Map.grab.spot.x = Map.mouse.x Map.grab.spot.y = Map.mouse.y Lx = theMap.origin.x Ly = theMap.origin.y # --------------------- # Draw a textured quad # --------------------- if not Map.textureless: bgl.glEnable(bgl.GL_BLEND) if Map.glImage.bindcode == 0: Map.load_gl_image() bgl.glBindTexture(bgl.GL_TEXTURE_2D, Map.glImage.bindcode[0]) bgl.glEnable(bgl.GL_TEXTURE_2D) bgl.glColor4f(1.0, 1.0, 1.0, Map.object[0].opacity) bgl.glBegin(bgl.GL_QUADS) bgl.glTexCoord2f(0.0, 0.0) bgl.glVertex2f(Lx, Ly) bgl.glTexCoord2f(1.0, 0.0) bgl.glVertex2f(Lx + theMap.width, Ly) bgl.glTexCoord2f(1.0, 1.0) bgl.glVertex2f(Lx + theMap.width, Ly + theMap.height) bgl.glTexCoord2f(0.0, 1.0) bgl.glVertex2f(Lx, theMap.height + Ly) bgl.glEnd() bgl.glDisable(bgl.GL_TEXTURE_2D) # ----------------------- # Output text for stats # ----------------------- if Map.action == 'TIME' or Map.action == 'DAY' or Map.showInfo: Map.show_text_in_viewport(Map.object[1]) # --------------------- # draw the crosshair # --------------------- x = theMap.width / 2.0 if crossChange and not Map.lockCrosshair: if Map.action != 'Y': Sun.SP.Longitude = newLongitude longitude = (Sun.SP.Longitude * x / 180.0) + x bgl.glEnable(bgl.GL_BLEND) bgl.glEnable(bgl.GL_LINES) bgl.glLineWidth(1.0) alpha = 1.0 if Map.action == 'Y' else 0.5 color = (0.894, 0.741, .510, alpha) bgl.glColor4f(color[0], color[1], color[2], color[3]) bgl.glBegin(bgl.GL_LINES) bgl.glVertex2f(Lx + longitude, Ly) bgl.glVertex2f(Lx + longitude, Ly + theMap.height) bgl.glEnd() y = theMap.height / 2.0 if crossChange and not Map.lockCrosshair: if Map.action != 'X': Sun.SP.Latitude = newLatitude latitude = (Sun.SP.Latitude * y / 90.0) + y alpha = 1.0 if Map.action == 'X' else 0.5 color = (0.894, 0.741, .510, alpha) bgl.glColor4f(color[0], color[1], color[2], color[3]) bgl.glBegin(bgl.GL_LINES) bgl.glVertex2f(Lx, Ly + latitude) bgl.glVertex2f(Lx + theMap.width, Ly + latitude) bgl.glEnd() # --------------------- # draw the border # --------------------- bgl.glDisable(bgl.GL_BLEND) color = (0.6, 0.6, .6, 1.0) bgl.glColor4f(color[0], color[1], color[2], color[3]) bgl.glBegin(bgl.GL_LINE_LOOP) bgl.glVertex2f(Lx, Ly) bgl.glVertex2f(Lx + theMap.width, Ly) bgl.glVertex2f(Lx + theMap.width, Ly + theMap.height) bgl.glVertex2f(Lx, theMap.height + Ly) bgl.glVertex2f(Lx, Ly) bgl.glEnd() if not Sun.ShowRiseSet or not Map.lineWidth: bgl.glDisable(bgl.GL_LINES) bgl.glFlush() return if Map.action == 'G': draw_text_region() # ------------------------ # draw the sunrise, sunset # ------------------------ def draw_angled_line(color, angle, bx, by): x = math.cos(angle) * radius y = math.sin(angle) * radius bgl.glColor4f(color[0], color[1], color[2], color[3]) bgl.glBegin(bgl.GL_LINES) bgl.glVertex2f(bx, by) bgl.glVertex2f(bx + x, by + y) bgl.glEnd() px = Lx + longitude py = Ly + latitude radius = 30 + Map.lineWidth * 10 if Sun.RiseSetOK and Map.lineWidth: color = (0.2, 0.6, 1.0, 0.9) angle = -(degToRad(Sun.Sunrise.azimuth) - math.pi / 2) bgl.glLineWidth(Map.lineWidth) draw_angled_line(color, angle, px, py) color = (0.86, 0.18, 0.18, 0.9) angle = -(degToRad(Sun.Sunset.azimuth) - math.pi / 2) draw_angled_line(color, angle, px, py) # ------------------------ # draw current time line # ------------------------ if Map.textureless: phi = degToRad(Sun.AzNorth) * -1 else: phi = degToRad(Sun.Azimuth) * -1 x = math.sin(phi) * math.sin(-Sun.Theta) * (radius + 10) y = math.sin(Sun.Theta) * math.cos(phi) * (radius + 10) night = (0.24, 0.29, 0.94, 0.9) day = (0.85, 0.77, 0.60, 0.9) if Sun.SolarNoon.elevation < 0.0: color = night elif Sun.Elevation >= Sun.Sunrise.elevation: if Sun.Time >= Sun.Sunset.time and \ Sun.Elevation <= Sun.Sunset.elevation: color = night else: color = day else: color = night bgl.glLineWidth(Map.lineWidth + 1.0) bgl.glColor4f(color[0], color[1], color[2], color[3]) bgl.glBegin(bgl.GL_LINES) bgl.glVertex2f(px, py) bgl.glVertex2f(px + x, py + y) bgl.glEnd() bgl.glLineWidth(1.0) bgl.glDisable(bgl.GL_LINES) bgl.glFlush() # --------------------------------------------------------------------------- def draw_text_region(): x = Map.object[1].origin.x y = Map.object[1].origin.y - 5 bgl.glEnable(bgl.GL_BLEND) color = (0.894, 0.741, .510, 0.2) bgl.glColor4f(color[0], color[1], color[2], color[3]) bgl.glBegin(bgl.GL_QUADS) bgl.glVertex2f(x, y) bgl.glVertex2f(x + Map.object[1].width, y) bgl.glVertex2f(x + Map.object[1].width, y + Map.object[1].height) bgl.glVertex2f(x, Map.object[1].height + y) bgl.glEnd() bgl.glDisable(bgl.GL_BLEND) # --------------------------------------------------------------------------- class SunPos_Help(bpy.types.Operator): bl_idname = "object.help_operator" bl_label = "Map help" def execute(self, context): self.report({'INFO'}, self.message) return {'FINISHED'} def invoke(self, context, event): wm = context.window_manager return wm.invoke_popup(self, width=400, height=200) def draw(self, context): self.layout.label(text="Available map commands:") row = self.layout.row() split = row.split(percentage=.27) colL = split.column() colR = split.column() colL.label(text="Esc or Right Mouse ") colR.label("Close map or text.") colL.label(text="Left Mouse") colR.label(text="Move crosshair.") colL.label(text="G or MiddleMouse") colR.label("Pan mode. Grab and move map or text.") colL.label(text="Ctrl Middlemouse") colR.label(text="Mouse zoom to point.") colL.label(text="C") colR.label("Invert text color.") colL.label(text="R") colR.label(text="Toggle through thickness of the radiating rise/set lines.") colL.label(text="S") colR.label(text="Show statistics data. Move with pan command.") self.layout.label("----- The following are changed by moving " + "the mouse or using the scroll wheel.") self.layout.label(text="----- Use Ctrl for coarse increments or Alt for fine.") row = self.layout.row() split = row.split(percentage=.25) colL = split.column() colR = split.column() colL.label(text="Scroll wheel") colR.label(text="Zoom to point.") colL.label(text="T") colR.label(text="Time mode.") colL.label(text="D") colR.label(text="Day mode.") colL.label(text="O") colR.label(text="Change map opacity.") colL.label(text="X") colR.label(text="Lock latitude and change longitude.") colL.label(text="Y") colR.label(text="Lock longitude and change latitude.") colL.label(text="A") colR.label(text="Show analemma if object group is set.") colL.label(text="E") colR.label(text="Show ecliptic if object group is set.")