diff --git a/extensions/fablabchemnitz_sundial_declining.inx b/extensions/fablabchemnitz_sundial_declining.inx new file mode 100644 index 00000000..e6a1cfa8 --- /dev/null +++ b/extensions/fablabchemnitz_sundial_declining.inx @@ -0,0 +1,46 @@ + + + <_name>Sundial Declining + fablabchemnitz.de.sundialdeclining + + + Location coordinates + 50 + 16 + 0 + false + + + Add 1 + 40 + 40 + <_param name="instructions" type="description" xml:space="preserve"> ( + West; - East) + 0 + <_param name="instructions" type="description" xml:space="preserve"> ( + x; - x) + + + Add 2 + + 0 + 3 + 7 + + + + +* Latitude from +10 to +70 +* Longitude (+ to E) from -180 to 180 +* Time Zone (+ to E) from -12 to 12 + + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz_sundial_declining.py b/extensions/fablabchemnitz_sundial_declining.py new file mode 100644 index 00000000..98e09e18 --- /dev/null +++ b/extensions/fablabchemnitz_sundial_declining.py @@ -0,0 +1,328 @@ +#!/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 SunDial(inkex.Effect): + def __init__(self): + inkex.Effect.__init__(self) + self.arg_parser.add_argument("--latitude", type=float, dest="latitude", default="50.3515") + self.arg_parser.add_argument("--longitude", type=float, dest="longitude", default="15.7512") + self.arg_parser.add_argument("--timezone", type=int, dest="timezone", default="0") + self.arg_parser.add_argument("--summer_time", type=inkex.Boolean, dest="summer_time", default='False') + self.arg_parser.add_argument("--gnom", type=float, dest="gnom", default="30") + self.arg_parser.add_argument("--decl", type=float, dest="decl", default="0") + self.arg_parser.add_argument("--incl", type=float, dest="incl", default="0") + self.arg_parser.add_argument("--DL", type=float, dest="DL", default="0") + self.arg_parser.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__': + SunDial().run() \ No newline at end of file