Module Sun
Expand source code
# Copyright (C) 2024
# Wassim Jabi <wassim.jabi@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free Software
# Foundation, either version 3 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 Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with
# this program. If not, see <https://www.gnu.org/licenses/>.
import os
import warnings
import topologic_core as topologic
try:
import ephem
except:
print("Sun - Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun - ephem library installed successfully.")
except:
warnings.warn("Sun - Error: Could not import ephem.")
class Sun():
@staticmethod
def WinterSolstice(latitude, year=None):
"""
Returns the winter solstice date for the input latitude and year. See https://en.wikipedia.org/wiki/Winter_solstice.
Parameters
----------
latitude : float
The input latitude.
year : integer , optional
The input year. The default is the current year.
Returns
-------
datetime
The datetime of the winter solstice
"""
import os
import warnings
try:
import ephem
except:
print("Sun.WinterSolstice - Information: Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun.WinterSolstice - Infromation: ephem library installed correctly.")
except:
warnings.warn("Sun.WinterSolstice - Error: Could not import ephem. Please try to install ephem manually. Returning None.")
return None
from datetime import datetime
if year == None:
year = datetime.now().year
if latitude >= 0:
solstice = ephem.next_solstice(ephem.Date(f"{year}/12/1"))
else:
solstice = ephem.next_solstice(ephem.Date(f"{year}/6/1"))
return solstice.datetime()
@staticmethod
def SummerSolstice(latitude, year):
"""
Returns the winter solstice date for the input latitude and year. See https://en.wikipedia.org/wiki/Summer_solstice.
Parameters
----------
latitude : float
The input latitude.
year : integer , optional
The input year. The default is the current year.
Returns
-------
datetime
The datetime of the summer solstice
"""
import os
import warnings
try:
import ephem
except:
print("Sun.SummerSolstice - Information: Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun.SummerSolstice - Infromation: ephem library installed correctly.")
except:
warnings.warn("Sun.SummerSolstice - Error: Could not import ephem. Please try to install ephem manually. Returning None.")
return None
if latitude >= 0:
solstice = ephem.next_solstice(ephem.Date(f"{year}/6/1"))
else:
solstice = ephem.next_solstice(ephem.Date(f"{year}/12/1"))
return solstice.datetime()
@staticmethod
def SpringEquinox(latitude, year):
"""
Returns the spring (vernal) equinox date for the input latitude and year. See https://en.wikipedia.org/wiki/March_equinox.
Parameters
----------
latitude : float
The input latitude.
year : integer , optional
The input year. The default is the current year.
Returns
-------
datetime
The datetime of the summer solstice
"""
import os
import warnings
try:
import ephem
except:
print("Sun.SpringEquinox - Information: Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun.SpringEquinox - Infromation: ephem library installed correctly.")
except:
warnings.warn("Sun.SpringEquinox - Error: Could not import ephem. Please try to install ephem manually. Returning None.")
return None
if latitude >= 0:
equinox = ephem.next_equinox(ephem.Date(f"{year}/3/1"))
else:
equinox = ephem.next_equinox(ephem.Date(f"{year}/9/1"))
return equinox.datetime()
@staticmethod
def AutumnEquinox(latitude, year):
"""
Returns the autumnal equinox date for the input latitude and year. See https://en.wikipedia.org/wiki/September_equinox.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
year : integer , optional
The input year. The default is the current year.
Returns
-------
datetime
The datetime of the summer solstice
"""
import os
import warnings
try:
import ephem
except:
print("Sun.AutumnEquinox - Information: Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun.AutumnEquinox - Infromation: ephem library installed correctly.")
except:
warnings.warn("Sun.AutumnEquinox - Error: Could not import ephem. Please try to install ephem manually. Returning None.")
return None
if latitude >= 0:
equinox = ephem.next_equinox(ephem.Date(f"{year}/9/1"))
else:
equinox = ephem.next_equinox(ephem.Date(f"{year}/3/1"))
return equinox.datetime()
@staticmethod
def Azimuth(latitude, longitude, date):
"""
Returns the Azimuth angle. See https://en.wikipedia.org/wiki/Azimuth.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
Returns
-------
float
The azimuth angle.
"""
import os
import warnings
import math
try:
import ephem
except:
print("Sun.Azimuth - Information: Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun.Azimuth - Infromation: ephem library installed correctly.")
except:
warnings.warn("Sun.Azimuth - Error: Could not import ephem. Please try to install ephem manually. Returning None.")
return None
observer = ephem.Observer()
observer.date = date
observer.lat = str(latitude)
observer.lon = str(longitude)
sun = ephem.Sun(observer)
sun.compute(observer)
azimuth = math.degrees(sun.az)
return azimuth
@staticmethod
def Altitude(latitude, longitude, date):
"""
Returns the Altitude angle. See https://en.wikipedia.org/wiki/Altitude.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
Returns
-------
float
The altitude angle.
"""
import os
import warnings
import math
try:
import ephem
except:
print("Sun.Altitude - Information: Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun.Altitude - Infromation: ephem library installed correctly.")
except:
warnings.warn("Sun.Altitude - Error: Could not import ephem. Please try to install ephem manually. Returning None.")
return None
observer = ephem.Observer()
observer.date = date
observer.lat = str(latitude)
observer.lon = str(longitude)
sun = ephem.Sun(observer)
sun.compute(observer)
altitude = math.degrees(sun.alt)
return altitude
@staticmethod
def Sunrise(latitude, longitude, date):
"""
Returns the Sunrise datetime.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
Returns
-------
datetime
The Sunrise datetime.
"""
import os
import warnings
try:
import ephem
except:
print("Sun.Sunrise - Information: Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun.Sunrise - Infromation: ephem library installed correctly.")
except:
warnings.warn("Sun.Sunrise - Error: Could not import ephem. Please try to install ephem manually. Returning None.")
return None
date = date.replace(hour=12, minute=0, second=0, microsecond=0)
observer = ephem.Observer()
observer.lat = str(latitude)
observer.lon = str(longitude)
observer.date = date
sunrise = observer.previous_rising(ephem.Sun()).datetime()
return sunrise
@staticmethod
def Sunset(latitude, longitude, date):
"""
Returns the Sunset datetime.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
Returns
-------
datetime
The Sunset datetime.
"""
import os
import warnings
try:
import ephem
except:
print("Sun.Sunset - Information: Installing required ephem library.")
try:
os.system("pip install ephem")
except:
os.system("pip install ephem --user")
try:
import ephem
print("Sun.Sunset - Infromation: ephem library installed correctly.")
except:
warnings.warn("Sun.Sunset - Error: Could not import ephem. Please try to install ephem manually. Returning None.")
return None
date = date.replace(hour=12, minute=0, second=0, microsecond=0)
observer = ephem.Observer()
observer.lat = str(latitude)
observer.lon = str(longitude)
observer.date = date
sunset = observer.next_setting(ephem.Sun()).datetime()
return sunset
@staticmethod
def Vector(latitude, longitude, date, north=0):
"""
Returns the Sun as a vector.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
-------
list
The sun vector pointing from the location of the sun towards the origin.
"""
from topologicpy.Vector import Vector
azimuth = Sun.Azimuth(latitude=latitude, longitude=longitude, date=date)
altitude = Sun.Altitude(latitude=latitude, longitude=longitude, date=date)
return Vector.ByAzimuthAltitude(azimuth=azimuth, altitude=altitude, north=north, reverse=True)
@staticmethod
def Position(latitude, longitude, date, origin=None, radius=0.5, north=0, mantissa=6):
"""
Returns the Sun as a position ([X,Y,Z]).
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
origin : topologic_core.Vertex , optional
The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius : float , optional
The desired radius of the sun orbit. The default is 0.5.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
mantissa : int , optional
The desired length of the mantissa. The default is 6.
Returns
-------
topologic_core.Vertex
The sun represented as a vertex.
"""
from topologicpy.Vertex import Vertex
sun_v = Sun.Vertex(latitude=latitude, longitude=longitude, date=date, origin=origin, radius=radius, north=north)
return Vertex.Coordinates(sun_v, mantissa=mantissa)
@staticmethod
def Vertex(latitude, longitude, date, origin=None, radius=0.5, north=0):
"""
Returns the Sun as a vertex.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
origin : topologic_core.Vertex , optional
The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius : float , optional
The desired radius of the sun orbit. The default is 0.5.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
-------
topologic_core.Vertex
The sun represented as a vertex.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Topology import Topology
from topologicpy.Vector import Vector
if origin == None:
origin = Vertex.Origin()
vector = Vector.Reverse(Sun.Vector(latitude=latitude, longitude=longitude, date=date, north=north))
sun_v = Topology.TranslateByDirectionDistance(origin, direction=vector, distance=radius)
return sun_v
@staticmethod
def Edge(latitude, longitude, date, origin=None, radius=0.5, north=0):
"""
Returns the Sun as a vector.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
origin : topologic_core.Vertex , optional
The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius : float , optional
The desired radius of the sun orbit. The default is 0.5.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
-------
topologic_core.Edge
The sun represented as an edge pointing from the location of the sun towards the origin.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Edge import Edge
from topologicpy.Topology import Topology
from topologicpy.Vector import Vector
if origin == None:
origin = Vertex.Origin()
vector = Vector.Reverse(Sun.Vector(latitude=latitude, longitude=longitude, date=date, north=north))
sun_v = Topology.TranslateByDirectionDistance(origin, direction=vector, distance=radius)
edge = Edge.ByVertices(sun_v, origin)
return edge
@staticmethod
def VerticesByDate(latitude, longitude, date, startTime=None, endTime=None, interval=60, origin=None, radius=0.5, north=0):
"""
Returns the Sun locations as vertices based on the input parameters.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
startTime : datetime , optional
The desired start time to compute the sun location. If set to None, Sun.Sunrise is used. The default is None.
endTime : datetime , optional
The desired end time to compute the sun location. If set to None, Sun.Sunset is used. The default is None.
interval : int , optional
The interval in minutes to compute the sun location. The default is 60.
origin : topologic_core.Vertex , optional
The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius : float , optional
The desired radius of the sun orbit. The default is 0.5.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
-------
list
The sun locations represented as a list of vertices.
"""
from datetime import timedelta
if startTime == None:
startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date)
if endTime == None:
endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date)
vertices = []
current_time = startTime
while current_time <= endTime:
v = Sun.Vertex(latitude=latitude, longitude=longitude, date=current_time, origin=origin, radius=radius, north=north)
vertices.append(v)
current_time += timedelta(minutes=interval)
return vertices
@staticmethod
def PathByDate(latitude, longitude, date, startTime=None, endTime=None, interval=60, origin=None, radius=0.5, sides=None, north=0):
"""
Returns the sun path based on the input parameters.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date : datetime
The input datetime.
startTime : datetime , optional
The desired start time to compute the sun location. If set to None, Sun.Sunrise is used. The default is None.
endTime : datetime , optional
The desired end time to compute the sun location. If set to None, Sun.Sunset is used. The default is None.
interval : int , optional
The interval in minutes to compute the sun location. The default is 60.
origin : topologic_core.Vertex , optional
The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius : float , optional
The desired radius of the sun orbit. The default is 0.5.
sides : int , optional
If set to None, the path is divided based on the interval. Otherwise, it is equally divided into the number of sides.
The default is None.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
-------
topologic_core.Wire
The sun path represented as a wire.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Wire import Wire
from topologicpy.Dictionary import Dictionary
from topologicpy.Topology import Topology
if origin == None:
origin = Vertex.Origin()
if startTime == None:
startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date)
if endTime == None:
endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date)
vertices = Sun.VerticesByDate(latitude=latitude, longitude=longitude, date=date,
startTime=startTime, endTime=endTime, interval=interval,
origin=origin, radius=radius, north=north)
if len(vertices) < 2:
return None
wire = Wire.ByVertices(vertices, close=False)
if not sides == None:
vertices = []
for i in range(sides):
u = float(i)/float(sides)
v = Wire.VertexByParameter(wire, u)
vertices.append(v)
wire = Wire.ByVertices(vertices, close=False)
d = Dictionary.ByKeysValues(["latitude", "longitude", "date", "startTime", "endTime", "interval", "type"],
[latitude, longitude, str(date), str(startTime), str(endTime), interval, "date"])
wire = Topology.SetDictionary(wire, d)
return wire
@staticmethod
def VerticesByHour(latitude, longitude, hour, startDay=1, endDay=365, interval=5, origin=None, radius=0.5, north=0):
"""
Returns the sun locations based on the input parameters.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
hour : datetime
The input hour.
startDay : integer , optional
The desired start day to compute the sun location. The default is 1.
endDay : integer , optional
The desired end day to compute the sun location. The default is 365.
interval : int , optional
The interval in days to compute the sun location. The default is 5.
origin : topologic_core.Vertex , optional
The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius : float , optional
The desired radius of the sun orbit. The default is 0.5.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
-------
list
The sun locations represented as a list of vertices.
"""
from datetime import datetime
from datetime import timedelta
def day_of_year_to_datetime(year, day_of_year):
# Construct a datetime object for the first day of the year
base_date = datetime(year, 1, 1)
# Add the number of days to get to the specified day of the year
target_date = base_date + timedelta(days=day_of_year - 1)
return target_date
now = datetime.now()
# Get the year component
year = now.year
vertices = []
for day_of_year in range(startDay, endDay, interval):
date = day_of_year_to_datetime(year, day_of_year)
date += timedelta(hours=hour)
v = Sun.Vertex(latitude=latitude, longitude=longitude, date=date, origin=origin, radius=radius, north=north)
vertices.append(v)
return vertices
@staticmethod
def PathByHour(latitude, longitude, hour, startDay=1, endDay=365, interval=5, origin=None, radius=0.5, sides=None, north=0):
"""
Returns the sun locations based on the input parameters.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
hour : datetime
The input hour.
startDay : integer , optional
The desired start day of the year to compute the sun location. The default is 1.
endDay : integer , optional
The desired end day of the year to compute the sun location. The default is 365.
interval : int , optional
The interval in days to compute the sun location. The default is 5.
origin : topologic_core.Vertex , optional
The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius : float , optional
The desired radius of the sun orbit. The default is 0.5.
sides : int , optional
If set to None, the path is divided based on the interval. Otherwise, it is equally divided into the number of sides.
The default is None.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
-------
topologic_core.Wire
The sun path represented as a topologic wire.
"""
from topologicpy.Wire import Wire
from topologicpy.Dictionary import Dictionary
from topologicpy.Topology import Topology
vertices = Sun.VerticesByHour(latitude=latitude, longitude=longitude, hour=hour,
startDay=startDay, endDay=endDay, interval=interval,
origin=origin, radius=radius, north=north)
if len(vertices) < 2:
return None
wire = Wire.ByVertices(vertices, close=False)
if not sides == None:
vertices = []
for i in range(sides):
u = float(i)/float(sides)
v = Wire.VertexByParameter(wire, u)
vertices.append(v)
wire = Wire.ByVertices(vertices, close=True)
d = Dictionary.ByKeysValues(["latitude", "longitude", "hour", "startDay", "endDay", "interval", "type"],
[latitude, longitude, hour, startDay, endDay, interval, "hour"])
wire = Topology.SetDictionary(wire, d)
return wire
@staticmethod
def Diagram(latitude, longitude, minuteInterval=30, dayInterval=15,
origin=None, radius=0.5, uSides=180, vSides=180, north=0,
compass = False, shell=False):
"""
Returns the sun diagram based on the input parameters. See https://hyperfinearchitecture.com/how-to-read-sun-path-diagrams/.
Parameters
----------
latitude : float
The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude : float
The input longitude. See https://en.wikipedia.org/wiki/Longitude.
minuteInterval : int , optional
The interval in minutes to compute the sun location for the date path. The default is 30.
dayInterval : int , optional
The interval in days for the hourly path to compute the sun location. The default is 15.
origin : topologic_core.Vertex , optional
The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius : float , optional
The desired radius of the sun orbit. The default is 0.5.
uSides : int , optional
The number of sides to divide the diagram horizontally (along the azimuth). The default is 180.
vSides : int , optional
The number of sides to divide the diagram paths vertically (along the altitude). The default is 180.
north : float, optional
The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
compass : bool , optional
If set to True, a compass (shell) is included. Othwerwise, it is is not.
shell : bool , optional
If set to True, the total surface (shell) of the sun paths is incldued. Otherwise, it is not.
Returns
-------
dict
A dictionary of the sun diagram shapes. The keys in this dictionary are:
- 'date_paths': These are the sun paths (wire) for the winter solstice, equinox, and summer solstice
- 'hourly_paths': These are the figure-8 (wire) for the sun location on the same hour on each selected day of the year.
- 'shell': This is the total surface (shell) of the sun paths. This is included only if the shell option is set to True.
- 'compass': This is the compass (shell) on the ground. It is made of 36 sides and 10 rings. This is included only
if the compass option is set to True.
- 'center' : This is a cross-shape (wire) at the center of the diagram. This is included only if the compass option is set to True.
- 'ground' : This is a circle (face) on the ground. It is made of 36 sides. This is included only if
the compass option is set to False.
"""
from datetime import datetime
from datetime import timedelta
from topologicpy.Vertex import Vertex
from topologicpy.Edge import Edge
from topologicpy.Wire import Wire
from topologicpy.Shell import Shell
from topologicpy.Cell import Cell
from topologicpy.Cluster import Cluster
from topologicpy.Topology import Topology
from topologicpy.Dictionary import Dictionary
if origin == None:
origin = Vertex.Origin()
cutter = Cell.Prism(origin=origin, width=radius*4, length=radius*4, height=radius*2)
cutter = Topology.Rotate(cutter, origin=origin, angle=-north)
cutter = Topology.Translate(cutter, 0,0,-radius)
now = datetime.now()
year = now.year
diagram = {}
winter_solstice = Sun.WinterSolstice(latitude=latitude, year=year)
summer_solstice = Sun.SummerSolstice(latitude=latitude, year=year)
equinox = Sun.AutumnEquinox(latitude=latitude, year=year)
dates = [winter_solstice, equinox, summer_solstice]
date_paths = []
for date in dates:
startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) - timedelta(hours=2)
endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) + timedelta(hours=2)
path = Sun.PathByDate(latitude=latitude, longitude=longitude, date=date,
startTime=startTime, endTime=endTime, interval=minuteInterval,
origin=origin, radius=radius, sides=uSides, north=north)
# Capture the path's dictionary to re-apply later
d = Topology.Dictionary(path)
# Clip the path to above ground level
path = Topology.Difference(path, cutter)
path = Topology.SetDictionary(path, d)
date_paths.append(path)
diagram['date_paths'] = date_paths
# Hourly paths
hourly_paths = []
for hour in range (0, 24, 1):
hourly_path = Sun.PathByHour(latitude, longitude, hour, startDay=0, endDay=365, interval=dayInterval,
origin=origin, radius=radius, sides=vSides*2, north=north)
d = Topology.Dictionary(hourly_path)
hourly_path = Topology.Difference(hourly_path, cutter)
if Topology.IsInstance(hourly_path, "topology"):
hourly_path = Topology.SetDictionary(hourly_path, d)
hourly_paths.append(hourly_path)
diagram['hourly_paths'] = hourly_paths
if shell:
shell_paths = []
dates = [summer_solstice]
delta = (winter_solstice - summer_solstice)/12
for i in range(1,12):
a_date = summer_solstice + delta*i
if abs(a_date - equinox) < timedelta(hours=24*5):
dates.append(equinox)
else:
dates.append(a_date)
dates.append(winter_solstice)
for date in dates:
startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) - timedelta(hours=2)
endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) + timedelta(hours=2)
shell_path = Sun.PathByDate(latitude=latitude, longitude=longitude, date=date,
startTime=startTime, endTime=endTime, interval=minuteInterval,
origin=origin, radius=radius, sides=uSides, north=north)
# Clip the path to above ground level
shell_path = Topology.Difference(shell_path, cutter)
path_vertices = []
for i in range(uSides+1):
u = float(i)/float(uSides)
v = Wire.VertexByParameter(shell_path, u)
path_vertices.append(v)
shell_path = Wire.ByVertices(path_vertices, close=False)
shell_paths.append(shell_path)
a_shell = Shell.ByWires(shell_paths, triangulate=True, silent=True)
d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "shell"])
a_shell = Topology.SetDictionary(a_shell, d)
diagram['shell']= a_shell
else:
diagram['shell'] = None
if compass:
compass = Shell.Pie(origin=origin, radiusA=radius, radiusB=radius*0.1, sides=36, rings=10)
d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "compass"])
compass = Topology.SetDictionary(compass, d)
diagram['compass'] = compass
edges = []
for i in range(0, 4, 1):
v2 = Topology.Translate(origin, 0, radius/float(9), 0)
edge = Edge.ByVertices(origin, v2)
edge = Topology.Rotate(edge, origin=origin, angle=90*i)
edge = Topology.Rotate(edge, origin=origin, angle=-north)
edges.append(edge)
center = Topology.SelfMerge(Cluster.ByTopologies(edges))
d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "center"])
center = Topology.SetDictionary(center, d)
diagram['center'] = center
else:
ground = Wire.Circle(origin=origin, radius=radius, sides=36)
d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "ground"])
ground = Topology.SetDictionary(ground, d)
diagram['compass'] = None
diagram['center'] = None
diagram['ground']= ground
return diagram
Classes
class Sun
-
Expand source code
class Sun(): @staticmethod def WinterSolstice(latitude, year=None): """ Returns the winter solstice date for the input latitude and year. See https://en.wikipedia.org/wiki/Winter_solstice. Parameters ---------- latitude : float The input latitude. year : integer , optional The input year. The default is the current year. Returns ------- datetime The datetime of the winter solstice """ import os import warnings try: import ephem except: print("Sun.WinterSolstice - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.WinterSolstice - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.WinterSolstice - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None from datetime import datetime if year == None: year = datetime.now().year if latitude >= 0: solstice = ephem.next_solstice(ephem.Date(f"{year}/12/1")) else: solstice = ephem.next_solstice(ephem.Date(f"{year}/6/1")) return solstice.datetime() @staticmethod def SummerSolstice(latitude, year): """ Returns the winter solstice date for the input latitude and year. See https://en.wikipedia.org/wiki/Summer_solstice. Parameters ---------- latitude : float The input latitude. year : integer , optional The input year. The default is the current year. Returns ------- datetime The datetime of the summer solstice """ import os import warnings try: import ephem except: print("Sun.SummerSolstice - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.SummerSolstice - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.SummerSolstice - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None if latitude >= 0: solstice = ephem.next_solstice(ephem.Date(f"{year}/6/1")) else: solstice = ephem.next_solstice(ephem.Date(f"{year}/12/1")) return solstice.datetime() @staticmethod def SpringEquinox(latitude, year): """ Returns the spring (vernal) equinox date for the input latitude and year. See https://en.wikipedia.org/wiki/March_equinox. Parameters ---------- latitude : float The input latitude. year : integer , optional The input year. The default is the current year. Returns ------- datetime The datetime of the summer solstice """ import os import warnings try: import ephem except: print("Sun.SpringEquinox - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.SpringEquinox - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.SpringEquinox - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None if latitude >= 0: equinox = ephem.next_equinox(ephem.Date(f"{year}/3/1")) else: equinox = ephem.next_equinox(ephem.Date(f"{year}/9/1")) return equinox.datetime() @staticmethod def AutumnEquinox(latitude, year): """ Returns the autumnal equinox date for the input latitude and year. See https://en.wikipedia.org/wiki/September_equinox. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. year : integer , optional The input year. The default is the current year. Returns ------- datetime The datetime of the summer solstice """ import os import warnings try: import ephem except: print("Sun.AutumnEquinox - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.AutumnEquinox - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.AutumnEquinox - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None if latitude >= 0: equinox = ephem.next_equinox(ephem.Date(f"{year}/9/1")) else: equinox = ephem.next_equinox(ephem.Date(f"{year}/3/1")) return equinox.datetime() @staticmethod def Azimuth(latitude, longitude, date): """ Returns the Azimuth angle. See https://en.wikipedia.org/wiki/Azimuth. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. Returns ------- float The azimuth angle. """ import os import warnings import math try: import ephem except: print("Sun.Azimuth - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.Azimuth - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.Azimuth - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None observer = ephem.Observer() observer.date = date observer.lat = str(latitude) observer.lon = str(longitude) sun = ephem.Sun(observer) sun.compute(observer) azimuth = math.degrees(sun.az) return azimuth @staticmethod def Altitude(latitude, longitude, date): """ Returns the Altitude angle. See https://en.wikipedia.org/wiki/Altitude. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. Returns ------- float The altitude angle. """ import os import warnings import math try: import ephem except: print("Sun.Altitude - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.Altitude - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.Altitude - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None observer = ephem.Observer() observer.date = date observer.lat = str(latitude) observer.lon = str(longitude) sun = ephem.Sun(observer) sun.compute(observer) altitude = math.degrees(sun.alt) return altitude @staticmethod def Sunrise(latitude, longitude, date): """ Returns the Sunrise datetime. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. Returns ------- datetime The Sunrise datetime. """ import os import warnings try: import ephem except: print("Sun.Sunrise - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.Sunrise - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.Sunrise - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None date = date.replace(hour=12, minute=0, second=0, microsecond=0) observer = ephem.Observer() observer.lat = str(latitude) observer.lon = str(longitude) observer.date = date sunrise = observer.previous_rising(ephem.Sun()).datetime() return sunrise @staticmethod def Sunset(latitude, longitude, date): """ Returns the Sunset datetime. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. Returns ------- datetime The Sunset datetime. """ import os import warnings try: import ephem except: print("Sun.Sunset - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.Sunset - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.Sunset - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None date = date.replace(hour=12, minute=0, second=0, microsecond=0) observer = ephem.Observer() observer.lat = str(latitude) observer.lon = str(longitude) observer.date = date sunset = observer.next_setting(ephem.Sun()).datetime() return sunset @staticmethod def Vector(latitude, longitude, date, north=0): """ Returns the Sun as a vector. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- list The sun vector pointing from the location of the sun towards the origin. """ from topologicpy.Vector import Vector azimuth = Sun.Azimuth(latitude=latitude, longitude=longitude, date=date) altitude = Sun.Altitude(latitude=latitude, longitude=longitude, date=date) return Vector.ByAzimuthAltitude(azimuth=azimuth, altitude=altitude, north=north, reverse=True) @staticmethod def Position(latitude, longitude, date, origin=None, radius=0.5, north=0, mantissa=6): """ Returns the Sun as a position ([X,Y,Z]). Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. mantissa : int , optional The desired length of the mantissa. The default is 6. Returns ------- topologic_core.Vertex The sun represented as a vertex. """ from topologicpy.Vertex import Vertex sun_v = Sun.Vertex(latitude=latitude, longitude=longitude, date=date, origin=origin, radius=radius, north=north) return Vertex.Coordinates(sun_v, mantissa=mantissa) @staticmethod def Vertex(latitude, longitude, date, origin=None, radius=0.5, north=0): """ Returns the Sun as a vertex. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- topologic_core.Vertex The sun represented as a vertex. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology from topologicpy.Vector import Vector if origin == None: origin = Vertex.Origin() vector = Vector.Reverse(Sun.Vector(latitude=latitude, longitude=longitude, date=date, north=north)) sun_v = Topology.TranslateByDirectionDistance(origin, direction=vector, distance=radius) return sun_v @staticmethod def Edge(latitude, longitude, date, origin=None, radius=0.5, north=0): """ Returns the Sun as a vector. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- topologic_core.Edge The sun represented as an edge pointing from the location of the sun towards the origin. """ from topologicpy.Vertex import Vertex from topologicpy.Edge import Edge from topologicpy.Topology import Topology from topologicpy.Vector import Vector if origin == None: origin = Vertex.Origin() vector = Vector.Reverse(Sun.Vector(latitude=latitude, longitude=longitude, date=date, north=north)) sun_v = Topology.TranslateByDirectionDistance(origin, direction=vector, distance=radius) edge = Edge.ByVertices(sun_v, origin) return edge @staticmethod def VerticesByDate(latitude, longitude, date, startTime=None, endTime=None, interval=60, origin=None, radius=0.5, north=0): """ Returns the Sun locations as vertices based on the input parameters. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. startTime : datetime , optional The desired start time to compute the sun location. If set to None, Sun.Sunrise is used. The default is None. endTime : datetime , optional The desired end time to compute the sun location. If set to None, Sun.Sunset is used. The default is None. interval : int , optional The interval in minutes to compute the sun location. The default is 60. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- list The sun locations represented as a list of vertices. """ from datetime import timedelta if startTime == None: startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) if endTime == None: endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) vertices = [] current_time = startTime while current_time <= endTime: v = Sun.Vertex(latitude=latitude, longitude=longitude, date=current_time, origin=origin, radius=radius, north=north) vertices.append(v) current_time += timedelta(minutes=interval) return vertices @staticmethod def PathByDate(latitude, longitude, date, startTime=None, endTime=None, interval=60, origin=None, radius=0.5, sides=None, north=0): """ Returns the sun path based on the input parameters. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. startTime : datetime , optional The desired start time to compute the sun location. If set to None, Sun.Sunrise is used. The default is None. endTime : datetime , optional The desired end time to compute the sun location. If set to None, Sun.Sunset is used. The default is None. interval : int , optional The interval in minutes to compute the sun location. The default is 60. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. sides : int , optional If set to None, the path is divided based on the interval. Otherwise, it is equally divided into the number of sides. The default is None. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- topologic_core.Wire The sun path represented as a wire. """ from topologicpy.Vertex import Vertex from topologicpy.Wire import Wire from topologicpy.Dictionary import Dictionary from topologicpy.Topology import Topology if origin == None: origin = Vertex.Origin() if startTime == None: startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) if endTime == None: endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) vertices = Sun.VerticesByDate(latitude=latitude, longitude=longitude, date=date, startTime=startTime, endTime=endTime, interval=interval, origin=origin, radius=radius, north=north) if len(vertices) < 2: return None wire = Wire.ByVertices(vertices, close=False) if not sides == None: vertices = [] for i in range(sides): u = float(i)/float(sides) v = Wire.VertexByParameter(wire, u) vertices.append(v) wire = Wire.ByVertices(vertices, close=False) d = Dictionary.ByKeysValues(["latitude", "longitude", "date", "startTime", "endTime", "interval", "type"], [latitude, longitude, str(date), str(startTime), str(endTime), interval, "date"]) wire = Topology.SetDictionary(wire, d) return wire @staticmethod def VerticesByHour(latitude, longitude, hour, startDay=1, endDay=365, interval=5, origin=None, radius=0.5, north=0): """ Returns the sun locations based on the input parameters. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. hour : datetime The input hour. startDay : integer , optional The desired start day to compute the sun location. The default is 1. endDay : integer , optional The desired end day to compute the sun location. The default is 365. interval : int , optional The interval in days to compute the sun location. The default is 5. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- list The sun locations represented as a list of vertices. """ from datetime import datetime from datetime import timedelta def day_of_year_to_datetime(year, day_of_year): # Construct a datetime object for the first day of the year base_date = datetime(year, 1, 1) # Add the number of days to get to the specified day of the year target_date = base_date + timedelta(days=day_of_year - 1) return target_date now = datetime.now() # Get the year component year = now.year vertices = [] for day_of_year in range(startDay, endDay, interval): date = day_of_year_to_datetime(year, day_of_year) date += timedelta(hours=hour) v = Sun.Vertex(latitude=latitude, longitude=longitude, date=date, origin=origin, radius=radius, north=north) vertices.append(v) return vertices @staticmethod def PathByHour(latitude, longitude, hour, startDay=1, endDay=365, interval=5, origin=None, radius=0.5, sides=None, north=0): """ Returns the sun locations based on the input parameters. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. hour : datetime The input hour. startDay : integer , optional The desired start day of the year to compute the sun location. The default is 1. endDay : integer , optional The desired end day of the year to compute the sun location. The default is 365. interval : int , optional The interval in days to compute the sun location. The default is 5. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. sides : int , optional If set to None, the path is divided based on the interval. Otherwise, it is equally divided into the number of sides. The default is None. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- topologic_core.Wire The sun path represented as a topologic wire. """ from topologicpy.Wire import Wire from topologicpy.Dictionary import Dictionary from topologicpy.Topology import Topology vertices = Sun.VerticesByHour(latitude=latitude, longitude=longitude, hour=hour, startDay=startDay, endDay=endDay, interval=interval, origin=origin, radius=radius, north=north) if len(vertices) < 2: return None wire = Wire.ByVertices(vertices, close=False) if not sides == None: vertices = [] for i in range(sides): u = float(i)/float(sides) v = Wire.VertexByParameter(wire, u) vertices.append(v) wire = Wire.ByVertices(vertices, close=True) d = Dictionary.ByKeysValues(["latitude", "longitude", "hour", "startDay", "endDay", "interval", "type"], [latitude, longitude, hour, startDay, endDay, interval, "hour"]) wire = Topology.SetDictionary(wire, d) return wire @staticmethod def Diagram(latitude, longitude, minuteInterval=30, dayInterval=15, origin=None, radius=0.5, uSides=180, vSides=180, north=0, compass = False, shell=False): """ Returns the sun diagram based on the input parameters. See https://hyperfinearchitecture.com/how-to-read-sun-path-diagrams/. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. minuteInterval : int , optional The interval in minutes to compute the sun location for the date path. The default is 30. dayInterval : int , optional The interval in days for the hourly path to compute the sun location. The default is 15. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. uSides : int , optional The number of sides to divide the diagram horizontally (along the azimuth). The default is 180. vSides : int , optional The number of sides to divide the diagram paths vertically (along the altitude). The default is 180. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. compass : bool , optional If set to True, a compass (shell) is included. Othwerwise, it is is not. shell : bool , optional If set to True, the total surface (shell) of the sun paths is incldued. Otherwise, it is not. Returns ------- dict A dictionary of the sun diagram shapes. The keys in this dictionary are: - 'date_paths': These are the sun paths (wire) for the winter solstice, equinox, and summer solstice - 'hourly_paths': These are the figure-8 (wire) for the sun location on the same hour on each selected day of the year. - 'shell': This is the total surface (shell) of the sun paths. This is included only if the shell option is set to True. - 'compass': This is the compass (shell) on the ground. It is made of 36 sides and 10 rings. This is included only if the compass option is set to True. - 'center' : This is a cross-shape (wire) at the center of the diagram. This is included only if the compass option is set to True. - 'ground' : This is a circle (face) on the ground. It is made of 36 sides. This is included only if the compass option is set to False. """ from datetime import datetime from datetime import timedelta from topologicpy.Vertex import Vertex from topologicpy.Edge import Edge from topologicpy.Wire import Wire from topologicpy.Shell import Shell from topologicpy.Cell import Cell from topologicpy.Cluster import Cluster from topologicpy.Topology import Topology from topologicpy.Dictionary import Dictionary if origin == None: origin = Vertex.Origin() cutter = Cell.Prism(origin=origin, width=radius*4, length=radius*4, height=radius*2) cutter = Topology.Rotate(cutter, origin=origin, angle=-north) cutter = Topology.Translate(cutter, 0,0,-radius) now = datetime.now() year = now.year diagram = {} winter_solstice = Sun.WinterSolstice(latitude=latitude, year=year) summer_solstice = Sun.SummerSolstice(latitude=latitude, year=year) equinox = Sun.AutumnEquinox(latitude=latitude, year=year) dates = [winter_solstice, equinox, summer_solstice] date_paths = [] for date in dates: startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) - timedelta(hours=2) endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) + timedelta(hours=2) path = Sun.PathByDate(latitude=latitude, longitude=longitude, date=date, startTime=startTime, endTime=endTime, interval=minuteInterval, origin=origin, radius=radius, sides=uSides, north=north) # Capture the path's dictionary to re-apply later d = Topology.Dictionary(path) # Clip the path to above ground level path = Topology.Difference(path, cutter) path = Topology.SetDictionary(path, d) date_paths.append(path) diagram['date_paths'] = date_paths # Hourly paths hourly_paths = [] for hour in range (0, 24, 1): hourly_path = Sun.PathByHour(latitude, longitude, hour, startDay=0, endDay=365, interval=dayInterval, origin=origin, radius=radius, sides=vSides*2, north=north) d = Topology.Dictionary(hourly_path) hourly_path = Topology.Difference(hourly_path, cutter) if Topology.IsInstance(hourly_path, "topology"): hourly_path = Topology.SetDictionary(hourly_path, d) hourly_paths.append(hourly_path) diagram['hourly_paths'] = hourly_paths if shell: shell_paths = [] dates = [summer_solstice] delta = (winter_solstice - summer_solstice)/12 for i in range(1,12): a_date = summer_solstice + delta*i if abs(a_date - equinox) < timedelta(hours=24*5): dates.append(equinox) else: dates.append(a_date) dates.append(winter_solstice) for date in dates: startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) - timedelta(hours=2) endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) + timedelta(hours=2) shell_path = Sun.PathByDate(latitude=latitude, longitude=longitude, date=date, startTime=startTime, endTime=endTime, interval=minuteInterval, origin=origin, radius=radius, sides=uSides, north=north) # Clip the path to above ground level shell_path = Topology.Difference(shell_path, cutter) path_vertices = [] for i in range(uSides+1): u = float(i)/float(uSides) v = Wire.VertexByParameter(shell_path, u) path_vertices.append(v) shell_path = Wire.ByVertices(path_vertices, close=False) shell_paths.append(shell_path) a_shell = Shell.ByWires(shell_paths, triangulate=True, silent=True) d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "shell"]) a_shell = Topology.SetDictionary(a_shell, d) diagram['shell']= a_shell else: diagram['shell'] = None if compass: compass = Shell.Pie(origin=origin, radiusA=radius, radiusB=radius*0.1, sides=36, rings=10) d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "compass"]) compass = Topology.SetDictionary(compass, d) diagram['compass'] = compass edges = [] for i in range(0, 4, 1): v2 = Topology.Translate(origin, 0, radius/float(9), 0) edge = Edge.ByVertices(origin, v2) edge = Topology.Rotate(edge, origin=origin, angle=90*i) edge = Topology.Rotate(edge, origin=origin, angle=-north) edges.append(edge) center = Topology.SelfMerge(Cluster.ByTopologies(edges)) d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "center"]) center = Topology.SetDictionary(center, d) diagram['center'] = center else: ground = Wire.Circle(origin=origin, radius=radius, sides=36) d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "ground"]) ground = Topology.SetDictionary(ground, d) diagram['compass'] = None diagram['center'] = None diagram['ground']= ground return diagram
Static methods
def Altitude(latitude, longitude, date)
-
Returns the Altitude angle. See https://en.wikipedia.org/wiki/Altitude.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
Returns
float
- The altitude angle.
Expand source code
@staticmethod def Altitude(latitude, longitude, date): """ Returns the Altitude angle. See https://en.wikipedia.org/wiki/Altitude. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. Returns ------- float The altitude angle. """ import os import warnings import math try: import ephem except: print("Sun.Altitude - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.Altitude - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.Altitude - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None observer = ephem.Observer() observer.date = date observer.lat = str(latitude) observer.lon = str(longitude) sun = ephem.Sun(observer) sun.compute(observer) altitude = math.degrees(sun.alt) return altitude
def AutumnEquinox(latitude, year)
-
Returns the autumnal equinox date for the input latitude and year. See https://en.wikipedia.org/wiki/September_equinox.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
year
:integer
, optional- The input year. The default is the current year.
Returns
datetime
- The datetime of the summer solstice
Expand source code
@staticmethod def AutumnEquinox(latitude, year): """ Returns the autumnal equinox date for the input latitude and year. See https://en.wikipedia.org/wiki/September_equinox. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. year : integer , optional The input year. The default is the current year. Returns ------- datetime The datetime of the summer solstice """ import os import warnings try: import ephem except: print("Sun.AutumnEquinox - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.AutumnEquinox - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.AutumnEquinox - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None if latitude >= 0: equinox = ephem.next_equinox(ephem.Date(f"{year}/9/1")) else: equinox = ephem.next_equinox(ephem.Date(f"{year}/3/1")) return equinox.datetime()
def Azimuth(latitude, longitude, date)
-
Returns the Azimuth angle. See https://en.wikipedia.org/wiki/Azimuth.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
Returns
float
- The azimuth angle.
Expand source code
@staticmethod def Azimuth(latitude, longitude, date): """ Returns the Azimuth angle. See https://en.wikipedia.org/wiki/Azimuth. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. Returns ------- float The azimuth angle. """ import os import warnings import math try: import ephem except: print("Sun.Azimuth - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.Azimuth - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.Azimuth - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None observer = ephem.Observer() observer.date = date observer.lat = str(latitude) observer.lon = str(longitude) sun = ephem.Sun(observer) sun.compute(observer) azimuth = math.degrees(sun.az) return azimuth
def Diagram(latitude, longitude, minuteInterval=30, dayInterval=15, origin=None, radius=0.5, uSides=180, vSides=180, north=0, compass=False, shell=False)
-
Returns the sun diagram based on the input parameters. See https://hyperfinearchitecture.com/how-to-read-sun-path-diagrams/.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
minuteInterval
:int
, optional- The interval in minutes to compute the sun location for the date path. The default is 30.
dayInterval
:int
, optional- The interval in days for the hourly path to compute the sun location. The default is 15.
origin
:topologic_core.Vertex
, optional- The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius
:float
, optional- The desired radius of the sun orbit. The default is 0.5.
uSides
:int
, optional- The number of sides to divide the diagram horizontally (along the azimuth). The default is 180.
vSides
:int
, optional- The number of sides to divide the diagram paths vertically (along the altitude). The default is 180.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
compass
:bool
, optional- If set to True, a compass (shell) is included. Othwerwise, it is is not.
shell
:bool
, optional- If set to True, the total surface (shell) of the sun paths is incldued. Otherwise, it is not.
Returns
dict
- A dictionary of the sun diagram shapes. The keys in this dictionary are: - 'date_paths': These are the sun paths (wire) for the winter solstice, equinox, and summer solstice - 'hourly_paths': These are the figure-8 (wire) for the sun location on the same hour on each selected day of the year. - 'shell': This is the total surface (shell) of the sun paths. This is included only if the shell option is set to True. - 'compass': This is the compass (shell) on the ground. It is made of 36 sides and 10 rings. This is included only if the compass option is set to True. - 'center' : This is a cross-shape (wire) at the center of the diagram. This is included only if the compass option is set to True. - 'ground' : This is a circle (face) on the ground. It is made of 36 sides. This is included only if the compass option is set to False.
Expand source code
@staticmethod def Diagram(latitude, longitude, minuteInterval=30, dayInterval=15, origin=None, radius=0.5, uSides=180, vSides=180, north=0, compass = False, shell=False): """ Returns the sun diagram based on the input parameters. See https://hyperfinearchitecture.com/how-to-read-sun-path-diagrams/. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. minuteInterval : int , optional The interval in minutes to compute the sun location for the date path. The default is 30. dayInterval : int , optional The interval in days for the hourly path to compute the sun location. The default is 15. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. uSides : int , optional The number of sides to divide the diagram horizontally (along the azimuth). The default is 180. vSides : int , optional The number of sides to divide the diagram paths vertically (along the altitude). The default is 180. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. compass : bool , optional If set to True, a compass (shell) is included. Othwerwise, it is is not. shell : bool , optional If set to True, the total surface (shell) of the sun paths is incldued. Otherwise, it is not. Returns ------- dict A dictionary of the sun diagram shapes. The keys in this dictionary are: - 'date_paths': These are the sun paths (wire) for the winter solstice, equinox, and summer solstice - 'hourly_paths': These are the figure-8 (wire) for the sun location on the same hour on each selected day of the year. - 'shell': This is the total surface (shell) of the sun paths. This is included only if the shell option is set to True. - 'compass': This is the compass (shell) on the ground. It is made of 36 sides and 10 rings. This is included only if the compass option is set to True. - 'center' : This is a cross-shape (wire) at the center of the diagram. This is included only if the compass option is set to True. - 'ground' : This is a circle (face) on the ground. It is made of 36 sides. This is included only if the compass option is set to False. """ from datetime import datetime from datetime import timedelta from topologicpy.Vertex import Vertex from topologicpy.Edge import Edge from topologicpy.Wire import Wire from topologicpy.Shell import Shell from topologicpy.Cell import Cell from topologicpy.Cluster import Cluster from topologicpy.Topology import Topology from topologicpy.Dictionary import Dictionary if origin == None: origin = Vertex.Origin() cutter = Cell.Prism(origin=origin, width=radius*4, length=radius*4, height=radius*2) cutter = Topology.Rotate(cutter, origin=origin, angle=-north) cutter = Topology.Translate(cutter, 0,0,-radius) now = datetime.now() year = now.year diagram = {} winter_solstice = Sun.WinterSolstice(latitude=latitude, year=year) summer_solstice = Sun.SummerSolstice(latitude=latitude, year=year) equinox = Sun.AutumnEquinox(latitude=latitude, year=year) dates = [winter_solstice, equinox, summer_solstice] date_paths = [] for date in dates: startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) - timedelta(hours=2) endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) + timedelta(hours=2) path = Sun.PathByDate(latitude=latitude, longitude=longitude, date=date, startTime=startTime, endTime=endTime, interval=minuteInterval, origin=origin, radius=radius, sides=uSides, north=north) # Capture the path's dictionary to re-apply later d = Topology.Dictionary(path) # Clip the path to above ground level path = Topology.Difference(path, cutter) path = Topology.SetDictionary(path, d) date_paths.append(path) diagram['date_paths'] = date_paths # Hourly paths hourly_paths = [] for hour in range (0, 24, 1): hourly_path = Sun.PathByHour(latitude, longitude, hour, startDay=0, endDay=365, interval=dayInterval, origin=origin, radius=radius, sides=vSides*2, north=north) d = Topology.Dictionary(hourly_path) hourly_path = Topology.Difference(hourly_path, cutter) if Topology.IsInstance(hourly_path, "topology"): hourly_path = Topology.SetDictionary(hourly_path, d) hourly_paths.append(hourly_path) diagram['hourly_paths'] = hourly_paths if shell: shell_paths = [] dates = [summer_solstice] delta = (winter_solstice - summer_solstice)/12 for i in range(1,12): a_date = summer_solstice + delta*i if abs(a_date - equinox) < timedelta(hours=24*5): dates.append(equinox) else: dates.append(a_date) dates.append(winter_solstice) for date in dates: startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) - timedelta(hours=2) endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) + timedelta(hours=2) shell_path = Sun.PathByDate(latitude=latitude, longitude=longitude, date=date, startTime=startTime, endTime=endTime, interval=minuteInterval, origin=origin, radius=radius, sides=uSides, north=north) # Clip the path to above ground level shell_path = Topology.Difference(shell_path, cutter) path_vertices = [] for i in range(uSides+1): u = float(i)/float(uSides) v = Wire.VertexByParameter(shell_path, u) path_vertices.append(v) shell_path = Wire.ByVertices(path_vertices, close=False) shell_paths.append(shell_path) a_shell = Shell.ByWires(shell_paths, triangulate=True, silent=True) d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "shell"]) a_shell = Topology.SetDictionary(a_shell, d) diagram['shell']= a_shell else: diagram['shell'] = None if compass: compass = Shell.Pie(origin=origin, radiusA=radius, radiusB=radius*0.1, sides=36, rings=10) d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "compass"]) compass = Topology.SetDictionary(compass, d) diagram['compass'] = compass edges = [] for i in range(0, 4, 1): v2 = Topology.Translate(origin, 0, radius/float(9), 0) edge = Edge.ByVertices(origin, v2) edge = Topology.Rotate(edge, origin=origin, angle=90*i) edge = Topology.Rotate(edge, origin=origin, angle=-north) edges.append(edge) center = Topology.SelfMerge(Cluster.ByTopologies(edges)) d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "center"]) center = Topology.SetDictionary(center, d) diagram['center'] = center else: ground = Wire.Circle(origin=origin, radius=radius, sides=36) d = Dictionary.ByKeysValues(["latitude", "longitude", "type"], [latitude, longitude, "ground"]) ground = Topology.SetDictionary(ground, d) diagram['compass'] = None diagram['center'] = None diagram['ground']= ground return diagram
def Edge(latitude, longitude, date, origin=None, radius=0.5, north=0)
-
Returns the Sun as a vector.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
origin
:topologic_core.Vertex
, optional- The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius
:float
, optional- The desired radius of the sun orbit. The default is 0.5.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
topologic_core.Edge
- The sun represented as an edge pointing from the location of the sun towards the origin.
Expand source code
@staticmethod def Edge(latitude, longitude, date, origin=None, radius=0.5, north=0): """ Returns the Sun as a vector. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- topologic_core.Edge The sun represented as an edge pointing from the location of the sun towards the origin. """ from topologicpy.Vertex import Vertex from topologicpy.Edge import Edge from topologicpy.Topology import Topology from topologicpy.Vector import Vector if origin == None: origin = Vertex.Origin() vector = Vector.Reverse(Sun.Vector(latitude=latitude, longitude=longitude, date=date, north=north)) sun_v = Topology.TranslateByDirectionDistance(origin, direction=vector, distance=radius) edge = Edge.ByVertices(sun_v, origin) return edge
def PathByDate(latitude, longitude, date, startTime=None, endTime=None, interval=60, origin=None, radius=0.5, sides=None, north=0)
-
Returns the sun path based on the input parameters.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
startTime
:datetime
, optional- The desired start time to compute the sun location. If set to None, Sun.Sunrise is used. The default is None.
endTime
:datetime
, optional- The desired end time to compute the sun location. If set to None, Sun.Sunset is used. The default is None.
interval
:int
, optional- The interval in minutes to compute the sun location. The default is 60.
origin
:topologic_core.Vertex
, optional- The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius
:float
, optional- The desired radius of the sun orbit. The default is 0.5.
sides
:int
, optional- If set to None, the path is divided based on the interval. Otherwise, it is equally divided into the number of sides. The default is None.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
topologic_core.Wire
- The sun path represented as a wire.
Expand source code
@staticmethod def PathByDate(latitude, longitude, date, startTime=None, endTime=None, interval=60, origin=None, radius=0.5, sides=None, north=0): """ Returns the sun path based on the input parameters. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. startTime : datetime , optional The desired start time to compute the sun location. If set to None, Sun.Sunrise is used. The default is None. endTime : datetime , optional The desired end time to compute the sun location. If set to None, Sun.Sunset is used. The default is None. interval : int , optional The interval in minutes to compute the sun location. The default is 60. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. sides : int , optional If set to None, the path is divided based on the interval. Otherwise, it is equally divided into the number of sides. The default is None. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- topologic_core.Wire The sun path represented as a wire. """ from topologicpy.Vertex import Vertex from topologicpy.Wire import Wire from topologicpy.Dictionary import Dictionary from topologicpy.Topology import Topology if origin == None: origin = Vertex.Origin() if startTime == None: startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) if endTime == None: endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) vertices = Sun.VerticesByDate(latitude=latitude, longitude=longitude, date=date, startTime=startTime, endTime=endTime, interval=interval, origin=origin, radius=radius, north=north) if len(vertices) < 2: return None wire = Wire.ByVertices(vertices, close=False) if not sides == None: vertices = [] for i in range(sides): u = float(i)/float(sides) v = Wire.VertexByParameter(wire, u) vertices.append(v) wire = Wire.ByVertices(vertices, close=False) d = Dictionary.ByKeysValues(["latitude", "longitude", "date", "startTime", "endTime", "interval", "type"], [latitude, longitude, str(date), str(startTime), str(endTime), interval, "date"]) wire = Topology.SetDictionary(wire, d) return wire
def PathByHour(latitude, longitude, hour, startDay=1, endDay=365, interval=5, origin=None, radius=0.5, sides=None, north=0)
-
Returns the sun locations based on the input parameters.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
hour
:datetime
- The input hour.
startDay
:integer
, optional- The desired start day of the year to compute the sun location. The default is 1.
endDay
:integer
, optional- The desired end day of the year to compute the sun location. The default is 365.
interval
:int
, optional- The interval in days to compute the sun location. The default is 5.
origin
:topologic_core.Vertex
, optional- The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius
:float
, optional- The desired radius of the sun orbit. The default is 0.5.
sides
:int
, optional- If set to None, the path is divided based on the interval. Otherwise, it is equally divided into the number of sides. The default is None.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
topologic_core.Wire
- The sun path represented as a topologic wire.
Expand source code
@staticmethod def PathByHour(latitude, longitude, hour, startDay=1, endDay=365, interval=5, origin=None, radius=0.5, sides=None, north=0): """ Returns the sun locations based on the input parameters. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. hour : datetime The input hour. startDay : integer , optional The desired start day of the year to compute the sun location. The default is 1. endDay : integer , optional The desired end day of the year to compute the sun location. The default is 365. interval : int , optional The interval in days to compute the sun location. The default is 5. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. sides : int , optional If set to None, the path is divided based on the interval. Otherwise, it is equally divided into the number of sides. The default is None. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- topologic_core.Wire The sun path represented as a topologic wire. """ from topologicpy.Wire import Wire from topologicpy.Dictionary import Dictionary from topologicpy.Topology import Topology vertices = Sun.VerticesByHour(latitude=latitude, longitude=longitude, hour=hour, startDay=startDay, endDay=endDay, interval=interval, origin=origin, radius=radius, north=north) if len(vertices) < 2: return None wire = Wire.ByVertices(vertices, close=False) if not sides == None: vertices = [] for i in range(sides): u = float(i)/float(sides) v = Wire.VertexByParameter(wire, u) vertices.append(v) wire = Wire.ByVertices(vertices, close=True) d = Dictionary.ByKeysValues(["latitude", "longitude", "hour", "startDay", "endDay", "interval", "type"], [latitude, longitude, hour, startDay, endDay, interval, "hour"]) wire = Topology.SetDictionary(wire, d) return wire
def Position(latitude, longitude, date, origin=None, radius=0.5, north=0, mantissa=6)
-
Returns the Sun as a position ([X,Y,Z]).
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
origin
:topologic_core.Vertex
, optional- The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius
:float
, optional- The desired radius of the sun orbit. The default is 0.5.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
mantissa
:int
, optional- The desired length of the mantissa. The default is 6.
Returns
topologic_core.Vertex
- The sun represented as a vertex.
Expand source code
@staticmethod def Position(latitude, longitude, date, origin=None, radius=0.5, north=0, mantissa=6): """ Returns the Sun as a position ([X,Y,Z]). Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. mantissa : int , optional The desired length of the mantissa. The default is 6. Returns ------- topologic_core.Vertex The sun represented as a vertex. """ from topologicpy.Vertex import Vertex sun_v = Sun.Vertex(latitude=latitude, longitude=longitude, date=date, origin=origin, radius=radius, north=north) return Vertex.Coordinates(sun_v, mantissa=mantissa)
def SpringEquinox(latitude, year)
-
Returns the spring (vernal) equinox date for the input latitude and year. See https://en.wikipedia.org/wiki/March_equinox.
Parameters
latitude
:float
- The input latitude.
year
:integer
, optional- The input year. The default is the current year.
Returns
datetime
- The datetime of the summer solstice
Expand source code
@staticmethod def SpringEquinox(latitude, year): """ Returns the spring (vernal) equinox date for the input latitude and year. See https://en.wikipedia.org/wiki/March_equinox. Parameters ---------- latitude : float The input latitude. year : integer , optional The input year. The default is the current year. Returns ------- datetime The datetime of the summer solstice """ import os import warnings try: import ephem except: print("Sun.SpringEquinox - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.SpringEquinox - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.SpringEquinox - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None if latitude >= 0: equinox = ephem.next_equinox(ephem.Date(f"{year}/3/1")) else: equinox = ephem.next_equinox(ephem.Date(f"{year}/9/1")) return equinox.datetime()
def SummerSolstice(latitude, year)
-
Returns the winter solstice date for the input latitude and year. See https://en.wikipedia.org/wiki/Summer_solstice.
Parameters
latitude
:float
- The input latitude.
year
:integer
, optional- The input year. The default is the current year.
Returns
datetime
- The datetime of the summer solstice
Expand source code
@staticmethod def SummerSolstice(latitude, year): """ Returns the winter solstice date for the input latitude and year. See https://en.wikipedia.org/wiki/Summer_solstice. Parameters ---------- latitude : float The input latitude. year : integer , optional The input year. The default is the current year. Returns ------- datetime The datetime of the summer solstice """ import os import warnings try: import ephem except: print("Sun.SummerSolstice - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.SummerSolstice - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.SummerSolstice - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None if latitude >= 0: solstice = ephem.next_solstice(ephem.Date(f"{year}/6/1")) else: solstice = ephem.next_solstice(ephem.Date(f"{year}/12/1")) return solstice.datetime()
def Sunrise(latitude, longitude, date)
-
Returns the Sunrise datetime.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
Returns
datetime
- The Sunrise datetime.
Expand source code
@staticmethod def Sunrise(latitude, longitude, date): """ Returns the Sunrise datetime. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. Returns ------- datetime The Sunrise datetime. """ import os import warnings try: import ephem except: print("Sun.Sunrise - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.Sunrise - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.Sunrise - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None date = date.replace(hour=12, minute=0, second=0, microsecond=0) observer = ephem.Observer() observer.lat = str(latitude) observer.lon = str(longitude) observer.date = date sunrise = observer.previous_rising(ephem.Sun()).datetime() return sunrise
def Sunset(latitude, longitude, date)
-
Returns the Sunset datetime.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
Returns
datetime
- The Sunset datetime.
Expand source code
@staticmethod def Sunset(latitude, longitude, date): """ Returns the Sunset datetime. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. Returns ------- datetime The Sunset datetime. """ import os import warnings try: import ephem except: print("Sun.Sunset - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.Sunset - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.Sunset - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None date = date.replace(hour=12, minute=0, second=0, microsecond=0) observer = ephem.Observer() observer.lat = str(latitude) observer.lon = str(longitude) observer.date = date sunset = observer.next_setting(ephem.Sun()).datetime() return sunset
def Vector(latitude, longitude, date, north=0)
-
Returns the Sun as a vector.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
list
- The sun vector pointing from the location of the sun towards the origin.
Expand source code
@staticmethod def Vector(latitude, longitude, date, north=0): """ Returns the Sun as a vector. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- list The sun vector pointing from the location of the sun towards the origin. """ from topologicpy.Vector import Vector azimuth = Sun.Azimuth(latitude=latitude, longitude=longitude, date=date) altitude = Sun.Altitude(latitude=latitude, longitude=longitude, date=date) return Vector.ByAzimuthAltitude(azimuth=azimuth, altitude=altitude, north=north, reverse=True)
def Vertex(latitude, longitude, date, origin=None, radius=0.5, north=0)
-
Returns the Sun as a vertex.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
origin
:topologic_core.Vertex
, optional- The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius
:float
, optional- The desired radius of the sun orbit. The default is 0.5.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
topologic_core.Vertex
- The sun represented as a vertex.
Expand source code
@staticmethod def Vertex(latitude, longitude, date, origin=None, radius=0.5, north=0): """ Returns the Sun as a vertex. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- topologic_core.Vertex The sun represented as a vertex. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology from topologicpy.Vector import Vector if origin == None: origin = Vertex.Origin() vector = Vector.Reverse(Sun.Vector(latitude=latitude, longitude=longitude, date=date, north=north)) sun_v = Topology.TranslateByDirectionDistance(origin, direction=vector, distance=radius) return sun_v
def VerticesByDate(latitude, longitude, date, startTime=None, endTime=None, interval=60, origin=None, radius=0.5, north=0)
-
Returns the Sun locations as vertices based on the input parameters.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
date
:datetime
- The input datetime.
startTime
:datetime
, optional- The desired start time to compute the sun location. If set to None, Sun.Sunrise is used. The default is None.
endTime
:datetime
, optional- The desired end time to compute the sun location. If set to None, Sun.Sunset is used. The default is None.
interval
:int
, optional- The interval in minutes to compute the sun location. The default is 60.
origin
:topologic_core.Vertex
, optional- The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius
:float
, optional- The desired radius of the sun orbit. The default is 0.5.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
list
- The sun locations represented as a list of vertices.
Expand source code
@staticmethod def VerticesByDate(latitude, longitude, date, startTime=None, endTime=None, interval=60, origin=None, radius=0.5, north=0): """ Returns the Sun locations as vertices based on the input parameters. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. date : datetime The input datetime. startTime : datetime , optional The desired start time to compute the sun location. If set to None, Sun.Sunrise is used. The default is None. endTime : datetime , optional The desired end time to compute the sun location. If set to None, Sun.Sunset is used. The default is None. interval : int , optional The interval in minutes to compute the sun location. The default is 60. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- list The sun locations represented as a list of vertices. """ from datetime import timedelta if startTime == None: startTime = Sun.Sunrise(latitude=latitude, longitude=longitude, date=date) if endTime == None: endTime = Sun.Sunset(latitude=latitude, longitude=longitude, date=date) vertices = [] current_time = startTime while current_time <= endTime: v = Sun.Vertex(latitude=latitude, longitude=longitude, date=current_time, origin=origin, radius=radius, north=north) vertices.append(v) current_time += timedelta(minutes=interval) return vertices
def VerticesByHour(latitude, longitude, hour, startDay=1, endDay=365, interval=5, origin=None, radius=0.5, north=0)
-
Returns the sun locations based on the input parameters.
Parameters
latitude
:float
- The input latitude. See https://en.wikipedia.org/wiki/Latitude.
longitude
:float
- The input longitude. See https://en.wikipedia.org/wiki/Longitude.
hour
:datetime
- The input hour.
startDay
:integer
, optional- The desired start day to compute the sun location. The default is 1.
endDay
:integer
, optional- The desired end day to compute the sun location. The default is 365.
interval
:int
, optional- The interval in days to compute the sun location. The default is 5.
origin
:topologic_core.Vertex
, optional- The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None.
radius
:float
, optional- The desired radius of the sun orbit. The default is 0.5.
north
:float
, optional- The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction.
Returns
list
- The sun locations represented as a list of vertices.
Expand source code
@staticmethod def VerticesByHour(latitude, longitude, hour, startDay=1, endDay=365, interval=5, origin=None, radius=0.5, north=0): """ Returns the sun locations based on the input parameters. Parameters ---------- latitude : float The input latitude. See https://en.wikipedia.org/wiki/Latitude. longitude : float The input longitude. See https://en.wikipedia.org/wiki/Longitude. hour : datetime The input hour. startDay : integer , optional The desired start day to compute the sun location. The default is 1. endDay : integer , optional The desired end day to compute the sun location. The default is 365. interval : int , optional The interval in days to compute the sun location. The default is 5. origin : topologic_core.Vertex , optional The desired origin of the world. If set to None, the origin will be set to (0,0,0). The default is None. radius : float , optional The desired radius of the sun orbit. The default is 0.5. north : float, optional The desired compass angle of the north direction. The default is 0 which points in the positive Y-axis direction. Returns ------- list The sun locations represented as a list of vertices. """ from datetime import datetime from datetime import timedelta def day_of_year_to_datetime(year, day_of_year): # Construct a datetime object for the first day of the year base_date = datetime(year, 1, 1) # Add the number of days to get to the specified day of the year target_date = base_date + timedelta(days=day_of_year - 1) return target_date now = datetime.now() # Get the year component year = now.year vertices = [] for day_of_year in range(startDay, endDay, interval): date = day_of_year_to_datetime(year, day_of_year) date += timedelta(hours=hour) v = Sun.Vertex(latitude=latitude, longitude=longitude, date=date, origin=origin, radius=radius, north=north) vertices.append(v) return vertices
def WinterSolstice(latitude, year=None)
-
Returns the winter solstice date for the input latitude and year. See https://en.wikipedia.org/wiki/Winter_solstice.
Parameters
latitude
:float
- The input latitude.
year
:integer
, optional- The input year. The default is the current year.
Returns
datetime
- The datetime of the winter solstice
Expand source code
@staticmethod def WinterSolstice(latitude, year=None): """ Returns the winter solstice date for the input latitude and year. See https://en.wikipedia.org/wiki/Winter_solstice. Parameters ---------- latitude : float The input latitude. year : integer , optional The input year. The default is the current year. Returns ------- datetime The datetime of the winter solstice """ import os import warnings try: import ephem except: print("Sun.WinterSolstice - Information: Installing required ephem library.") try: os.system("pip install ephem") except: os.system("pip install ephem --user") try: import ephem print("Sun.WinterSolstice - Infromation: ephem library installed correctly.") except: warnings.warn("Sun.WinterSolstice - Error: Could not import ephem. Please try to install ephem manually. Returning None.") return None from datetime import datetime if year == None: year = datetime.now().year if latitude >= 0: solstice = ephem.next_solstice(ephem.Date(f"{year}/12/1")) else: solstice = ephem.next_solstice(ephem.Date(f"{year}/6/1")) return solstice.datetime()