Changeset View
Changeset View
Standalone View
Standalone View
sun_position/sun_calc.py
| # SPDX-License-Identifier: GPL-2.0-or-later | # SPDX-License-Identifier: GPL-2.0-or-later | ||||
| import bpy | import bpy | ||||
| from bpy.app.handlers import persistent | from bpy.app.handlers import persistent | ||||
| import gpu | |||||
| from gpu_extras.batch import batch_for_shader | |||||
| from mathutils import Euler, Vector | from mathutils import Euler, Vector | ||||
| import math | import math | ||||
| from math import degrees, radians, pi | from math import degrees, radians, pi | ||||
| import datetime | import datetime | ||||
| from .geo import parse_position | from .geo import parse_position | ||||
| class SunInfo: | class SunInfo: | ||||
| Show All 33 Lines | class SunInfo: | ||||
| use_daylight_savings = False | use_daylight_savings = False | ||||
| sun = SunInfo() | sun = SunInfo() | ||||
| def sun_update(self, context): | def sun_update(self, context): | ||||
| update_time(context) | update_time(context) | ||||
| move_sun(context) | move_sun(context) | ||||
| if self.show_surface: | |||||
| surface_update(self, context) | |||||
| if self.show_analemmas: | |||||
| analemmas_update(self, context) | |||||
| def parse_coordinates(self, context): | def parse_coordinates(self, context): | ||||
| error_message = "ERROR: Could not parse coordinates" | error_message = "ERROR: Could not parse coordinates" | ||||
| sun_props = context.scene.sun_pos_properties | sun_props = context.scene.sun_pos_properties | ||||
| if sun_props.co_parser: | if sun_props.co_parser: | ||||
| parsed_co = parse_position(sun_props.co_parser) | parsed_co = parse_position(sun_props.co_parser) | ||||
| ▲ Show 20 Lines • Show All 496 Lines • ▼ Show 20 Lines | |||||
| def mean_anomaly_sun(t): | def mean_anomaly_sun(t): | ||||
| return (357.52911 + t * (35999.05029 - 0.0001537 * t)) | return (357.52911 + t * (35999.05029 - 0.0001537 * t)) | ||||
| def eccentricity_earth_orbit(t): | def eccentricity_earth_orbit(t): | ||||
| return (0.016708634 - 0.000042037 * t - 0.0000001267 * t ** 2) | return (0.016708634 - 0.000042037 * t - 0.0000001267 * t ** 2) | ||||
| def calc_surface(context): | |||||
| coords = [] | |||||
| sun_props = context.scene.sun_pos_properties | |||||
| zone = -sun_props.UTC_zone | |||||
| north_offset = degrees(sun_props.north_offset) | |||||
| def get_surface_coordinates(time, month): | |||||
| _, theta, phi, _, _ = get_sun_coordinates( | |||||
| time, sun_props.latitude, sun_props.longitude, north_offset, | |||||
| zone, month, 1, sun_props.year, sun_props.sun_distance) | |||||
| sun_vector = get_sun_vector(theta, phi) * sun_props.sun_distance | |||||
| sun_vector.z = max(0, sun_vector.z) | |||||
| return sun_vector | |||||
| for month in range(1, 7): | |||||
| for time in range(24): | |||||
| coords.append(get_surface_coordinates(time, month)) | |||||
| coords.append(get_surface_coordinates(time + 1, month)) | |||||
| coords.append(get_surface_coordinates(time, month + 1)) | |||||
| coords.append(get_surface_coordinates(time, month + 1)) | |||||
| coords.append(get_surface_coordinates(time + 1, month + 1)) | |||||
| coords.append(get_surface_coordinates(time + 1, month)) | |||||
| return coords | |||||
| def calc_analemma(context, h): | |||||
| vertices = [] | |||||
| sun_props = context.scene.sun_pos_properties | |||||
| zone = -sun_props.UTC_zone | |||||
| north_offset = degrees(sun_props.north_offset) | |||||
| for day_of_year in range(1, 367, 5): | |||||
| day, month = day_of_year_to_month_day(sun_props.year, day_of_year) | |||||
| _, theta, phi, _, _ = get_sun_coordinates( | |||||
| h, sun_props.latitude, sun_props.longitude, | |||||
| north_offset, zone, month, day, sun_props.year, | |||||
| sun_props.sun_distance) | |||||
| sun_vector = get_sun_vector(theta, phi) * sun_props.sun_distance | |||||
| if sun_vector.z > 0: | |||||
| vertices.append(sun_vector) | |||||
| return vertices | |||||
| def draw_surface(batch, shader): | |||||
| blend = gpu.state.blend_get() | |||||
| gpu.state.blend_set("ALPHA") | |||||
| shader.uniform_float("color", (.8, .6, 0, 0.2)) | |||||
| batch.draw(shader) | |||||
| gpu.state.blend_set(blend) | |||||
| def draw_analemmas(batch, shader): | |||||
| shader.uniform_float("color", (1, 0, 0, 1)) | |||||
| batch.draw(shader) | |||||
| _handle_surface = None | |||||
| def surface_update(self, context): | |||||
| global _handle_surface | |||||
| if self.show_surface: | |||||
| coords = calc_surface(context) | |||||
| shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') | |||||
| batch = batch_for_shader(shader, 'TRIS', {"pos": coords}) | |||||
| if _handle_surface is not None: | |||||
| bpy.types.SpaceView3D.draw_handler_remove(_handle_surface, 'WINDOW') | |||||
| _handle_surface = bpy.types.SpaceView3D.draw_handler_add( | |||||
| draw_surface, (batch, shader), 'WINDOW', 'POST_VIEW') | |||||
| elif _handle_surface is not None: | |||||
| bpy.types.SpaceView3D.draw_handler_remove(_handle_surface, 'WINDOW') | |||||
| _handle_surface = None | |||||
| _handle_analemmas = None | |||||
| def analemmas_update(self, context): | |||||
pioverfour: It looks like this is computed on every update, whether or not the surface is actually shown. | |||||
| global _handle_analemmas | |||||
| if self.show_analemmas: | |||||
| coords = [] | |||||
| indices = [] | |||||
| coord_offset = 0 | |||||
| for h in range(24): | |||||
| analemma_verts = calc_analemma(context, h) | |||||
| coords.extend(analemma_verts) | |||||
| for i in range(len(analemma_verts) - 1): | |||||
| indices.append((coord_offset + i, | |||||
| coord_offset + i+1)) | |||||
| coord_offset += len(analemma_verts) | |||||
| shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') | |||||
| batch = batch_for_shader(shader, 'LINES', | |||||
| {"pos": coords}, indices=indices) | |||||
| if _handle_analemmas is not None: | |||||
| bpy.types.SpaceView3D.draw_handler_remove(_handle_analemmas, 'WINDOW') | |||||
| _handle_analemmas = bpy.types.SpaceView3D.draw_handler_add( | |||||
Not Done Inline ActionsIt looks like this is computed on every update, whether or not the analemma is actually shown. Can this be skipped? pioverfour: It looks like this is computed on every update, whether or not the analemma is actually shown. | |||||
| draw_analemmas, (batch, shader), 'WINDOW', 'POST_VIEW') | |||||
| elif _handle_analemmas is not None: | |||||
| bpy.types.SpaceView3D.draw_handler_remove(_handle_analemmas, 'WINDOW') | |||||
| _handle_analemmas = None | |||||
It looks like this is computed on every update, whether or not the surface is actually shown. Can this be skipped?