libaditya 0.3.4__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. libaditya/__init__.py +46 -0
  2. libaditya/_version.py +29 -0
  3. libaditya/calc/__init__.py +9 -0
  4. libaditya/calc/api.py +30 -0
  5. libaditya/calc/avasthas.py +346 -0
  6. libaditya/calc/docs/jaimini-get-arch.md +95 -0
  7. libaditya/calc/hellenistic.py +37 -0
  8. libaditya/calc/jaimini.py +335 -0
  9. libaditya/calc/jaimini_get.py +240 -0
  10. libaditya/calc/kala.py +73 -0
  11. libaditya/calc/panchanga.py +422 -0
  12. libaditya/calc/rashi.py +612 -0
  13. libaditya/calc/returns.py +50 -0
  14. libaditya/calc/swe_functions.py +118 -0
  15. libaditya/calc/varga.py +287 -0
  16. libaditya/calc/vimshottari.py +431 -0
  17. libaditya/cards/__init__.py +5 -0
  18. libaditya/cards/card.py +90 -0
  19. libaditya/cards/cards_constants.py +115 -0
  20. libaditya/cards/cards_of_truth.py +323 -0
  21. libaditya/cards/cot.py +142 -0
  22. libaditya/cards/deck.py +52 -0
  23. libaditya/charts/__init__.py +6 -0
  24. libaditya/charts/api.py +36 -0
  25. libaditya/charts/bodygraph.py +80 -0
  26. libaditya/charts/chart.py +286 -0
  27. libaditya/charts/jaimini.py +83 -0
  28. libaditya/charts/tajika.py +36 -0
  29. libaditya/constants.py +1776 -0
  30. libaditya/draw/__init__.py +20 -0
  31. libaditya/draw/draw_bodygraph.py +489 -0
  32. libaditya/draw/draw_sbc.py +712 -0
  33. libaditya/draw/themes/default-theme.hd +53 -0
  34. libaditya/ephe/ast0/se00010s.se1 +0 -0
  35. libaditya/ephe/seas_00.se1 +0 -0
  36. libaditya/ephe/seas_06.se1 +0 -0
  37. libaditya/ephe/seas_12.se1 +0 -0
  38. libaditya/ephe/seas_18.se1 +0 -0
  39. libaditya/ephe/seas_24.se1 +0 -0
  40. libaditya/ephe/seas_30.se1 +0 -0
  41. libaditya/ephe/seas_36.se1 +0 -0
  42. libaditya/ephe/seas_42.se1 +0 -0
  43. libaditya/ephe/seas_48.se1 +0 -0
  44. libaditya/ephe/seasm06.se1 +0 -0
  45. libaditya/ephe/seasm12.se1 +0 -0
  46. libaditya/ephe/seasm18.se1 +0 -0
  47. libaditya/ephe/seasm24.se1 +0 -0
  48. libaditya/ephe/seasm30.se1 +0 -0
  49. libaditya/ephe/seasm36.se1 +0 -0
  50. libaditya/ephe/seasm42.se1 +0 -0
  51. libaditya/ephe/seasm48.se1 +0 -0
  52. libaditya/ephe/seasm54.se1 +0 -0
  53. libaditya/ephe/sefstars.txt +4245 -0
  54. libaditya/ephe/semo_00.se1 +0 -0
  55. libaditya/ephe/semo_06.se1 +0 -0
  56. libaditya/ephe/semo_12.se1 +0 -0
  57. libaditya/ephe/semo_18.se1 +0 -0
  58. libaditya/ephe/semo_24.se1 +0 -0
  59. libaditya/ephe/semo_30.se1 +0 -0
  60. libaditya/ephe/semo_36.se1 +0 -0
  61. libaditya/ephe/semo_42.se1 +0 -0
  62. libaditya/ephe/semo_48.se1 +0 -0
  63. libaditya/ephe/semom06.se1 +0 -0
  64. libaditya/ephe/semom12.se1 +0 -0
  65. libaditya/ephe/semom18.se1 +0 -0
  66. libaditya/ephe/semom24.se1 +0 -0
  67. libaditya/ephe/semom30.se1 +0 -0
  68. libaditya/ephe/semom36.se1 +0 -0
  69. libaditya/ephe/semom42.se1 +0 -0
  70. libaditya/ephe/semom48.se1 +0 -0
  71. libaditya/ephe/semom54.se1 +0 -0
  72. libaditya/ephe/sepl_00.se1 +0 -0
  73. libaditya/ephe/sepl_06.se1 +0 -0
  74. libaditya/ephe/sepl_12.se1 +0 -0
  75. libaditya/ephe/sepl_18.se1 +0 -0
  76. libaditya/ephe/sepl_24.se1 +0 -0
  77. libaditya/ephe/sepl_30.se1 +0 -0
  78. libaditya/ephe/sepl_36.se1 +0 -0
  79. libaditya/ephe/sepl_42.se1 +0 -0
  80. libaditya/ephe/sepl_48.se1 +0 -0
  81. libaditya/ephe/seplm06.se1 +0 -0
  82. libaditya/ephe/seplm12.se1 +0 -0
  83. libaditya/ephe/seplm18.se1 +0 -0
  84. libaditya/ephe/seplm24.se1 +0 -0
  85. libaditya/ephe/seplm30.se1 +0 -0
  86. libaditya/ephe/seplm36.se1 +0 -0
  87. libaditya/ephe/seplm42.se1 +0 -0
  88. libaditya/ephe/seplm48.se1 +0 -0
  89. libaditya/ephe/seplm54.se1 +0 -0
  90. libaditya/hd/__init__.py +8 -0
  91. libaditya/hd/calc.py +55 -0
  92. libaditya/hd/constants.py +127 -0
  93. libaditya/hd/longitude.py +271 -0
  94. libaditya/objects/__init__.py +19 -0
  95. libaditya/objects/celestial_object.py +206 -0
  96. libaditya/objects/context.py +133 -0
  97. libaditya/objects/cusps.py +259 -0
  98. libaditya/objects/julian_day.py +265 -0
  99. libaditya/objects/location.py +167 -0
  100. libaditya/objects/longitude.py +987 -0
  101. libaditya/objects/nakshatras.py +285 -0
  102. libaditya/objects/planets.py +2059 -0
  103. libaditya/objects/shadbala.py +398 -0
  104. libaditya/objects/signs.py +690 -0
  105. libaditya/objects/swe_functions.py +75 -0
  106. libaditya/print_functions.py +548 -0
  107. libaditya/read.py +665 -0
  108. libaditya/stars/__init__.py +4 -0
  109. libaditya/stars/fixed_star.py +216 -0
  110. libaditya/stars/make_swe_stars.py +407 -0
  111. libaditya/stars/star-sign-boundaries +44 -0
  112. libaditya/stars/stellarium/__init__.py +6 -0
  113. libaditya/stars/stellarium/remote_control/__init__.py +22 -0
  114. libaditya/stars/stellarium/remote_control/location.py +82 -0
  115. libaditya/stars/stellarium/remote_control/locationsearch.py +35 -0
  116. libaditya/stars/stellarium/remote_control/main.py +165 -0
  117. libaditya/stars/stellarium/remote_control/objects.py +63 -0
  118. libaditya/stars/stellarium/remote_control/scripts.py +81 -0
  119. libaditya/stars/stellarium/remote_control/simbad.py +20 -0
  120. libaditya/stars/stellarium/remote_control/stelaction.py +31 -0
  121. libaditya/stars/stellarium/remote_control/stelproperty.py +30 -0
  122. libaditya/stars/stellarium/remote_control/view.py +85 -0
  123. libaditya/stars/stellarium/stellarium.py +92 -0
  124. libaditya/stars/the_stars.py +522 -0
  125. libaditya/stars/utilities.py +539 -0
  126. libaditya/utils.py +431 -0
  127. libaditya/write.py +67 -0
  128. libaditya-0.3.4.dist-info/METADATA +588 -0
  129. libaditya-0.3.4.dist-info/RECORD +131 -0
  130. libaditya-0.3.4.dist-info/WHEEL +5 -0
  131. libaditya-0.3.4.dist-info/licenses/LICENSE +661 -0
@@ -0,0 +1,20 @@
1
+ # This file is part of libaditya.
2
+ #
3
+ # Copyright (c) 2025 Josh Harper <humanhaven@substack.com>
4
+ #
5
+ # libaditya is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # libaditya is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with libaditya. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+
19
+ from .draw_bodygraph import DrawBodyGraph
20
+ from .draw_sbc import DrawSBC
@@ -0,0 +1,489 @@
1
+ # This file is part of libaditya.
2
+ #
3
+ # Copyright (c) 2025 Josh Harper <humanhaven@substack.com>
4
+ #
5
+ # libaditya is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # libaditya is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with libaditya. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ import drawsvg as draw
19
+
20
+ from libaditya import constants as const
21
+ from libaditya.hd import constants as hdc
22
+
23
+ class DrawBodyGraph:
24
+ """
25
+ Mixin that inherits unto charts.bodygraph.Bodygraph in order to drawsvg this bodygraph
26
+ """
27
+
28
+ def draw_svg(self, theme_file=hdc.default_theme, outfile=None):
29
+ """
30
+ output a .svg of this bodygraph
31
+
32
+ default outfile is name associated with the chart, all lowercase, spaces replaced with "-"
33
+ if there is no name and outfile=None, then it uses the julianday number as the file name
34
+ """
35
+ d = draw.Drawing(500, 500)
36
+ # initialize the theme from the theme_file
37
+ theme = const.init_theme(theme_file)
38
+ theme["gates"] = self.gates_theme(theme["gates"])
39
+ theme = self.get_defined_centers(theme,self.all_gates())
40
+ d = self.draw_bodygraph(d,theme,self.conscious_planets().gates(),self.unconscious_planets().gates(),self.context.get_info_str_hd(),self.unconscious_planets().context.get_info_str_hd())
41
+ # display to the correct output file
42
+ d.set_pixel_scale(1)
43
+ if outfile == None:
44
+ name = self.context.name.lower().replace(" ","-")
45
+ if not name:
46
+ # if name is empty, use julian day number
47
+ name = f"{self.context.timeJD.jd_number()}"
48
+ foutname = f"{name}.svg"
49
+ else:
50
+ foutname = outfile
51
+ d.save_svg(foutname)
52
+ d
53
+
54
+ def get_defined_centers(self,theme,gates):
55
+ """
56
+ determine which centers are defined
57
+ center colors and undefined centers are given in theme
58
+ we check if a center is defined, if it is we leave the
59
+ theme[center] alone; if the center is undefined, we change
60
+ that to theme[center]=undefined
61
+ """
62
+
63
+ # gates[n] is a floating point gate.line
64
+ # so transform to int(gate)
65
+ gates = [int(str(x).split('.')[0]) for x in gates]
66
+
67
+ head = False
68
+ ajna = False
69
+ throat = False
70
+ ji = False
71
+ sacral = False
72
+ root = False
73
+ spleen = False
74
+ solar = False
75
+ will = False
76
+
77
+ if 64 in gates and 47 in gates:
78
+ head = True
79
+ ajna = True
80
+ if 61 in gates and 24 in gates:
81
+ head = True
82
+ ajna = True
83
+ if 63 in gates and 4 in gates:
84
+ head = True
85
+ ajna = True
86
+ if 17 in gates and 62 in gates:
87
+ ajna = True
88
+ throat = True
89
+ if 43 in gates and 23 in gates:
90
+ ajna = True
91
+ throat = True
92
+ if 11 in gates and 56 in gates:
93
+ ajna = True
94
+ throat = True
95
+ if 31 in gates and 7 in gates:
96
+ throat = True
97
+ ji = True
98
+ if 8 in gates and 1 in gates:
99
+ throat = True
100
+ ji = True
101
+ if 33 in gates and 13 in gates:
102
+ throat = True
103
+ ji = True
104
+ if 15 in gates and 5 in gates:
105
+ ji = True
106
+ sacral = True
107
+ if 2 in gates and 14 in gates:
108
+ ji = True
109
+ sacral = True
110
+ if 46 in gates and 29 in gates:
111
+ ji = True
112
+ sacral = True
113
+ if 42 in gates and 53 in gates:
114
+ sacral = True
115
+ root = True
116
+ if 3 in gates and 60 in gates:
117
+ sacral = True
118
+ root = True
119
+ if 9 in gates and 52 in gates:
120
+ sacral = True
121
+ root = True
122
+ if 16 in gates and 48 in gates:
123
+ throat = True
124
+ spleen = True
125
+ if 20 in gates and 57 in gates:
126
+ throat = True
127
+ spleen = True
128
+ if 35 in gates and 36 in gates:
129
+ throat = True
130
+ solar = True
131
+ if 12 in gates and 22 in gates:
132
+ throat = True
133
+ solar = True
134
+ if 45 in gates and 21 in gates:
135
+ throat = True
136
+ will = True
137
+ if 25 in gates and 51 in gates:
138
+ ji = True
139
+ will = True
140
+ if 37 in gates and 40 in gates:
141
+ solar = True
142
+ will = True
143
+ if 44 in gates and 26 in gates:
144
+ spleen = True
145
+ will = True
146
+ if 59 in gates and 6 in gates:
147
+ sacral = True
148
+ solar = True
149
+ if 27 in gates and 50 in gates:
150
+ sacral = True
151
+ spleen = True
152
+ if 34 in gates and 57 in gates:
153
+ sacral = True
154
+ spleen = True
155
+ if 34 in gates and 10 in gates:
156
+ sacral = True
157
+ ji = True
158
+ if 34 in gates and 20 in gates:
159
+ sacral = True
160
+ throat = True
161
+ if 32 in gates and 54 in gates:
162
+ spleen = True
163
+ root = True
164
+ if 57 in gates and 10 in gates:
165
+ spleen = True
166
+ ji = True
167
+ if 28 in gates and 38 in gates:
168
+ spleen = True
169
+ root = True
170
+ if 18 in gates and 58 in gates:
171
+ spleen = True
172
+ root = True
173
+ if 49 in gates and 19 in gates:
174
+ solar = True
175
+ root = True
176
+ if 55 in gates and 39 in gates:
177
+ solar = True
178
+ root = True
179
+ if 30 in gates and 41 in gates:
180
+ solar = True
181
+ root = True
182
+
183
+ if not head:
184
+ theme["head"]=theme["undefined"]
185
+ if not ajna:
186
+ theme["ajna"]=theme["undefined"]
187
+ if not throat:
188
+ theme["throat"]=theme["undefined"]
189
+ if not ji:
190
+ theme["ji"]=theme["undefined"]
191
+ if not sacral:
192
+ theme["sacral"]=theme["undefined"]
193
+ if not root:
194
+ theme["root"]=theme["undefined"]
195
+ if not spleen:
196
+ theme["spleen"]=theme["undefined"]
197
+ if not solar:
198
+ theme["solar"]=theme["undefined"]
199
+ if not will:
200
+ theme["will"]=theme["undefined"]
201
+
202
+ return theme
203
+
204
+ # centers are always taken care of in this order
205
+ # head
206
+ # ajna
207
+ # throat
208
+ # ji
209
+ # sacral
210
+ # root
211
+ # spleen
212
+ # solar
213
+ # will
214
+ def draw_bodygraph(self,d,theme,cgates,ugates,rstr,lstr):
215
+
216
+ d.append(draw.Rectangle(0, 0, 500, 500, rx=None, ry=None, fill=theme["background"]))
217
+
218
+ # draw the channels
219
+ # technically, draw the half-channel for each gate that is defined
220
+ d = self.draw_channels(d,theme,cgates,ugates)
221
+
222
+ # draw the centers and color them according to defined or undefined
223
+ d = self.draw_centers(d,theme)
224
+
225
+ # theme["gates"] is 0 for numbers, 1 for hexagrams
226
+ # corresponding to the proper index of the gate tuple
227
+ # in the hdc.gates dictionary
228
+ # this draws the gate numbers/hexagrams in the centers
229
+ d = self.draw_gates(d,theme,cgates+ugates)
230
+
231
+ # draw the gate information on the sides of the bodygraph
232
+ d = self.draw_gate_boxes(d,theme,cgates,ugates)
233
+
234
+ # info boxes mean the name and birth or time/date information
235
+ d = self.draw_info_boxes(d,theme,rstr,lstr)
236
+
237
+ return d
238
+
239
+ def draw_centers(self,d,theme):
240
+ # draw head center
241
+ head = draw.Lines(210, 50, 250, 10, 290, 50, 210, 50, stroke=theme["lines"], fill=theme["head"])
242
+ d.append(head)
243
+
244
+ # draw ajna center
245
+ ajna = draw.Lines(210, 70, 250, 120, 290, 70, 210, 70, stroke=theme["lines"], fill=theme["ajna"])
246
+ d.append(ajna)
247
+
248
+ # draw throat center
249
+ throat = draw.Rectangle(220,140,60,60,rx=5,stroke=theme["lines"], fill=theme["throat"])
250
+ d.append(throat)
251
+
252
+ # draw ji center
253
+ ji = draw.Rectangle(220,210,60,60,rx=5,stroke=theme["lines"],transform="rotate(45,230,250)", fill=theme["ji"])
254
+ d.append(ji)
255
+
256
+ # draw sacral center
257
+ sacral = draw.Rectangle(220,330,60,60,rx=5,stroke=theme["lines"], fill=theme["sacral"])
258
+ d.append(sacral)
259
+
260
+ # draw root center
261
+ root = draw.Rectangle(220,420,60,60,rx=5,stroke=theme["lines"], fill=theme["root"])
262
+ d.append(root)
263
+
264
+ # draw spleen center
265
+ spleen = draw.Lines(100, 400, 100, 330, 170, 365, 100, 400, stroke=theme["lines"], fill=theme["spleen"])
266
+ d.append(spleen)
267
+
268
+ # draw solar center
269
+ solar = draw.Lines(400, 400, 400, 330, 330, 370, 400, 400, stroke=theme["lines"], fill=theme["solar"])
270
+ d.append(solar)
271
+
272
+ # draw will center
273
+ will = draw.Lines(295, 300, 315, 255, 360, 290, 295, 300, stroke=theme["lines"], fill=theme["will"])
274
+ d.append(will)
275
+
276
+ return d
277
+
278
+
279
+ def draw_gates(self,d,theme,gates):
280
+
281
+ gtype = theme["gates"]
282
+ gx = 2
283
+ gy = 3
284
+
285
+ # for drawing circles around defined gates
286
+ #gates=[int(x) for x in gates]
287
+
288
+ # make an x-coordinate offset for when printing gates as hexagrams
289
+ xoff = 0
290
+ if gtype == 1:
291
+ xoff = 2
292
+
293
+ for i in range(1,65):
294
+ d.append(draw.Text(hdc.gates[i][gtype],x=xoff+hdc.gates[i][gx],y=hdc.gates[i][gy], font_size=10))
295
+ # for drawing circles around defined gates, but i dont like how it looks
296
+ #if i in gates:
297
+ #d.append(draw.Circle(xoff+hdc.gates[i][gx]+6,hdc.gates[i][gy]-3,6,stroke="black",fill="none"))
298
+
299
+ return d
300
+
301
+ def gates_theme(self, argsgates):
302
+ # choose how gates will be displayed on the bodygraph and sides
303
+ # 0 and 1 are the indexes for pconst.gates which hold
304
+ # a string representation of the number and the hexgram respectively
305
+ gatestheme = 0
306
+ if argsgates:
307
+ if argsgates == "numbers":
308
+ gatestheme = 0
309
+ elif argsgates == "hexagrams":
310
+ gatestheme = 1
311
+ else: # wrong argument or a type, use numbers
312
+ print(f"argument was given but not recognized; check spelling; using numbers for gates")
313
+ gatestheme = 0
314
+ else:
315
+ if gatestheme == "numbers":
316
+ gatestheme = 0
317
+ if gatestheme == "hexagrams":
318
+ gatestheme = 1
319
+ return gatestheme
320
+
321
+ def draw_channels(self,d,theme,cgates,ugates):
322
+ """
323
+ each gate draws into own half of the channel
324
+ they meet in the middle
325
+
326
+ if an gate is both unconscious and conscious
327
+ draw the unconscious first, then draw the conscious one
328
+ with stroke_dasharray='5,9'), which will cause it to have
329
+ dashes in both collors, like this:
330
+ d.append(draw.Line(140,350,300,297, stroke="orange", stroke_width=5, stroke_dasharray='5,9'))
331
+
332
+ if just one is defined, draw the whole channel with that color
333
+ """
334
+
335
+ # since some channels need to be drawn below others
336
+ # this list is that order; that is why it is not done with
337
+ # a simple range() loop
338
+ gs=[57,10,34,44,26,12,22,35,36,21,45,51,25,20,40,37,59,6,27,50,48,16,58,18,38,28,54,32,41,30,39,55,19,49,64,47,61,24,63,4,17,62,11,56,43,23,31,7,1,8,33,13,15,5,46,29,2,14,42,53,3,60,9,52]
339
+
340
+ # take out the chiron gate, since we print it, but it does not acutally activate a gate
341
+ if len(cgates) == 14:
342
+ cgates = cgates[:13]
343
+ if len(ugates) == 14:
344
+ ugates = ugates[:13]
345
+ if len(cgates) == 28:
346
+ cgates = cgates[:13]+cgates[14:27]
347
+ if len(ugates) == 28:
348
+ ugates = ugates[:13]+ugates[14:27]
349
+
350
+ # indexes of coordinates in hdc.gates
351
+ csx=4
352
+ csy=5
353
+ cex=6
354
+ cey=7
355
+
356
+ # cgates and ugates contain a float, gate.line, so get rid of the line number
357
+ cgates=[int(x) for x in cgates]
358
+ ugates=[int(x) for x in ugates]
359
+
360
+ # for channels between 57,34,10,20
361
+ # need to do some manual drawing
362
+ for g in gs:
363
+ if g in cgates and g in ugates:
364
+ d.append(draw.Line(hdc.gates[g][csx],hdc.gates[g][csy],hdc.gates[g][cex],hdc.gates[g][cey], stroke=theme["unconscious"], stroke_width=5))
365
+ d.append(draw.Line(hdc.gates[g][csx],hdc.gates[g][csy],hdc.gates[g][cex],hdc.gates[g][cey], stroke=theme["conscious"], stroke_width=5, stroke_dasharray='2,2'))
366
+ if g == 34:
367
+ # draw extra line towards
368
+ if 20 in cgates or 20 in ugates:
369
+ d.append(draw.Line(140,311,180,230, stroke=theme["unconscious"], stroke_width=5))
370
+ d.append(draw.Line(140,311,180,230, stroke=theme["conscious"], stroke_width=5, stroke_dasharray='2,2'))
371
+ if 10 in cgates or 10 in ugates:
372
+ d.append(draw.Line(140,311,167,258, stroke=theme["unconscious"], stroke_width=5))
373
+ d.append(draw.Line(140,311,167,258, stroke=theme["conscious"], stroke_width=5, stroke_dasharray='2,2'))
374
+ if g == 10:
375
+ if 20 in cgates or 20 in ugates:
376
+ d.append(draw.Line(167,258,180,230, stroke=theme["unconscious"], stroke_width=5))
377
+ d.append(draw.Line(167,258,180,230, stroke=theme["conscious"], stroke_width=5, stroke_dasharray='2,2'))
378
+ elif g in cgates:
379
+ d.append(draw.Line(hdc.gates[g][csx],hdc.gates[g][csy],hdc.gates[g][cex],hdc.gates[g][cey], stroke=theme["conscious"], stroke_width=5))
380
+ if g == 34:
381
+ # draw extra line towards
382
+ if 20 in cgates or 20 in ugates:
383
+ d.append(draw.Line(140,311,180,230, stroke=theme["conscious"], stroke_width=5))
384
+ if 10 in cgates or 10 in ugates:
385
+ d.append(draw.Line(140,311,167,258, stroke=theme["conscious"], stroke_width=5))
386
+ if g == 10:
387
+ if 20 in cgates or 20 in ugates:
388
+ d.append(draw.Line(167,258,180,230, stroke=theme["conscious"], stroke_width=5))
389
+ elif g in ugates:
390
+ d.append(draw.Line(hdc.gates[g][csx],hdc.gates[g][csy],hdc.gates[g][cex],hdc.gates[g][cey], stroke=theme["unconscious"], stroke_width=5))
391
+ if g == 34:
392
+ # draw extra line towards
393
+ if 20 in cgates or 20 in ugates:
394
+ d.append(draw.Line(140,311,180,230, stroke=theme["unconscious"], stroke_width=5))
395
+ if 10 in cgates or 10 in ugates:
396
+ d.append(draw.Line(140,311,167,258, stroke=theme["unconscious"], stroke_width=5))
397
+ if g == 10:
398
+ if 20 in cgates or 20 in ugates:
399
+ d.append(draw.Line(167,258,180,230, stroke=theme["unconscious"], stroke_width=5))
400
+ else:
401
+ d.append(draw.Line(hdc.gates[g][csx],hdc.gates[g][csy],hdc.gates[g][cex],hdc.gates[g][cey], stroke=theme["undefined"], stroke_width=5))
402
+
403
+ return d
404
+
405
+ def draw_gate_boxes(self,d,theme,cgates,ugates):
406
+ cx=450
407
+ ux=30
408
+ y=15
409
+
410
+ if len(ugates) == 14:
411
+ # just a bodygraph
412
+ d.append(draw.Text("Personality",font_size=10,x=cx-20,y=8,stroke=theme["right-text"]))
413
+ d.append(draw.Text("Design",font_size=10,x=ux,y=8,stroke=theme["left-text"]))
414
+ elif len(ugates) == 28 and len(cgates) == 14:
415
+ # a bodygraph and transit chart; bodygraph gates on left, transit on right
416
+ d.append(draw.Text("Transit",font_size=10,x=cx-3,y=8,stroke=theme["right-text"]))
417
+ d.append(draw.Text("D",font_size=10,x=ux+5,y=8,stroke=theme["left-text"]))
418
+ d.append(draw.Text("P",font_size=10,x=ux+37,y=8,stroke=theme["left-text"]))
419
+ elif len(ugates) == 28 and len(cgates) == 28:
420
+ # this is a composite chart, so two sets of gates on each side
421
+ d.append(draw.Text("D",font_size=10,x=cx,y=8,stroke=theme["right-text"]))
422
+ d.append(draw.Text("P",font_size=10,x=cx+30,y=8,stroke=theme["right-text"]))
423
+ d.append(draw.Text("D",font_size=10,x=ux+5,y=8,stroke=theme["left-text"]))
424
+ d.append(draw.Text("P",font_size=10,x=ux+37,y=8,stroke=theme["left-text"]))
425
+ else:
426
+ # ugates is an empty list, meaning this is a transit only chart
427
+ d.append(draw.Text("Transit",font_size=10,x=cx-3,y=8,stroke=theme["right-text"]))
428
+
429
+ # each element of cgates/ugates is a float gate.line
430
+ # turn each element into a list of strings ["gate","line"]
431
+ cgates = [str(x).split('.') for x in cgates]
432
+ ugates = [str(x).split('.') for x in ugates]
433
+
434
+ # gates on the right side
435
+ if not ugates:
436
+ # a transit only chart, so draw gates in transit color
437
+ # transits if present are in cgates
438
+ for n in range(0,14):
439
+ d.append(draw.Rectangle(cx,y+n*35,25,25,rx=2,stroke=theme["lines"], fill=theme["transit"]))
440
+ d.append(draw.Text(hdc.hd_glyphs[n],font_size=13,x=cx+8,y=y+n*35+12))
441
+ d.append(draw.Text(hdc.gates[int(cgates[n][0])][theme["gates"]]+"."+cgates[n][1],font_size=10,x=cx+4,y=y+n*35+22))
442
+ elif len(cgates) == 28:
443
+ # a composite chart
444
+ for n in range(0,14):
445
+ d.append(draw.Rectangle(cx-10,y+n*35,25,25,rx=2,stroke=theme["lines"], fill=theme["conscious"]))
446
+ d.append(draw.Text(hdc.hd_glyphs[n],font_size=13,x=cx-3,y=y+n*35+12))
447
+ d.append(draw.Text(hdc.gates[int(cgates[n][0])][theme["gates"]]+"."+cgates[n][1],font_size=10,x=cx-6,y=y+n*35+22))
448
+ for n in range(0,14):
449
+ d.append(draw.Rectangle(cx+20,y+n*35,25,25,rx=2,stroke=theme["lines"], fill=theme["conscious"]))
450
+ d.append(draw.Text(hdc.hd_glyphs[n],font_size=13,x=cx+28,y=y+n*35+12))
451
+ d.append(draw.Text(hdc.gates[int(cgates[n+14][0])][theme["gates"]]+"."+cgates[n+14][1],font_size=10,x=cx+24,y=y+n*35+22))
452
+ else:
453
+ # just a bodygraph
454
+ for n in range(0,14):
455
+ d.append(draw.Rectangle(cx,y+n*35,25,25,rx=2,stroke=theme["lines"], fill=theme["conscious"]))
456
+ d.append(draw.Text(hdc.hd_glyphs[n],font_size=13,x=cx+8,y=y+n*35+12))
457
+ d.append(draw.Text(hdc.gates[int(cgates[n][0])][theme["gates"]]+"."+cgates[n][1],font_size=10,x=cx+4,y=y+n*35+22))
458
+
459
+ # gates on the left side
460
+ if len(ugates) == 14:
461
+ # just a bodygraph
462
+ for n in range(0,14):
463
+ d.append(draw.Rectangle(ux,y+n*35,25,25,rx=2,stroke=theme["lines"], fill=theme["unconscious"]))
464
+ d.append(draw.Text(hdc.hd_glyphs[n],font_size=13,x=ux+8,y=y+n*35+12))
465
+ d.append(draw.Text(hdc.gates[int(ugates[n][0])][theme["gates"]]+"."+ugates[n][1],font_size=10,x=ux+4,y=y+n*35+22))
466
+ elif len(ugates) == 28:
467
+ # transits with a bodygraph, draw both sets of gates on the left
468
+ # or a composite chart
469
+ for n in range(0,14):
470
+ d.append(draw.Rectangle(ux,y+n*35,25,25,rx=2,stroke=theme["lines"], fill=theme["unconscious"]))
471
+ d.append(draw.Text(hdc.hd_glyphs[n],font_size=13,x=ux+8,y=y+n*35+12))
472
+ d.append(draw.Text(hdc.gates[int(ugates[n][0])][theme["gates"]]+"."+ugates[n][1],font_size=10,x=ux+4,y=y+n*35+22))
473
+ for n in range(0,14):
474
+ d.append(draw.Rectangle(ux+30,y+n*35,25,25,rx=2,stroke=theme["lines"], fill=theme["unconscious"]))
475
+ d.append(draw.Text(hdc.hd_glyphs[n],font_size=13,x=ux+36,y=y+n*35+12))
476
+ d.append(draw.Text(hdc.gates[int(ugates[n+14][0])][theme["gates"]]+"."+ugates[n+14][1],font_size=10,x=ux+33,y=y+n*35+22))
477
+ else:
478
+ # dont draw anything on the left
479
+ n=0
480
+
481
+ return d
482
+
483
+ def draw_info_boxes(self,d,theme,rstr,lstr):
484
+
485
+ d.append(draw.Text(rstr,font_size=10,x=305,y=10,stroke=theme["right-text"]))
486
+ d.append(draw.Text(lstr,font_size=10,x=80,y=10,stroke=theme["left-text"]))
487
+
488
+ return d
489
+