/* * [CalcBiorhythms.java] * * Summary: Calculates Biorhythm values for any given day. * * Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 2.6 2009-03-24 fix layout bug, use anti-aliasing. */ package com.mindprod.bio; import com.mindprod.common18.Misc; import java.awt.Color; /** * Calculates Biorhythm values for any given day. * * @author Roedy Green, Canadian Mind Products * @version 2.6 2009-03-24 fix layout bug, use anti-aliasing. * @since 1999 */ final class CalcBiorhythms { /** * length of combined cycle in days. * * @noinspection WeakerAccess */ static final int COMBI_PERIOD = 23 * 28 * 33; /** * length of emotional cycle in days. * * @noinspection WeakerAccess */ static final int EMOTIONAL_PERIOD = 28; /** * length of intellectual cycle in days. * * @noinspection WeakerAccess */ static final int INTELLECTUAL_PERIOD = 33; /** * length of physical cycle in days. * * @noinspection WeakerAccess */ static final int PHYSICAL_PERIOD = 23; /** * colour for combined cycle line. */ static final Color FOREGROUND_FOR_COMBI = new Color( 0xffa500 );/* orange */ /** * colour for emotional cycle line. */ static final Color FOREGROUND_FOR_EMOTIONAL = Color.blue; /** * colour for intellectual cycle line dark green. */ static final Color FOREGROUND_FOR_INTELLECTUAL = new Color( 0x008000 ); /** * colour for physical cycle line. */ static final Color FOREGROUND_FOR_PHYSICAL = Color.red; /** * calculate combined biorhythm. * * @param daysSinceBirth number of days since birthdate to calculate for. * * @return weighted average of phys, emot, intel biorhythms -1 .. +1. */ private static double combiLevel( int daysSinceBirth ) { double phys = Math.sin( Math.PI * 2 / PHYSICAL_PERIOD * ( daysSinceBirth % PHYSICAL_PERIOD ) ); double emot = Math.sin( Math.PI * 2 / EMOTIONAL_PERIOD * ( daysSinceBirth % EMOTIONAL_PERIOD ) ); double intel = Math.sin( Math.PI * 2 / INTELLECTUAL_PERIOD * ( daysSinceBirth % INTELLECTUAL_PERIOD ) ); // magic constant are arbitrary fiddled to give more weight to phys return phys * 0.37 + emot * 0.34 + intel * 0.29; } /** * calculate biorhythm. * * @param daysSinceBirth number of days since birthdate to calculate for. * @param period periodicity in days. Period of that type of biorhythm, 0 for combination. * * @return phys, emot or intel biorhythms -1.0 .. +1.0 * @noinspection WeakerAccess */ static double level( int daysSinceBirth, int period ) { if ( period == COMBI_PERIOD ) { return combiLevel( daysSinceBirth ); } else { return Math.sin( Math.PI * 2 / period * ( daysSinceBirth % period ) ); } } /** * Calculate a value for today for given biorhythm. * * @param daysSinceBirth days since the person was born. This lets you calculate the biorythm for any day. * @param period Number of days for the period. 0 means combined. * * @return String representing how high that type of biorhythm is today e.g. "very high", "high", l"low", "very * low", "critical". */ static String levelInWords( int daysSinceBirth, int period ) { // value of sine wave today double todayLevel = level( daysSinceBirth, period ); if ( todayLevel >= +.8 ) { return "very high"; } if ( todayLevel <= -.8 ) { return "very low"; } if ( todayLevel >= +.5 ) { return "high"; } if ( todayLevel <= -.5 ) { return "low"; } if ( todayLevel >= +.1 ) { return "average"; } if ( todayLevel <= -.1 ) { return "below average"; } // it almost critical. To count as "the" critical day you must have: // 1. a sign change between today and either yesterday or tomorrow. // 2. be closer in absolute value to 0 than yesterday or tomorrow. // value of sine wave yesterday double yesterdayLevel = level( daysSinceBirth - 1, period ); // value of sine wave tomorrow double tomorrowLevel = level( daysSinceBirth + 1, period ); if ( ( signDiff( yesterdayLevel, todayLevel ) || signDiff( todayLevel, tomorrowLevel ) ) && ( Math.abs( todayLevel ) <= Math.abs( yesterdayLevel ) ) && ( Math.abs( todayLevel ) <= Math.abs( tomorrowLevel ) ) ) { return "critical"; } // must be -.1 .. +.1 return "average"; } /** * Returns random string describing luck level. * * @param daysSinceBirth How many days since birth, not necessarily representing today. * * @return String, possibly empty, describing luck level. */ static String luckLevelInWords( int daysSinceBirth ) { double luck = level( daysSinceBirth, COMBI_PERIOD ); double yesterdayLuck = level( daysSinceBirth - 1, COMBI_PERIOD ); double tomorrowLuck = level( daysSinceBirth + 1, COMBI_PERIOD ); if ( luck > 0.5 && luck > yesterdayLuck && luck > tomorrowLuck ) { return "Today is your lucky day!"; } else { return ""; } } /** * Do a and b differ in sign?. * * @param a first number to compare. * @param b second number to compare. * * @return true of have different sign. */ private static boolean signDiff( double a, double b ) { return Misc.signum( a ) != Misc.signum( b ); } }