#!/usr/bin/env python """ Copyright (c) 2020 Sublunar Psionics ---- MIT License ---- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import sys import time import math import swisseph as swe import drawSvg as svg from openlocationcode import openlocationcode as olc def astroChart(lat, lon, epoch, canvas, colors = ['violet', 'yellow', 'white', 'orange', 'green', 'red', 'royalblue', 'indigo']): print("drawing astro chart for", epoch) planets = [0,1,2,3,4,5,6] tmp = time.gmtime(epoch) # convert epoch to time hours = tmp.tm_hour + tmp.tm_min / 60 + tmp.tm_sec / 3600 # convert hh:mm:ss to decimal hours jd = swe.julday(tmp.tm_year,tmp.tm_mon,tmp.tm_mday,hours,1) # convert to Julian day te = jd + swe.deltat(jd) # add deltaT # get ecliptic planet locations for i in range(len(planets)): planets[i] = swe.calc(te, i) # clean up for i in range(len(planets)): planets[i] = planets[i][0][0] cusps = swe.houses_ex(jd, lat, lon, b'P',0) # get ecliptic ascendant degree planets.insert(0, cusps[0][0]) # add to list # draw arcs for ascendant + planets for i in range(len(planets)): circleColor = colors[i] degree = planets[i] startArc = degree + 90 # 0° is at the 12 o'clock position endArc = degree - 110 + 90 radius = 180 + i * 10 canvas.append(svg.ArcLine(0, 0, radius, startArc, endArc, stroke=circleColor, stroke_width=7, fill='none')) def magicSquareSigil(plusCode, canvas, color='white'): # draw sigil based on OLC magic square codeList = list(plusCode.replace('+', '')) # remove the + in the string print("sigilizing", codeList) length = len(codeList) grid = { 'R' : [-103, 112], 'V' : [-35, 112], 'W' : [35, 112], 'X' : [103, 112], # | R | V | W | X | 'J' : [-103, 56], 'M' : [-35, 56], 'P' : [35, 56], 'Q' : [103, 56], # | J | M | P | Q | 'C' : [-103, 0], 'F' : [-35, 0], 'G' : [35, 0], 'H' : [103, 0], # | C | F | G | H | '6' : [-103, -56], '7' : [-35, -56], '8' : [35, -56], '9' : [103, -56], # | 6 | 7 | 8 | 9 | '2' : [-103, -112], '3' : [-35, -112], '4' : [35, -112], '5' : [103, -112] # | 2 | 3 | 4 | 5 | } # setup sigil dash = svg.Marker(-0.5, -0.5, 0.5, 0.5, scale=5, orient='auto') # define line to terminate the sigil dash.append(svg.Line(-0., -0.5, 0., 0.5, stroke_width=0.2, stroke=color)) dot = svg.Marker(-0.8, -0.5, 0.5, 0.5, scale=5, orient='auto') # define circle to start the sigil dot.append(svg.Circle(-0.3, 0.0, 0.3, stroke_width=0.2, stroke=color, fill='none')) p = svg.Path(stroke_width=7, stroke=color, fill='none', marker_start=dot, marker_end=dash) # draw sigil for c in range(length): if c == 0: originX = grid[codeList[0]][0] originY = grid[codeList[0]][1] p.M(originX, originY) else: x = grid[codeList[c]][0] - originX # abs. to rel. coords y = grid[codeList[c]][1] - originY # abs. to rel. coords p.l(x, y) # draw originX = grid[codeList[c]][0] originY = grid[codeList[c]][1] # add to canvas canvas.append(p) def radialSigil(plusCode, canvas, color='red'): # draw sigil based on concentric circle positions codeList = list(plusCode.replace('+', '')) # remove the + in the string print("sigilizing", codeList) length = len(codeList) decoder = ['2', '3', '4', '5', '6', '7', '8', '9', 'C', 'F', 'G', 'H', 'J', 'M', 'P', 'Q', 'R', 'V', 'W', 'X'] #draw global area sigil arrow2 = svg.Marker(-0.5, -0.5, 0.5, 0.5, scale=5, orient='auto') # define line to terminate the sigil arrow2.append(svg.Line(-0., -0.5, 0., 0.5, stroke_width=0.2, stroke=color)) dot2 = svg.Marker(-0.8, -0.5, 0.5, 0.5, scale=5, orient='auto') # define circle to start the sigil dot2.append(svg.Circle(-0.3, 0.0, 0.3, stroke_width=0.2, stroke=color, fill='none')) # set up sigil path p = svg.Path(stroke_width=7, stroke=color, fill='none', marker_start=dot2, marker_end=arrow2) for c in range(length): index = decoder.index(codeList[c]) # find coordinates on circle every 18° (360° / 20 digits) radius = 145 - c * 20 angle = 18 * index x = radius * math.cos(angle) y = radius * math.sin(angle) if c == 0: p.M(x,y) # starting point originX = x originY = y else: p.l(x - originX, y - originY) # draw originX = x originY = y canvas.append(p) def nameToPlusCode(name): vowels = [ 'A', 'E', 'I', 'O', 'U'] translate = { 'B' : '2', 'D' : '3', 'K' : '4', 'L' : '5', 'N' : '6', 'S' : '7', 'T' : '8', 'Z' : '9', 'Y' : 'J' } newName = name.upper().replace(" ", "") for x in newName: if x in vowels: newName = newName.replace(x,"") if x in translate.keys(): newName = newName.replace(x, translate[x]) return newName def drawSigil(lat, lon, epoch, squareSigilize, radialSigilize, fileName): # set up SVG canvas d = svg.Drawing(600, 600, origin='center') # define canvas # Create gradients gradient = svg.RadialGradient(0,0,260) gradient.addStop(0, '#211d05', 1) gradient.addStop(1, 'black', 1) rusty = svg.RadialGradient(0,0,260) rusty.addStop(0.5, '#d17b0a', 1) rusty.addStop(1, '#453905', 1) silver = svg.RadialGradient(0,0,260) silver.addStop(0.5, 'white', 0.8) silver.addStop(1, 'grey', 1) # Background circle c = svg.Circle(0, 0, 260, fill=gradient, stroke_width=0) d.append(c) # draw astro chart for epoch moment astroChart(lat, lon, epoch, d, [rusty, rusty, rusty, rusty, rusty, rusty, rusty, rusty]) # draw sigils radialSigil(radialSigilize, d) magicSquareSigil(squareSigilize, d) # save sigil to SVG file d.saveSvg(fileName) def main(): argNo = len(sys.argv) - 1 if argNo == 5: # if coordinates, timestamp, and two strings (first + last name)are provided lat = float(sys.argv[1]) lon = float(sys.argv[2]) epoch = float(sys.argv[3]) squareSigilize = nameToPlusCode(sys.argv[4]) # first name radialSigilize = nameToPlusCode(sys.argv[5]) # last name fileName = '%s_%s.svg' % (sys.argv[5], sys.argv[4]) drawSigil(lat, lon, epoch, squareSigilize, radialSigilize, fileName) if argNo == 3: # if coordinates, and timestamp are provided lat = float(sys.argv[1]) lon = float(sys.argv[2]) epoch = float(sys.argv[3]) plusCode = olc.encode(lat,lon,10) # generate Open Location Code aka. plus code from coordinates squareSigilize = plusCode[4:] radialSigilize = plusCode[0:4] fileName = '%s-%s.svg' % (plusCode, epoch) drawSigil(lat, lon, epoch, squareSigilize, radialSigilize, fileName) if argNo == 2: # if just coordinates are provided lat = float(sys.argv[1]) lon = float(sys.argv[2]) epoch = time.time() plusCode = olc.encode(lat,lon,10) # generate Open Location Code aka. plus code from coordinates squareSigilize = plusCode[4:] radialSigilize = plusCode[0:4] fileName = '%s-%s.svg' % (plusCode, epoch) drawSigil(lat, lon, epoch, squareSigilize, radialSigilize, fileName) else: print("--------------------------------------------") print("Please provide arguments: ( )") print("--------------------------------------------") print("If you only provide latitude and longitude, the timestamp is calculated automatically for this moment.") print("If you provice first- and last name of a person, please provide their birth-location coordinates and birth-time as geospatial arguments") print("--------------------------------------------") if __name__ == "__main__": main()