├── includes ├── js_pre.js ├── css_post.css ├── js_post.js └── pre.all ├── .gitignore ├── CONTRIBUTING.md ├── language └── js.hxml ├── scripts ├── pre-commit-hook └── template ├── .gitmodules ├── templates ├── haxelib.json.jq ├── pre.all.jq ├── composer.json.jq ├── README.md.j2 ├── ports_README.md.j2 └── base.md.j2 ├── haxelib.json ├── package.json ├── LICENSE.md ├── .travis.yml ├── test ├── test.js └── Test.hx ├── README.md ├── metainfo.json ├── Makefile └── src └── suncalc └── SunCalc.hx /includes/js_pre.js: -------------------------------------------------------------------------------- 1 | (function () { 'use strict'; 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | dependencies.hxml 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Refer to the [README](/README.md) for how to report issues and contribute. 2 | -------------------------------------------------------------------------------- /includes/css_post.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-spacing: 5px; 3 | border-collapse: separate; 4 | } 5 | -------------------------------------------------------------------------------- /language/js.hxml: -------------------------------------------------------------------------------- 1 | # -dce full 2 | # -dce std 3 | # -dce no 4 | # -D js-flatten 5 | -D shallow-expose 6 | -------------------------------------------------------------------------------- /scripts/pre-commit-hook: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | make docs 4 | make build/test_suncalc.js 5 | make dist-push 6 | make check-diff 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "build/suncalc_php"] 2 | path = ports/suncalc-php 3 | url = https://github.com/ypid/suncalc-php.git 4 | [submodule "docs"] 5 | path = docs 6 | url = https://github.com/ypid/suncalc.git 7 | -------------------------------------------------------------------------------- /includes/js_post.js: -------------------------------------------------------------------------------- 1 | 2 | // Export as AMD module / Node module / browser variable. 3 | if (typeof define === 'function' && define.amd) define(suncalc.SunCalc); 4 | else if (typeof module !== 'undefined') module.exports = suncalc.SunCalc; 5 | else window.SunCalc = suncalc.SunCalc; 6 | 7 | }()); 8 | -------------------------------------------------------------------------------- /includes/pre.all: -------------------------------------------------------------------------------- 1 | /* 2 | * @name: suncalc 3 | * @description: Calculate sun position, sunlight phases, moon position and lunar phase. 4 | * @source: https://github.com/ypid/suncalc/blob/master/src/suncalc/SunCalc.hx 5 | * @license: BSD-2-Clause 6 | * @author: Robin Schneider 7 | * @author: Vladimir Agafonkin 8 | */ 9 | -------------------------------------------------------------------------------- /templates/haxelib.json.jq: -------------------------------------------------------------------------------- 1 | { 2 | name: .[0].name, 3 | url: .[0].url, 4 | license: .[0].license.name.short, 5 | tags: (.[1].keywords + [ "cross" ] | sort), 6 | description: .[0].description, 7 | version: .[0].version, 8 | releasenote: .[0].releasenote, 9 | contributors: ([ .[0].authors | sort_by(.name) | .[] | select(contains({ targets: [ "haxe" ]})).nick ] ), 10 | dependencies: .[0].dependencies.haxe, 11 | } 12 | -------------------------------------------------------------------------------- /templates/pre.all.jq: -------------------------------------------------------------------------------- 1 | "/* 2 | * @name: " + .[0].name + " 3 | * @description: " + .[0].description + " 4 | * @source: " + .[0].target_info.haxe.source_file + " 5 | * @license: " + .[0].license.name.spdx_identifier + " 6 | " + 7 | ( [ .[0].authors | sort_by(.name) 8 | | .[] | select(contains({ targets: [ "haxe" ]}) or contains({ targets: [ "role::upstream" ]})) 9 | | (" * @author: " + .name + (if has("email") then (" <" + .email + ">") else "" end)) ] 10 | | join("\n") ) + " 11 | */" 12 | -------------------------------------------------------------------------------- /templates/composer.json.jq: -------------------------------------------------------------------------------- 1 | { 2 | ## https://getcomposer.org/doc/04-schema.md 3 | name: ("ypid/" + .[0].name), 4 | type: "library", 5 | description: .[0].description, 6 | keywords: (.[1].keywords | sort), 7 | homepage: .[0].url, 8 | support: .[0].support, 9 | license: .[0].license.name.spdx_identifier, 10 | authors: ([ .[0].authors | sort_by(.name) | .[] | select(contains({ targets: [ "php" ]}) or contains({ targets: [ "role::upstream" ]})) ] ), 11 | # FIXME 12 | # "autoload": { 13 | # "psr-4" : { 14 | # "suncalc_SunCalc\\" : "lib" 15 | # } 16 | # } 17 | } 18 | -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "suncalc", 3 | "url": "https://github.com/ypid/suncalc", 4 | "license": "BSD", 5 | "tags": [ 6 | "astronomy", 7 | "calculation", 8 | "cross", 9 | "illumination", 10 | "math", 11 | "moon", 12 | "sun", 13 | "sunrise", 14 | "sunset", 15 | "twilight" 16 | ], 17 | "description": "Calculate sun position, sunlight phases, moon position and lunar phase.", 18 | "version": "1.7.0", 19 | "releasenote": "First release of this port written in Haxe.", 20 | "contributors": [ 21 | "ypid" 22 | ], 23 | "dependencies": { 24 | "datetime": "", 25 | "version": "" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "suncalc", 3 | "version": "1.7.0", 4 | "description": "A tiny JavaScript library for calculating sun/moon positions and phases.", 5 | "homepage": "https://github.com/mourner/suncalc", 6 | "keywords": [ 7 | "sun", 8 | "astronomy", 9 | "math", 10 | "calculation", 11 | "sunrise", 12 | "sunset", 13 | "twilight", 14 | "moon", 15 | "illumination" 16 | ], 17 | "author": "Vladimir Agafonkin", 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/mourner/suncalc.git" 21 | }, 22 | "main": "suncalc.js", 23 | "devDependencies": { 24 | "eslint": "^1.9.0", 25 | "eslint-config-mourner": "^1.0.1", 26 | "tap": "^2.2.0" 27 | }, 28 | "eslintConfig": { 29 | "extends": "mourner", 30 | "rules": { 31 | "indent": 0, 32 | "array-bracket-spacing": 0, 33 | "strict": 0, 34 | "brace-style": 0 35 | }, 36 | "env": { 37 | "amd": true 38 | } 39 | }, 40 | "scripts": { 41 | "pretest": "eslint suncalc.js test.js", 42 | "test": "tap test.js", 43 | "cov": "tap test.js --cov" 44 | }, 45 | "jshintConfig": { 46 | "quotmark": "single", 47 | "trailing": true, 48 | "unused": true 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011-2015, Vladimir Agafonkin 2 | 3 | Copyright (C) 2015 Robin Schneider 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 | -------------------------------------------------------------------------------- /templates/README.md.j2: -------------------------------------------------------------------------------- 1 | {% extends 'templates/base.md.j2' %} 2 | 3 | {% block content %} 4 | ## Supported languages/platforms 5 | 6 | {% for target_key in meta.target_info.keys()|sort %} 7 | {%- set target = meta.target_info[target_key] -%} 8 | {{ supported_lang(target) }} 9 | {% endfor %} 10 | 11 | ## Supported languages/platforms not generated by Haxe 12 | 13 | {% for target_key in meta.target_info_haxe_unsupported.keys()|sort %} 14 | {%- set target = meta.target_info_haxe_unsupported[target_key] -%} 15 | {{ supported_lang(target) }} 16 | {% endfor %} 17 | 18 | ## Limitations 19 | 20 | The following limitations seems to be related which should mean that when they are fixed for one target, the tests for the other targets should also pass. If you need `SunCalc.getMoonTimes` for one of those targets, feel free to debug it further. 21 | 22 | * Python: `SunCalc.getMoonTimes` (`rise` date can not be calculated.). 23 | * C++: `SunCalc.getMoonTimes` (`segmentation fault`). 24 | * Java: `SunCalc.getMoonTimes` (`java.lang.NullPointerException`). 25 | * Neko: `SunCalc.getMoonTimes` 26 | 27 | ## Unsure/untested 28 | 29 | * ActionScript 3: Does compile but I have no idea how to test it. 30 | * Flash: Does compile but I have no idea how to test it. 31 | 32 | ## Unsupported 33 | 34 | * C#: Dependency `datetime` does not compile on target "datetime/3,0,2/src/datetime/DateTime.hx:146: characters 28-110 : haxe.Int64 should be Float" 35 | 36 | Priority low. 37 | {% endblock %} 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: haxe 4 | 5 | haxe: 6 | - '3.2.1' 7 | 8 | ## We test if all the target builds are source code deterministic. 9 | ## This can only be ensured to work against the version on my dev machine. 10 | # - 'development' 11 | 12 | addons: 13 | apt: 14 | packages: 15 | - python3 16 | - python3-jinja2 17 | - php5-cli 18 | 19 | ## This can be done but it has lots of overhead as all base dependencies are installed 8 times. 20 | ## Also, Travis seems not to support to create status images for each target individually. 21 | # env: 22 | # matrix: 23 | # - TARGET=node 24 | # - TARGET=java 25 | # - TARGET=php 26 | # - TARGET=python 27 | # - TARGET=cpp 28 | # - TARGET=neko 29 | # - TARGET=swf 30 | # - TARGET=as3 31 | 32 | install: 33 | ## https://github.com/jdonaldson/promhx/blob/master/.travis.yml 34 | # - sh -c "if [ '$TARGET' = 'cpp' ]; then haxelib install hxcpp; fi" 35 | # - sh -c "if [ '$TARGET' = 'cs' ]; then haxelib install hxcs; fi" 36 | # - sh -c "if [ '$TARGET' = 'java' ]; then haxelib install hxjava; fi" 37 | # - sh -c "if [ '$TARGET' = 'node' ]; then haxelib install hxnodejs; fi" 38 | - make dependencies-get 39 | - git submodule foreach rm -rf * 40 | 41 | script: 42 | - make all 43 | 44 | ## All files should be properly rebuild, nothing should be changed. 45 | ## Assumes that software versions are the same which is difficult. 46 | ## Also assumes reproducible builds which seems to be the case. 47 | # - make check-diff 48 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var SunCalc = require('../build/suncalc_js/suncalc'), 2 | t = require('tap'); 3 | 4 | function near(val1, val2, margin) { 5 | return Math.abs(val1 - val2) < (margin || 1E-15); 6 | } 7 | 8 | var date = new Date('2013-03-05UTC'), 9 | lat = 50.5, 10 | lng = 30.5; 11 | 12 | var testTimes = { 13 | solarNoon: '2013-03-05T10:10:57Z', 14 | nadir: '2013-03-04T22:10:57Z', 15 | sunrise: '2013-03-05T04:34:56Z', 16 | sunset: '2013-03-05T15:46:57Z', 17 | sunriseEnd: '2013-03-05T04:38:19Z', 18 | sunsetStart: '2013-03-05T15:43:34Z', 19 | dawn: '2013-03-05T04:02:17Z', 20 | dusk: '2013-03-05T16:19:36Z', 21 | nauticalDawn: '2013-03-05T03:24:31Z', 22 | nauticalDusk: '2013-03-05T16:57:22Z', 23 | nightEnd: '2013-03-05T02:46:17Z', 24 | night: '2013-03-05T17:35:36Z', 25 | goldenHourEnd: '2013-03-05T05:19:01Z', 26 | goldenHour: '2013-03-05T15:02:52Z' 27 | }; 28 | 29 | t.test('getPosition returns azimuth and altitude for the given time and location', function (t) { 30 | var sunPos = SunCalc.getPosition(date, lat, lng); 31 | 32 | t.ok(near(sunPos.azimuth, -2.5003175907168385), 'azimuth'); 33 | t.ok(near(sunPos.altitude, -0.7000406838781611), 'altitude'); 34 | t.end(); 35 | }); 36 | 37 | t.test('getTimes returns sun phases for the given date and location', function (t) { 38 | var times = SunCalc.getTimes(date, lat, lng); 39 | 40 | for (var i in testTimes) { 41 | t.equal(new Date(testTimes[i]).toUTCString(), times[i].toUTCString(), i); 42 | } 43 | t.end(); 44 | }); 45 | 46 | t.test('getMoonPosition returns moon position data given time and location', function (t) { 47 | var moonPos = SunCalc.getMoonPosition(date, lat, lng); 48 | 49 | t.ok(near(moonPos.azimuth, -0.9783999522438226), 'azimuth'); 50 | t.ok(near(moonPos.altitude, 0.006969727754891917), 'altitude'); 51 | t.ok(near(moonPos.distance, 364121.37256256194), 'distance'); 52 | t.end(); 53 | }); 54 | 55 | t.test('getMoonIllumination returns fraction and angle of moon\'s illuminated limb and phase', function (t) { 56 | var moonIllum = SunCalc.getMoonIllumination(date); 57 | 58 | t.ok(near(moonIllum.fraction, 0.4848068202456373), 'fraction'); 59 | t.ok(near(moonIllum.phase, 0.7548368838538762), 'phase'); 60 | t.ok(near(moonIllum.angle, 1.6732942678578346), 'angle'); 61 | t.end(); 62 | }); 63 | 64 | t.test('getMoonTimes returns moon rise and set times', function (t) { 65 | var moonTimes = SunCalc.getMoonTimes(new Date('2013-03-04UTC'), lat, lng, true); 66 | 67 | console.log(moonTimes); 68 | t.equal(moonTimes.rise.toUTCString(), 'Mon, 04 Mar 2013 23:57:55 GMT'); 69 | t.equal(moonTimes.set.toUTCString(), 'Mon, 04 Mar 2013 07:28:41 GMT'); 70 | 71 | t.end(); 72 | }); 73 | -------------------------------------------------------------------------------- /scripts/template: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # @author Copyright (C) 2015-2016 Robin Schneider 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as 7 | # published by the Free Software Foundation, version 3 of the 8 | # License. 9 | # 10 | # This program 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 this program. If not, see . 17 | 18 | __author__ = 'Robin Schneider ' 19 | __license__ = 'AGPL-3.0' 20 | __version__ = '0.5.0' 21 | 22 | """ 23 | README generator using Jinja2. 24 | """ 25 | 26 | 27 | import json 28 | import xml.etree.ElementTree 29 | import jinja2 30 | from argparse import ArgumentParser 31 | 32 | args_parser = ArgumentParser( 33 | description=__doc__, 34 | ) 35 | args_parser.add_argument( 36 | '-V', '--version', 37 | action='version', 38 | version='%(prog)s {version}'.format(version=__version__) 39 | ) 40 | args_parser.add_argument( 41 | '-i', '--input-json-file', 42 | required=True, 43 | help="JSON file to decode and provide to Jinja2 as `meta`.", 44 | ) 45 | args_parser.add_argument( 46 | '-t', '--input-template-file', 47 | required=True, 48 | help="File path of the template file.", 49 | ) 50 | args_parser.add_argument( 51 | '-d', '--input-doc-xml-file', 52 | help="XML file generated by Haxe about a module.", 53 | ) 54 | args_parser.add_argument( 55 | '-k', '--key-value', 56 | action='append', 57 | type=lambda kv: kv.split("="), 58 | help="Additional key value options to make available during templating.", 59 | ) 60 | args = args_parser.parse_args() 61 | 62 | with open(args.input_json_file) as data_file: 63 | meta = json.load(data_file) 64 | 65 | template_vars = { 66 | 'meta': meta, 67 | 'source': { 68 | 'meta': args.input_json_file, 69 | 'template': args.input_template_file, 70 | 'script': __file__, 71 | }, 72 | } 73 | 74 | if args.key_value: 75 | template_vars['kv'] = dict([(elem[0], elem[1]) for elem in args.key_value]) 76 | 77 | if args.input_doc_xml_file: 78 | xml = xml.etree.ElementTree.parse(args.input_doc_xml_file).getroot() 79 | for haxe_class in xml.iter('class'): 80 | if 'path' in haxe_class.attrib and haxe_class.attrib['path'] == 'suncalc.SunCalc': 81 | haxe_doc = haxe_class.find('haxe_doc').text 82 | template_vars['haxe_doc'] = haxe_doc 83 | template_vars['source']['xml'] = args.input_doc_xml_file 84 | 85 | templateLoader = jinja2.FileSystemLoader(searchpath='.') 86 | templateEnv = jinja2.Environment( 87 | loader=templateLoader, 88 | undefined=jinja2.StrictUndefined, 89 | trim_blocks=True, 90 | ) 91 | template = templateEnv.get_template(args.input_template_file) 92 | 93 | print(template.render(template_vars)) 94 | -------------------------------------------------------------------------------- /test/Test.hx: -------------------------------------------------------------------------------- 1 | import haxe.unit.TestCase; 2 | import haxe.unit.TestRunner; 3 | import datetime.DateTime; 4 | 5 | import suncalc.SunCalc; 6 | 7 | class Test extends TestCase { 8 | 9 | var date:Date = DateTime.fromString('2013-03-05T00:00:00Z'); 10 | var lat = 50.5; 11 | var lng = 30.5; 12 | 13 | var testTimes:Map = [ 14 | 'solarNoon' => '2013-03-05T10:10:57Z', 15 | 'nadir' => '2013-03-04T22:10:57Z', 16 | 'sunrise' => '2013-03-05T04:34:56Z', 17 | 'sunset' => '2013-03-05T15:46:57Z', 18 | 'sunriseEnd' => '2013-03-05T04:38:19Z', 19 | 'sunsetStart' => '2013-03-05T15:43:34Z', 20 | 'dawn' => '2013-03-05T04:02:17Z', 21 | 'dusk' => '2013-03-05T16:19:36Z', 22 | 'nauticalDawn' => '2013-03-05T03:24:31Z', 23 | 'nauticalDusk' => '2013-03-05T16:57:22Z', 24 | 'nightEnd' => '2013-03-05T02:46:17Z', 25 | 'night' => '2013-03-05T17:35:36Z', 26 | 'goldenHourEnd' => '2013-03-05T05:19:01Z', 27 | 'goldenHour' => '2013-03-05T15:02:52Z', 28 | ]; 29 | 30 | private function near(val1:Float, val2:Float, margin:Float = 1E-15):Bool { 31 | return Math.abs(val1 - val2) < margin; 32 | } 33 | 34 | private function testGetPosition():Void { 35 | var sunPos = SunCalc.getPosition(date, lat, lng); 36 | 37 | assertTrue(near(sunPos.azimuth, -2.5003175907168385)); 38 | assertTrue(near(sunPos.altitude, -0.7000406838781611)); 39 | } 40 | 41 | private function testGetTimes():Void { 42 | var times = SunCalc.getTimes(date, lat, lng); 43 | 44 | for (testTime in testTimes.keys()) { 45 | var test_date:Date = DateTime.fromString(testTimes[testTime]); 46 | assertEquals(DateTime.fromDate(test_date).utc().toString(), DateTime.fromDate(times[testTime]).utc().toString()); 47 | } 48 | } 49 | 50 | private function testGetMoonPosition():Void { 51 | var moonPos = SunCalc.getMoonPosition(date, lat, lng); 52 | 53 | assertTrue(near(moonPos.azimuth, -0.9783999522438226)); 54 | assertTrue(near(moonPos.altitude, 0.006969727754891917)); 55 | assertTrue(near(moonPos.distance, 364121.37256256194)); 56 | } 57 | 58 | private function testGetMoonIllumination():Void { 59 | var moonIllum = SunCalc.getMoonIllumination(date); 60 | 61 | assertTrue(near(moonIllum.fraction, 0.4848068202456373)); 62 | assertTrue(near(moonIllum.phase, 0.7548368838538762)); 63 | assertTrue(near(moonIllum.angle, 1.6732942678578346)); 64 | } 65 | 66 | /* 67 | * See README.md under limitations for details. 68 | */ 69 | #if !(cpp || java || python || neko) 70 | private function testGetMoonTimes():Void { 71 | var moon_date:Date = DateTime.fromString('2013-03-04'); 72 | var moonTimes = SunCalc.getMoonTimes(moon_date, lat, lng, true); 73 | 74 | assertTrue(Std.is(moonTimes.get('rise'), Date)); 75 | assertTrue(Std.is(moonTimes.get('set'), Date)); 76 | assertEquals(DateTime.fromString('2013-03-04T23:57:55Z').utc().toString(), DateTime.fromDate(moonTimes.get('rise')).utc().toString()); 77 | assertEquals(DateTime.fromString('2013-03-04T07:28:41Z').utc().toString(), DateTime.fromDate(moonTimes.get('set')).utc().toString()); 78 | } 79 | #end 80 | 81 | static public function main():Void { 82 | 83 | var runner = new TestRunner(); 84 | runner.add(new Test()); 85 | var all_tests_passed:Bool = runner.run(); 86 | Sys.exit(all_tests_passed ? 0 : 1); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /templates/ports_README.md.j2: -------------------------------------------------------------------------------- 1 | {% extends 'templates/base.md.j2' %} 2 | {% set target_info = meta.target_info[kv.target] %} 3 | 4 | {% block vcs_badges %} 5 | {% if "repo_url" in target_info %} 6 | 7 | {% set github_repo_path = target_info.repo_url | replace("https://github.com/", "") %} 8 | [![GitHub stars](https://img.shields.io/github/stars/{{ github_repo_path }}.svg?style=social&label=Star&maxAge=2592000)]({{ target_info.repo_url }}/stargazers) 9 | [![GitHub forks](https://img.shields.io/github/forks/{{ github_repo_path }}.svg?style=social&label=Fork&maxAge=2592000)]({{ target_info.repo_url }}/network) 10 | [![GitHub watchers](https://img.shields.io/github/watchers/{{ github_repo_path }}.svg?style=social&label=Watch&maxAge=2592000)]({{ target_info.repo_url }}/watchers) 11 | [![GitHub open issues](https://img.shields.io/github/issues-raw/{{ github_repo_path }}.svg?&maxAge=2592000)]({{ target_info.repo_url }}/issues) 12 | [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/{{ github_repo_path }}.svg?maxAge=2592000)]({{ target_info.repo_url }}/issues?q=is%3Aissue+is%3Aclosed) 13 | [![GitHub open pull requests](https://img.shields.io/github/issues-pr-raw/{{ github_repo_path }}.svg?&maxAge=2592000)]({{ target_info.repo_url }}/pulls) 14 | [![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/{{ github_repo_path }}.svg?&maxAge=2592000)]({{ target_info.repo_url }}/pulls?q=is%3Apr+is%3Aclosed) 15 | {% endif %} 16 | {% endblock %} 17 | 18 | {% block additional_badges %} 19 | {% if "additional_badges" in meta.target_info[kv.target] %} 20 | {% for item in meta.target_info[kv.target].additional_badges %} 21 | {% if item|length == 3 %} 22 | {% set badge_alt_tag = item[0] %} 23 | {% set badge_img_url = item[1] %} 24 | {% set badge_href_url = item[2] | replace("$package_url", meta.target_info[kv.target].package_url) %} 25 | [![{{ badge_alt_tag }}]({{ badge_img_url }})]({{ badge_href_url }}) 26 | {% else %} 27 | {# Empty line to end paragraph. #} 28 | 29 | {% endif %} 30 | {% endfor %} 31 | {% endif %} 32 | {% endblock %} 33 | 34 | {% block content %} 35 | 36 | {% if kv.target == 'php' %} 37 | ## Getting started 38 | 39 | Check out the following example to get started. 40 | 41 | ```php 42 | ## Needed when executed in the root of this repository. 43 | require_once __DIR__ . '/lib/php/Boot.class.php'; 44 | 45 | ## Needed when installed via composer. FIXME 46 | # require_once __DIR__ . '/vendor/ypid/suncalc/lib/php/Boot.class.php'; 47 | 48 | echo suncalc_SunCalc::getMoonIllumination(new Date(2000, 1, 1, 0, 0, 0)); 49 | ``` 50 | 51 | ## TODO 52 | 53 | Maintainer/tester with PHP knowledge wanted :wink: 54 | 55 | Composer does provide a [autoload feature](https://getcomposer.org/doc/04-schema.md#autoload) which is currently not used. 56 | My experience with PHP is very limited which is the reason I wrote in Haxe and 57 | generated this PHP target only because all unit tests for PHP passed. If you 58 | know how to properly support the autoload feature for this library, I will be 59 | happy to integrate it. 60 | 61 | {% endif %} 62 | 63 | ## Internals 64 | This library was automatically build using [Haxe](http://haxe.org/) to target {{ target_info.target_env_name }}. 65 | 66 | Refer to {{ meta.url }} when you want to contribute. Note that you should only report issues against [the {{ target_info.target_env_name }} target repository]({{ meta.target_info[kv.target].repo_url }}) when you think the issue only occurs in the {{ target_info.target_env_name }} port of this library. If you are unsure, report [against the source repository]({{ meta.url }}) instead. 67 | 68 | ## Unit testing 69 | 70 | Unit testing is done [against the source repository]({{ meta.url }}) in Haxe, 71 | as well as against each transcompile target ({{ target_info.target_env_name }} in this 72 | case). You can check them out in the [source repository]({{ meta.url }}). 73 | 74 | ## Maintainer 75 | 76 | {% for author in meta.authors %} 77 | {% if (target_info.target_env_name|lower) in author.targets %} 78 | * [{{ author.name }}]({{ author.homepage }}), role: {{ author.role }} 79 | {% endif %} 80 | {% endfor %} 81 | 82 | 83 | {% endblock %} 84 | -------------------------------------------------------------------------------- /templates/base.md.j2: -------------------------------------------------------------------------------- 1 | {%- macro supported_lang(target) -%}{# ((( #} 2 | {%- if target.package_url is defined and target.package_url is string -%} 3 | * [{{ target.target_env_name }}]({{ target.package_url }}) 4 | {%- else -%} 5 | * {{ target.target_env_name }} 6 | {%- endif -%} 7 | {%- if target.repo_url is string %} 8 | ([{{ 'target build ' if (target.type|d('none') == 'target') else (target.type + ' ') }}repository]({{ target.repo_url }})) 9 | {%- endif -%} 10 | {%- endmacro -%}{# ))) 11 | 12 | #} 13 | {% block title %} 14 | # {{ meta.name }} 15 | {% endblock %} 16 | 17 | {% block script_generated %} 18 | 20 | {% endblock %} 21 | 22 | {% block build_status %} 23 | [![Build Status]({{ meta.integration_testing.img }})]({{ meta.integration_testing.url}}) 24 | {% endblock %} 25 | {% block license_badge %} 26 | [![{{ meta.license.name.short }} licensed](https://img.shields.io/badge/license-{{ meta.license.name.short }}-blue.svg)]({{ meta.license.url.default }}) 27 | {% endblock %} 28 | {% block target_package_badges %} 29 | {% for target_key in meta.target_info.keys()|sort %} 30 | {% set target = meta.target_info[target_key] %} 31 | {% if target.package_badge is defined and target.package_badge is string %} 32 | [![{{ target.package_platform }} version]({{ target.package_badge | replace("VERSION", "v" + meta.version) }})]({{ target.package_url }}) 33 | {% endif %} 34 | {% endfor %} 35 | {% endblock %} 36 | {% block vcs_badges %} 37 | {% if "https://github.com" in meta.url %} 38 | 39 | {% set github_repo_path = meta.url | replace("https://github.com/", "") %} 40 | [![GitHub stars](https://img.shields.io/github/stars/{{ github_repo_path }}.svg?style=social&label=Star&maxAge=2592000)]({{ meta.url }}/stargazers) 41 | [![GitHub forks](https://img.shields.io/github/forks/{{ github_repo_path }}.svg?style=social&label=Fork&maxAge=2592000)]({{ meta.url }}/network) 42 | [![GitHub watchers](https://img.shields.io/github/watchers/{{ github_repo_path }}.svg?style=social&label=Watch&maxAge=2592000)]({{ meta.url }}/watchers) 43 | [![GitHub open issues](https://img.shields.io/github/issues-raw/{{ github_repo_path }}.svg?&maxAge=2592000)]({{ meta.url }}/issues) 44 | [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/{{ github_repo_path }}.svg?maxAge=2592000)]({{ meta.url }}/issues?q=is%3Aissue+is%3Aclosed) 45 | [![GitHub open pull requests](https://img.shields.io/github/issues-pr-raw/{{ github_repo_path }}.svg?&maxAge=2592000)]({{ meta.url }}/pulls) 46 | [![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/{{ github_repo_path }}.svg?&maxAge=2592000)]({{ meta.url }}/pulls?q=is%3Apr+is%3Aclosed) 47 | {% endif %} 48 | {% endblock %} 49 | {% block additional_badges %} 50 | {% endblock %} 51 | {% block post_badges %} 52 | {% endblock %} 53 | 54 | {% block pre_haxe_doc %}{% endblock %} 55 | 56 | {% block haxe_doc %} 57 | {{ haxe_doc|replace(' ', '') }} 58 | 59 | Refer to the [API documentation]({{ meta.support.docs }}) for details. 60 | {% endblock %} 61 | 62 | {% block install %} 63 | ## Install 64 | 65 | Install the library for your favorite language by executing one of the following commands: 66 | 67 | ```Shell 68 | {% for target_key in meta.target_info.keys()|sort %} 69 | {% set target = meta.target_info[target_key] %} 70 | {% if target.package_url is defined and target.package_url is string %} 71 | {% set install_cmd = target.install_cmd | d(target.package_platform.lower() + ' install ' + meta.name) %} 72 | {% set needed_space = 42 - 10 - (install_cmd|length) %} 73 | {{ install_cmd }}{{ ' ' * needed_space }}# {{ target.target_env_name }} 74 | {% endif %} 75 | {% endfor %} 76 | ``` 77 | {% endblock %} 78 | 79 | {% block content %}{% endblock %} 80 | 81 | {% block license %} 82 | ## License 83 | 84 | [{{ meta.license.name.spdx_identifier }}]({{ meta.license.url.default }}) 85 | {%- endblock %} 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # suncalc 2 | 3 | 5 | 6 | [![Build Status](https://travis-ci.org/ypid/suncalc.svg?branch=master)](https://travis-ci.org/ypid/suncalc) 7 | [![BSD licensed](https://img.shields.io/badge/license-BSD-blue.svg)](https://tldrlegal.com/license/bsd-2-clause-license-%28freebsd%29) 8 | [![haxelib version](https://img.shields.io/badge/Haxe-v1.7.0-blue.svg)](https://lib.haxe.org/p/suncalc) 9 | [![NPM version](https://img.shields.io/npm/v/suncalc.svg)](https://www.npmjs.org/package/suncalc) 10 | [![Packagist version](https://img.shields.io/packagist/v/ypid/suncalc.svg)](https://packagist.org/packages/ypid/suncalc) 11 | 12 | [![GitHub stars](https://img.shields.io/github/stars/ypid/suncalc.svg?style=social&label=Star&maxAge=2592000)](https://github.com/ypid/suncalc/stargazers) 13 | [![GitHub forks](https://img.shields.io/github/forks/ypid/suncalc.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/ypid/suncalc/network) 14 | [![GitHub watchers](https://img.shields.io/github/watchers/ypid/suncalc.svg?style=social&label=Watch&maxAge=2592000)](https://github.com/ypid/suncalc/watchers) 15 | [![GitHub open issues](https://img.shields.io/github/issues-raw/ypid/suncalc.svg?&maxAge=2592000)](https://github.com/ypid/suncalc/issues) 16 | [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/ypid/suncalc.svg?maxAge=2592000)](https://github.com/ypid/suncalc/issues?q=is%3Aissue+is%3Aclosed) 17 | [![GitHub open pull requests](https://img.shields.io/github/issues-pr-raw/ypid/suncalc.svg?&maxAge=2592000)](https://github.com/ypid/suncalc/pulls) 18 | [![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/ypid/suncalc.svg?&maxAge=2592000)](https://github.com/ypid/suncalc/pulls?q=is%3Apr+is%3Aclosed) 19 | 20 | 21 | The SunCalc module allows to calculate sun position, 22 | sunlight phases (times for sunrise, sunset, dusk, etc.), 23 | moon position and lunar phase for the given location and time. 24 | 25 | SunCalc was ported to [Haxe](https://en.wikipedia.org/wiki/Haxe) by [Robin `ypid` Schneider](https://github.com/ypid) to allow using it in a [planed rewrite of the opening hours library](https://github.com/opening-hours/opening_hours.js/issues/136). 26 | 27 | It is based on the [JavaScript implementation](https://github.com/mourner/suncalc) 28 | created by [Vladimir Agafonkin](http://agafonkin.com/en) ([@mourner](https://github.com/mourner)) 29 | as a part of the [SunCalc.net project](http://suncalc.net). 30 | 31 | Most calculations are based on the formulas given in the excellent Astronomy Answers articles 32 | about [position of the sun](http://aa.quae.nl/en/reken/zonpositie.html) 33 | and [the planets](http://aa.quae.nl/en/reken/hemelpositie.html). 34 | You can read about different twilight phases calculated by SunCalc 35 | in the [Twilight article on Wikipedia](https://en.wikipedia.org/wiki/Twilight). 36 | 37 | Refer to the [API documentation](https://ypid.github.io/suncalc/suncalc/SunCalc.html) for details. 38 | 39 | ## Install 40 | 41 | Install the library for your favorite language by executing one of the following commands: 42 | 43 | ```Shell 44 | haxelib install suncalc # Haxe 45 | npm install suncalc # JavaScript/Node.JS 46 | composer require ypid/suncalc # PHP 47 | ``` 48 | 49 | ## Supported languages/platforms 50 | 51 | * C++ 52 | * [Haxe](https://lib.haxe.org/p/suncalc) 53 | * Java ([native port repository](https://github.com/mncaudill/SunCalc-Java)) 54 | * [JavaScript/Node.JS](https://www.npmjs.org/package/suncalc) ([native port repository](https://github.com/mourner/suncalc)) 55 | * NekoVM 56 | * [PHP](https://packagist.org/packages/ypid/suncalc) ([target build repository](https://github.com/ypid/suncalc-php)) 57 | * Python ([native port repository](https://github.com/Broham/suncalcPy)) 58 | 59 | ## Supported languages/platforms not generated by Haxe 60 | 61 | * Go ([native port repository](https://github.com/mourner/suncalc-go)) 62 | * Objective-C ([native port repository](https://github.com/swerdlow/suncalc-objective-c)) 63 | * Swift ([native port repository](https://github.com/shanus/suncalc-swift)) 64 | 65 | ## Limitations 66 | 67 | The following limitations seems to be related which should mean that when they are fixed for one target, the tests for the other targets should also pass. If you need `SunCalc.getMoonTimes` for one of those targets, feel free to debug it further. 68 | 69 | * Python: `SunCalc.getMoonTimes` (`rise` date can not be calculated.). 70 | * C++: `SunCalc.getMoonTimes` (`segmentation fault`). 71 | * Java: `SunCalc.getMoonTimes` (`java.lang.NullPointerException`). 72 | * Neko: `SunCalc.getMoonTimes` 73 | 74 | ## Unsure/untested 75 | 76 | * ActionScript 3: Does compile but I have no idea how to test it. 77 | * Flash: Does compile but I have no idea how to test it. 78 | 79 | ## Unsupported 80 | 81 | * C#: Dependency `datetime` does not compile on target "datetime/3,0,2/src/datetime/DateTime.hx:146: characters 28-110 : haxe.Int64 should be Float" 82 | 83 | Priority low. 84 | 85 | ## License 86 | 87 | [BSD-2-Clause](https://tldrlegal.com/license/bsd-2-clause-license-%28freebsd%29) 88 | -------------------------------------------------------------------------------- /metainfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "suncalc", 3 | "url" : "https://github.com/ypid/suncalc", 4 | "support": { 5 | "issues": "https://github.com/ypid/suncalc/issues", 6 | "docs": "https://ypid.github.io/suncalc/suncalc/SunCalc.html" 7 | }, 8 | "integration_testing": { 9 | "name": "Travis CI", 10 | "url": "https://travis-ci.org/ypid/suncalc", 11 | "img": "https://travis-ci.org/ypid/suncalc.svg?branch=master" 12 | }, 13 | "license": { 14 | "name": { 15 | "short": "BSD", 16 | "full": "BSD 2-clause \"Simplified\" License", 17 | "spdx_identifier": "BSD-2-Clause" 18 | }, 19 | "url": { 20 | "default": "https://tldrlegal.com/license/bsd-2-clause-license-%28freebsd%29", 21 | "tldrlegal": "https://tldrlegal.com/license/bsd-2-clause-license-%28freebsd%29", 22 | "spdx": "https://spdx.org/licenses/BSD-2-Clause.html", 23 | "wikipedia": "https://en.wikipedia.org/wiki/BSD_licenses#2-clause" 24 | } 25 | }, 26 | "description": "Calculate sun position, sunlight phases, moon position and lunar phase.", 27 | "version": "1.7.0", 28 | "releasenote": "First release of this port written in Haxe.", 29 | "target_info": { 30 | "haxe": { 31 | "target_env_name": "Haxe", 32 | "target_env_url": "https://en.wikipedia.org/wiki/Haxe", 33 | "package_platform": "haxelib", 34 | "package_url": "https://lib.haxe.org/p/suncalc", 35 | "package_badge": "https://img.shields.io/badge/Haxe-VERSION-blue.svg", 36 | "type": "native port", 37 | "source_file": "https://github.com/ypid/suncalc/blob/master/src/suncalc/SunCalc.hx" 38 | }, 39 | "js": { 40 | "target_env_name": "JavaScript/Node.JS", 41 | "target_env_url": "https://en.wikipedia.org/wiki/JavaScript", 42 | "package_platform": "NPM", 43 | "package_url": "https://www.npmjs.org/package/suncalc", 44 | "package_badge": "https://img.shields.io/npm/v/suncalc.svg", 45 | "repo_url": "https://github.com/mourner/suncalc", 46 | "type": "native port" 47 | }, 48 | "java": { 49 | "target_env_name": "Java", 50 | "target_env_url": "https://en.wikipedia.org/wiki/Java_%28programming_language%29", 51 | "repo_url": "https://github.com/mncaudill/SunCalc-Java", 52 | "type": "native port" 53 | }, 54 | "php": { 55 | "target_env_name": "PHP", 56 | "target_env_url": "https://en.wikipedia.org/wiki/PHP", 57 | "package_platform": "Packagist", 58 | "package_url": "https://packagist.org/packages/ypid/suncalc", 59 | "package_badge": "https://img.shields.io/packagist/v/ypid/suncalc.svg", 60 | "additional_badges": [ 61 | [], 62 | [ "PHPPackages Rank", "https://phppackages.org/p/ypid/suncalc/badge/rank.svg", "https://phppackages.org/p/ypid/suncalc" ], 63 | [ "PHPPackages Referenced By", "https://phppackages.org/p/ypid/suncalc/badge/referenced-by.svg", "https://phppackages.org/p/ypid/suncalc" ], 64 | [ "Packagist monthly downloads", "https://img.shields.io/packagist/dm/ypid/suncalc.svg", "$package_url" ], 65 | [ "Packagist daily downloads", "https://img.shields.io/packagist/dd/ypid/suncalc.svg", "$package_url" ], 66 | [ "Packagist total downloads", "https://img.shields.io/packagist/dt/ypid/suncalc.svg", "$package_url" ] 67 | ], 68 | "install_cmd": "composer require ypid/suncalc", 69 | "repo_url": "https://github.com/ypid/suncalc-php", 70 | "type": "target" 71 | }, 72 | "python": { 73 | "target_env_name": "Python", 74 | "target_env_url": "https://en.wikipedia.org/wiki/Python_%28programming_language%29", 75 | "repo_url": "https://github.com/Broham/suncalcPy", 76 | "type": "native port" 77 | }, 78 | "cpp": { 79 | "target_env_name": "C++", 80 | "target_env_url": "https://en.wikipedia.org/wiki/C%2B%2B" 81 | }, 82 | "neko": { 83 | "target_env_name": "NekoVM", 84 | "target_env_url": "https://en.wikipedia.org/wiki/Neko_%28programming_language%29" 85 | } 86 | }, 87 | "target_info_unsupported": { 88 | "swf": { 89 | "target_env_name": "Adobe Flash", 90 | "target_env_url": "https://en.wikipedia.org/wiki/Adobe_Flash" 91 | }, 92 | "as3": { 93 | "target_env_name": "ActionScript 3", 94 | "target_env_url": "https://en.wikipedia.org/wiki/ActionScript" 95 | } 96 | }, 97 | "target_info_haxe_unsupported": { 98 | "go": { 99 | "target_env_name": "Go", 100 | "target_env_url": "https://en.wikipedia.org/wiki/Go_%28programming_language%29", 101 | "repo_url": "https://github.com/mourner/suncalc-go", 102 | "type": "native port" 103 | }, 104 | "swift": { 105 | "target_env_name": "Swift", 106 | "target_env_url": "https://en.wikipedia.org/wiki/Swift_%28programming_language%29", 107 | "repo_url": "https://github.com/shanus/suncalc-swift", 108 | "type": "native port" 109 | }, 110 | "objective-c": { 111 | "target_env_name": "Objective-C", 112 | "target_env_url": "https://en.wikipedia.org/wiki/Objective-C", 113 | "repo_url": "https://github.com/swerdlow/suncalc-objective-c", 114 | "type": "native port" 115 | } 116 | }, 117 | "authors": [ 118 | { 119 | "name": "Robin Schneider", 120 | "nick": "ypid", 121 | "email": "ypid@riseup.net", 122 | "homepage": "http://ypid.de/", 123 | "role": "Maintainer, Rewrite in Haxe", 124 | "targets": [ "haxe", "php" ] 125 | }, 126 | { 127 | "name": "Vladimir Agafonkin", 128 | "nick": "mourner", 129 | "email": "agafonkin@gmail.com", 130 | "homepage": "http://agafonkin.com/en", 131 | "role": "Initial implementation in JavaScript", 132 | "targets": [ "js", "go", "role::upstream" ] 133 | } 134 | ], 135 | "dependencies": { 136 | "haxe": { 137 | "datetime": "", 138 | "version": "" 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## Variables {{{ 2 | LIBS ?= -lib datetime -lib version 3 | HMAIN ?= suncalc.SunCalc 4 | HFLAGS ?= -cp src 5 | HFLAGS_BUILD ?= $(HMAIN) $(HFLAGS) -D normal_build $(LIBS) 6 | 7 | SRC ?= $(wildcard src/suncalc/*.hx) 8 | TEST_SRC ?= $(wildcard test/*) 9 | TEMPLATE_SRC ?= $(wildcard templates/*.j2) 10 | 11 | TARGET_SUPPORT_LIBS ?= hxcpp hxjava hxnodejs 12 | DEV_LIBS ?= dox 13 | 14 | MAKE_OPTIONS ?= --no-print-directory 15 | ## }}} 16 | 17 | .PHONY: default 18 | default: docs 19 | 20 | .PHONY: check 21 | check: test check-diff 22 | 23 | ## Test and build for all supported targets. 24 | .PHONY: all 25 | all: test build dist 26 | 27 | ## make common targets {{{ 28 | 29 | .PHONY: .FORCE 30 | .FORCE: 31 | 32 | .PHONY: clean 33 | clean: 34 | rm -rf build 35 | 36 | ## }}} 37 | 38 | ## development setup {{{ 39 | .PHONY: dependencies-get 40 | dependencies-get: haxe-dependencies-get haxe-dependencies-target-get node-dependencies-get 41 | 42 | .PHONY: node-dependencies-get 43 | node-dependencies-get: package.json 44 | npm install 45 | 46 | .PHONY: haxe-dependencies-get 47 | haxe-dependencies-get: haxelib.json 48 | jq '.dependencies | keys | join("\n")' "$<" --raw-output | while read lib; do yes | haxelib install "$$lib"; done 49 | 50 | .PHONY: haxe-dependencies-target-get 51 | haxe-dependencies-target-get: Makefile 52 | for lib in $(TARGET_SUPPORT_LIBS) $(DEV_LIBS); do yes | haxelib install "$$lib"; done 53 | 54 | link-hooks: .git/hooks/pre-commit 55 | 56 | .git/hooks/%: scripts/%-hook 57 | ln --symbolic --force "../../$<" "$@" 58 | ## }}} 59 | 60 | ## development work {{{ 61 | 62 | ## Fix branches of submodules after cloning. 63 | .PHONY: fix-sub-branches 64 | fix-sub-branches: 65 | cd docs && git checkout gh-pages 66 | 67 | ## All files should be properly rebuild, nothing should be changed. 68 | .PHONY: check-diff 69 | check-diff: 70 | git submodule foreach "find . -type f -not -iregex '\(.*suncalc.*\|\./\.git.*\)' -print0 | xargs -0 git diff --exit-code" 71 | git diff --exit-code --ignore-submodules=dirty 72 | 73 | .PHONY: push 74 | push: check-diff 75 | git submodule foreach git push 76 | git push 77 | 78 | ## }}} 79 | 80 | ## build {{{ 81 | 82 | ## Build for all supported targets. 83 | .PHONY: build 84 | build: js \ 85 | java \ 86 | php \ 87 | python \ 88 | cpp \ 89 | neko \ 90 | swf \ 91 | as3 92 | 93 | ## }}} 94 | 95 | 96 | ## haxe {{{ 97 | .PHONY: haxe 98 | haxe: build/suncalc_js/suncalc.js 99 | 100 | haxelib.json: templates/haxelib.json.jq metainfo.json package.json 101 | jq --slurp --from-file $^ > "$@" 102 | 103 | includes/pre.all: templates/pre.all.jq metainfo.json package.json 104 | jq --slurp --from-file $^ --raw-output > "$@" 105 | 106 | .PHONY: build/suncalc_haxe 107 | build/suncalc_haxe: src/suncalc/SunCalc.hx includes/pre.all README.md haxelib.json 108 | mkdir --parents "$@/suncalc" 109 | cat includes/pre.all "$<" > "$@/suncalc/SunCalc.hx" 110 | cp haxelib.json README.md CONTRIBUTING.md LICENSE.md "$@" 111 | 112 | haxe-dist: build/suncalc_haxe 113 | haxelib submit "$<" 114 | 115 | ## }}} 116 | 117 | ## js {{{ 118 | .PHONY: js 119 | js: build/suncalc_js/suncalc.js 120 | 121 | .PHONY: node 122 | node: js 123 | 124 | build/test_suncalc.js: language/js.hxml $(SRC) $(TEST_SRC) 125 | haxe $(HFLAGS) $(LIBS) -lib hxnodejs -cp test -main Test -js "$@" 126 | node "$@" 127 | 128 | build/suncalc_js/suncalc.js: language/js.hxml $(SRC) $(TEST_SRC) includes/pre.all includes/js_pre.js includes/js_post.js 129 | mkdir --parents $(shell dirname $@) 130 | haxe "$<" $(HFLAGS_BUILD) -js build/suncalc.haxe.js 131 | cat includes/pre.all includes/js_pre.js build/suncalc.haxe.js includes/js_post.js > "$@" 132 | @echo 'Run native JS tests from mourner to ensure API compatibility.' 133 | node test/test.js >/dev/zero 134 | 135 | .PHONY: min 136 | min: build/suncalc_js/suncalc.min.js 137 | build/suncalc_js/suncalc.min.js: build/suncalc_js/suncalc.js 138 | uglifyjs "$<" --output "$@" --comments '/github.com/' --lint 139 | ## }}} 140 | 141 | ## java {{{ 142 | .PHONY: java 143 | java: build/suncalc_java 144 | 145 | build/test_suncalc_java: $(SRC) $(TEST_SRC) 146 | haxe $(HFLAGS) $(LIBS) -cp test -main Test -java "$@" 147 | java -jar "$@/Test.jar" 148 | 149 | .PHONY: build/suncalc_java 150 | build/suncalc_java: $(SRC) includes/pre.all 151 | haxe $(HFLAGS_BUILD) -java "$@" 152 | @cat includes/pre.all "$@/src/suncalc/SunCalc.java" > "$@/src/suncalc/SunCalc.java.tmp" 153 | @mv "$@/src/suncalc/SunCalc.java.tmp" "$@/src/suncalc/SunCalc.java" 154 | ## }}} 155 | 156 | ## php {{{ 157 | .PHONY: php 158 | php: ports/suncalc-php 159 | 160 | build/test_suncalc_php: $(SRC) $(TEST_SRC) 161 | haxe $(HFLAGS) $(LIBS) -cp test -main Test -php "$@" 162 | php "$@/index.php" 163 | 164 | ports/suncalc-php: $(SRC) includes/pre.all .FORCE 165 | haxe $(HFLAGS_BUILD) -php "$@" 166 | @echo ' "$@/lib/suncalc/SunCalc.class.php.tmp" 167 | @grep --invert-match --fixed-strings '> "$@/lib/suncalc/SunCalc.class.php.tmp" 168 | @mv "$@/lib/suncalc/SunCalc.class.php.tmp" "$@/lib/suncalc/SunCalc.class.php" 169 | cp CONTRIBUTING.md LICENSE.md "$@" 170 | 171 | ports/suncalc-php/composer.json: templates/composer.json.jq metainfo.json package.json 172 | jq --slurp --from-file $^ > "$@" 173 | 174 | ports/suncalc-php/README.md: metainfo.json $(TEMPLATE_SRC) build/doc.xml scripts/template 175 | scripts/template -i "$<" -t templates/ports_README.md.j2 -d build/doc.xml --key-value target=php > "$@" 176 | 177 | .PHONY: php-dist 178 | php-dist: ports/suncalc-php ports/suncalc-php/composer.json ports/suncalc-php/README.md 179 | 180 | ## }}} 181 | 182 | ## python {{{ 183 | .PHONY: python 184 | python: build/suncalc.py 185 | 186 | build/test_suncalc.py: $(SRC) $(TEST_SRC) 187 | haxe $(HFLAGS) $(LIBS) -cp test -main Test -python "$@" 188 | python3 "$@" 189 | 190 | build/suncalc.py: $(SRC) includes/pre.all 191 | haxe $(HFLAGS_BUILD) -python "$@" 192 | ## }}} 193 | 194 | ## cpp {{{ 195 | .PHONY: cpp 196 | cpp: build/suncalc_cpp 197 | 198 | build/test_suncalc_cpp: $(SRC) $(TEST_SRC) 199 | haxe $(HFLAGS) $(LIBS) -cp test -main Test -cpp "$@" 200 | $@/Test 201 | 202 | .PHONY: build/suncalc_cpp 203 | build/suncalc_cpp: $(SRC) includes/pre.all 204 | haxe $(HFLAGS_BUILD) -cpp "$@" 205 | @cat includes/pre.all "$@/src/suncalc/SunCalc.cpp" > "$@/src/suncalc/SunCalc.cpp.tmp" 206 | @mv "$@/src/suncalc/SunCalc.cpp.tmp" "$@/src/suncalc/SunCalc.cpp" 207 | ## }}} 208 | 209 | ## neko {{{ 210 | .PHONY: neko 211 | neko: build/suncalc.n 212 | 213 | build/test_suncalc.n: $(SRC) $(TEST_SRC) 214 | haxe $(HFLAGS) $(LIBS) -cp test -main Test -neko "$@" 215 | neko "$@" 216 | 217 | build/suncalc.n: $(SRC) includes/pre.all 218 | haxe $(HFLAGS_BUILD) -neko "$@" 219 | ## }}} 220 | 221 | ## swf {{{ 222 | .PHONY: swf 223 | swf: build/suncalc.swf 224 | 225 | build/suncalc.swf: $(SRC) 226 | haxe $(HFLAGS_BUILD) -swf "$@" 227 | ## }}} 228 | 229 | ## as3 {{{ 230 | .PHONY: as3 231 | as3: build/suncalc_as3 232 | 233 | build/suncalc_as3: $(SRC) 234 | haxe $(HFLAGS_BUILD) -as3 "$@" 235 | ## }}} 236 | 237 | ## cs {{{ 238 | .PHONY: cs 239 | cs: build/suncalc_cs 240 | 241 | build/suncalc_cs: $(SRC) includes/pre.all 242 | haxe $(HFLAGS_BUILD) -cs "$@" 243 | ## }}} 244 | 245 | 246 | ## docs {{{ 247 | build/doc.xml: $(SRC) 248 | haxe $(HMAIN) $(HFLAGS) $(LIBS) -xml "$@" 249 | 250 | .PHONY: docs 251 | docs: build/doc.xml includes/css_post.css README.md 252 | haxelib run dox -i "$<" -o "$@" 253 | cat includes/css_post.css >> "$@/styles.css" 254 | cd "$@" && git commit --all -m 'Auto commit without commit message.' && git push || : 255 | 256 | README.md: metainfo.json $(TEMPLATE_SRC) build/doc.xml scripts/template 257 | scripts/template -i "$<" -t templates/README.md.j2 -d build/doc.xml > "$@" 258 | ## }}} 259 | 260 | ## test {{{ 261 | .PHONY: test 262 | test: docs 263 | @echo 264 | @echo --------Testing JavaScript target. 265 | @$(MAKE) $(MAKE_OPTIONS) --always-make build/test_suncalc.js build/suncalc_js/suncalc.js 266 | @echo 267 | @echo -------- Testing Python target. 268 | @$(MAKE) $(MAKE_OPTIONS) --always-make build/test_suncalc.py 269 | @echo 270 | @echo --------Testing PHP target. 271 | @$(MAKE) $(MAKE_OPTIONS) --always-make build/test_suncalc_php 272 | @echo 273 | @echo -------- Testing C++ target. 274 | @$(MAKE) $(MAKE_OPTIONS) --always-make build/test_suncalc_cpp 275 | @echo 276 | @echo -------- Testing Java target. 277 | @$(MAKE) $(MAKE_OPTIONS) --always-make build/test_suncalc_java 278 | @echo 279 | @echo -------- Testing Neko target. 280 | @$(MAKE) $(MAKE_OPTIONS) --always-make build/test_suncalc.n 281 | ## }}} 282 | 283 | ## dist {{{ 284 | .PHONY: dist 285 | dist: php-dist 286 | 287 | .PHONY: dist-push 288 | dist-push: dist 289 | git submodule foreach '[ "$$(dirname $$name)" = "build" ] && git commit --all -m "Auto commit without commit message." && git push || :' 290 | ## }}} 291 | -------------------------------------------------------------------------------- /src/suncalc/SunCalc.hx: -------------------------------------------------------------------------------- 1 | package suncalc; 2 | 3 | #if !js 4 | import datetime.DateTime; 5 | #end 6 | 7 | /* 8 | * Only inline code/values when they are only used once to allow caching 9 | * optimization to happen for the different targets. 10 | */ 11 | 12 | /** 13 | The SunCalc module allows to calculate sun position, 14 | sunlight phases (times for sunrise, sunset, dusk, etc.), 15 | moon position and lunar phase for the given location and time. 16 | 17 | SunCalc was ported to [Haxe](https://en.wikipedia.org/wiki/Haxe) by [Robin `ypid` Schneider](https://github.com/ypid) to allow using it in a [planed rewrite of the opening hours library](https://github.com/opening-hours/opening_hours.js/issues/136). 18 | 19 | It is based on the [JavaScript implementation](https://github.com/mourner/suncalc) 20 | created by [Vladimir Agafonkin](http://agafonkin.com/en) ([@mourner](https://github.com/mourner)) 21 | as a part of the [SunCalc.net project](http://suncalc.net). 22 | 23 | Most calculations are based on the formulas given in the excellent Astronomy Answers articles 24 | about [position of the sun](http://aa.quae.nl/en/reken/zonpositie.html) 25 | and [the planets](http://aa.quae.nl/en/reken/hemelpositie.html). 26 | You can read about different twilight phases calculated by SunCalc 27 | in the [Twilight article on Wikipedia](https://en.wikipedia.org/wiki/Twilight). 28 | **/ 29 | 30 | @:expose 31 | class SunCalc { 32 | 33 | /** 34 | Version of the suncalc library written in Haxe. 35 | **/ 36 | public static var version(default, never):String = Version.getVersion(); 37 | 38 | /** 39 | Version of Haxe used to build the target port. 40 | **/ 41 | public static var version_haxe_compiler(default, never):String = Version.getHaxeCompilerVersion(); 42 | 43 | /* Date/time constants and conversions. {{{ */ 44 | private static var dayMs:Int = 1000 * 60 * 60 * 24; /* Used: toJulian, fromJulian, hoursLater */ 45 | private static var J1970:Int = 2440588; /* Used: toJulian, fromJulian */ 46 | private static var J2000:Int = 2451545; /* Used: toDays, solarTransitJ */ 47 | /* }}} */ 48 | 49 | /* General calculations for position. {{{ */ 50 | private static var rad:Float = Math.PI / 180; 51 | private static var e:Float = Math.PI / 180 * 23.4397; /* Obliquity of the Earth. */ 52 | /* }}} */ 53 | 54 | /* Helper functions. {{{ */ 55 | 56 | /* Used: 1*toDays */ 57 | private static inline function toJulian(date: Date):Float { 58 | return date.getTime() / dayMs - 0.5 + J1970; 59 | } 60 | 61 | /* Used: 4*getTimes */ 62 | private static function fromJulian(j: Float):Date { 63 | return Date.fromTime((j + 0.5 - J1970) * dayMs); 64 | } 65 | 66 | /* Used: getPosition, getTimes, getMoonPosition, getMoonIllumination */ 67 | private static function toDays(date: Date):Float { 68 | return toJulian(date) - J2000; 69 | } 70 | 71 | /* Used: sunCoords, moonCoords */ 72 | private static function rightAscension(l, b):Float { 73 | return Math.atan2( 74 | Math.sin(l) * Math.cos(e) - Math.tan(b) * Math.sin(e), 75 | Math.cos(l)); 76 | } 77 | 78 | /* Used: sunCoords, moonCoords, getTimes */ 79 | private static function declination(l, b):Float { 80 | return Math.asin(Math.sin(b) * Math.cos(e) + Math.cos(b) * Math.sin(e) * Math.sin(l)); 81 | } 82 | 83 | /* Used: getPosition, getMoonPosition */ 84 | private static function azimuth(H, phi, dec):Float { 85 | return Math.atan2(Math.sin(H), Math.cos(H) * Math.sin(phi) - Math.tan(dec) * Math.cos(phi)); 86 | } 87 | 88 | /* Used: getPosition, getMoonPosition */ 89 | private static function altitude(H, phi, dec):Float { 90 | return Math.asin(Math.sin(phi) * Math.sin(dec) + Math.cos(phi) * Math.cos(dec) * Math.cos(H)); 91 | } 92 | 93 | /* Used: getPosition, getMoonPosition */ 94 | private static function siderealTime(d:Float, lw:Float):Float { 95 | return rad * (280.16 + 360.9856235 * d) - lw; 96 | } 97 | 98 | /* }}} */ 99 | 100 | /* General sun calculations. {{{ */ 101 | 102 | /* Used: sunCoords, getTimes */ 103 | private static function solarMeanAnomaly(d:Float):Float { 104 | return rad * (357.5291 + 0.98560028 * d); 105 | } 106 | 107 | /* Used: sunCoords, getTimes */ 108 | private static function eclipticLongitude(M):Float { 109 | var C = rad * (1.9148 * Math.sin(M) + 0.02 * Math.sin(2 * M) + 0.0003 * Math.sin(3 * M)), // equation of center 110 | P = rad * 102.9372; // perihelion of the Earth 111 | 112 | return M + C + P + Math.PI; 113 | } 114 | 115 | /* Used: getPosition, getMoonPosition */ 116 | private static function sunCoords(d) { 117 | var M = solarMeanAnomaly(d), 118 | L = eclipticLongitude(M); 119 | 120 | return { 121 | dec: declination(L, 0), 122 | ra: rightAscension(L, 0) 123 | }; 124 | } 125 | 126 | /* public: getPosition {{{ */ 127 | /** 128 | Returns an object with the following properties: 129 | 130 | * `altitude`: Sun altitude above the horizon in radians, 131 | e.g. `0` at the horizon and `PI/2` at the zenith (straight over your head). 132 | 133 | * `azimuth`: Sun azimuth in radians (direction along the horizon, measured from south to west), 134 | e.g. `0` is south and `PI * 3/4` is northwest. 135 | 136 | **/ 137 | public static function getPosition(date:Date, lat:Float, lng:Float) { 138 | var lw = rad * -lng, 139 | phi = rad * lat, 140 | d = toDays(date), 141 | 142 | c = sunCoords(d), 143 | H = siderealTime(d, lw) - c.ra; 144 | 145 | return { 146 | azimuth: azimuth(H, phi, c.dec), 147 | altitude: altitude(H, phi, c.dec) 148 | }; 149 | }; 150 | 151 | /** 152 | Contains all currently defined times. 153 | **/ 154 | public static var times: Array> = [ 155 | [-0.833, 'sunrise', 'sunset' ], 156 | [ -0.3, 'sunriseEnd', 'sunsetStart' ], 157 | [ -6, 'dawn', 'dusk' ], 158 | [ -12, 'nauticalDawn', 'nauticalDusk'], 159 | [ -18, 'nightEnd', 'night' ], 160 | [ 6, 'goldenHourEnd', 'goldenHour' ], 161 | ]; 162 | /* }}} */ 163 | 164 | /** 165 | Adds a custom time to the `times` configuration. 166 | **/ 167 | public static function addTime(angle:Float, riseName:String, setName:String) { 168 | times.push([angle, riseName, setName]); 169 | }; 170 | 171 | // calculations for sun times 172 | private static var J0 = 0.0009; 173 | 174 | /* Used: 1*getTimes */ 175 | private static inline function julianCycle(d:Float, lw:Float) { 176 | return Math.round(d - J0 - lw / (2 * Math.PI)); 177 | } 178 | /* Used: 1*getSetJ, 1*getTimes */ 179 | private static function approxTransit(Ht:Float, lw, n) { 180 | return J0 + (Ht + lw) / (2 * Math.PI) + n; 181 | } 182 | /* Used: 1*getSetJ, 1*getTimes */ 183 | private static function solarTransitJ(ds:Float, M:Float, L:Float) { 184 | return J2000 + ds + 0.0053 * Math.sin(M) - 0.0069 * Math.sin(2 * L); 185 | } 186 | 187 | /* Used: 1*getSetJ */ 188 | private static inline function hourAngle(h, phi, d) { 189 | return Math.acos((Math.sin(h) - Math.sin(phi) * Math.sin(d)) / (Math.cos(phi) * Math.cos(d))); 190 | } 191 | 192 | /* Returns set time for the given sun altitude. 193 | * Used: 1*getTimes 194 | * Can not be inlined as of Haxe 3.2.1. 195 | */ 196 | private static function getSetJ(h, lw, phi, dec, n, M, L) { 197 | var w = hourAngle(h, phi, dec), 198 | a = approxTransit(w, lw, n); 199 | return solarTransitJ(a, M, L); 200 | } 201 | 202 | /* Calculates sun times for a given date and latitude/longitude. {{{ */ 203 | /** 204 | 205 | Returns an object with the following properties (each is a `Date` object): 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 |
PropertyDescription
sunrisesunrise (top edge of the sun appears on the horizon)
sunriseEndsunrise ends (bottom edge of the sun touches the horizon)
goldenHourEndmorning golden hour (soft light, best time for photography) ends
solarNoonsolar noon (sun is in the highest position)
goldenHourevening golden hour starts
sunsetStartsunset starts (bottom edge of the sun touches the horizon)
sunsetsunset (sun disappears below the horizon, evening civil twilight starts)
duskdusk (evening nautical twilight starts)
nauticalDusknautical dusk (evening astronomical twilight starts)
nightnight starts (dark enough for astronomical observations)
nadirnadir (darkest moment of the night, sun is in the lowest position)
nightEndnight ends (morning astronomical twilight starts)
nauticalDawnnautical dawn (morning nautical twilight starts)
dawndawn (morning nautical twilight ends, morning civil twilight starts)
270 | 271 | **/ 272 | public static function getTimes(date:Date, lat:Float, lng:Float):Map { 273 | var lw = rad * -lng, 274 | phi = rad * lat, 275 | 276 | d = toDays(date), 277 | n = julianCycle(d, lw), 278 | ds:Float = approxTransit(0, lw, n), 279 | 280 | M = solarMeanAnomaly(ds), 281 | L = eclipticLongitude(M), 282 | dec = declination(L, 0), 283 | 284 | Jnoon = solarTransitJ(ds, M, L), 285 | 286 | i, len, time, Jset, Jrise; 287 | 288 | var result = new Map(); 289 | result['solarNoon'] = fromJulian(Jnoon); 290 | result['nadir'] = fromJulian(Jnoon - 0.5); 291 | 292 | for (time in times) { 293 | 294 | Jset = getSetJ(time[0] * rad, lw, phi, dec, n, M, L); 295 | Jrise = Jnoon - (Jset - Jnoon); 296 | 297 | result[time[1]] = fromJulian(Jrise); 298 | result[time[2]] = fromJulian(Jset); 299 | } 300 | 301 | #if (normal_build && js) 302 | return untyped result.h; 303 | #else 304 | return result; 305 | #end 306 | }; /* }}} */ 307 | 308 | /* }}} */ 309 | 310 | /* Moon position calculations. {{{ 311 | * Based on http://aa.quae.nl/en/reken/hemelpositie.html formulas. 312 | */ 313 | 314 | /** 315 | Geocentric ecliptic coordinates of the moon. 316 | **/ 317 | private static function moonCoords(d:Float) { 318 | 319 | var L = rad * (218.316 + 13.176396 * d), /* Ecliptic longitude. */ 320 | M = rad * (134.963 + 13.064993 * d), /* Mean anomaly. */ 321 | F = rad * (93.272 + 13.229350 * d), /* Mean distance. */ 322 | 323 | longitude = L + rad * 6.289 * Math.sin(M), 324 | latitude = rad * 5.128 * Math.sin(F), 325 | dt = 385001 - 20905 * Math.cos(M); /* Distance to the moon in km. */ 326 | 327 | return { 328 | ra: rightAscension(longitude, latitude), 329 | dec: declination(longitude, latitude), 330 | dist: dt 331 | }; 332 | } 333 | 334 | /** 335 | Returns an object with the following properties: 336 | 337 | - `altitude`: Moon altitude above the horizon in radians. 338 | 339 | - `azimuth`: Moon azimuth in radians. 340 | 341 | - `distance`: Distance to moon in kilometers. 342 | **/ 343 | public static function getMoonPosition (date:Date, lat:Float, lng:Float) { 344 | var lw = rad * -lng, 345 | phi = rad * lat, 346 | d:Float = toDays(date), 347 | 348 | c = moonCoords(d), 349 | H = siderealTime(d, lw) - c.ra, 350 | h:Float = altitude(H, phi, c.dec); 351 | 352 | // altitude correction for refraction 353 | h = h + rad * 0.017 / Math.tan(h + rad * 10.26 / (h + rad * 5.10)); 354 | 355 | return { 356 | azimuth: azimuth(H, phi, c.dec), 357 | altitude: h, 358 | distance: c.dist 359 | }; 360 | }; 361 | 362 | /* Calculations for illumination parameters of the moon. {{{ 363 | * Based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and 364 | * Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. 365 | */ 366 | /** 367 | 368 | Returns an object with the following properties: 369 | 370 | - `fraction`: Illuminated fraction of the moon; varies from `0.0` (new moon) to `1.0` (full moon). 371 | 372 | - `phase`: Moon phase; varies from `0.0` to `1.0`, described below. 373 | 374 | - `angle`: Midpoint angle in radians of the illuminated limb of the moon reckoned eastward from the north point of the disk; 375 | the moon is waxing if the angle is negative, and waning if positive. 376 | 377 | Moon phase value should be interpreted like this: 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 |
PhaseName
0New Moon, Waxing Crescent
0.25First Quarter, Waxing Gibbous
0.5Full Moon, Waning Gibbous
0.75Last Quarter, Waning Crescent
402 | 403 | **/ 404 | public static function getMoonIllumination(date:Date) { 405 | var d:Float = toDays(date), 406 | s = sunCoords(d), 407 | m = moonCoords(d), 408 | 409 | astronomical_unit:Int = 149598000, 410 | /* Roughly the distance from the Earth to the Sun in km. */ 411 | 412 | phi = Math.acos(Math.sin(s.dec) * Math.sin(m.dec) + Math.cos(s.dec) * Math.cos(m.dec) * Math.cos(s.ra - m.ra)), 413 | inc = Math.atan2(astronomical_unit * Math.sin(phi), m.dist - astronomical_unit * Math.cos(phi)), 414 | angle = Math.atan2(Math.cos(s.dec) * Math.sin(s.ra - m.ra), Math.sin(s.dec) * Math.cos(m.dec) - 415 | Math.cos(s.dec) * Math.sin(m.dec) * Math.cos(s.ra - m.ra)); 416 | 417 | return { 418 | fraction: (1 + Math.cos(inc)) / 2, 419 | phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI, 420 | angle: angle 421 | }; 422 | }; /* }}} */ 423 | 424 | /* Calculations for moon rise/set times. {{{ 425 | * Based on http://www.stargazing.net/kepler/moonrise.html article. 426 | */ 427 | 428 | private static function hoursLater(date:Date, h:Dynamic) { 429 | return Date.fromTime(date.getTime() + h * dayMs / 24); 430 | } 431 | 432 | /** 433 | Returns an object with the following properties: 434 | 435 | - `rise`: Moon rise time as `Date`. 436 | 437 | - `set`: Moon set time as `Date`. 438 | 439 | - `alwaysUp`: `true` if the moon never rises/sets and is always _above_ the horizon during the day. 440 | 441 | - `alwaysDown`: `true` if the moon is always _below_ the horizon. 442 | 443 | By default, it will search for moon rise and set during local user's day (from 0 to 24 hours). 444 | If `inUTC` is set to true, it will instead search the specified date from 0 to 24 UTC hours. 445 | **/ 446 | public static function getMoonTimes(date:Date, lat:Float, lng:Float, inUTC:Bool = false) { 447 | if (inUTC) { 448 | #if js 449 | untyped date.setUTCHours(0, 0, 0, 0); 450 | #else 451 | date = DateTime.fromDate(date).utc(); 452 | date = new Date( date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0 ); 453 | #end 454 | } else { 455 | #if js 456 | untyped date.setHours(0, 0, 0, 0); 457 | #else 458 | date = new Date( date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0 ); 459 | #end 460 | } 461 | 462 | var hc:Float = 0.133 * rad, 463 | h0:Float = getMoonPosition(date, lat, lng).altitude - hc, 464 | h1:Float, h2:Float, 465 | rise:Float = 0.0, 466 | set:Float = 0.0, 467 | a:Float, b:Float, xe:Float, 468 | ye:Float = 0.0, 469 | d:Float, 470 | roots:Int, 471 | x1:Float = 0.0, 472 | x2:Float = 0.0, 473 | dx:Float; 474 | 475 | /* Go in 2-hour chunks, each time seeing if a 3-point quadratic curve 476 | * crosses zero (which means rise or set) */ 477 | var i = 1; 478 | while (i <= 24) { 479 | h1 = getMoonPosition(hoursLater(date, i), lat, lng).altitude - hc; 480 | h2 = getMoonPosition(hoursLater(date, i + 1), lat, lng).altitude - hc; 481 | 482 | a = (h0 + h2) / 2 - h1; 483 | b = (h2 - h0) / 2; 484 | xe = -b / (2 * a); 485 | ye = (a * xe + b) * xe + h1; 486 | d = b * b - 4 * a * h1; 487 | 488 | roots = 0; 489 | 490 | if (d >= 0) { 491 | dx = Math.sqrt(d) / (Math.abs(a) * 2); 492 | x1 = xe - dx; 493 | x2 = xe + dx; 494 | if (Math.abs(x1) <= 1) roots++; 495 | if (Math.abs(x2) <= 1) roots++; 496 | if (x1 < -1) x1 = x2; 497 | } 498 | 499 | if (roots == 1) { 500 | if (h0 < 0) rise = i + x1; 501 | else set = i + x1; 502 | } else if (roots == 2) { 503 | rise = i + (ye < 0 ? x2 : x1); 504 | set = i + (ye < 0 ? x1 : x2); 505 | } 506 | 507 | if (rise != 0 && set != 0) { 508 | break; 509 | } 510 | 511 | h0 = h2; 512 | 513 | i += 2; 514 | } 515 | 516 | var result = new Map(); 517 | 518 | if (rise != 0) result['rise'] = hoursLater(date, rise); 519 | if (set != 0) result['set'] = hoursLater(date, set); 520 | 521 | if (rise == 0 && set == 0) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; 522 | 523 | #if (normal_build && js) 524 | return untyped result.h; 525 | #else 526 | return result; 527 | #end 528 | }; /* }}} */ 529 | 530 | /* }}} */ 531 | 532 | static function main() { 533 | } 534 | } 535 | --------------------------------------------------------------------------------