328 lines
14 KiB
Python
328 lines
14 KiB
Python
#!/usr/bin/python3
|
|
|
|
# --------------------------------------------------------------------------------------
|
|
#http://astrodinamica.altervista.org/ESU/sundial/Condensed-vector-theory.pdf
|
|
#https://www.helios-sonnenuhren.de/sites/default/files/upload/the_calculation_of_declining_and_inclining_sundials_an_unusual_approach.pdf
|
|
# --------------------------------------------------------------------------------------
|
|
|
|
from __future__ import division
|
|
import inkex
|
|
from datetime import datetime, time, timedelta
|
|
from math import *
|
|
from lxml import etree
|
|
|
|
class sundialDeclining(inkex.EffectExtension):
|
|
|
|
def add_arguments(self, pars):
|
|
pars.add_argument("--latitude", type=float, dest="latitude", default="50.3515")
|
|
pars.add_argument("--longitude", type=float, dest="longitude", default="15.7512")
|
|
pars.add_argument("--timezone", type=int, dest="timezone", default="0")
|
|
pars.add_argument("--summer_time", type=inkex.Boolean, dest="summer_time", default='False')
|
|
pars.add_argument("--gnom", type=float, dest="gnom", default="30")
|
|
pars.add_argument("--decl", type=float, dest="decl", default="0")
|
|
pars.add_argument("--incl", type=float, dest="incl", default="0")
|
|
pars.add_argument("--DL", type=float, dest="DL", default="0")
|
|
pars.add_argument("--tab")
|
|
|
|
def effect(self):
|
|
def draw_SVG_line(x1, y1, x2, y2, width, stroke, name, parent):
|
|
style = { 'stroke': stroke, 'stroke-width':str(width), 'fill': 'none' }
|
|
line_attribs = {'style':str(inkex.Style(style)),
|
|
inkex.addNS('label','inkscape'):name,
|
|
'd':'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)}
|
|
etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs )
|
|
|
|
def draw_SVG_circle(cx, cy, r, width, stroke, fill, name, parent):
|
|
style = { 'stroke': stroke, 'stroke-width':str(width), 'fill':fill}
|
|
circle_attribs = {'style':str(inkex.Style(style)),
|
|
inkex.addNS('label','inkscape'):name,
|
|
'cx':str(cx), 'cy':str(cy), 'r':str(r)}
|
|
etree.SubElement(parent, inkex.addNS('circle','svg'), circle_attribs )
|
|
|
|
def draw_SVG_tri(x1, y1, x2, y2, x3, y3, width, stroke, name, parent):
|
|
style = { 'stroke': stroke, 'stroke-width':str(width), 'fill': 'none' }
|
|
tri_attribs = {'style':str(inkex.Style(style)),
|
|
inkex.addNS('label','inkscape'):name,
|
|
'd':'M '+str(x1)+','+str(y1)+
|
|
' L '+str(x2)+','+str(y2)+
|
|
' L '+str(x3)+','+str(y3)+
|
|
' L '+str(x1)+','+str(y1)+' z'}
|
|
etree.SubElement(parent, inkex.addNS('path','svg'), tri_attribs )
|
|
|
|
def draw_SVG_rect(x, y, w, h, width, fill, name, parent):
|
|
style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill':fill}
|
|
rect_attribs = {'style':str(inkex.Style(style)),
|
|
inkex.addNS('label','inkscape'):name,
|
|
'x':str(x), 'y':str(y), 'width':str(w), 'height':str(h)}
|
|
etree.SubElement(parent, inkex.addNS('rect','svg'), rect_attribs )
|
|
|
|
def draw_SVG_polyline(DP, width, colour, fill, name, parent):
|
|
style = { 'stroke': colour, 'stroke-width': str(width), 'fill':fill}
|
|
polyline_attribs = {'style':str(inkex.Style(style)),
|
|
inkex.addNS('label','inkscape'):name,
|
|
'd':'M' +str(DP)}
|
|
etree.SubElement(parent, inkex.addNS('path','svg'), polyline_attribs )
|
|
|
|
def draw_SVG_text(x, y, textvalue, font, text_size, parent):
|
|
text = etree.Element(inkex.addNS('text','svg'))
|
|
text.set('x', str(x))
|
|
text.set('y', str(y))
|
|
style = {'text-align' : 'center', 'font-family': str(font) ,'text-anchor': 'middle', 'alignment-baseline' : 'center', 'font-size' : str(text_size), 'vertical-align' : 'middle'}
|
|
text.set('style', str(inkex.Style(style)))
|
|
text.text = textvalue
|
|
parent.append(text)
|
|
|
|
so = self.options
|
|
parent = self.svg.get_current_layer()
|
|
|
|
border=5
|
|
widthgrid = 200
|
|
heightgrid = 150
|
|
|
|
# Grid
|
|
Gx=15
|
|
Gy=9
|
|
|
|
# Get SVG document dimensions
|
|
svg = self.document.getroot()
|
|
width = self.svg.unittouu(svg.get('width'))
|
|
height = self.svg.unittouu(svg.attrib['height'])
|
|
|
|
# Embed grid in group
|
|
#Put in in the centre of the current view
|
|
#t = 'translate(' + str( self.view_center[0]- width/2.0) + ',' + str( self.view_center[1]- height/2.0) + ')'
|
|
#t = 'translate(0,' + str(height) + ') rotate(-180,0,0)'
|
|
t = 'translate(' + str(width/2) + ',' + str(border) + ')'
|
|
#t = 'translate(0 ,0)'
|
|
|
|
g_attribs = {inkex.addNS('label','inkscape'):'SunDial_Lat:' + str( so.latitude )+';Long:'+str( so.longitude ),'transform':t}
|
|
grid = etree.SubElement(self.svg.get_current_layer(), 'g', g_attribs)
|
|
|
|
#Group for x gridlines
|
|
g_attribs = {inkex.addNS('label','inkscape'):'XGridlines'}
|
|
glx = etree.SubElement(grid, 'g', g_attribs)
|
|
|
|
#Group for y gridlines
|
|
g_attribs = {inkex.addNS('label','inkscape'):'YGridlines'}
|
|
gly = etree.SubElement(grid, 'g', g_attribs)
|
|
|
|
#Group for Hour lines vertical SunDial
|
|
g_attribs = {inkex.addNS('label','inkscape'):'VerticalHourLines'}
|
|
vhl = etree.SubElement(grid, 'g', g_attribs)
|
|
|
|
#Group for Nodus vertical SunDial
|
|
g_attribs = {inkex.addNS('label','inkscape'):'Nodus'}
|
|
nod = etree.SubElement(grid, 'g', g_attribs)
|
|
|
|
#Group for zodiac line
|
|
g_attribs = {inkex.addNS('label','inkscape'):'Line of zodiac'}
|
|
loz = etree.SubElement(grid, 'g', g_attribs)
|
|
|
|
# ----------Grid and border------------------------------------------------------------------
|
|
# Border
|
|
draw_SVG_rect(-width/2+border, -0, width-2*border, heightgrid, 0.8, 'none', 'Border', grid) #border rectangle
|
|
|
|
# XGridLine
|
|
for i in range(Gx): #x divisons
|
|
distX=widthgrid/(Gx-1)
|
|
draw_SVG_line(distX*i-width/2+border, heightgrid, distX*i-width/2+border, 0, 0.1, '#0000FF', 'X'+str(i), glx)
|
|
|
|
# YGridLine
|
|
for i in range(Gy): #y divisons
|
|
distY=heightgrid/(Gy-1)
|
|
draw_SVG_line(-width/2+border, distY*i, width/2-border, distY*i, 0.1, '#0000FF', 'Y'+str(i), gly)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
Time = [4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
|
|
T = {} #
|
|
T_rad = {} #
|
|
|
|
# Line of zodiac
|
|
if so.DL == 0:
|
|
D = []
|
|
if so.DL == 3:
|
|
D = [-23.44, 0.0001, 23.44]
|
|
if so.DL == 7:
|
|
D = [-23.44, -20.15, -11.47, 0.0001, 11.47, 20.15, 23.44] #https://www.mysundial.ca/tsp/the_zodiac.html
|
|
|
|
D_rad = {}
|
|
|
|
W = so.decl*pi/180 # Declination of wall in radian https://www.mysundial.ca/tsp/vertical_declining_sundial.html
|
|
R = so.incl*pi/180 # Inclination of wall in radian
|
|
L = so.latitude*pi/180 # Latitude in radian
|
|
|
|
#Text
|
|
textvalue='Sundials for Latitude: %s; Wall azimuth: %s; Wall inclination: %s --- (c)2019 Tomas Urban ' % (so.latitude, round(W*180/pi,2), round(R*180/pi,2))
|
|
draw_SVG_text(0, heightgrid+4, textvalue, 'san-serif', 4, gly)
|
|
|
|
# ----------Gnomon ----------------------------------------------------------------------------
|
|
Xf =-so.gnom*(sin(W)*cos(L))/(cos(R)*cos(W)*cos(L)-sin(R)*sin(L))
|
|
Zf = so.gnom*((sin(R)*cos(W)*cos(L))+(cos(R)*sin(L)))/(cos(R)*cos(W)*cos(L)-sin(R)*sin(L))
|
|
g = asin(cos(R)*cos(W)*cos(L)-sin(R)*sin(L))
|
|
f = atan(-sin(W)*cos(L)/(sin(R)*cos(W)*cos(L)+cos(R)*sin(L)))
|
|
P = -so.gnom/(cos(R)*cos(W)*cos(L)-sin(R)*sin(L))
|
|
|
|
#Text
|
|
#textvalue='Xf: %s; Zf: %s; g: %s; P: %s; f: %s' % (round(Xf,2), round(Zf,2), round(g*180/pi,2), round(P,2), round(f*180/pi,2))
|
|
#draw_SVG_text(0, 120, textvalue, 'san-serif', 4, gly)
|
|
#textvalue='G*cos(f): %s; G*sin(f): %s; g: %s; P: %s; f: %s' % (round(so.gnom*cos(f),2), round(so.gnom*sin(f),2), round(so.gnom*180/pi,2), round(P,2), round(f*180/pi,2))
|
|
#draw_SVG_text(0, 125, textvalue, 'san-serif', 4, gly)
|
|
|
|
# Horizont line
|
|
draw_SVG_line(-width/2+border, Zf, width/2-border, Zf, 0.5, '#000000', 'Horizont line', nod)
|
|
|
|
# Nodus
|
|
a = (0,0)
|
|
b = (-Xf, Zf)
|
|
c = (-Xf+so.gnom*cos(f),Zf+so.gnom*sin(f))
|
|
draw_SVG_tri(a[0], a[1], b[0], b[1], c[0], c[1], 0.35, '#FF00FF', 'Nodus', nod)
|
|
draw_SVG_circle(-Xf,Zf, 2, 0.3, '#000000', '#0000FF', 'Nodus', nod)
|
|
|
|
# --------- Line of zodiac ----------------------------------------------------------------------
|
|
A = -cos(R)*sin(W)
|
|
B = -cos(R)*cos(W)
|
|
C = sin(R)
|
|
#textvalue='A: %s; B: %s; C: %s' % (A, B, C)
|
|
#draw_SVG_text(0, 125, textvalue, 'san-serif', 4, gly)
|
|
|
|
for i in range(len(D)):
|
|
D_rad[i]= D[i]*pi/180
|
|
DP=''
|
|
for ii in range(len(Time)):
|
|
T[ii]=(Time[ii]-12)*15
|
|
T_rad[ii]=T[ii]*pi/180
|
|
AzSun = atan(sin(T_rad[ii])/(sin(L)*cos(T_rad[ii]) - tan(D_rad[i])*cos(L)))
|
|
AltSun = asin(sin(D_rad[i])*sin(L) + cos(D_rad[i])*cos(L)*cos(T_rad[ii]))
|
|
|
|
if T[ii] < 0:
|
|
if AzSun > 0:
|
|
AzSun=AzSun+pi
|
|
else:
|
|
AzSun = AzSun+2*pi
|
|
else:
|
|
if AzSun >= 0:
|
|
AzSun=AzSun
|
|
else:
|
|
AzSun = AzSun+pi
|
|
|
|
#Text
|
|
#textvalue='AzSun: %s; AltSun: %s; T: %s' % (round(AzSun*180/pi,2), round(AltSun*180/pi,2), Time[ii])
|
|
#draw_SVG_text(200, 220+5*ii+100*i, textvalue, 'san-serif', 4, gly)
|
|
|
|
X0= -cos(AltSun)*sin(AzSun)
|
|
Y0= -cos(AltSun)*cos(AzSun)
|
|
Z0= sin(AltSun)
|
|
|
|
X1=X0*cos(W)-Y0*sin(W)
|
|
Y1=X0*sin(W)+Y0*cos(W)
|
|
Z1=Z0
|
|
|
|
X2=X1
|
|
Y2=Y1*cos(R)-Z1*sin(R)
|
|
Z2=Y1*sin(R)+Z1*cos(R)
|
|
|
|
X3=so.gnom*X2/Y2
|
|
Z3=-so.gnom*Z2/Y2
|
|
p1= X0*A+Y0*B+Z0*C
|
|
|
|
Xe = X3 - Xf
|
|
Ze = Z3 + Zf
|
|
|
|
if p1 >0:
|
|
DP = DP +' '+str(Xe)+', '+str(Ze)
|
|
|
|
# draw polyline
|
|
draw_SVG_polyline(DP, 0.5,'#FF0000', 'none', 'Zodiac line '+str(i+1), loz)
|
|
|
|
# --------- Time Line ----------------------------------------------------------------------
|
|
ALFA= atan(widthgrid/(2*heightgrid)) # Line for help
|
|
|
|
for i in range(len(Time)):
|
|
T[i]=(Time[i]-12)*15
|
|
T_rad[i]=T[i]*pi/180
|
|
TL=''
|
|
|
|
D = [-23.44, -20.15, -11.47, 0.0001, 11.47, 20.15, 23.44]
|
|
for ii in range(len(D)):
|
|
D_rad[ii]= D[ii]*pi/180
|
|
TL= '0, 0'
|
|
|
|
AzSun = atan(sin(T_rad[i])/(sin(L)*cos(T_rad[i]) - tan(D_rad[ii])*cos(L)))
|
|
AltSun = asin(sin(D_rad[ii])*sin(L) + cos(D_rad[ii])*cos(L)*cos(T_rad[i]))
|
|
|
|
if T[i] < 0:
|
|
if AzSun > 0:
|
|
AzSun=AzSun+pi
|
|
else:
|
|
AzSun = AzSun+2*pi
|
|
else:
|
|
if AzSun >= 0:
|
|
AzSun=AzSun
|
|
else:
|
|
AzSun = AzSun+pi
|
|
|
|
X0= -cos(AltSun)*sin(AzSun)
|
|
Y0= -cos(AltSun)*cos(AzSun)
|
|
Z0= sin(AltSun)
|
|
|
|
X1=X0*cos(W)-Y0*sin(W)
|
|
Y1=X0*sin(W)+Y0*cos(W)
|
|
Z1=Z0
|
|
|
|
X2=X1
|
|
Y2=Y1*cos(R)-Z1*sin(R)
|
|
Z2=Y1*sin(R)+Z1*cos(R)
|
|
|
|
X3=so.gnom*X2/Y2
|
|
Z3=so.gnom*Z2/Y2
|
|
|
|
Xe = X3 - Xf
|
|
Ze = -Z3 + Zf
|
|
|
|
if Ze == 0:
|
|
Ze = 0.0001
|
|
|
|
SG = atan(Xe/Ze)
|
|
#Xe = so.gnom /((cos(R)/tan(AzSun-W))+(sin(R)*tan(AltSun)/sin(AzSun-W))) - Xf
|
|
#Ze = -so.gnom *((tan(R)-(tan(AltSun)/cos(AzSun-W)))/(1+(tan(R)*tan(AltSun))/cos(AzSun-W))) + Zf
|
|
p1= X0*A+Y0*B+Z0*C
|
|
|
|
if p1 >=0:
|
|
#if SG <= pi and SG >=-pi:
|
|
TL = TL +' '+str(Xe)+', '+str(Ze)
|
|
else:
|
|
Xe=-Xe
|
|
Ze=-Ze
|
|
TL = TL +' '+str(Xe)+', '+str(Ze)
|
|
|
|
if T[i] < 0:
|
|
if SG >= 0:
|
|
SG = SG-pi
|
|
else:
|
|
SG = SG
|
|
else:
|
|
if SG >= 0:
|
|
SG = SG
|
|
else:
|
|
SG = SG+pi
|
|
|
|
if SG >= (-pi) and SG < -ALFA:
|
|
draw_SVG_text(-widthgrid/2+5, -widthgrid/(2*tan(SG)), str(Time[i]), 'Algerian', 8, vhl)
|
|
|
|
if SG > (-ALFA) and SG < ALFA:
|
|
draw_SVG_text(heightgrid*tan(SG), heightgrid-5, str(Time[i]), 'Algerian',8, vhl)
|
|
|
|
if SG > ALFA and SG <= (pi):
|
|
if Time[i] == 12: #workaround because y coordinate gets extreme values like "-816561967659768448.0000"
|
|
draw_SVG_text(0, heightgrid-5, str(Time[i]), 'Algerian',8, vhl)
|
|
else:
|
|
draw_SVG_text(widthgrid/2-8, widthgrid/(2*tan(SG)), str(Time[i]), 'Algerian',8, vhl)
|
|
#Text
|
|
#textvalue='Xe: %s; Ze: %s; T: %s; SG: %s' % (round(Xe,2), round(Ze,2), Time[i], SG*180/pi)
|
|
#draw_SVG_text(0, 220+5*i, textvalue, 'san-serif', 4, gly)
|
|
|
|
# draw polyline
|
|
draw_SVG_polyline(TL, 0.5,'#008000', 'none', 'Time line '+str(Time[i]), loz)
|
|
|
|
if __name__ == '__main__':
|
|
sundialDeclining().run() |