Skip to content

Instantly share code, notes, and snippets.

@ryochin
Created August 19, 2011 05:35
Show Gist options
  • Save ryochin/1156124 to your computer and use it in GitHub Desktop.
Save ryochin/1156124 to your computer and use it in GitHub Desktop.
Moonphase for Objective-C
@interface MoonPhase : NSObject {
@private
NSDate *now;
}
- (float) phase;
@end
// ---------------------------------------
#import "MoonPhase.h"
float fixangle( float angle ){
return angle - 360.0f * ( floor ( angle / 360.0f ) );
}
float torad( float deg ){
return deg * ( M_PI / 180.0f );
}
float todeg( float rad ){
return rad * ( 180.0f / M_PI );
}
float dsin( float deg ){
return sin( torad( deg ) );
}
double jtime( double t ){
return (t / 86400.0f) + 2440587.5f;
}
float kepler( float m, float ecc ){
float EPSILON = 0.000001f;
m = torad(m);
float e = m;
float delta;
// first time
delta = e - ecc * sin(e) - m;
e -= delta / ( 1.0f - ecc * cos(e) );
// loop
while( abs(delta) > EPSILON ){
delta = e - ecc * sin(e) - m;
e -= delta / ( 1.0f - ecc * cos(e) );
}
return e;
}
@implementation MoonPhase
- (id) init {
self = [super init];
if (self) {
now = [NSDate date];
}
return self;
}
- (void) dealloc {
[super dealloc];
}
- (float) phase {
// const
double Epoch = 2444238.5;
float Elonge = 278.833540;
float Elongp = 282.596403;
float Eccent = 0.016718;
float Mmlong = 64.975464;
float Mmlongp = 349.383063;
float Mlnode = 151.950429;
float Minc = 5.145396;
NSTimeInterval d = [now timeIntervalSince1970];
double pdate = jtime( (float)d );
double Day = pdate - Epoch;
double N = fixangle( ( 360.0f / 365.2422f ) * Day );
double M = fixangle( N + Elonge - Elongp );
double Ec = kepler( M, Eccent );
Ec = sqrt( ( 1.0f + Eccent ) / ( 1.0f - Eccent ) ) * tan( Ec / 2.0f );
Ec = 2.0f * todeg( atan( Ec ) );
double Lambdasun = fixangle( Ec + Elongp );
double ml = fixangle( 13.1763966f * Day + Mmlong );
double MM = fixangle( ml - 0.1114041f * Day - Mmlongp );
double MN = fixangle( Mlnode - 0.0529539f * Day );
double Ev = 1.2739f * sin( torad( 2.0f * ( ml - Lambdasun ) - MM ) );
double Ae = 0.1858f * sin( torad( M ) );
double A3 = 0.37f * sin( torad( M ) );
double MmP = MM + Ev - Ae - A3;
double mEc = 6.2886f * sin( torad( MmP ) );
double A4 = 0.214f * sin( torad( 2.0f * MmP ) );
double lP = ml + Ev + mEc - Ae + A4;
double V = 0.6583f * sin( torad( 2.0f * ( lP - Lambdasun ) ) );
double lPP = lP + V;
double NP = MN - 0.16f * sin( torad( M ) );
double y = sin( torad( lPP - NP ) ) * cos( torad( Minc ) );
double x = cos( torad( lPP - NP ) );
double Lambdamoon = todeg( atan2( y, x ) );
Lambdamoon += NP;
double MoonAge = lPP - Lambdasun;
float mpfrac = fixangle( MoonAge ) / 360.0f;
return mpfrac;
}
@end
@real19
Copy link

real19 commented Aug 1, 2012

So how can we do something similar to Astro::Moonphase Perl .

See http://search.cpan.org/~brett/Astro-MoonPhase/MoonPhase.pm#phase()

where it prints:

Example:

@phases = phasehunt();
print "New Moon      = ", scalar(localtime($phases[0])), "\n";
print "First quarter = ", scalar(localtime($phases[1])), "\n";
print "Full moon     = ", scalar(localtime($phases[2])), "\n";
print "Last quarter  = ", scalar(localtime($phases[3])), "\n";
print "New Moon      = ", scalar(localtime($phases[4])), "\n";

could print something like this:

New Moon      = Wed Jun 24 06:51:47 1998
First quarter = Wed Jul  1 21:42:19 1998
Full moon     = Thu Jul  9 19:02:47 1998
Last quarter  = Thu Jul 16 18:15:18 1998
New Moon      = Thu Jul 23 16:45:01 1998

@real19
Copy link

real19 commented Aug 1, 2012

I am just interested in the new moons

@kirk-kerekes
Copy link

The // commented lines in this copy are flagged as not necessary by XCode. (the results are not used anywhere)

That is possibly a danger sign. I don't understand the code enough to judge. And I certainly don't know enough PERL to validate the port.

  • (float) phase
    {

    double Epoch = 2444238.5;
    float Elonge = 278.833540;
    float Elongp = 282.596403;
    float Eccent = 0.016718;
    float Mmlong = 64.975464;
    float Mmlongp = 349.383063;
    // float Mlnode = 151.950429;
    // float Minc = 5.145396;

    NSTimeInterval d = [self timeIntervalSince1970];

    double pdate = jtime( (float)d );
    double Day = pdate - Epoch;

    double N = fixangle( ( 360.0f / 365.2422f ) * Day );
    double M = fixangle( N + Elonge - Elongp );
    double Ec = kepler( M, Eccent );
    Ec = sqrt( ( 1.0f + Eccent ) / ( 1.0f - Eccent ) ) * tan( Ec / 2.0f );
    Ec = 2.0f * todeg( atan( Ec ) );
    double Lambdasun = fixangle( Ec + Elongp );

    double ml = fixangle( 13.1763966f * Day + Mmlong );
    double MM = fixangle( ml - 0.1114041f * Day - Mmlongp );
    // double MN = fixangle( Mlnode - 0.0529539f * Day );
    double Ev = 1.2739f * sin( torad( 2.0f * ( ml - Lambdasun ) - MM ) );
    double Ae = 0.1858f * sin( torad( M ) );
    double A3 = 0.37f * sin( torad( M ) );
    double MmP = MM + Ev - Ae - A3;
    double mEc = 6.2886f * sin( torad( MmP ) );
    double A4 = 0.214f * sin( torad( 2.0f * MmP ) );
    double lP = ml + Ev + mEc - Ae + A4;
    double V = 0.6583f * sin( torad( 2.0f * ( lP - Lambdasun ) ) );
    double lPP = lP + V;
    // double NP = MN - 0.16f * sin( torad( M ) );
    // double y = sin( torad( lPP - NP ) ) * cos( torad( Minc ) );
    // double x = cos( torad( lPP - NP ) );
    // double Lambdamoon = todeg( atan2( y, x ) );
    // Lambdamoon += NP;

    double MoonAge = lPP - Lambdasun;
    float mpfrac = fixangle( MoonAge ) / 360.0f;

    return mpfrac;

@kirk-kerekes
Copy link

I looked at the PERL on CPAN and it looks likely that the redundant code is for calculations that this phase-only version omits -- the PERL module returns an array of lunar statistics, not just the moon phase.

But "likely" is not "Certain".

@ktamiola
Copy link

Hey! Thanks for posting! How can we access MoonPhase.h ?

Copy link

ghost commented Jan 27, 2015

I ported this to php from the perl module.

This module is wrong. The system time needs to be EPOCH time in milliseconds from 1980 as per the perl module which is UNIX.

Therefore I am always getting GMT and can never get local time.

How do I get local time as this tells you the correct lunar illumination?

I have tried converting the NSDate using NSTimeIntervalSince but have failed.

Can you help rectify the problem with the module?

The conversion otherwise is fine. Good work but is useless without local time.

I would expect to see the time not initialized the way you have but created on the fly checking and using local time and must recognise daylight savings time.

Copy link

ghost commented Jan 27, 2015

UNIX Epoch is since 1980 and XCODE is since 1970.

Copy link

ghost commented Jan 27, 2015

I compared the output with the perl and php modules and this is out.

Copy link

ghost commented Jan 27, 2015

How do I change the now variable to seconds since 1980?

Copy link

ghost commented Jan 27, 2015

//NSDate * aDate = [NSDate dateWithString:@"1980-01-01 00:00:00 +1100"];
NSDate *aDate = (NSDate*)@"1980-01-01 00:00:00 +1100";
//NSDate *since1980 = [NSDate date];
//NSDate *tomarow = [today dateByAddingTimeInterval:60*60*24];
NSDate *seconds = [NSDate dateWithTimeInterval:60*60*24 sinceDate:aDate];
NSLog(@"seconds since Jan 1980 %@",seconds);

NSTimeInterval d = [now timeIntervalSince1970];

@fnavarromachio
Copy link

So how can we do something similar to Astro::Moonphase Perl .

See http://search.cpan.org/~brett/Astro-MoonPhase/MoonPhase.pm#phase()

where it prints:

Example:

@phases = phasehunt();
print "New Moon      = ", scalar(localtime($phases[0])), "\n";
print "First quarter = ", scalar(localtime($phases[1])), "\n";
print "Full moon     = ", scalar(localtime($phases[2])), "\n";
print "Last quarter  = ", scalar(localtime($phases[3])), "\n";
print "New Moon      = ", scalar(localtime($phases[4])), "\n";

could print something like this:

New Moon      = Wed Jun 24 06:51:47 1998
First quarter = Wed Jul  1 21:42:19 1998
Full moon     = Thu Jul  9 19:02:47 1998
Last quarter  = Thu Jul 16 18:15:18 1998
New Moon      = Thu Jul 23 16:45:01 1998

How to show moonrise in objective c pleasE? thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment