Skip to content
Snippets Groups Projects
Commit ca85dbc7 authored by meta-androcto's avatar meta-androcto
Browse files

sun position: update working version: T69936

parent 9e4579b1
Branches
Tags
No related merge requests found
......@@ -28,67 +28,65 @@
# NASA's image use policy can be found at:
# http://www.nasa.gov/audience/formedia/features/MP_Photo_Guidelines.html
# --------------------------------------------------------------------------
# The geo parser script is by Maximilian Högner, released
# under the GNU GPL license:
# http://hoegners.de/Maxi/geo/
# --------------------------------------------------------------------------
# <pep8 compliant>
bl_info = {
"name": "Sun Position 2.8",
"author": "Michael Martin, Kevan Cress",
"version": (3, 0, 1),
"name": "Sun Position",
"author": "Michael Martin",
"version": (3, 1, 0),
"blender": (2, 80, 0),
"location": "World > Sun Position",
"description": "Show sun position with objects and/or sky texture",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/" \
"Scripts/3D_interaction/Sun_Position",
"tracker_url": "https://projects.blender.org/tracker/" \
"index.php?func=detail&aid=29714",
"category": "3D View"} # "Lighting"} ?
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/3D_interaction/Sun_Position",
"tracker_url": "https://projects.blender.org/tracker/"
"index.php?func=detail&aid=29714",
"category": "Lighting"}
import bpy
from . properties import *
from . ui_sun import *
from . map import SunPos_Help
from . hdr import SunPos_HdrHelp
if "bpy" in locals():
import importlib
importlib.reload(properties)
importlib.reload(ui_sun)
importlib.reload(map)
importlib.reload(hdr)
############################################################################
else:
from . import properties, ui_sun, map, hdr
import bpy
classes = (
SunPos_OT_Controller,
SunPos_OT_Preferences,
SunPos_OT_PreferencesDone,
SunPos_OT_DayRange,
SunPos_OT_SetObjectGroup,
SunPos_OT_ClearObjectGroup,
SunPos_OT_TimePlace,
SunPos_OT_Map,
SunPos_OT_Hdr,
SPOS_PT_Panel,
SunPos_OT_MapChoice,
SunPos_Help,
SunPos_HdrHelp,
)
def register():
bpy.utils.register_class(SunPosSettings)
bpy.types.Scene.SunPos_property = (
bpy.props.PointerProperty(type=SunPosSettings,
bpy.utils.register_class(properties.SunPosProperties)
bpy.types.Scene.sun_pos_properties = (
bpy.props.PointerProperty(type=properties.SunPosProperties,
name="Sun Position",
description="Sun Position Settings"))
bpy.utils.register_class(SunPosPreferences)
bpy.types.Scene.SunPos_pref_property = (
bpy.props.PointerProperty(type=SunPosPreferences,
name="Sun Position Preferences",
description="SP Preferences"))
bpy.utils.register_class(properties.SunPosAddonPreferences)
bpy.utils.register_class(ui_sun.SUNPOS_OT_AddPreset)
bpy.utils.register_class(ui_sun.SUNPOS_OT_DefaultPresets)
bpy.utils.register_class(ui_sun.SUNPOS_MT_Presets)
bpy.utils.register_class(ui_sun.SUNPOS_PT_Panel)
bpy.utils.register_class(hdr.SUNPOS_OT_ShowHdr)
# bpy.utils.register_class(map.SunPos_Help)
for c in classes:
bpy.utils.register_class(c)
bpy.app.handlers.frame_change_post.append(sun_calc.sun_handler)
def unregister():
for c in reversed(classes):
bpy.utils.unregister_class(c)
# bpy.utils.unregister_class(map.SunPos_Help)
bpy.utils.unregister_class(hdr.SUNPOS_OT_ShowHdr)
bpy.utils.unregister_class(ui_sun.SUNPOS_PT_Panel)
bpy.utils.unregister_class(ui_sun.SUNPOS_MT_Presets)
bpy.utils.unregister_class(ui_sun.SUNPOS_OT_DefaultPresets)
bpy.utils.unregister_class(ui_sun.SUNPOS_OT_AddPreset)
bpy.utils.unregister_class(properties.SunPosAddonPreferences)
del bpy.types.Scene.sun_pos_properties
bpy.utils.unregister_class(properties.SunPosProperties)
del bpy.types.Scene.SunPos_pref_property
bpy.utils.unregister_class(SunPosPreferences)
del bpy.types.Scene.SunPos_property
bpy.utils.unregister_class(SunPosSettings)
bpy.app.handlers.frame_change_post.remove(sun_calc.sun_handler)
This diff is collapsed.
### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# -*- coding: utf-8 -*-
import bpy
......@@ -8,8 +26,8 @@ import os
import datetime
import math
from . sun_calc import degToRad, format_hms
from . properties import Display, Sun
from math import radians
from . sun_calc import format_hms, sun
# ---------------------------------------------------------------------------
......@@ -24,16 +42,16 @@ class MapObject:
self.type = t
self.width = w
self.height = h
self.heightFactor = .50
self.height_factor = .50
self.opacity = 1.0
self.focused = False
self.view3d_area = None
self.colorStyle = 'N'
self.color_style = 'N'
self.origin = self.Origin()
def set_dimensions(self, width):
self.width = width
self.height = int(width * self.heightFactor)
self.height = int(width * self.height_factor)
def check_focus(self, context, event):
self.focused = self.is_focused(context, event)
......@@ -132,16 +150,16 @@ class MapClass:
def reset(self, location):
self.init(location)
self.action = None
self.isActive = False
self.is_active = False
self.start = False
self.stop = False
self.lockCrosshair = True
self.showInfo = False
self.lock_crosshair = True
self.show_info = False
self.latitude = 0.0
self.longitude = 0.0
self.ctrlPress = False
self.altPress = False
self.lineWidth = 1.0
self.ctrl_press = False
self.alt_press = False
self.line_width = 1.0
self.textureless = False
self.mouse.x = 0
self.mouse.y = 0
......@@ -205,7 +223,7 @@ class MapClass:
self.handler1 = bpy.types.SpaceView3D.draw_handler_add(
Map_load_callback,
(self, context), 'WINDOW', 'POST_PIXEL')
self.isActive = True
self.is_active = True
return True
else:
return False
......@@ -238,14 +256,13 @@ class MapClass:
self.image.free_it = False
self.glImage = None
self.image.bindcode = 0
self.isActive = False
#if Sun.SP: # why removed?
Sun.SP.ShowMap = False # indent?
self.is_active = False
sun.sp.show_map = False
def load_blender_image(self, file_name):
if file_name == "None":
self.textureless = True
self.object[0].heightFactor = .5
self.object[0].height_factor = .5
return True
else:
self.textureless = False
......@@ -259,7 +276,7 @@ class MapClass:
if self.glImage is not None:
self.image.loaded = True
self.glImage.user_clear()
self.object[0].heightFactor = \
self.object[0].height_factor = \
self.glImage.size[1] / self.glImage.size[0]
return True
else:
......@@ -286,7 +303,7 @@ class MapClass:
fy -= 20
return fy
if text.colorStyle == 'N':
if text.color_style == 'N':
tColor = (0.8, 0.8, 0.8, 1.0)
vColor = (1.0, 1.0, 1.0, 1.0)
else:
......@@ -296,31 +313,31 @@ class MapClass:
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 + 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 + 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))
fy = text_line(fx + 40, fy, True, vColor, format_hms(sun.sp.time))
if Sun.ShowRiseSet:
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))
format_hms(sun.SolarNoon.time))
fy -= 10
fy = text_line(fx, fy, False, tColor, "Rise: ")
if Sun.RiseSetOK:
if sun.RiseSetOK:
fy = text_line(fx + 40, fy, True, vColor,
format_hms(Sun.Sunrise.time))
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:
if sun.RiseSetOK:
fy = text_line(fx + 40, fy, True, vColor,
format_hms(Sun.Sunset.time))
format_hms(sun.sunset.time))
else:
fy = text_line(fx + 40, fy, True, vColor, "--------")
......@@ -337,7 +354,7 @@ class MapClass:
def event_controller(self, context, event):
if not Sun.SP.ShowMap or event.type == 'TIMER':
if not sun.sp.show_map or event.type == 'TIMER':
return {'PASS_THROUGH'}
mapInFocus = self.object[0].check_focus(context, event)
......@@ -488,7 +505,7 @@ def key_MiddleMouse(context, event):
def key_A(event):
if event.value == 'PRESS':
if Map.object[0].focused:
Sun.SP.ObjectGroup = 'ANALEMMA'
sun.sp.object_group = 'ANALEMMA'
else:
return {'PASS_THROUGH'}
return {'RUNNING_MODAL'}
......@@ -497,10 +514,10 @@ def key_A(event):
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'
if Map.object[1].color_style == 'N':
Map.object[1].color_style = 'R'
else:
Map.object[1].colorStyle = 'N'
Map.object[1].color_style = 'N'
else:
return {'PASS_THROUGH'}
return {'RUNNING_MODAL'}
......@@ -509,7 +526,7 @@ def key_C(event):
def key_E(event):
if event.value == 'PRESS':
if Map.object[0].focused:
Sun.SP.ObjectGroup = 'ECLIPTIC'
sun.sp.object_group = 'ECLIPTIC'
else:
return {'PASS_THROUGH'}
return {'RUNNING_MODAL'}
......@@ -556,8 +573,8 @@ 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
sun.PP.ShowRiseSet = True
sun.ShowRiseSet = True
else:
return {'PASS_THROUGH'}
return {'RUNNING_MODAL'}
......@@ -749,10 +766,10 @@ def mouse_zoom():
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
if sun.sp.time > 24.0:
sun.sp.time += -24.0
elif sun.sp.time < 0.0:
sun.sp.time += 24.0
Display.refresh()
......@@ -762,7 +779,7 @@ def time_change_wheel(action):
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
sun.sp.time += mf * val
check_time_boundary()
......@@ -774,7 +791,7 @@ def time_change():
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
sun.sp.time += sx
Map.grab.spot.x = Map.mouse.x
check_time_boundary()
......@@ -799,18 +816,18 @@ def day_change():
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
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
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()
# ---------------------------------------------------------------------------
......@@ -861,22 +878,22 @@ def opacity_change_bounds(obj):
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
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
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
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
sun.sp.latitude += wf
def wheel_factor(action):
......@@ -892,11 +909,11 @@ def wheel_factor(action):
def Map_load_callback(self, context):
if Sun.SP.ShowMap and not Map.image.loaded:
if sun.sp.show_map and not Map.image.loaded:
Map.glImage = None
if not Map.load_blender_image(Sun.MapName):
if not Map.load_blender_image(sun.MapName):
print("Could not load image file: ", Map.image.name)
Sun.SP.ShowMap = False
sun.SP.ShowMap = False
if Map.start:
def set_region_data():
......@@ -933,13 +950,13 @@ def Map_load_callback(self, context):
print("Could not get texture in gl_load()")
Map.glImage = None
Map.image.bindcode = 0
Sun.SP.ShowMap = False
sun.sp.show_map = False
elif Map.textureless:
set_region_data()
return
else:
Sun.SP.ShowMap = False
sun.sp.show_map = False
return
if Map.stop:
......@@ -992,10 +1009,10 @@ def Draw_map_callback(self, context):
# 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
zLong = the_map.width / 2
longFac = z_long / 180
zLat = the_map.height / 2
latFac = z_lat / 90
crossChange = True
if not Map.action == 'PAN':
......@@ -1092,8 +1109,8 @@ def Draw_map_callback(self, context):
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
sun.sp.longitude = newLongitude
longitude = (sun.sp.longitude * x / 180.0) + x
bgl.glEnable(bgl.GL_BLEND)
bgl.glEnable(bgl.GL_LINES)
......@@ -1109,8 +1126,8 @@ def Draw_map_callback(self, context):
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
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)
......@@ -1134,7 +1151,7 @@ def Draw_map_callback(self, context):
bgl.glVertex2f(Lx, Ly)
bgl.glEnd()
if not Sun.ShowRiseSet or not Map.lineWidth:
if not sun.ShowRiseSet or not Map.lineWidth:
bgl.glDisable(bgl.GL_LINES)
bgl.glFlush()
return
......@@ -1159,14 +1176,14 @@ def Draw_map_callback(self, context):
py = Ly + latitude
radius = 30 + Map.lineWidth * 10
if Sun.RiseSetOK and Map.lineWidth:
if sun.RiseSetOK and Map.lineWidth:
color = (0.2, 0.6, 1.0, 0.9)
angle = -(degToRad(Sun.Sunrise.azimuth) - math.pi / 2)
angle = -(radians(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)
angle = -(radians(sun.sunset.azimuth) - math.pi / 2)
draw_angled_line(color, angle, px, py)
# ------------------------
......@@ -1174,18 +1191,18 @@ def Draw_map_callback(self, context):
# ------------------------
if Map.textureless:
phi = degToRad(Sun.AzNorth) * -1
phi = radians(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)
phi = radians(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:
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:
elif sun.Elevation >= sun.Sunrise.elevation:
if sun.Time >= sun.Sunset.time and \
sun.Elevation <= sun.Sunset.elevation:
color = night
else:
color = day
......
### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
import bgl
import math
import gpu
from gpu_extras.batch import batch_for_shader
from mathutils import Vector
from .shader import Dashed_Shader_3D
from . properties import Sun
dashedLineShader = gpu.types.GPUShader(Dashed_Shader_3D.vertex_shader, Dashed_Shader_3D.fragment_shader)
class NorthClass:
def __init__(self):
self.handler = None
self.isActive = False
def refresh_screen(self):
#bpy.context.scene.cursor.location.x += 0.0
bpy.context.area.tag_redraw()
def activate(self, context):
if context.area.type == 'PROPERTIES':
self.handler = bpy.types.SpaceView3D.draw_handler_add(
DrawNorth_callback,
#(self, context), 'WINDOW', 'POST_PIXEL') # why changed?
(self, context), 'WINDOW', 'POST_VIEW')
self.isActive = True
self.refresh_screen()
return True
return False
def deactivate(self):
if self.handler is not None:
bpy.types.SpaceView3D.draw_handler_remove(self.handler, 'WINDOW')
self.handler = None
self.isActive = False
self.refresh_screen()
#if Sun.SP: # why removed?
Sun.SP.ShowNorth = False # indent?
Sun.ShowNorth = False
North = NorthClass()
def DrawNorth_callback(self, context):
if not Sun.SP.ShowNorth and North.isActive:
North.deactivate()
return
# ------------------------------------------------------------------
# Set up the compass needle using the current north offset angle
# less 90 degrees. This forces the unit circle to begin at the
# 12 O'clock instead of 3 O'clock position.
# ------------------------------------------------------------------
#color = (0.2, 0.6, 1.0, 0.7)
color = (0.2, 0.6, 1.0, 1)
radius = 100
angle = -(Sun.NorthOffset - math.pi / 2)
x = math.cos(angle) * radius
y = math.sin(angle) * radius
#p1, p2 = (0, 0, 0), (x, y, 0) # Start & end of needle
# much removed / changed from original below
bgl.glEnable(bgl.GL_MULTISAMPLE)
bgl.glEnable(bgl.GL_LINE_SMOOTH)
bgl.glEnable(bgl.GL_BLEND)
bgl.glEnable(bgl.GL_DEPTH_TEST)
bgl.glDepthMask(False)
bgl.glLineWidth(2)
p1 = (0, 0, 0)
p2 = (x/20 , y/20, 0)
coords = [p1, p2] # Start & end of needle
arclengths = [0,(Vector(p1)-Vector(p2)).length]
batch = batch_for_shader(dashedLineShader, 'LINES', {"pos": coords,"arcLength":arclengths})
dashedLineShader.bind()
dashedLineShader.uniform_float("finalColor", color)
dashedLineShader.uniform_float("u_Scale", 10)
batch.draw(dashedLineShader)
if bpy.app.background: # ignore north line in background mode
def north_update(self, context):
pass
else:
vertex_shader = '''
uniform mat4 u_ViewProjectionMatrix;
in vec3 position;
flat out vec2 v_StartPos;
out vec4 v_VertPos;
void main()
{
vec4 pos = u_ViewProjectionMatrix * vec4(position, 1.0f);
gl_Position = pos;
v_StartPos = (pos / pos.w).xy;
v_VertPos = pos;
}
'''
fragment_shader = '''
uniform vec4 u_Color;
flat in vec2 v_StartPos;
in vec4 v_VertPos;
uniform vec2 u_Resolution;
void main()
{
vec4 vertPos_2d = v_VertPos / v_VertPos.w;
vec2 dir = (vertPos_2d.xy - v_StartPos.xy) * u_Resolution;
float dist = length(dir);
if (step(sin(dist / 5.0f), 0.0) == 1) discard;
gl_FragColor = u_Color;
}
'''
shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
def draw_north_callback():
# ------------------------------------------------------------------
# Set up the compass needle using the current north offset angle
# less 90 degrees. This forces the unit circle to begin at the
# 12 O'clock instead of 3 O'clock position.
# ------------------------------------------------------------------
addon_prefs = bpy.context.preferences.addons[__package__].preferences
sun_props = bpy.context.scene.sun_pos_properties
color = (0.2, 0.6, 1.0, 0.7)
radius = 100
angle = -(sun_props.north_offset - math.pi / 2)
x = math.cos(angle) * radius
y = math.sin(angle) * radius
coords = Vector((x, y, 0)), Vector((0, 0, 0)) # Start & end of needle
batch = batch_for_shader(
shader, 'LINE_STRIP',
{"position": coords},
)
shader.bind()
matrix = bpy.context.region_data.perspective_matrix
shader.uniform_float("u_ViewProjectionMatrix", matrix)
shader.uniform_float("u_Resolution", (bpy.context.region.width, bpy.context.region.height))
shader.uniform_float("u_Color", color)
bgl.glLineWidth(2.0)
batch.draw(shader)
_handle = None
def north_update(self, context):
global _handle
if self.show_north and _handle is None:
_handle = bpy.types.SpaceView3D.draw_handler_add(draw_north_callback, (), 'WINDOW', 'POST_VIEW')
elif _handle is not None:
bpy.types.SpaceView3D.draw_handler_remove(_handle, 'WINDOW')
_handle = None
context.area.tag_redraw()
import bpy
import datetime
from . properties import *
from . sun_calc import Move_sun
from . north import *
from . map import Map
from . hdr import Hdr
# ---------------------------------------------------------------------------
class ControlClass:
region = None
handler = None
def callback(self, os, context):
if Sun.SP.IsActive:
if self.panel_changed():
Move_sun()
else:
self.remove_handler()
def activate(self, context):
if context.area.type == 'PROPERTIES':
if Display.ENABLE:
Display.setAction('PANEL')
Sun.SP.IsActive = True
self.region = context.region
self.add_handler(context)
return {'RUNNING_MODAL'}
else:
Display.setAction('ENABLE')
Sun.SP.IsActive = False
Map.deactivate()
Hdr.deactivate()
return {'FINISHED'}
else:
self.report({'WARNING'}, "Context not available")
return {'CANCELLED'}
def add_handler(self, context):
self.handler = bpy.types.SpaceView3D.draw_handler_add(self.callback,
(self, context), 'WINDOW', 'POST_PIXEL')
def remove_handler(self):
if self.handler:
bpy.types.SpaceView3D.draw_handler_remove(self.handler, 'WINDOW')
self.handler = None
def panel_changed(self):
rv = False
sp = Sun.SP
if not Sun.UseDayMonth and sp.Day_of_year != Sun.Day_of_year:
dt = (datetime.date(sp.Year, 1, 1) +
datetime.timedelta(sp.Day_of_year - 1))
Sun.Day = dt.day
Sun.Month = dt.month
Sun.Day_of_year = sp.Day_of_year
sp.Day = dt.day
sp.Month = dt.month
rv = True
elif (sp.Day != Sun.Day or sp.Month != Sun.Month):
try:
dt = datetime.date(sp.Year, sp.Month, sp.Day)
sp.Day_of_year = dt.timetuple().tm_yday
Sun.Day = sp.Day
Sun.Month = sp.Month
Sun.Day_of_year = sp.Day_of_year
rv = True
except:
pass
if Sun.PP.UsageMode == "HDR":
if sp.BindToSun != Sun.BindToSun:
Sun.BindToSun = sp.BindToSun
if Sun.BindToSun:
nt = bpy.context.scene.world.node_tree.nodes
envTex = nt.get(sp.HDR_texture)
if envTex:
if envTex.type == "TEX_ENVIRONMENT":
Sun.Bind.tex_location = envTex.texture_mapping.rotation
Sun.Bind.azStart = sp.HDR_azimuth
obj = bpy.context.view_layer.objects.get(Sun.SunObject)
Sun.HDR_texture = sp.HDR_texture
Sun.Elevation = sp.HDR_elevation
Sun.Azimuth = sp.HDR_azimuth
Sun.Bind.elevation = sp.HDR_elevation
Sun.Bind.azimuth = sp.HDR_azimuth
Sun.SunDistance = sp.SunDistance
return True
if (sp.HDR_elevation != Sun.Bind.elevation or
sp.HDR_azimuth != Sun.Bind.azimuth or
sp.SunDistance != Sun.SunDistance):
Sun.Elevation = sp.HDR_elevation
Sun.Azimuth = sp.HDR_azimuth
Sun.Bind.elevation = sp.HDR_elevation
Sun.Bind.azimuth = sp.HDR_azimuth
Sun.SunDistance = sp.SunDistance
return True
return False
if (rv or sp.Time != Sun.Time or
sp.TimeSpread != Sun.TimeSpread or
sp.SunDistance != Sun.SunDistance or
sp.Latitude != Sun.Latitude or
sp.Longitude != Sun.Longitude or
sp.UTCzone != Sun.UTCzone or
sp.Year != Sun.Year or
sp.UseSkyTexture != Sun.UseSkyTexture or
sp.SkyTexture != Sun.SkyTexture or
sp.HDR_texture != Sun.HDR_texture or
sp.UseSunObject != Sun.UseSunObject or
sp.SunObject != Sun.SunObject or
sp.UseObjectGroup != Sun.UseObjectGroup or
sp.ObjectGroup != Sun.ObjectGroup or
sp.DaylightSavings != Sun.DaylightSavings or
sp.ShowRefraction != Sun.ShowRefraction or
sp.ShowNorth != Sun.ShowNorth or
sp.NorthOffset != Sun.NorthOffset):
Sun.Time = sp.Time
Sun.TimeSpread = sp.TimeSpread
Sun.SunDistance = sp.SunDistance
Sun.Latitude = sp.Latitude
Sun.Longitude = sp.Longitude
Sun.UTCzone = sp.UTCzone
Sun.Year = sp.Year
Sun.UseSkyTexture = sp.UseSkyTexture
Sun.SkyTexture = sp.SkyTexture
Sun.HDR_texture = sp.HDR_texture
Sun.UseSunObject = sp.UseSunObject
Sun.SunObject = sp.SunObject
Sun.UseObjectGroup = sp.UseObjectGroup
Sun.ObjectGroup = sp.ObjectGroup
Sun.DaylightSavings = sp.DaylightSavings
Sun.ShowRefraction = sp.ShowRefraction
Sun.ShowNorth = sp.ShowNorth
Sun.NorthOffset = sp.NorthOffset
return True
return False
Controller = ControlClass()
# ---------------------------------------------------------------------------
class SunPos_OT_Controller(bpy.types.Operator):
bl_idname = "world.sunpos_controller"
bl_label = "Sun panel event handler"
bl_description = "Enable sun panel"
def __del__(self):
Stop_all_handlers()
Controller.remove_handler()
Display.setAction('ENABLE')
#try:
Sun.SP.IsActive = False # indent?
#except:
# pass
def modal(self, context, event):
if Display.PANEL:
if Sun.SP.ShowMap:
if not Map.isActive:
if not Map.activate(context):
Sun.SP.ShowMap = False
elif Map.isActive:
Map.deactivate()
if Sun.SP.ShowHdr:
if not Hdr.isActive:
Sun.SP.BindToSun = False
if not Hdr.activate(context):
Sun.SP.ShowHdr = False
elif Hdr.isActive:
Hdr.deactivate()
if Sun.SP.ShowNorth:
if not North.isActive:
North.activate(context)
elif North.isActive:
North.deactivate()
return {'PASS_THROUGH'}
Display.refresh()
return {'FINISHED'}
def invoke(self, context, event):
Sun.verify_ObjectGroup()
Map.init(Sun.PP.MapLocation)
Hdr.init()
retval = Controller.activate(context)
if retval != {'RUNNING_MODAL'}:
return retval
context.window_manager.modal_handler_add(self)
Sun.PreBlend_handler = SunPos_new_blendfile
bpy.app.handlers.load_pre.append(SunPos_new_blendfile)
Sun.Frame_handler = Frame_handler
bpy.app.handlers.frame_change_pre.append(Frame_handler)
Display.setAction('PANEL')
Sun.SP.IsActive = True
return {'RUNNING_MODAL'}
############################################################################
class SunPos_OT_Map(bpy.types.Operator):
bl_idname = "sunpos.map"
bl_label = "World map"
def modal(self, context, event):
if Map.view3d_area != context.area or not Sun.SP.ShowMap:
Map.deactivate()
Display.refresh()
return {'FINISHED'}
elif not Display.PANEL:
Stop_all_handlers()
return {'FINISHED'}
return Map.event_controller(context, event)
def invoke(self, context, event):
context.window_manager.modal_handler_add(self)
Display.refresh()
return {'RUNNING_MODAL'}
############################################################################
class SunPos_OT_Hdr(bpy.types.Operator):
bl_idname = "sunpos.hdr"
bl_label = "HDR map"
def modal(self, context, event):
if Hdr.view3d_area != context.area or not Sun.SP.ShowHdr:
Hdr.deactivate()
Display.refresh()
return {'FINISHED'}
elif not Display.PANEL:
Stop_all_handlers()
return {'FINISHED'}
return Hdr.event_controller(context, event)
def invoke(self, context, event):
context.window_manager.modal_handler_add(self)
Display.refresh()
return {'RUNNING_MODAL'}
############################################################################
def SunPos_new_blendfile(context):
Stop_all_handlers()
Cleanup_objects()
def Cleanup_callback(self, context):
Stop_all_handlers()
Cleanup_objects()
def Cleanup_objects():
try:
#if Sun.SP: # why removed?
Sun.SP.UseObjectGroup = False # indent?
Sun.UseObjectGroup = False
except:
pass
del Sun.Selected_objects[:]
del Sun.Selected_names[:]
Display.setAction('ENABLE')
#if Sun.SP: # why removed?
Sun.SP.IsActive = False # indent?
def Stop_all_handlers():
North.deactivate()
Map.deactivate()
Hdr.deactivate()
if Sun.Frame_handler is not None:
try:
bpy.app.handlers.frame_change_pre.remove(Frame_handler)
except:
pass
Sun.Frame_handler = None
if Sun.PreBlend_handler is not None:
try:
bpy.app.handlers.load_pre.remove(SunPos_new_blendfile)
except:
pass
Sun.PreBlend_handler = None
############################################################################
# The Frame_handler is called while rendering when the scene changes
# to make sure objects are updated according to any keyframes.
############################################################################
def Frame_handler(context):
Controller.panel_changed()
Move_sun()
import bpy
from bpy.props import (
StringProperty, EnumProperty,
IntProperty, FloatProperty,
BoolProperty
)
from bpy.types import (
PropertyGroup
)
class DisplayAction:
ENABLE = True
PANEL = False
PREFERENCES = False
def __init__(self):
self.invert_zoom_wheel = False
self.invert_mouse_zoom = False
def setAction(self, VAL):
if VAL == 'ENABLE':
self.ENABLE = True
self.PANEL = self.PREFERENCES = False
elif VAL == 'PANEL':
self.PANEL = True
self.ENABLE = self.PREFERENCES = False
else:
self.PREFERENCES = True
self.ENABLE = self.PANEL = False
def refresh(self):
# Touching the cursor forces a screen refresh
#bpy.context.scene.cursor.location.x += 0.0
bpy.context.area.tag_redraw()
Display = DisplayAction()
Display.setAction('ENABLE')
### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
############################################################################
# SunClass is used for storing and comparing changes in panel values
# as well as general traffic direction.
############################################################################
import bpy
from bpy.types import AddonPreferences, PropertyGroup
from bpy.props import (StringProperty, EnumProperty, IntProperty,
FloatProperty, BoolProperty, PointerProperty)
from .sun_calc import sun_update, parse_coordinates
from .north import north_update
class SunClass:
class TazEl:
time = 0.0
azimuth = 0.0
elevation = 0.0
class CLAMP:
tex_location = None
elevation = 0.0
azimuth = 0.0
azStart = 0.0
azDiff = 0.0
Sunrise = TazEl()
Sunset = TazEl()
SolarNoon = TazEl()
RiseSetOK = False
Bind = CLAMP()
BindToSun = False
PlaceLabel = "Time & Place"
PanelLabel = "Panel Location"
MapName = "WorldMapLR.jpg"
MapLocation = 'VIEWPORT'
Latitude = 0.0
Longitude = 0.0
Elevation = 0.0
Azimuth = 0.0
AzNorth = 0.0
Phi = 0.0
Theta = 0.0
LX = 0.0
LY = 0.0
LZ = 0.0
Month = 0
Day = 0
Year = 0
Day_of_year = 0
Time = 0.0
UTCzone = 0
SunDistance = 0.0
TimeSpread = 23.50
UseDayMonth = True
DaylightSavings = False
ShowRiseSet = True
ShowRefraction = True
NorthOffset = 0.0
UseSunObject = False
SunObject = "Sun"
UseSkyTexture = False
SkyTexture = "Sky Texture"
HDR_texture = "Environment Texture"
UseObjectGroup = False
ObjectGroup = 'ECLIPTIC'
Selected_objects = []
Selected_names = []
ObjectGroup_verified = False
PreBlend_handler = None
Frame_handler = None
SP = None
PP = None
Counter = 0
# ----------------------------------------------------------------------
# There are times when the object group needs to be deleted such as
# when opening a new file or when objects might be deleted that are
# part of the group. If such is the case, delete the object group.
# ----------------------------------------------------------------------
def verify_ObjectGroup(self):
if not self.ObjectGroup_verified:
if len(self.Selected_names) > 0:
names = [x.name for x in bpy.data.objects]
for x in self.Selected_names:
if not x in names:
del self.Selected_objects[:]
del self.Selected_names[:]
break
self.ObjectGroup_verified = True
Sun = SunClass()
############################################################################
# Sun panel properties
############################################################################
class SunPosSettings(PropertyGroup):
IsActive: BoolProperty(
description="True if panel enabled.",
default=False)
class SunPosProperties(PropertyGroup):
usage_mode: EnumProperty(
name="Usage mode",
description="Operate in normal mode or environment texture mode",
items=(
('NORMAL', "Normal", ""),
('HDR', "Sun + HDR texture", ""),
),
default='NORMAL',
update=sun_update)
ShowMap: BoolProperty(
show_map: BoolProperty(
description="Show world map.",
default=False)
default=False,
update=sun_update)
DaylightSavings: BoolProperty(
daylight_savings: BoolProperty(
description="Daylight savings time adds 1 hour to standard time.",
default=0)
default=0,
update=sun_update)
ShowRefraction: BoolProperty(
show_refraction: BoolProperty(
description="Show apparent sun position due to refraction.",
default=1)
default=1,
update=sun_update)
ShowNorth: BoolProperty(
show_north: BoolProperty(
description="Draws line pointing north.",
default=0)
default=0,
update=north_update)
Latitude: FloatProperty(
latitude: FloatProperty(
attr="",
name="Latitude",
description="Latitude: (+) Northern (-) Southern",
soft_min=-90.000, soft_max=90.000, step=3.001,
default=40.000, precision=3)
default=40.000, precision=3,
update=sun_update)
Longitude: FloatProperty(
longitude: FloatProperty(
attr="",
name="Longitude",
description="Longitude: (-) West of Greenwich (+) East of Greenwich",
soft_min=-180.000, soft_max=180.000,
step=3.001, default=1.000, precision=3)
step=3.001, default=1.000, precision=3,
update=sun_update)
Month: IntProperty(
co_parser: StringProperty(
attr="",
name="Enter coordinates",
description="Enter coordinates from an online map",
update=parse_coordinates)
month: IntProperty(
attr="",
name="Month",
description="",
min=1, max=12, default=6)
min=1, max=12, default=6,
update=sun_update)
Day: IntProperty(
day: IntProperty(
attr="",
name="Day",
description="",
min=1, max=31, default=21)
min=1, max=31, default=21,
update=sun_update)
Year: IntProperty(
year: IntProperty(
attr="",
name="Year",
description="",
min=1800, max=4000, default=2012)
min=1800, max=4000, default=2012,
update=sun_update)
use_day_of_year: BoolProperty(
description="Use a single value for day of year",
name="Use day of year",
default=False,
update=sun_update)
Day_of_year: IntProperty(
day_of_year: IntProperty(
attr="",
name="Day of year",
description="",
min=1, max=366, default=1)
min=1, max=366, default=1,
update=sun_update)
UTCzone: IntProperty(
UTC_zone: IntProperty(
attr="",
name="UTC zone",
description="Time zone: Difference from Greenwich England in hours.",
min=0, max=12, default=0)
min=-12, max=12, default=0,
update=sun_update)
Time: FloatProperty(
time: FloatProperty(
attr="",
name="Time",
description="",
precision=4,
soft_min=0.00, soft_max=23.9999, step=1.00, default=12.00)
soft_min=0.00, soft_max=23.9999, step=1.00, default=12.00,
update=sun_update)
NorthOffset: FloatProperty(
north_offset: FloatProperty(
attr="",
name="",
description="North offset in degrees or radians "
"from scene's units settings",
unit="ROTATION",
soft_min=-3.14159265, soft_max=3.14159265, step=10.00, default=0.00)
soft_min=-3.14159265, soft_max=3.14159265, step=10.00, default=0.00,
update=sun_update)
SunDistance: FloatProperty(
sun_distance: FloatProperty(
attr="",
name="Distance",
description="Distance to sun from XYZ axes intersection.",
unit="LENGTH",
soft_min=1, soft_max=3000.00, step=10.00, default=50.00)
soft_min=1, soft_max=3000.00, step=10.00, default=50.00,
update=sun_update)
use_sun_object: BoolProperty(
description="Enable sun positioning of named lamp or mesh",
default=False,
update=sun_update)
sun_object: PointerProperty(
type=bpy.types.Object,
# default="Sun",
description="Sun object to set in the scene",
poll=lambda self, obj: obj.type == 'LIGHT',
update=sun_update)
use_object_collection: BoolProperty(
description="Allow a group of objects to be positioned.",
default=False,
update=sun_update)
UseSunObject: BoolProperty(
description="Enable sun positioning of named light or mesh",
default=False)
object_collection: PointerProperty(
type=bpy.types.Collection,
description="Collection of objects used for analemma",
update=sun_update)
SunObject: StringProperty(
default="Sun",
name="theSun",
description="Name of sun object")
object_collection_type: EnumProperty(
name="Display type",
description="Show object group on ecliptic or as analemma",
items=(
('ECLIPTIC', "On the Ecliptic", ""),
('ANALEMMA', "As Analemma", ""),
),
default='ECLIPTIC',
update=sun_update)
UseSkyTexture: BoolProperty(
use_sky_texture: BoolProperty(
description="Enable use of Cycles' "
"sky texture. World nodes must be enabled, "
"then set color to Sky Texture.",
default=False)
default=False,
update=sun_update)
SkyTexture: StringProperty(
sky_texture: StringProperty(
default="Sky Texture",
name="sunSky",
description="Name of sky texture to be used")
description="Name of sky texture to be used",
update=sun_update)
ShowHdr: BoolProperty(
description="Click to set sun location on environment texture",
default=False)
HDR_texture: StringProperty(
hdr_texture: StringProperty(
default="Environment Texture",
name="envSky",
description="Name of texture to use. World nodes must be enabled "
"and color set to Environment Texture")
"and color set to Environment Texture",
update=sun_update)
HDR_azimuth: FloatProperty(
hdr_azimuth: FloatProperty(
attr="",
name="Rotation",
description="Rotation angle of sun and environment texture "
"in degrees or radians from scene's units settings",
unit="ROTATION",
step=1.00, default=0.00, precision=3)
step=10.0,
default=0.0, precision=3,
update=sun_update)
HDR_elevation: FloatProperty(
hdr_elevation: FloatProperty(
attr="",
name="Elevation",
description="Elevation angle of sun",
step=3.001,
default=0.000, precision=3)
unit="ROTATION",
step=10.0,
default=0.0, precision=3,
update=sun_update)
BindToSun: BoolProperty(
bind_to_sun: BoolProperty(
description="If true, Environment texture moves with sun.",
default=False)
UseObjectGroup: BoolProperty(
description="Allow a group of objects to be positioned.",
default=False)
default=False,
update=sun_update)
TimeSpread: FloatProperty(
time_spread: FloatProperty(
attr="",
name="Time Spread",
description="Time period in which to spread object group",
precision=4,
soft_min=1.00, soft_max=24.00, step=1.00, default=23.00)
soft_min=1.00, soft_max=24.00, step=1.00, default=23.00,
update=sun_update)
ObjectGroup: EnumProperty(
name="Display type",
description="Show object group on ecliptic or as analemma",
items=(
('ECLIPTIC', "On the Ecliptic", ""),
('ANALEMMA', "As and Analemma", ""),
),
default='ECLIPTIC')
Location: StringProperty(
location: StringProperty(
default="view3d",
name="location",
description="panel location")
description="panel location",
update=sun_update)
############################################################################
......@@ -306,18 +245,10 @@ class SunPosSettings(PropertyGroup):
############################################################################
class SunPosPreferences(PropertyGroup):
class SunPosAddonPreferences(AddonPreferences):
bl_idname = __package__
UsageMode: EnumProperty(
name="Usage mode",
description="operate in normal mode or environment texture mode",
items=(
('NORMAL', "Normal", ""),
('HDR', "Sun + HDR texture", ""),
),
default='NORMAL')
MapLocation: EnumProperty(
map_location: EnumProperty(
name="Map location",
description="Display map in viewport or world panel",
items=(
......@@ -326,43 +257,69 @@ class SunPosPreferences(PropertyGroup):
),
default='VIEWPORT')
UseOneColumn: BoolProperty(
description="Set panel to use one column.",
default=False)
UseTimePlace: BoolProperty(
description="Show time/place presets.",
use_time_place: BoolProperty(
description="Show time/place presets",
default=False)
UseObjectGroup: BoolProperty(
description="Use object group option.",
use_object_collection: BoolProperty(
description="Use object collection",
default=True)
ShowDMS: BoolProperty(
description="Show lat/long degrees,minutes,seconds labels.",
show_dms: BoolProperty(
description="Show lat/long degrees, minutes, seconds labels",
default=True)
ShowNorth: BoolProperty(
description="Show north offset choice and slider.",
default=True)
show_north: BoolProperty(
description="Show north offset choice and slider",
default=True,
update=sun_update)
ShowRefraction: BoolProperty(
description="Show sun refraction choice.",
default=True)
show_refraction: BoolProperty(
description="Show sun refraction choice",
default=True,
update=sun_update)
ShowAzEl: BoolProperty(
description="Show azimuth and solar elevation info.",
show_az_el: BoolProperty(
description="Show azimuth and solar elevation info",
default=True)
ShowDST: BoolProperty(
description="Show daylight savings time choice.",
show_dst: BoolProperty(
description="Show daylight savings time choice",
default=True)
ShowRiseSet: BoolProperty(
description="Show sunrise and sunset.",
show_rise_set: BoolProperty(
description="Show sunrise and sunset",
default=True)
MapName: StringProperty(
default="WorldMap.jpg",
name="WorldMap",
description="Name of world map")
# Uncomment this if you add other map images
# map_name: StringProperty(
# default="WorldMap.jpg",
# name="WorldMap",
# description="Name of world map")
def draw(self, context):
layout = self.layout
box = layout.box()
col = box.column()
# Uncomment this if you add other map images
# row = col.row()
# row.label(text="World map options:")
# row.operator_menu_enum('world.wmp_operator',
# 'map_presets', text=Sun.map_name)
# col.separator()
col.prop(self, "map_location")
col.separator()
col.label(text="Show or use:")
flow = col.grid_flow(columns=0, even_columns=True, even_rows=False, align=False)
flow.prop(self, "use_time_place", text="Time/place presets")
flow.prop(self, "use_object_collection", text="Use collection")
flow.prop(self, "show_dms", text="D° M' S\"")
flow.prop(self, "show_north", text="North offset")
flow.prop(self, "show_refraction", text="Refraction")
flow.prop(self, "show_az_el", text="Azimuth, elevation")
flow.prop(self, "show_dst", text="Daylight savings time")
flow.prop(self, "show_rise_set", text="Sunrise, sunset")
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment