Code Sketch
chakra rashi yoiiiiiiiiiiiiiiiii
Category: Programming
import javax.swing._
import javax.swing.border.EmptyBorder
import java.awt._
import java.awt.event._
import java.text.DecimalFormat
import scala.math._
/*
================================================================
KUNDALI PURAN - VEDIC KUNDALI GUI
---------------------------------------------------------------
Standalone Scala Swing application.
Default:
Shailesh Shahare
09/04/1973
07:30 AM
Ambedkar Ward No. 3, Sadak Arjuni, Gondia, Maharashtra
IST +05:30
IMPORTANT:
This standalone version uses astronomical approximation formulas.
Professional ephemeris accuracy requires Swiss Ephemeris or
another dedicated ephemeris engine.
================================================================
*/
class KundaliPuranFrame extends JFrame {
// ==============================================================
// COLORS
// ==============================================================
private val bg = new Color(14, 18, 30)
private val panelBg = new Color(23, 29, 46)
private val panel2 = new Color(30, 38, 60)
private val gold = new Color(245, 190, 70)
private val gold2 = new Color(255, 215, 120)
private val white = new Color(242, 245, 250)
private val muted = new Color(175, 185, 205)
private val green = new Color(100, 220, 150)
private val red = new Color(240, 105, 105)
private val blue = new Color(110, 180, 255)
private val df = new DecimalFormat("0.000")
private val df2 = new DecimalFormat("0.00")
// ==============================================================
// INPUT FIELDS
// ==============================================================
private val firstName = new JTextField("Shailesh", 12)
private val lastName = new JTextField("Shahare", 12)
private val day = new JTextField("09", 4)
private val month = new JTextField("04", 4)
private val year = new JTextField("1973", 6)
private val hour = new JTextField("07", 4)
private val minute = new JTextField("30", 4)
private val ampm = new JComboBox[String](
Array("AM", "PM")
)
private val place = new JTextField(
"Ambedkar Ward No. 3, Sadak Arjuni, Gondia, Maharashtra",
25
)
private val latitude = new JTextField("21.090017", 10)
private val longitude = new JTextField("80.163083", 10)
private val timezone = new JTextField("5.5", 6)
private val calculateButton = new JButton(" ? CALCULATE KUNDALI ? ")
private val clearButton = new JButton("Clear")
private val statusLabel = new JLabel("Ready")
private val resultArea = new JTextArea()
// ==============================================================
// SIGN DATA
// ==============================================================
private val signs = Array(
"Mesha (Aries)",
"Vrishabha (Taurus)",
"Mithuna (Gemini)",
"Karka (Cancer)",
"Simha (Leo)",
"Kanya (Virgo)",
"Tula (Libra)",
"Vrishchika (Scorpio)",
"Dhanu (Sagittarius)",
"Makara (Capricorn)",
"Kumbha (Aquarius)",
"Meena (Pisces)"
)
private val signShort = Array(
"Mesha",
"Vrishabha",
"Mithuna",
"Karka",
"Simha",
"Kanya",
"Tula",
"Vrishchika",
"Dhanu",
"Makara",
"Kumbha",
"Meena"
)
private val nakshatras = Array(
"Ashwini",
"Bharani",
"Krittika",
"Rohini",
"Mrigashira",
"Ardra",
"Punarvasu",
"Pushya",
"Ashlesha",
"Magha",
"Purva Phalguni",
"Uttara Phalguni",
"Hasta",
"Chitra",
"Swati",
"Vishakha",
"Anuradha",
"Jyeshtha",
"Mula",
"Purva Ashadha",
"Uttara Ashadha",
"Shravana",
"Dhanishtha",
"Shatabhisha",
"Purva Bhadrapada",
"Uttara Bhadrapada",
"Revati"
)
private val nakLords = Array(
"Ketu",
"Venus",
"Sun",
"Moon",
"Mars",
"Rahu",
"Jupiter",
"Saturn",
"Mercury",
"Ketu",
"Venus",
"Sun",
"Moon",
"Mars",
"Rahu",
"Jupiter",
"Saturn",
"Mercury",
"Ketu",
"Venus",
"Sun",
"Moon",
"Mars",
"Rahu",
"Jupiter",
"Saturn",
"Mercury"
)
// ==============================================================
// PLANET NAMES
// ==============================================================
private val planetNames = Array(
"Sun",
"Moon",
"Mars",
"Mercury",
"Jupiter",
"Venus",
"Saturn",
"Rahu",
"Ketu"
)
// ==============================================================
// SETUP
// ==============================================================
setTitle("Kundali Puran - Vedic Kundali")
setSize(1180, 820)
setMinimumSize(new Dimension(1000, 700))
setLocationRelativeTo(null)
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
private val root = new JPanel(new BorderLayout(10, 10))
root.setBackground(bg)
root.setBorder(new EmptyBorder(12, 12, 12, 12))
setContentPane(root)
buildGUI()
// ==============================================================
// GUI
// ==============================================================
private def buildGUI(): Unit = {
val header = new JPanel(new BorderLayout())
header.setBackground(panelBg)
header.setBorder(new EmptyBorder(14, 18, 14, 18))
val title = new JLabel("? KUNDALI PURAN ?")
title.setForeground(gold2)
title.setFont(new Font("Serif", Font.BOLD, 28))
val subtitle = new JLabel(
"Vedic / Sidereal ? Lahiri-style calculation ? Birth Chart"
)
subtitle.setForeground(muted)
subtitle.setFont(new Font("SansSerif", Font.PLAIN, 13))
val titleBox = new JPanel()
titleBox.setOpaque(false)
titleBox.setLayout(new BoxLayout(titleBox, BoxLayout.Y_AXIS))
titleBox.add(title)
titleBox.add(Box.createVerticalStrut(4))
titleBox.add(subtitle)
header.add(titleBox, BorderLayout.WEST)
root.add(header, BorderLayout.NORTH)
val center = new JPanel(new BorderLayout(10, 10))
center.setOpaque(false)
val inputPanel = createInputPanel()
center.add(inputPanel, BorderLayout.NORTH)
resultArea.setEditable(false)
resultArea.setFont(new Font("Monospaced", Font.PLAIN, 13))
resultArea.setForeground(white)
resultArea.setBackground(new Color(9, 12, 21))
resultArea.setCaretColor(white)
resultArea.setLineWrap(false)
val scroll = new JScrollPane(resultArea)
scroll.setBorder(BorderFactory.createLineBorder(new Color(65, 75, 100)))
center.add(scroll, BorderLayout.CENTER)
root.add(center, BorderLayout.CENTER)
val bottom = new JPanel(new BorderLayout())
bottom.setBackground(panelBg)
bottom.setBorder(new EmptyBorder(8, 12, 8, 12))
statusLabel.setForeground(green)
statusLabel.setFont(new Font("SansSerif", Font.BOLD, 12))
bottom.add(statusLabel, BorderLayout.WEST)
val note = new JLabel(
" Vedic/Sidereal ? IST ? Lahiri-style ? Standalone astronomical approximation"
)
note.setForeground(muted)
note.setFont(new Font("SansSerif", Font.PLAIN, 11))
bottom.add(note, BorderLayout.EAST)
root.add(bottom, BorderLayout.SOUTH)
calculateButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
calculate()
}
})
clearButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
resultArea.setText("")
statusLabel.setText("Cleared")
statusLabel.setForeground(muted)
}
})
// Press Enter to calculate.
firstName.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = calculate()
})
// Default AM.
ampm.setSelectedItem("AM")
// Calculate automatically after GUI opens.
SwingUtilities.invokeLater(new Runnable {
override def run(): Unit = calculate()
})
}
private def createInputPanel(): JPanel = {
val outer = new JPanel(new BorderLayout())
outer.setBackground(panelBg)
outer.setBorder(new EmptyBorder(12, 12, 12, 12))
val grid = new JPanel(new GridBagLayout())
grid.setOpaque(false)
val c = new GridBagConstraints()
c.insets = new Insets(5, 5, 5, 5)
c.fill = GridBagConstraints.HORIZONTAL
c.anchor = GridBagConstraints.WEST
addLabel(grid, c, "First Name", 0, 0)
addField(grid, c, firstName, 1, 0)
addLabel(grid, c, "Surname", 2, 0)
addField(grid, c, lastName, 3, 0)
addLabel(grid, c, "Date", 0, 1)
val datePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 0))
datePanel.setOpaque(false)
datePanel.add(day)
datePanel.add(new JLabel("/"))
datePanel.add(month)
datePanel.add(new JLabel("/"))
datePanel.add(year)
styleField(day)
styleField(month)
styleField(year)
addComponent(grid, c, datePanel, 1, 1)
addLabel(grid, c, "Time", 2, 1)
val timePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 0))
timePanel.setOpaque(false)
timePanel.add(hour)
timePanel.add(new JLabel(":"))
timePanel.add(minute)
timePanel.add(ampm)
styleField(hour)
styleField(minute)
styleCombo(ampm)
addComponent(grid, c, timePanel, 3, 1)
addLabel(grid, c, "Birth Place", 0, 2)
addField(grid, c, place, 1, 2)
c.gridwidth = 3
c.weightx = 1.0
grid.add(place, position(c, 1, 2, 3, 1))
c.gridwidth = 1
addLabel(grid, c, "Latitude", 0, 3)
addField(grid, c, latitude, 1, 3)
addLabel(grid, c, "Longitude", 2, 3)
addField(grid, c, longitude, 3, 3)
addLabel(grid, c, "Timezone", 0, 4)
addField(grid, c, timezone, 1, 4)
val systemLabel = new JLabel(
"Calculation: Vedic / Sidereal ? Lahiri-style ? North Indian convention"
)
systemLabel.setForeground(gold2)
systemLabel.setFont(new Font("SansSerif", Font.BOLD, 12))
c.gridx = 2
c.gridy = 4
c.gridwidth = 2
grid.add(systemLabel, c)
c.gridwidth = 1
val buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 2))
buttonPanel.setOpaque(false)
calculateButton.setBackground(new Color(80, 60, 20))
calculateButton.setForeground(gold2)
calculateButton.setFont(new Font("SansSerif", Font.BOLD, 13))
calculateButton.setFocusPainted(false)
clearButton.setBackground(panel2)
clearButton.setForeground(white)
clearButton.setFocusPainted(false)
buttonPanel.add(clearButton)
buttonPanel.add(calculateButton)
outer.add(grid, BorderLayout.CENTER)
outer.add(buttonPanel, BorderLayout.SOUTH)
outer
}
private def addLabel(
panel: JPanel,
c: GridBagConstraints,
text: String,
x: Int,
y: Int
): Unit = {
val l = new JLabel(text)
l.setForeground(muted)
l.setFont(new Font("SansSerif", Font.BOLD, 12))
panel.add(l, position(c, x, y, 1, 1))
}
private def addField(
panel: JPanel,
c: GridBagConstraints,
field: JTextField,
x: Int,
y: Int
): Unit = {
styleField(field)
panel.add(field, position(c, x, y, 1, 1))
}
private def addComponent(
panel: JPanel,
c: GridBagConstraints,
component: Component,
x: Int,
y: Int
): Unit = {
panel.add(component, position(c, x, y, 1, 1))
}
private def position(
c0: GridBagConstraints,
x: Int,
y: Int,
w: Int,
h: Int
): GridBagConstraints = {
val c = c0.clone().asInstanceOf[GridBagConstraints]
c.gridx = x
c.gridy = y
c.gridwidth = w
c.gridheight = h
c.weightx = if (w > 1) 1.0 else 0.0
c.weighty = 0.0
c.fill = GridBagConstraints.HORIZONTAL
c
}
private def styleField(f: JTextField): Unit = {
f.setBackground(new Color(11, 15, 27))
f.setForeground(white)
f.setCaretColor(white)
f.setFont(new Font("SansSerif", Font.PLAIN, 12))
f.setBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(65, 75, 100)),
new EmptyBorder(5, 7, 5, 7)
)
)
}
private def styleCombo(c: JComboBox[String]): Unit = {
c.setBackground(new Color(11, 15, 27))
c.setForeground(white)
c.setFont(new Font("SansSerif", Font.PLAIN, 12))
}
// ==============================================================
// SAFE PARSING
// ==============================================================
private def readInt(f: JTextField, name: String): Int = {
try {
f.getText.trim.toInt
} catch {
case _: Throwable =>
throw new IllegalArgumentException(
"Invalid " + name + "."
)
}
}
private def readDouble(f: JTextField, name: String): Double = {
try {
f.getText.trim.toDouble
} catch {
case _: Throwable =>
throw new IllegalArgumentException(
"Invalid " + name + "."
)
}
}
// ==============================================================
// MAIN CALCULATION
// ==============================================================
private def calculate(): Unit = {
try {
statusLabel.setText("Calculating...")
statusLabel.setForeground(gold2)
val d = readInt(day, "day")
val m = readInt(month, "month")
val y = readInt(year, "year")
val h0 = readInt(hour, "hour")
val min = readInt(minute, "minute")
val lat = readDouble(latitude, "latitude")
val lon = readDouble(longitude, "longitude")
val tz = readDouble(timezone, "timezone")
if (d < 1 || d > 31)
throw new IllegalArgumentException("Day must be 1-31.")
if (m < 1 || m > 12)
throw new IllegalArgumentException("Month must be 1-12.")
if (h0 < 1 || h0 > 12)
throw new IllegalArgumentException("Hour must be 1-12.")
if (min < 0 || min > 59)
throw new IllegalArgumentException("Minute must be 0-59.")
if (lat < -90 || lat > 90)
throw new IllegalArgumentException("Latitude must be between -90 and +90.")
if (lon < -180 || lon > 180)
throw new IllegalArgumentException("Longitude must be between -180 and +180.")
val isPM = ampm.getSelectedItem.toString == "PM"
var hour24 = h0 % 12
if (isPM) hour24 += 12
val localDecimalHour =
hour24.toDouble + min.toDouble / 60.0
val utcDecimalHour =
localDecimalHour - tz
val jd =
julianDay(y, m, d, utcDecimalHour)
val days =
jd - 2451543.5
// ------------------------------------------------------------
// Planetary longitudes
// ------------------------------------------------------------
val tropicalSun = sunLongitude(days)
val tropicalMoon = moonLongitude(days)
val tropicalMercury =
planetLongitude(days, 48.3313, 3.24587, 0.387098,
7.0047, 0.00000005,
29.1241, 1.01444E-5,
0.387098, 0.0,
168.0, 4.0923344368)
val tropicalVenus =
planetLongitude(days, 76.6799, 2.46590E-5, 0.72333,
3.3946, 2.75E-8,
54.8910, 1.38374E-5,
0.72333, 0.0,
48.0052, 1.6021302244)
val tropicalMars =
planetLongitude(days, 49.5574, 2.11081E-5, 1.523688,
1.8497, 1.78E-8,
286.5016, 2.92961E-5,
1.523688, 0.0,
18.6021, 0.5240207766)
val tropicalJupiter =
planetLongitude(days, 100.4542, 2.76854E-5, 5.20256,
1.3030, -1.557E-7,
273.8777, 1.64505E-5,
5.20256, 0.0,
19.8950, 0.0830853001)
val tropicalSaturn =
planetLongitude(days, 113.6634, 2.38980E-5, 9.55475,
2.4886, -1.081E-7,
339.3939, 2.97661E-5,
9.55475, 0.0,
316.9670, 0.0334442282)
val tropicalRahu =
normalize360(125.04452 - 0.0529538083 * days)
val tropicalKetu =
normalize360(tropicalRahu + 180.0)
// ------------------------------------------------------------
// Approximate Lahiri ayanamsha
// ------------------------------------------------------------
val ayanamsha = lahiriAyanamsha(jd)
val sun = sidereal(tropicalSun, ayanamsha)
val moon = sidereal(tropicalMoon, ayanamsha)
val mercury = sidereal(tropicalMercury, ayanamsha)
val venus = sidereal(tropicalVenus, ayanamsha)
val mars = sidereal(tropicalMars, ayanamsha)
val jupiter = sidereal(tropicalJupiter, ayanamsha)
val saturn = sidereal(tropicalSaturn, ayanamsha)
val rahu = sidereal(tropicalRahu, ayanamsha)
val ketu = sidereal(tropicalKetu, ayanamsha)
// ------------------------------------------------------------
// Ascendant
// ------------------------------------------------------------
val lst = localSiderealTime(jd, lon)
val asc = calculateAscendant(
jd,
lat,
lst,
ayanamsha
)
// ------------------------------------------------------------
// Moon Rashi / Nakshatra
// ------------------------------------------------------------
val moonInfo = zodiacInfo(moon)
val ascInfo = zodiacInfo(asc)
// ------------------------------------------------------------
// D9
// ------------------------------------------------------------
val navMoon = navamshaSign(moon)
val navAsc = navamshaSign(asc)
// ------------------------------------------------------------
// Vimshottari
// ------------------------------------------------------------
val moonNakIndex =
floor(normalize360(moon) / (360.0 / 27.0)).toInt
val moonNakName =
nakshatras(clamp(moonNakIndex, 0, 26))
val moonNakLord =
nakLords(clamp(moonNakIndex, 0, 26))
val dashaReport =
vimshottariReport(
moon,
moonNakIndex
)
// ------------------------------------------------------------
// Planet table
// ------------------------------------------------------------
val planets = Array(
("Surya / Sun", sun),
("Chandra / Moon", moon),
("Mangal / Mars", mars),
("Budha / Mercury", mercury),
("Guru / Jupiter", jupiter),
("Shukra / Venus", venus),
("Shani / Saturn", saturn),
("Rahu", rahu),
("Ketu", ketu)
)
val sb = new StringBuilder
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" KUNDALI PURAN\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" ???? ??????\n")
sb.append("??????????????????????????????????????????????????????????????\n\n")
sb.append("PERSONAL INFORMATION\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append("Name : ")
sb.append(firstName.getText.trim)
sb.append(" ")
sb.append(lastName.getText.trim)
sb.append("\n")
sb.append("Birth Date : ")
sb.append(f"$d%02d/$m%02d/$y%04d")
sb.append("\n")
sb.append("Birth Time : ")
sb.append(f"$h0%02d:$min%02d ${ampm.getSelectedItem}")
sb.append("\n")
sb.append("Birth Place : ")
sb.append(place.getText.trim)
sb.append("\n")
sb.append("Latitude : ")
sb.append(df2.format(lat))
sb.append("\n")
sb.append("Longitude : ")
sb.append(df2.format(lon))
sb.append("\n")
sb.append("Timezone : UTC")
sb.append(if (tz >= 0) "+" else "")
sb.append(df2.format(tz))
sb.append("\n")
sb.append("Julian Day : ")
sb.append(df.format(jd))
sb.append("\n")
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" MAIN RESULT\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append("CHANDRA RASHI : ")
sb.append(moonInfo.sign)
sb.append("\n")
sb.append("Moon Degree : ")
sb.append(formatDMS(moon))
sb.append("\n")
sb.append("NAKSHATRA : ")
sb.append(moonInfo.nakshatra)
sb.append("\n")
sb.append("NAKSHATRA PADA : ")
sb.append(moonInfo.pada)
sb.append("\n")
sb.append("NAKSHATRA LORD : ")
sb.append(moonInfo.nakLord)
sb.append("\n")
sb.append("LAGNA : ")
sb.append(ascInfo.sign)
sb.append("\n")
sb.append("Lagna Degree : ")
sb.append(formatDMS(asc))
sb.append("\n")
sb.append("LAGNA NAKSH. : ")
sb.append(ascInfo.nakshatra)
sb.append(" Pada ")
sb.append(ascInfo.pada)
sb.append("\n")
sb.append("AYANAMSHA : ")
sb.append(df2.format(ayanamsha))
sb.append("� (Lahiri-style approximation)")
sb.append("\n")
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" PLANETARY POSITIONS\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(
String.format(
"%-20s %-20s %-17s %-8s\n",
"Planet",
"Sidereal Sign",
"Degree",
"House"
)
)
sb.append("??????????????????????????????????????????????????????????????\n")
planets.foreach {
case (name, lon0) =>
val info = zodiacInfo(lon0)
val house = houseFromAsc(asc, lon0)
sb.append(
String.format(
"%-20s %-20s %-17s %-8s\n",
name,
info.sign,
formatDMS(lon0),
house.toString
)
)
}
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" NAKSHATRA DETAILS\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append("Moon Nakshatra : ")
sb.append(moonInfo.nakshatra)
sb.append("\n")
sb.append("Pada : ")
sb.append(moonInfo.pada)
sb.append("\n")
sb.append("Nakshatra Lord : ")
sb.append(moonInfo.nakLord)
sb.append("\n")
sb.append("Moon Position : ")
sb.append(formatDMS(moon))
sb.append("\n")
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" NAVAMSHA / D9\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append("D9 Lagna : ")
sb.append(navAsc)
sb.append("\n")
sb.append("D9 Moon : ")
sb.append(navMoon)
sb.append("\n")
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" 12 HOUSE OVERVIEW\n")
sb.append("??????????????????????????????????????????????????????????????\n")
for (i <- 1 to 12) {
val houseSign =
signShort(
((signIndex(asc) + i - 1) % 12 + 12) % 12
)
val occupantNames =
planets
.filter {
case (_, p) =>
houseFromAsc(asc, p) == i
}
.map(_._1)
.mkString(", ")
sb.append(
f"House $i%2d : ${houseSign}%-14s"
)
if (occupantNames.isEmpty)
sb.append(" No listed planet")
else
sb.append(" " + occupantNames)
sb.append("\n")
}
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" VIMSHOTTARI DASHA\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(dashaReport)
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" SPIRITUAL SECTION\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append("Moon Rashi : ")
sb.append(moonInfo.sign)
sb.append("\n")
sb.append("Nakshatra : ")
sb.append(moonInfo.nakshatra)
sb.append("\n")
sb.append("Nakshatra Lord : ")
sb.append(moonInfo.nakLord)
sb.append("\n")
sb.append("\n")
sb.append("Traditional deity associations can vary by lineage,\n")
sb.append("sampradaya and astrologer's method. This program does\n")
sb.append("not claim that one particular deity is objectively\n")
sb.append("assigned by astronomy.\n")
sb.append("\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(" IMPORTANT\n")
sb.append("??????????????????????????????????????????????????????????????\n")
sb.append(
"This is a standalone astronomical approximation.\n"
)
sb.append(
"For professional-grade exact planetary positions,\n"
)
sb.append(
"use a dedicated ephemeris such as Swiss Ephemeris.\n"
)
sb.append(
"Small differences in planetary degrees, Lagna,\n"
)
sb.append(
"Nakshatra or Dasha timing can occur between methods.\n"
)
sb.append(
"Astrological interpretations are traditional beliefs,\n"
)
sb.append(
"not scientifically established predictions.\n"
)
resultArea.setText(sb.toString())
resultArea.setCaretPosition(0)
statusLabel.setText(
"? Calculation complete ? " + moonInfo.sign
)
statusLabel.setForeground(green)
} catch {
case ex: Throwable =>
statusLabel.setText("Error")
statusLabel.setForeground(red)
JOptionPane.showMessageDialog(
this,
ex.getMessage,
"Input Error",
JOptionPane.ERROR_MESSAGE
)
}
}
// ==============================================================
// JULIAN DAY
// ==============================================================
private def julianDay(
year: Int,
month: Int,
day: Int,
hour: Double
): Double = {
var y = year
var m = month
if (m <= 2) {
y -= 1
m += 12
}
val a = floor(y / 100.0)
val b = 2.0 - a + floor(a / 4.0)
floor(365.25 * (y + 4716.0)) +
floor(30.6001 * (m + 1.0)) +
day +
b -
1524.5 +
hour / 24.0
}
// ==============================================================
// BASIC ASTRONOMICAL FUNCTIONS
// ==============================================================
private def rev(x: Double): Double = {
var r = x % 360.0
if (r < 0) r += 360.0
r
}
private def normalize360(x: Double): Double = rev(x)
private def sinD(x: Double): Double =
sin(toRadians(x))
private def cosD(x: Double): Double =
cos(toRadians(x))
private def tanD(x: Double): Double =
tan(toRadians(x))
private def atan2D(y: Double, x: Double): Double =
toDegrees(atan2(y, x))
// ==============================================================
// SUN
// ==============================================================
private def sunLongitude(days: Double): Double = {
val w =
normalize360(282.9404 + 4.70935E-5 * days)
val e =
0.016709 - 1.151E-9 * days
val m =
normalize360(356.0470 + 0.9856002585 * days)
val mr = toRadians(m)
val E =
m +
toDegrees(
e * sin(mr) *
(1.0 + e * cos(mr))
)
val x =
cosD(E) - e
val y =
sqrt(1.0 - e * e) * sinD(E)
val v =
atan2D(y, x)
normalize360(v + w)
}
// ==============================================================
// MOON
// ==============================================================
// Compact low-order lunar approximation.
// Intended mainly for determining the zodiac region and
// nakshatra-level result, not professional ephemeris work.
private def moonLongitude(days: Double): Double = {
val N =
normalize360(125.1228 - 0.0529538083 * days)
val i = 5.1454
val w =
normalize360(318.0634 + 0.1643573223 * days)
val a = 60.2666
val e = 0.054900
val M =
normalize360(115.3654 + 13.0649929509 * days)
val E =
eccentricAnomaly(M, e)
val xv =
a * (cosD(E) - e)
val yv =
a *
(sqrt(1.0 - e * e) * sinD(E))
val v =
atan2D(yv, xv)
val r =
sqrt(xv * xv + yv * yv)
val xh =
r *
(cosD(N) * cosD(v + w) -
sinD(N) * sinD(v + w) * cosD(i))
val yh =
r *
(sinD(N) * cosD(v + w) +
cosD(N) * sinD(v + w) * cosD(i))
val zh =
r *
(sinD(v + w) * sinD(i))
var lon =
atan2D(yh, xh)
// Solar perturbations improve the rough lunar position.
val sunLon = sunLongitude(days)
val Ms =
normalize360(
356.0470 + 0.9856002585 * days
)
val Ls =
normalize360(
sunLon
)
val Lm =
normalize360(
N + w + M
)
val D =
normalize360(Lm - Ls)
val F =
normalize360(Lm - N)
lon +=
-1.274 * sinD(M - 2.0 * D) +
0.658 * sinD(2.0 * D) -
0.186 * sinD(Ms) -
0.059 * sinD(2.0 * M - 2.0 * D) -
0.057 * sinD(M - 2.0 * D + Ms) +
0.053 * sinD(M + 2.0 * D) +
0.046 * sinD(2.0 * D - Ms) +
0.041 * sinD(M - Ms) -
0.035 * sinD(D) -
0.031 * sinD(M + Ms) -
0.015 * sinD(2.0 * F - 2.0 * D) +
0.011 * sinD(M - 4.0 * D)
normalize360(lon)
}
private def eccentricAnomaly(
Mdeg: Double,
e: Double
): Double = {
val M = toRadians(Mdeg)
var E = M
var i = 0
while (i < 10) {
val delta =
(E - e * sin(E) - M) /
(1.0 - e * cos(E))
E -= delta
i += 1
}
toDegrees(E)
}
// ==============================================================
// GENERIC PLANET APPROXIMATION
// ==============================================================
private def planetLongitude(
days: Double,
N0: Double,
Nd: Double,
a0: Double,
i0: Double,
id: Double,
w0: Double,
wd: Double,
aDummy: Double,
eDummy: Double,
M0: Double,
Md: Double
): Double = {
val N = normalize360(N0 + Nd * days)
val i = i0 + id * days
val w = normalize360(w0 + wd * days)
val a = a0
val e =
if (a < 1.0) 0.03
else if (a < 2.0) 0.09
else if (a < 7.0) 0.05
else 0.05
val M =
normalize360(M0 + Md * days)
val E =
eccentricAnomaly(M, e)
val xv =
a * (cosD(E) - e)
val yv =
a *
sqrt(1.0 - e * e) *
sinD(E)
val v =
atan2D(yv, xv)
val r =
sqrt(xv * xv + yv * yv)
val xh =
r *
(cosD(N) * cosD(v + w) -
sinD(N) * sinD(v + w) * cosD(i))
val yh =
r *
(sinD(N) * cosD(v + w) +
cosD(N) * sinD(v + w) * cosD(i))
normalize360(
atan2D(yh, xh)
)
}
// ==============================================================
// LAHIRI-STYLE AYANAMSHA
// ==============================================================
private def lahiriAyanamsha(jd: Double): Double = {
val T =
(jd - 2451545.0) / 36525.0
// Compact approximation around modern epochs.
// Used only as a standalone approximation.
normalize360(
23.85675 +
1.39656 * T +
0.000308 * T * T
)
}
private def sidereal(
tropical: Double,
ayan: Double
): Double = {
normalize360(
tropical - ayan
)
}
// ==============================================================
// SIDEREAL TIME
// ==============================================================
private def localSiderealTime(
jd: Double,
longitude: Double
): Double = {
val T =
(jd - 2451545.0) / 36525.0
val gmst =
280.46061837 +
360.98564736629 *
(jd - 2451545.0) +
0.000387933 * T * T -
T * T * T / 38710000.0
normalize360(
gmst + longitude
)
}
// ==============================================================
// ASCENDANT
// ==============================================================
private def calculateAscendant(
jd: Double,
latitude: Double,
lst: Double,
ayanamsha: Double
): Double = {
val T =
(jd - 2451545.0) / 36525.0
val eps =
23.439291 -
0.0130042 * T
val theta =
toRadians(lst)
val phi =
toRadians(latitude)
val e =
toRadians(eps)
val y =
-cos(theta)
val x =
sin(theta) * cos(e) +
tan(phi) * sin(e)
var ascTropical =
atan2D(y, x)
ascTropical =
normalize360(
ascTropical
)
normalize360(
ascTropical - ayanamsha
)
}
// ==============================================================
// ZODIAC INFORMATION
// ==============================================================
case class ZodiacInfo(
sign: String,
nakshatra: String,
pada: Int,
nakLord: String,
degreeInSign: Double
)
private def zodiacInfo(lon: Double): ZodiacInfo = {
val x = normalize360(lon)
val signIndex =
floor(x / 30.0).toInt
val degreeInSign =
x - signIndex * 30.0
val nakSize =
360.0 / 27.0
val nakIndex =
floor(x / nakSize).toInt
val safeNak =
clamp(nakIndex, 0, 26)
val insideNak =
x - safeNak * nakSize
val pada =
clamp(
floor(
insideNak /
(nakSize / 4.0)
).toInt + 1,
1,
4
)
ZodiacInfo(
signs(
clamp(signIndex, 0, 11)
),
nakshatras(safeNak),
pada,
nakLords(safeNak),
degreeInSign
)
}
private def signIndex(lon: Double): Int =
floor(
normalize360(lon) / 30.0
).toInt % 12
private def clamp(
x: Int,
lo: Int,
hi: Int
): Int = {
max(lo, min(hi, x))
}
// ==============================================================
// HOUSE
// ==============================================================
private def houseFromAsc(
asc: Double,
planet: Double
): Int = {
val diff =
normalize360(
planet - asc
)
floor(diff / 30.0).toInt + 1
}
// ==============================================================
// NAVAMSHA
// ==============================================================
private def navamshaSign(
longitude: Double
): String = {
val sign =
signIndex(longitude)
val degree =
normalize360(longitude) -
sign * 30.0
val nav =
floor(
degree / (30.0 / 9.0)
).toInt
// Movable: starts from same sign
// Fixed: starts from 9th sign
// Dual: starts from 5th sign
val start =
if (
sign == 0 ||
sign == 3 ||
sign == 6 ||
sign == 9
) {
sign
} else if (
sign == 1 ||
sign == 4 ||
sign == 7 ||
sign == 10
) {
(sign + 8) % 12
} else {
(sign + 4) % 12
}
val n =
(start + nav) % 12
signShort(n)
}
// ==============================================================
// VIMSHOTTARI
// ==============================================================
private val dashaYears =
Map(
"Ketu" -> 7.0,
"Venus" -> 20.0,
"Sun" -> 6.0,
"Moon" -> 10.0,
"Mars" -> 7.0,
"Rahu" -> 18.0,
"Jupiter" -> 16.0,
"Saturn" -> 19.0,
"Mercury" -> 17.0
)
private val dashaOrder =
Array(
"Ketu",
"Venus",
"Sun",
"Moon",
"Mars",
"Rahu",
"Jupiter",
"Saturn",
"Mercury"
)
private def vimshottariReport(
moon: Double,
nakIndex: Int
): String = {
val lord =
nakLords(
clamp(nakIndex, 0, 26)
)
val totalNak =
360.0 / 27.0
val nakStart =
nakIndex * totalNak
val travelled =
normalize360(moon) - nakStart
val fraction =
max(
0.0,
min(
1.0,
travelled / totalNak
)
)
val lordYears =
dashaYears(lord)
val remainingYears =
lordYears * (1.0 - fraction)
val sb = new StringBuilder
sb.append(
"Starting Mahadasha : "
)
sb.append(lord)
sb.append("\n")
sb.append(
"Approx. balance : "
)
sb.append(
df2.format(remainingYears)
)
sb.append(" years\n\n")
sb.append(
"Mahadasha sequence:\n"
)
val startIndex =
dashaOrder.indexOf(lord)
for (i <- 0 until 9) {
val name =
dashaOrder(
(startIndex + i) %
dashaOrder.length
)
sb.append(
f"${i + 1}%2d. ${name}%-10s "
)
sb.append(
df2.format(
dashaYears(name)
)
)
sb.append(" years\n")
}
sb.append("\n")
sb.append(
"Note: exact calendar dates for Mahadasha/\n"
)
sb.append(
"Antardasha require a high-precision ephemeris\n"
)
sb.append(
"and exact Moon longitude.\n"
)
sb.toString
}
// ==============================================================
// DEGREE FORMAT
// ==============================================================
private def formatDMS(
longitude: Double
): String = {
val x =
normalize360(longitude)
val sign =
floor(x / 30.0).toInt
val deg =
x - sign * 30.0
val d =
floor(deg).toInt
val minutesFloat =
(deg - d) * 60.0
val min =
floor(minutesFloat).toInt
val sec =
floor(
(minutesFloat - min) * 60.0
).toInt
f"${signShort(sign)} $d%02d� $min%02d' $sec%02d\""
}
}
// ================================================================
// START APPLICATION
// ================================================================
// Direct startup is intentional so it works in worksheet/Kojo-like
// environments where object Main.main is not automatically invoked.
SwingUtilities.invokeLater(
new Runnable {
override def run(): Unit = {
val frame =
new KundaliPuranFrame()
frame.setVisible(true)
}
}
)