import bpy import datetime from . properties import * from . operators import * from . sun_calc import Degrees, format_lat_long, degToRad, \ format_time, format_hms, Move_sun #--------------------------------------------------------------------------- # # Draw the Sun Panel, sliders, et. al. # #--------------------------------------------------------------------------- class SunPos_Panel(bpy.types.Panel): bl_idname = "panel.SunPos_world" bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "world" bl_label = "Sun Position" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): if context.area.type == 'PROPERTIES': return 1 return 0 def enable(self, layout): row = layout.row() split = row.split(percentage=.90) colL = split.column() colL.alignment = 'LEFT' colR = split.column() colR.alignment = 'RIGHT' colL.operator('world.sunpos_controller', 'Enable', icon='PLAY') colR.operator('world.sunpos_preferences', '', icon='PREFERENCES') Map.init_zoom_preference = True def disable(self, context, layout): p = context.scene.SunPos_pref_property if Map.init_zoom_preference: Map.zoom_preferences(bpy.context.preferences.inputs.invert_zoom_wheel, bpy.context.preferences.inputs.invert_mouse_zoom) Hdr.zoom_preferences(bpy.context.preferences.inputs.invert_zoom_wheel, bpy.context.preferences.inputs.invert_mouse_zoom) row = self.layout.row() if p.UseOneColumn: col1 = row.column() col2 = col1 elif p.UseTimePlace: split = row.split(percentage=.3) col1 = split.column() col2 = split.column() else: col1 = row.column() col1.operator('world.sunpos_controller', 'Disable', icon='X') if p.UseTimePlace: col2.operator_menu_enum('world.pdp_operator', 'timePlacePresets', text=Sun.PlaceLabel) def show_preferences(self, context, layout): p = context.scene.SunPos_pref_property box = self.layout.box() row = box.row(align=True) row.alignment = 'CENTER' row.label(text="Preferences") col = box.column(align=True) col.label(text="Usage mode:") col.props_enum(p, "UsageMode") col.separator() if p.UsageMode == "NORMAL": cb = col.box() tr = cb.row() rr = tr.row(align=True) cs = rr.split() cl = cs.column() cr = cs.column() cl.label(text="World map options:") cl.operator_menu_enum('world.wmp_operator', 'mapPresets', text=Sun.MapName) cr.label(text="Display map in:") cr.props_enum(p, "MapLocation") col.separator() col.label(text="Show or use:") col.alignment = 'LEFT' col.prop(p, "UseOneColumn", text="Single column mode") col.prop(p, "UseTimePlace", text="Time/place presets") col.prop(p, "UseObjectGroup", text="Object group") col.prop(p, "ShowDMS", text="D\xb0 M' S\"") col.prop(p, "ShowNorth", text="North offset") col.prop(p, "ShowRefraction", text="Refraction") col.prop(p, "ShowAzEl", text="Azimuth, elevation") col.prop(p, "ShowDST", text="Daylight savings time") col.prop(p, "ShowRiseSet", text="Sunrise, sunset") col.separator() col.operator('world.sunpos_pref_done', 'Done', icon='QUIT') Sun.ShowRiseSet = p.ShowRiseSet def draw(self, context): sp = context.scene.SunPos_property p = context.scene.SunPos_pref_property layout = self.layout if Display.PREFERENCES: self.show_preferences(context, layout) elif Display.ENABLE: Sun.SP = sp Sun.PP = p self.enable(layout) else: Sun.SP = sp Sun.PP = p self.disable(context, layout) if Display.PANEL: if Sun.SP.IsActive: self.draw_panel(context, sp, p, layout) else: Display.setAction('ENABLE') def draw_panel(self, context, sp, p, layout): if p.UsageMode == "HDR": self.draw_environ_panel(context, sp, p, layout) elif p.UseOneColumn: self.draw_one_column(context, sp, p, layout) else: self.draw_two_columns(context, sp, p, layout) def draw_environ_panel(self, context, sp, p, layout): box = self.layout.box() toprow = box.row() row = toprow.row(align=False) row.alignment = 'CENTER' col = row.column(align=True) have_texture = False try: col.separator() col.label(text="Use environment texture:") col.prop_search(sp, "HDR_texture", context.scene.world.node_tree, "nodes", text="") col.separator() try: nt = bpy.context.scene.world.node_tree.nodes envTex = nt.get(sp.HDR_texture) if envTex: if envTex.type == "TEX_ENVIRONMENT": if envTex.image != None: have_texture = True if Sun.Bind.azDiff == 0: if envTex.texture_mapping.rotation.z == 0.0: Sun.Bind.azDiff = degToRad(90.0) except: pass except: pass try: col.label(text="Use sun object:") col.prop_search(sp, "SunObject", context.scene, "objects", text="") Sun.SunObject = sp.SunObject except: pass col.separator() col.prop(sp, "SunDistance") if not sp.BindToSun: col.prop(sp, "HDR_elevation") col.prop(sp, "HDR_azimuth") col.separator() toprow1 = box.row() row1 = toprow1.row(align=False) row1.alignment = 'CENTER' if not sp.BindToSun: row1.prop(sp, "BindToSun", toggle=True, icon="CONSTRAINT", text="Bind Texture to Sun ") else: row1.prop(sp, "BindToSun", toggle=True, icon="CONSTRAINT", text="Release binding") toprow2 = box.row() row2 = toprow2.row(align=False) row2.alignment = 'CENTER' row2.prop(sp, "ShowHdr", text="Sync Sun to Texture", toggle=True, icon='LAMP_SUN') if have_texture == False: row2.enabled = False elif sp.BindToSun: row2.enabled = False else: row2.enabled = True if have_texture == False: row1.enabled = False elif sp.ShowHdr: row1.enabled = False else: row1.enabled = True def draw_one_column(self, context, sp, p, layout): box = self.layout.box() toprow = box.row() row = toprow.row(align=False) row.alignment = 'CENTER' col = row.column(align=True) col.prop(sp, "UseSkyTexture", text="Cycles sky") if sp.UseSkyTexture: try: col.prop_search(sp, "SkyTexture", context.scene.world.node_tree, "nodes", text="") except: pass col.prop(sp, "UseSunObject", text="Use object") if(sp.UseSunObject): try: col.prop_search(sp, "SunObject", context.scene, "objects", text="") except: pass if p.UseObjectGroup: col.prop(sp, "UseObjectGroup", text="Object group") if sp.UseObjectGroup: Sun.verify_ObjectGroup() if len(Sun.Selected_objects) > 0: col.operator('world.sunpos_clear_objects', 'Release Group') col.separator() if(sp.ObjectGroup == 'ECLIPTIC'): col.prop(sp, "TimeSpread") col.props_enum(sp, "ObjectGroup") else: col.operator('world.sunpos_set_objects', 'Set Object Group') else: Sun.ObjectGroup_verified = False row = layout.row() row.prop(sp, "ShowMap", text="Show Map", toggle=True, icon='WORLD') box = self.layout.box() toprow = box.row() row = toprow.row(align=True) row.alignment = 'CENTER' col = row.column(align=True) col.alignment = 'CENTER' col.prop(sp, "Latitude") if p.ShowDMS: col.label(text=format_lat_long(sp.Latitude, True)) col.prop(sp, "Longitude") if p.ShowDMS: col.label(text=format_lat_long(sp.Longitude, False)) cb = col.box() tr = cb.row() rr = tr.row(align=True) if p.ShowNorth: cs = rr.split() cl = cs.column() cr = cs.column() cl.prop(sp, "ShowNorth", text="Show North", toggle=True) cr.prop(sp, "NorthOffset") col.prop(sp, "SunDistance") else: rr.prop(sp, "SunDistance") if p.ShowRefraction: col.prop(sp, "ShowRefraction", text="Show refraction") if p.ShowAzEl: col.label(text="Azimuth: " + str(round(Sun.Azimuth, 3)) + Degrees) col.label(text="Elevation: " + str(round(Sun.Elevation, 3)) + Degrees) box = self.layout.box() toprow = box.row() row = toprow.row(align=False) row.alignment = 'CENTER' col = row.column(align=False) col.alignment = 'CENTER' tr = col.row() rr = tr.row(align=True) if Sun.UseDayMonth: cs = rr.split(percentage=.82) cl = cs.column() cl.alignment = 'LEFT' cr = cs.column() cr.alignment = 'RIGHT' cl.prop(sp, "Month") cr.operator('world.sunpos_day_range', '', icon='SORTTIME') col.prop(sp, "Day") else: cs = rr.split(percentage=.90) cl = cs.column() cr = cs.column() cl.alignment = 'LEFT' cr.alignment = 'RIGHT' cl.prop(sp, "Day_of_year") cr.operator('world.sunpos_day_range', '', icon='SORTTIME') col.prop(sp, "Year") col.prop(sp, "UTCzone", slider=True) col.prop(sp, "Time") lt, ut = format_time(sp.Time, sp.UTCzone, sp.DaylightSavings, sp.Longitude) col.label(text=lt, icon='TIME') col.label(text=" " + ut, icon='PREVIEW_RANGE') if p.ShowRiseSet: if Sun.Sunrise.time == Sun.Sunset.time or \ Sun.Sunrise.elevation > -0.4 or Sun.Sunset.elevation > -0.4: Sun.RiseSetOK = False tsr = "Sunrise: --------" tss = " Sunset: --------" else: Sun.RiseSetOK = True sr = format_hms(Sun.Sunrise.time) ss = format_hms(Sun.Sunset.time) tsr = "Sunrise: " + sr tss = " Sunset: " + ss col.label(text=tsr, icon='LAMP_SUN') col.label(text=tss, icon='SOLO_ON') if p.ShowDST: col.prop(sp, "DaylightSavings", text="Daylight Savings") def draw_two_columns(self, context, sp, p, layout): box = self.layout.box() toprow = box.row() row = toprow.row(align=True) row.alignment = 'CENTER' col = row.column(align=True) split = col.split(percentage=.5) cL = split.column() cR = split.column() cL.alignment = 'LEFT' cR.alignment = 'RIGHT' cLi = cRi = 1 cL.prop(sp, "UseSkyTexture", text="Cycles sky") if sp.UseSkyTexture: try: cL.prop_search(sp, "SkyTexture", context.scene.world.node_tree, "nodes", text="") cLi += 1 except: pass cR.prop(sp, "UseSunObject", text="Use object") if(sp.UseSunObject): try: cR.prop_search(sp, "SunObject", context.scene, "objects", text="") cRi += 1 except: pass if p.UseObjectGroup: cLi += 1 cL.prop(sp, "UseObjectGroup", text="Object group") if sp.UseObjectGroup: Sun.verify_ObjectGroup() if len(Sun.Selected_objects) > 0: while cRi < cLi: cR.label(text=" ") cRi += 1 cL.operator('world.sunpos_clear_objects', 'Release Group') cL.label(text=" ") if(sp.ObjectGroup == 'ECLIPTIC'): cR.prop(sp, "TimeSpread") cR.props_enum(sp, "ObjectGroup") else: cL.operator('world.sunpos_set_objects', 'Set Object Group') else: Sun.ObjectGroup_verified = False box = self.layout.box() toprow = box.row() row = toprow.row(align=False) row.alignment = 'CENTER' col = row.column(align=False) col.prop(sp, "ShowMap", text="Show Map", toggle=True, icon='WORLD') distanceSet = False if p.ShowDMS: split = col.split(percentage=.5) cL = split.column() cR = split.column() cL.alignment = 'LEFT' cR.alignment = 'RIGHT' cL.prop(sp, "Latitude") cR.label(text=format_lat_long(sp.Latitude, True)) cL.prop(sp, "Longitude") cR.label(text=format_lat_long(sp.Longitude, False)) if p.ShowNorth: cL.prop(sp, "ShowNorth", text="Show North", toggle=True) cR.prop(sp, "NorthOffset") if p.ShowAzEl: cL.label(text="Azimuth: " + str(round(Sun.Azimuth, 3)) + Degrees) cR.label(text="Elevation: " + str(round(Sun.Elevation, 3)) + Degrees) if p.ShowRefraction: cL.prop(sp, "ShowRefraction", text="Show refraction") cR.prop(sp, "SunDistance") distanceSet = True else: cb = col.box() tr = cb.row() rr = tr.row(align=True) cs = rr.split() cL = cs.column(align=True) cR = cs.column(align=True) cL.prop(sp, "Latitude") cR.prop(sp, "Longitude") if p.ShowNorth: col.separator() cL.prop(sp, "ShowNorth", text="Show North", toggle=True) cR.prop(sp, "NorthOffset") if p.ShowAzEl: cL.label(text="Azimuth: " + str(round(Sun.Azimuth, 3)) + Degrees) cR.label(text="Elevation: " + str(round(Sun.Elevation, 3)) + Degrees) if p.ShowRefraction: cL.prop(sp, "ShowRefraction", text="Show refraction") cR.prop(sp, "SunDistance") distanceSet = True if not distanceSet: col.prop(sp, "SunDistance") box = self.layout.box() toprow = box.row() row = toprow.row(align=False) row.alignment = 'CENTER' if Sun.UseDayMonth: split = row.split(percentage=.5) colL = split.column() colMid = split.column() colMsplit = colMid.split(percentage=.82) colM = colMsplit.column() colR = colMsplit.column() colL.prop(sp, "Month") colM.prop(sp, "Day") colR.operator('world.sunpos_day_range', '', icon='SORTTIME') else: split = row.split(percentage=.50) colL = split.column() colL.alignment = 'LEFT' colMid = split.column() colMsplit = colMid.split(percentage=.90) colM = colMsplit.column() colR = colM.column() colR.alignment = 'RIGHT' colL.prop(sp, "Day_of_year") colR.operator('world.sunpos_day_range', '', icon='SORTTIME') colL.prop(sp, "Year") colM.prop(sp, "UTCzone", slider=True) lt, ut = format_time(sp.Time, sp.UTCzone, sp.DaylightSavings, sp.Longitude) colL.prop(sp, "Time") colM.label(text=lt, icon='TIME') if p.ShowDST: colL.prop(sp, "DaylightSavings", text="Daylight Savings") colM.label(text=" " + ut, icon='PREVIEW_RANGE') if p.ShowRiseSet: if Sun.Sunrise.time == Sun.Sunset.time or \ Sun.Sunrise.elevation > -0.4 or Sun.Sunset.elevation > -0.4: Sun.RiseSetOK = False tsr = "Sunrise: --------" tss = " Sunset: --------" else: Sun.RiseSetOK = True sr = format_hms(Sun.Sunrise.time) ss = format_hms(Sun.Sunset.time) tsr = "Sunrise: " + sr tss = " Sunset: " + ss colL.label(text=tsr, icon='LAMP_SUN') if p.ShowDST: colM.label(text=tss, icon='SOLO_ON') else: colL.label(text=tss, icon='SOLO_ON') ############################################################################ class SunPos_OT_Preferences(bpy.types.Operator): bl_idname = "world.sunpos_preferences" bl_label = "Set preferences" bl_description = "Press to set your preferences" def execute(self, context): Display.setAction('PREFERENCES') return {'FINISHED'} class SunPos_OT_PreferencesDone(bpy.types.Operator): bl_idname = "world.sunpos_pref_done" bl_label = "Preferences done" bl_description = "Press to complete your preferences" def execute(self, context): Display.setAction('ENABLE') p = context.scene.SunPos_pref_property Sun.UsageMode = p.UsageMode Sun.MapLocation = p.MapLocation if not p.UseObjectGroup: sp = context.scene.SunPos_property sp.UseObjectGroup = False Sun.UseObjectGroup = False return {'FINISHED'} class SunPos_OT_DayRange(bpy.types.Operator): bl_idname = "world.sunpos_day_range" bl_label = "toggleDayRange" bl_description = "Toggle day or (month / day) range" def execute(self, context): sp = context.scene.SunPos_property if Sun.UseDayMonth: try: dt = datetime.date(sp.Year, sp.Month, sp.Day) sp.Day_of_year = dt.timetuple().tm_yday except: pass Sun.UseDayMonth = False else: Sun.UseDayMonth = True dt = (datetime.date(sp.Year, 1, 1) + datetime.timedelta(sp.Day_of_year - 1)) sp.Day = dt.day sp.Month = dt.month return {'FINISHED'} class SunPos_OT_SetObjectGroup(bpy.types.Operator): bl_idname = "world.sunpos_set_objects" bl_label = "Set object group" bl_description = "Set currently selected objects as object group" def execute(self, context): del Sun.Selected_objects[:] del Sun.Selected_names[:] if (len(bpy.context.selected_objects) > 0): Sun.Selected_names = [x.name for x in bpy.context.selected_objects] Sun.Selected_objects = bpy.context.selected_objects bpy.ops.object.select_all(action='DESELECT') Move_sun() else: self.report({'WARNING'}, "No objects selected") return {'FINISHED'} class SunPos_OT_ClearObjectGroup(bpy.types.Operator): bl_idname = "world.sunpos_clear_objects" bl_label = "Release object group" bl_description = "Release object group" def execute(self, context): bpy.ops.object.select_all(action='DESELECT') Sun.ObjectGroup_verified = False Sun.verify_ObjectGroup() try: for x in Sun.Selected_objects: x.select_set(True) except: pass del Sun.Selected_objects[:] del Sun.Selected_names[:] return {'FINISHED'} # --------------------------------------------------------------------------- # Choice List of places, month and day at 12:00 noon # --------------------------------------------------------------------------- class SunPos_OT_TimePlace(bpy.types.Operator): bl_idname = "world.pdp_operator" bl_label = "Place & Day Presets" #----------- Description --------- M D UTC Lat Long DaySav pdp = [["North Pole, Summer Solstice", 6, 21, 0, 90.000, 0.0000, False], ["Equator, Vernal Equinox", 3, 20, 0, 0.0000, 0.0000, False], ["Rio de Janeiro, May 10th", 5, 10, 3, -22.9002, -43.2334, False], ["Tokyo, August 20th", 8, 20, 9, 35.7002, 139.7669, False], ["Boston, Autumnal Equinox", 9, 22, 5, 42.3502, -71.0500, True], ["Boston, Vernal Equinox", 3, 20, 5, 42.3502, -71.0500, True], ["Honolulu, Winter Solstice", 12, 21, 10, 21.3001, -157.850, False], ["Honolulu, Summer Solstice", 6, 21, 10, 21.3001, -157.850, False]] from bpy.props import EnumProperty timePlacePresets: EnumProperty( name="Time & place presets", description="Preset Place & Day", items=( ("7", pdp[7][0], ""), ("6", pdp[6][0], ""), ("5", pdp[5][0], ""), ("4", pdp[4][0], ""), ("3", pdp[3][0], ""), ("2", pdp[2][0], ""), ("1", pdp[1][0], ""), ("0", pdp[0][0], ""), ), default="4") def execute(self, context): sp = context.scene.SunPos_property pdp = self.pdp i = int(self.properties.timePlacePresets) it = pdp[i] Sun.PlaceLabel = it[0] sp.Month = it[1] sp.Day = it[2] sp.Time = 12.00 sp.UTCzone = it[3] sp.Latitude = it[4] sp.Longitude = it[5] sp.DaylightSavings = it[6] dt = datetime.date(sp.Year, sp.Month, sp.Day) sp.Day_of_year = dt.timetuple().tm_yday # Force screen update Display.refresh() return {'FINISHED'} # --------------------------------------------------------------------------- # Choice List of world maps # --------------------------------------------------------------------------- class SunPos_OT_MapChoice(bpy.types.Operator): bl_idname = "world.wmp_operator" bl_label = "World map files" """ wmp = [["1536 x 768", "WorldMap.jpg"], ["768 x 384", "WorldMapLR.jpg"], ["512 x 256", "WorldMapLLR.jpg"], ["Textureless", "None"]] """ # S.L. provide one single optimized map < 100k wmp = [["1536 x 768", "World.jpg"], ["Textureless", "None"]] from bpy.props import EnumProperty mapPresets: EnumProperty( name="World map presets", description="world map files", items=( # ("3", wmp[3][0], ""), #("2", wmp[2][0], ""), ("1", wmp[1][0], ""), ("0", wmp[0][0], ""), ), default="1") def execute(self, context): sp = context.scene.SunPos_property wmp = self.wmp i = int(self.properties.mapPresets) sp.MapName = wmp[i] Sun.MapName = wmp[i][1] return {'FINISHED'}